diff options
author | Ray Strode <rstrode@redhat.com> | 2007-05-02 19:55:47 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2007-05-02 19:55:47 -0400 |
commit | e129869c6bbde326954915f560c5d26750cfdf9a (patch) | |
tree | 124ccd318fadd589400b467609339d192c1cdc49 | |
parent | b690a4fd2c1a0976bb88b210ce96fadac705125f (diff) |
just chugging along on the transaction stuff...
-rw-r--r-- | src/pop-transaction.c | 422 | ||||
-rw-r--r-- | src/pop-transaction.h | 4 |
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 |