summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-05-02 19:55:47 -0400
committerRay Strode <rstrode@redhat.com>2007-05-02 19:55:47 -0400
commite129869c6bbde326954915f560c5d26750cfdf9a (patch)
tree124ccd318fadd589400b467609339d192c1cdc49
parentb690a4fd2c1a0976bb88b210ce96fadac705125f (diff)
just chugging along on the transaction stuff...
-rw-r--r--src/pop-transaction.c422
-rw-r--r--src/pop-transaction.h4
2 files changed, 275 insertions, 151 deletions
diff --git a/src/pop-transaction.c b/src/pop-transaction.c
index 5fc1c77..0e2ae24 100644
--- a/src/pop-transaction.c
+++ b/src/pop-transaction.c
@@ -27,7 +27,14 @@
#include <glib-object.h>
#include <glib/gi18n.h>
-typedef enum _PopTransactionState PopTransactionState;
+typedef enum
+{
+ POP_TRANSACTION_STATE_UNCOMMITED = 0,
+ POP_TRANSACTION_STATE_COMMITED,
+ POP_TRANSACTION_STATE_PROCESSING,
+ POP_TRANSACTION_STATE_ROLLING_BACK,
+ POP_TRANSACTION_STATE_FINISHED,
+} PopTransactionState;
struct _PopTransactionPrivate
{
@@ -44,14 +51,6 @@ struct _PopTransactionPrivate
guint wait_id;
};
-enum _PopTransactionState
-{
- POP_TRANSACTION_STATE_UNCOMMITED = 0,
- POP_TRANSACTION_STATE_COMMITED,
- POP_TRANSACTION_STATE_PROCESSING,
- POP_TRANSACTION_STATE_ROLLING_BACK,
-}
-
typedef struct
{
PopActionProcessFunc process_func;
@@ -73,6 +72,7 @@ static void pop_transaction_set_property (GObject * object,
static void pop_transaction_get_property (GObject * object,
guint prop_id,
GValue * value, GParamSpec * pspec);
+static void pop_transaction_fail (PopTransaction *transaction);
enum
{
@@ -85,7 +85,6 @@ enum
PROCESS = 0,
WAIT,
RESUME,
- CANCELED,
NUMBER_OF_SIGNALS
};
@@ -137,13 +136,6 @@ pop_transaction_class_install_signals (PopTransactionClass *
G_STRUCT_OFFSET (PopTransactionClass, resume),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
transaction_class->resume = NULL;
-
- pop_transaction_signals[CANCELED] =
- g_signal_new ("canceled", G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PopTransactionClass, canceled),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
- transaction_class->canceled = NULL;
}
static void
@@ -158,7 +150,7 @@ pop_transaction_class_install_properties (PopTransactionClass *transaction_class
param_spec = g_param_spec_pointer ("completion-closure", _("Completion Closure"),
_("Closure to invoke when transaction is complete"),
- NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
g_object_class_install_property (object_class, PROP_COMPLETION_CLOSURE, param_spec);
}
@@ -168,6 +160,8 @@ pop_transaction_init (PopTransaction *transaction)
transaction->priv = G_TYPE_INSTANCE_GET_PRIVATE (transaction,
POP_TYPE_TRANSACTION,
PopTransactionPrivate);
+ transaction->priv->actions = g_queue_new ();
+ transaction->priv->status = POP_TRANSACTION_STATUS_NOT_FINISHED;
}
static void
@@ -180,6 +174,8 @@ pop_transaction_finalize (GObject * object)
parent_class = G_OBJECT_CLASS (pop_transaction_parent_class);
+ g_queue_free (transaction->priv->actions);
+
if (parent_class->finalize != NULL)
parent_class->finalize (object);
}
@@ -247,12 +243,13 @@ pop_transaction_error_quark (void)
PopTransaction *
pop_transaction_new (PopTransactionCompleteFunc complete_func,
- gpointer user_data);
+ gpointer user_data)
{
PopTransaction *transaction;
GClosure *closure;
closure = g_cclosure_new (G_CALLBACK (complete_func), user_data, NULL);
+ g_closure_set_marshal (closure, g_cclosure_marshal_VOID__INT);
transaction = g_object_new (POP_TYPE_TRANSACTION,
"completion-closure", closure,
@@ -267,7 +264,7 @@ pop_action_new (PopActionProcessFunc action_process_func,
{
PopAction *action;
- action = g_slice_new (PopAction);
+ action = g_slice_new0 (PopAction);
action->process_func = action_process_func;
action->rollback_func = action_rollback_func;
@@ -278,7 +275,7 @@ pop_action_new (PopActionProcessFunc action_process_func,
static void
pop_action_free (PopAction *action)
{
- g_slice_free (action);
+ g_slice_free (PopAction, action);
}
void
@@ -325,126 +322,153 @@ pop_transaction_wait_for_timeout (PopTransaction *transaction,
g_source_unref (source);
}
-static gboolean
-pop_transaction_wait_callback (PopTransaction *transaction)
+static guint
+pop_transaction_call_on_idle (PopTransaction *transaction,
+ PopTransactionIdleFunc callback)
{
-
- switch (transaction->priv->state)
- {
- case POP_TRANSACTION_STATE_PROCESSING:
- pop_transaction_process_on_idle (transaction);
- break;
+ GSource *source;
+ guint idle_id;
- case POP_TRANSACTION_STATE_ROLLING_BACK:
- pop_transaction_rollback_on_idle (transaction);
- break;
- }
+ source = g_idle_source_new ();
+ g_object_ref (transaction);
+ g_source_set_callback (source, (GSourceFunc) callback, transaction,
+ (GDestroyNotify) g_object_unref);
- g_source_remove (transaction->priv->wait_id);
- transaction->priv->wait_id = 0;
+ idle_id = g_source_attach (source, transaction->priv->context);
+ g_source_unref (source);
- return FALSE;
+ return idle_id;
}
static gboolean
-pop_transaction_is_active (PopTransaction *transaction)
+pop_transaction_is_at_first_action (PopTransaction *transaction)
{
- return transaction->priv->state >= POP_TRANSACTION_STATE_PROCESSING;
-}
+ GList *first_action_node;
-void
-pop_transaction_wait_for_source (PopTransaction *transaction,
- GSource *source)
-{
- g_return_if_fail (POP_IS_TRANSACTION (transaction));
- g_return_if_fail (pop_transaction_is_active (transaction));
-
- switch (transaction->priv->state)
- {
- case POP_TRANSACTION_STATE_PROCESSING:
- g_assert (transaction->priv->process_idle_id != 0);
- g_assert (transaction->priv->rollback_idle_id == 0);
- g_source_remove (transaction->priv->process_idle_id);
- transaction->priv->process_idle_id = 0;
- break;
-
- case POP_TRANSACTION_STATE_ROLLING_BACK:
- g_assert (transaction->priv->rollback_idle_id != 0);
- g_assert (transaction->priv->process_idle_id == 0);
- g_source_remove (transaction->priv->rollback_idle_id);
- transaction->priv->rollback_idle_id = 0;
- break;
+ g_assert (transaction->priv->current_action_node != NULL);
- default:
- g_assert_not_reached ();
- break;
- }
-
- g_source_set_callback (source, (GSourceFunc) pop_transaction_wait_callback, transaction, NULL);
- transaction->priv->wait_id = g_source_attach (source,
- transaction->priv->context);
- g_source_unref (source);
+ first_action_node = g_queue_peek_head_link (transaction->priv->actions);
+ return first_action_node == transaction->priv->current_action_node;
}
static gboolean
-pop_transaction_is_attached (PopTransaction *transaction)
+pop_transaction_rewind (PopTransaction *transaction)
{
- return transaction->priv->context != NULL;
+ if (pop_transaction_is_at_first_action (transaction))
+ return FALSE;
+
+ transaction->priv->current_action_node =
+ transaction->priv->current_action_node->prev;
+
+ return TRUE;
}
-void
-pop_transaction_attach (PopTransaction *transaction,
- GMainContext *context)
+static gboolean
+pop_transaction_seek_forward (PopTransaction *transaction)
{
- g_return_if_fail (POP_IS_TRANSACTION (transaction));
- g_return_if_fail (!pop_transaction_is_attached (transaction));
+ g_assert (transaction->priv->current_action_node != NULL);
- transaction->priv->context = g_main_context_ref (context);
+ transaction->priv->current_action_node =
+ transaction->priv->current_action_node->next;
+
+ return transaction->priv->current_action_node != NULL;
}
static void
-pop_transaction_finish (PopTransaction *transaction)
+pop_transaction_complete (PopTransaction *transaction)
{
- transaction->priv->status = POP_TRANSACTION_STATUS_FINISHED;
-}
+ GValue arguments[2] = { 0 };
-static guint
-pop_transaction_call_on_idle (PopTransaction *transaction,
- PopTransactionIdleFunc callback)
-{
- guint idle_id;
+ transaction->priv->state = POP_TRANSACTION_STATE_FINISHED;
- source = g_idle_source_new ();
- g_source_set_callback (source, (GSourceFunc) callback, transaction, NULL);
+ /* The below is a cryptic way of saying
+ * transaction_complete_func (transaction, transaction->priv->status, user_data);
+ */
+ g_value_init (&arguments[0], POP_TYPE_TRANSACTION);
+ g_value_set_instance (&arguments[0], transaction);
- g_source_remove (transaction->priv->idle_id);
- idle_id = g_source_attach (source, transaction->priv->context);
- g_source_unref (source);
+ g_value_init (&arguments[1], G_TYPE_INT);
+ g_value_set_int (&arguments[1], transaction->priv->status);
- return idle_id;
+ g_object_ref (transaction);
+ g_closure_invoke (transaction->priv->completion_closure,
+ NULL, G_N_ELEMENTS (arguments), arguments, NULL);
+ g_object_unref (transaction);
}
static gboolean
-pop_transaction_rewind (PopTransaction *transaction)
+pop_transaction_process_current_action_and_seek_forward (PopTransaction *transaction)
{
+ PopAction *action;
+ PopActionProcessStatus status;
+ gboolean should_continue;
+
g_assert (transaction->priv->current_action_node != NULL);
- transaction->priv->current_action_node =
- transaction->priv->current_action_node->prev;
+ if (transaction->priv->state == POP_TRANSACTION_STATE_COMMITED)
+ {
+ transaction->priv->state = POP_TRANSACTION_STATE_PROCESSING;
+ g_signal_emit (transaction, pop_transaction_signals[PROCESS], 0);
+ }
+
+ g_assert (transaction->priv->state == POP_TRANSACTION_STATE_PROCESSING);
+
+ action = (PopAction *) transaction->priv->current_action_node->data;
+
+ if (action->process_func != NULL)
+ status = action->process_func (transaction);
+ else
+ status = POP_ACTION_PROCESS_STATUS_FINISHED;
+
+ switch (status)
+ {
+ case POP_ACTION_PROCESS_STATUS_NOT_FINISHED:
+ should_continue = TRUE;
+ break;
+
+ case POP_ACTION_PROCESS_STATUS_FINISHED:
+ if (!pop_transaction_seek_forward (transaction))
+ {
+ transaction->priv->status = POP_TRANSACTION_STATUS_FINISHED;
+ pop_transaction_complete (transaction);
+ should_continue = FALSE;
+ }
+ else
+ should_continue = TRUE;
+ break;
+
+ default:
+ g_warning ("status %d is not valid processing status\n", (int) status);
+
+ /* Fall through and fail the action because it's not behaving
+ */
+
+ case POP_ACTION_PROCESS_STATUS_FAILED:
+ should_continue = FALSE;
+ pop_transaction_fail (transaction);
+ break;
+ }
+
+
+ if (!should_continue)
+ {
+ g_source_remove (transaction->priv->process_idle_id);
+ transaction->priv->process_idle_id = 0;
+ }
- return transaction->priv->current_action_node == NULL;
+ return should_continue;
}
-static gboolean
-pop_transaction_seek_forward (PopTransaction *transaction)
+static void
+pop_transaction_process_on_idle (PopTransaction *transaction)
{
- g_assert (transaction->priv->current_action_node != NULL);
-
- transaction->priv->current_action_node =
- transaction->priv->current_action_node->next;
+ transaction->priv->current_action_node =
+ g_queue_peek_head_link (transaction->priv->actions);
- return transaction->priv->current_action_node == NULL;
+ transaction->priv->process_idle_id =
+ pop_transaction_call_on_idle (transaction,
+ pop_transaction_process_current_action_and_seek_forward);
}
static gboolean
@@ -463,7 +487,10 @@ pop_transaction_rollback_current_action_and_rewind (PopTransaction *transaction)
action = (PopAction *) transaction->priv->current_action_node->data;
- status = action->rollback_func (transaction);
+ if (action->rollback_func != NULL)
+ status = action->rollback_func (transaction);
+ else
+ status = POP_ACTION_ROLLBACK_STATUS_FINISHED;
switch (status)
{
@@ -486,7 +513,12 @@ pop_transaction_rollback_current_action_and_rewind (PopTransaction *transaction)
}
if (!should_continue)
- pop_transaction_finish (transaction);
+ {
+ g_source_remove (transaction->priv->rollback_idle_id);
+ transaction->priv->rollback_idle_id = 0;
+
+ pop_transaction_complete (transaction);
+ }
return should_continue;
}
@@ -502,70 +534,100 @@ pop_transaction_rollback_on_idle (PopTransaction *transaction)
}
static void
+pop_transaction_rollback_and_complete (PopTransaction *transaction)
+{
+ if (pop_transaction_is_at_first_action (transaction))
+ {
+ pop_transaction_complete (transaction);
+ return;
+ }
+
+ pop_transaction_rollback_on_idle (transaction);
+}
+
+static void
pop_transaction_fail (PopTransaction *transaction)
{
+
transaction->priv->status = POP_TRANSACTION_STATUS_FAILED;
- pop_transaction_rollback_on_idle (transaction);
+ pop_transaction_rollback_and_complete (transaction);
}
static gboolean
-pop_transaction_process_current_action_and_seek_forward (PopTransaction *transaction)
+pop_transaction_wait_callback (PopTransaction *transaction)
{
- PopAction *action;
- PopActionProcessStatus status;
- gboolean should_continue;
+
+ switch (transaction->priv->state)
+ {
+ case POP_TRANSACTION_STATE_PROCESSING:
+ pop_transaction_process_on_idle (transaction);
+ break;
- g_assert (transaction->priv->current_action_node != NULL);
+ case POP_TRANSACTION_STATE_ROLLING_BACK:
+ pop_transaction_rollback_on_idle (transaction);
+ break;
+ }
- if (transaction->priv->state == POP_TRANSACTION_STATE_COMMITED)
- transaction->priv->state = POP_TRANSACTION_STATE_PROCESSING;
+ g_source_remove (transaction->priv->wait_id);
+ transaction->priv->wait_id = 0;
- g_assert (transaction->priv->state == POP_TRANSACTION_STATE_PROCESSING);
+ g_signal_emit (transaction, pop_transaction_signals[RESUME], 0);
- action = (PopAction *) transaction->priv->current_action_node->data;
+ return FALSE;
+}
- status = action->process_func (transaction);
+static gboolean
+pop_transaction_is_active (PopTransaction *transaction)
+{
+ return transaction->priv->state >= POP_TRANSACTION_STATE_PROCESSING;
+}
- switch (status)
- {
- case POP_ACTION_PROCESS_STATUS_NOT_FINISHED:
- should_continue = TRUE;
- break;
+void
+pop_transaction_wait_for_source (PopTransaction *transaction,
+ GSource *source)
+{
+ g_return_if_fail (POP_IS_TRANSACTION (transaction));
+ g_return_if_fail (pop_transaction_is_active (transaction));
- case POP_ACTION_PROCESS_STATUS_FINISHED:
- if (!pop_transaction_seek_forward (transaction))
- {
- pop_transaction_finish (transaction);
- should_continue = FALSE;
- }
- else
- should_continue = TRUE;
+ switch (transaction->priv->state)
+ {
+ case POP_TRANSACTION_STATE_PROCESSING:
+ g_assert (transaction->priv->process_idle_id != 0);
+ g_assert (transaction->priv->rollback_idle_id == 0);
+ g_source_remove (transaction->priv->process_idle_id);
+ transaction->priv->process_idle_id = 0;
break;
- default:
- g_warning ("status %d is not valid processing status\n", (int) status);
-
- /* Fall through and fail the action because it's not behaving
- */
-
- case POP_ACTION_PROCESS_STATUS_FAILED:
- should_continue = FALSE;
- pop_transaction_fail (transaction);
+ case POP_TRANSACTION_STATE_ROLLING_BACK:
+ g_assert (transaction->priv->rollback_idle_id != 0);
+ g_assert (transaction->priv->process_idle_id == 0);
+ g_source_remove (transaction->priv->rollback_idle_id);
+ transaction->priv->rollback_idle_id = 0;
break;
}
+
+ g_source_set_callback (source, (GSourceFunc) pop_transaction_wait_callback, transaction, NULL);
+ transaction->priv->wait_id = g_source_attach (source,
+ transaction->priv->context);
+ g_source_unref (source);
- return should_continue;
+ g_signal_emit (transaction, pop_transaction_signals[WAIT], 0);
}
-static void
-pop_transaction_process_on_idle (PopTransaction *transaction)
+static gboolean
+pop_transaction_is_attached (PopTransaction *transaction)
{
- transaction->priv->current_action_node =
- g_queue_peek_head_link (transaction->priv->actions);
+ return transaction->priv->context != NULL;
+}
- transaction->priv->process_idle_id =
- pop_transaction_call_on_idle (transaction,
- pop_transaction_process_current_action_and_seek_forward);
+void
+pop_transaction_attach (PopTransaction *transaction,
+ GMainContext *context)
+{
+ g_return_if_fail (POP_IS_TRANSACTION (transaction));
+ g_return_if_fail (!pop_transaction_is_attached (transaction));
+
+ transaction->priv->context = g_main_context_ref (context);
}
static gboolean
@@ -585,7 +647,7 @@ pop_transaction_commit (PopTransaction *transaction)
{
g_return_if_fail (POP_IS_TRANSACTION (transaction));
g_return_if_fail (!pop_transaction_is_empty (transaction));
- g_return_if_fail (pop_transaction_is_commited (transaction));
+ g_return_if_fail (!pop_transaction_is_committed (transaction));
pop_transaction_process_on_idle (transaction);
@@ -601,7 +663,7 @@ pop_transaction_cancel (PopTransaction *transaction)
return FALSE;
transaction->priv->status = POP_TRANSACTION_STATUS_CANCELED;
- pop_transaction_rollback_on_idle (transaction);
+ pop_transaction_rollback_and_complete (transaction);
return TRUE;
}
@@ -611,9 +673,49 @@ pop_transaction_cancel (PopTransaction *transaction)
#include <stdio.h>
#include <glib.h>
+static void
+on_transaction_complete (PopTransaction *transaction,
+ PopTransactionStatus transaction_status,
+ gpointer data)
+{
+ GMainLoop *loop;
+
+ loop = (GMainLoop *) data;
+ g_print ("transaction completed with status %d\n", transaction);
+
+ g_main_loop_quit (loop);
+}
+
+static PopActionProcessStatus
+hi_world (PopTransaction *transaction)
+{
+ gboolean should_fail;
+ should_fail = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (transaction),
+ "should-fail"));
+ g_print ("hello world!\n");
+
+ if (should_fail)
+ {
+ g_print ("I'm a failure.\n");
+ return POP_ACTION_PROCESS_STATUS_FAILED;
+ }
+
+ g_object_set_data (G_OBJECT (transaction), "should-fail",
+ GINT_TO_POINTER (TRUE));
+ return POP_ACTION_PROCESS_STATUS_FINISHED;
+}
+
+static PopActionRollbackStatus
+bye_world (PopTransaction *transaction)
+{
+ g_print ("goodbye world!\n");
+ return POP_ACTION_ROLLBACK_STATUS_FINISHED;
+}
+
int
main (int argc, char **argv)
{
+ GMainLoop *loop;
PopTransaction *transaction;
int exit_code;
@@ -622,10 +724,32 @@ main (int argc, char **argv)
g_type_init ();
+ loop = g_main_loop_new (NULL, FALSE);
+
g_message ("creating instance of 'transaction' object...");
- transaction = pop_transaction_new ();
+ transaction = pop_transaction_new (on_transaction_complete, loop);
g_message ("'transaction' object created successfully");
+ g_message ("adding simple hello world action...");
+ pop_transaction_add_action (transaction, hi_world, bye_world);
+ g_message ("done adding simple hello world action...");
+
+ g_message ("adding duplicate hello world action...");
+ pop_transaction_add_action (transaction, hi_world, bye_world);
+ g_message ("done adding duplicate hello world action...");
+
+ g_message ("committing transaction to be processed...");
+ pop_transaction_commit (transaction);
+ g_message ("done committing transaction to be processed...");
+
+ g_message ("running event loop...");
+ g_main_loop_run (loop);
+ g_message ("done running event loop...");
+
+ g_message ("cleaning up event loop...");
+ g_main_loop_unref (loop);
+ g_message ("done cleaning up event loop...");
+
g_message ("destroying previously created 'transaction' object...");
g_object_unref (transaction);
g_message ("'transaction' object destroyed successfully");
diff --git a/src/pop-transaction.h b/src/pop-transaction.h
index 2972e14..54b1574 100644
--- a/src/pop-transaction.h
+++ b/src/pop-transaction.h
@@ -38,7 +38,8 @@ typedef enum _PopTransactionError PopTransactionError;
typedef enum _PopTransactionStatus PopTransactionStatus;
typedef void (* PopTransactionCompleteFunc) (PopTransaction *transaction,
- PopTransactionStatus status);
+ PopTransactionStatus status,
+ gpointer user_data);
typedef enum _PopActionProcessStatus PopActionProcessStatus;
typedef PopActionProcessStatus (* PopActionProcessFunc) (PopTransaction *transaction);
@@ -62,7 +63,6 @@ struct _PopTransactionClass
void (* process) (PopTransaction *transaction);
void (* wait) (PopTransaction *transaction);
void (* resume) (PopTransaction *transaction);
- void (* canceled) (PopTransaction *transaction);
};
enum _PopTransactionError