diff options
author | Ray Strode <rstrode@redhat.com> | 2007-05-06 01:41:18 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2007-05-06 01:41:18 -0400 |
commit | 8ca8f791e7d8b25022b428d14b58d26015c62837 (patch) | |
tree | 993d3b66151412fe5ef790f9da0bff63ea7f3681 | |
parent | e3aa16afa3e6a6809ab70a95b841ecb36b42e0dd (diff) |
save action status on action object. If we ever come back to an action that's
already finished (because say it added some actions to the queue before
finishing and those actions finished), then just return.
Drop lame test case and start to write one that is more real-world (will
eventually copy a file)
-rw-r--r-- | src/pop-transaction.c | 262 |
1 files changed, 175 insertions, 87 deletions
diff --git a/src/pop-transaction.c b/src/pop-transaction.c index 2e33e55..c8891be 100644 --- a/src/pop-transaction.c +++ b/src/pop-transaction.c @@ -65,7 +65,11 @@ struct _PopTransactionPrivate typedef struct { PopActionProcessFunc process_func; + PopActionProcessStatus process_status; + PopActionRollbackFunc rollback_func; + PopActionRollbackStatus rollback_status; + gpointer user_data; GDestroyNotify free_func; } PopAction; @@ -349,7 +353,9 @@ pop_action_new (PopActionProcessFunc action_process_func, action = g_slice_new0 (PopAction); action->process_func = action_process_func; + action->process_status = POP_ACTION_PROCESS_STATUS_NOT_FINISHED; action->rollback_func = action_rollback_func; + action->rollback_status = POP_ACTION_ROLLBACK_STATUS_NOT_FINISHED; action->user_data = user_data; action->free_func = free_func; @@ -722,7 +728,6 @@ static gboolean pop_transaction_run_action_and_seek_forward (PopTransaction *transaction) { PopAction *action; - PopActionProcessStatus status; gboolean should_continue; g_assert (POP_IS_TRANSACTION (transaction)); @@ -738,18 +743,21 @@ pop_transaction_run_action_and_seek_forward (PopTransaction *transaction) action = (PopAction *) transaction->priv->current_action_node->data; + if (action->process_status != POP_ACTION_PROCESS_STATUS_NOT_FINISHED) + return FALSE; + transaction->priv->is_in_action = TRUE; if (action->process_func != NULL) { - status = action->process_func (transaction, action->user_data); + action->process_status = action->process_func (transaction, action->user_data); } else { - status = POP_ACTION_PROCESS_STATUS_SUCCEEDED; + action->process_status = POP_ACTION_PROCESS_STATUS_SUCCEEDED; } transaction->priv->is_in_action = FALSE; - switch (status) + switch (action->process_status) { case POP_ACTION_PROCESS_STATUS_NOT_FINISHED: should_continue = TRUE; @@ -770,7 +778,7 @@ pop_transaction_run_action_and_seek_forward (PopTransaction *transaction) break; default: - g_warning ("status %d is not valid processing status\n", (int) status); + g_warning ("status %d is not valid processing status\n", (int) action->process_status); /* Fall through and fail the action because it's not behaving */ @@ -807,7 +815,6 @@ static gboolean pop_transaction_rollback_action_and_rewind (PopTransaction *transaction) { PopAction *action; - PopActionRollbackStatus status; gboolean should_continue; g_assert (POP_IS_TRANSACTION (transaction)); @@ -822,14 +829,17 @@ pop_transaction_rollback_action_and_rewind (PopTransaction *transaction) action = (PopAction *) transaction->priv->current_action_node->data; + if (action->rollback_status != POP_ACTION_ROLLBACK_STATUS_NOT_FINISHED) + return FALSE; + transaction->priv->is_in_action = TRUE; if (action->rollback_func != NULL) { - status = action->rollback_func (transaction, action->user_data); + action->rollback_status = action->rollback_func (transaction, action->user_data); } else { - status = POP_ACTION_ROLLBACK_STATUS_FINISHED; + action->rollback_status = POP_ACTION_ROLLBACK_STATUS_FINISHED; } transaction->priv->is_in_action = FALSE; @@ -840,7 +850,7 @@ pop_transaction_rollback_action_and_rewind (PopTransaction *transaction) break; default: - g_warning ("status %d is not valid rollback status\n", (int) status); + g_warning ("status %d is not valid rollback status\n", (int) action->rollback_status); /* Fall through and finish the action because it's not behaving */ @@ -1145,88 +1155,173 @@ process_write_action (PopTransaction *transaction, arguments, G_IO_OUT); } -static void -on_transaction_finish (PopTransaction *transaction, - PopTransactionStatus status, - gpointer data) +typedef struct { - GMainLoop *loop; + const char *filename; + int flags; + mode_t mode; +} OpenArguments; - loop = (GMainLoop *) data; - g_print ("transaction completed with status %d\n", status); +static PopActionProcessStatus +open_action (PopTransaction *transaction, + OpenArguments *arguments) +{ + int fd; - g_main_loop_quit (loop); + fd = open (arguments->filename, arguments->flags, arguments->mode); + + if (fd < 0) + { + GError *error; + + if (errno == EWOULDBLOCK) + { + pop_transaction_wait_a_while (transaction, 500); + return POP_ACTION_PROCESS_STATUS_NOT_FINISHED; + } + + error = g_error_new_literal (G_FILE_ERROR, + g_file_error_from_errno (errno), + g_strerror (errno)); + + pop_transaction_set_error (transaction, error); + g_error_free (error); + return POP_ACTION_PROCESS_STATUS_FAILED; + } + + g_object_set_data (G_OBJECT (transaction), "fd", GINT_TO_POINTER (fd)); + g_object_set_data (G_OBJECT (transaction), "fd-is-set", GINT_TO_POINTER (TRUE)); + + return POP_ACTION_PROCESS_STATUS_SUCCEEDED; } +static PopActionRollbackStatus +open_action_cleanup (PopTransaction *transaction, + OpenArguments *arguments) +{ + gboolean fd_is_set; + int fd, status; + + fd_is_set = g_object_get_data (G_OBJECT (transaction), "fd-is-set"); + + if (!fd_is_set) + return POP_ACTION_ROLLBACK_STATUS_FINISHED; + + fd = g_object_get_data (G_OBJECT (transaction), "fd"); + + if (fd < 0) + { + g_object_set_data (G_OBJECT (transaction), "fd-is-set", + GPOINTER_TO_INT (FALSE)); + return POP_ACTION_ROLLBACK_STATUS_FINISHED; + } + + if ((close (fd) < 0) && (errno == EINTR)) + { + return POP_ACTION_ROLLBACK_STATUS_NOT_FINISHED; + } + + g_object_set_data (G_OBJECT (transaction), "fd-is-set", + GPOINTER_TO_INT (FALSE)); + + return POP_ACTION_ROLLBACK_STATUS_FINISHED; +} + + static PopActionProcessStatus -preemptive_action (PopTransaction *transaction, - gpointer user_data) +save_fd_action (PopTransaction *transaction, + const char *name) { - g_print ("Hello World! should get printed I guess before " - "the transaction continues...so Hello World!\n"); - return POP_ACTION_PROCESS_STATUS_SUCCEEDED; + int fd; + + g_return_val_if_fail (g_object_get_data (G_OBJECT (transaction), + "fd-is-set"), + POP_ACTION_PROCESS_STATUS_FAILED); + + fd = g_object_get_data (G_OBJECT (transaction), "fd"); + g_object_set_data (G_OBJECT (transaction), name, GINT_TO_POINTER (fd)); +} + +static PopActionRollbackStatus +save_fd_action_cleanup (PopTransaction *transaction, + const char *name) +{ + g_return_val_if_fail (g_object_get_data (G_OBJECT (transaction), + "fd-is-set"), + POP_ACTION_PROCESS_STATUS_FAILED); + + g_object_set_data (G_OBJECT (transaction), name, NULL); } static PopActionProcessStatus -test_action (PopTransaction *transaction, - gpointer user_data) +open_files_action (PopTransaction *transaction, + const char **files) { - PopActionProcessStatus status; + OpenArguments *input_file_args, *output_file_args; + int index; - int generation; + g_return_val_if_fail (files != NULL, POP_ACTION_PROCESS_STATUS_FAILED); + g_return_val_if_fail (g_strv_length (files) == 2, + POP_ACTION_PROCESS_STATUS_FAILED); - generation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (transaction), - "generation")); - g_print ("Generation %d\n", generation); - switch (generation) - { - case 0: - g_print ("First instance of test action\n"); - g_print ("Press enter to continue\n"); - pop_transaction_wait_for_fd (transaction, fileno (stdin), G_IO_IN, NULL); - status = POP_ACTION_PROCESS_STATUS_NOT_FINISHED; - break; + input_file_args = g_slice_new0 (OpenArguments); + input_file_args->filename = g_strdup (files[0]); + input_file_args->flags = O_RDONLY; - case 1: - getc (stdin); - g_print ("enter detected, will continue in 5 seconds...\n"); - pop_transaction_wait_a_while (transaction, 5 * 1000); - status = POP_ACTION_PROCESS_STATUS_NOT_FINISHED; - break; + pop_transaction_add_action (transaction, open_action, open_action_cleanup, + input_file_args); + g_object_set_data (G_OBJECT (transaction), "input-file-args", input_file_args); - case 2: - g_print ("5 seconds elapsed, finishing first action...\n"); - status = POP_ACTION_PROCESS_STATUS_SUCCEEDED; - break; + pop_transaction_add_action (transaction, save_fd_action, save_fd_action_cleanup, + "input-fd"); - case 3: - g_print ("Second instance of test action\n"); - g_print ("waiting on blocking action before continuing.\n"); - pop_transaction_add_action (transaction, preemptive_action, NULL, NULL); - status = POP_ACTION_PROCESS_STATUS_NOT_FINISHED; - break; + output_file_args = g_slice_new0 (OpenArguments); + output_file_args->filename = g_strdup (files[1]); + output_file_args->flags = O_WRONLY | O_CREAT; + output_file_args->mode = 0644; - case 4: - g_print ("blocking action complete.\n"); - g_print ("failing anyway because I'm a failure.\n"); - status = POP_ACTION_PROCESS_STATUS_FAILED; - break; - } + pop_transaction_add_action (transaction, open_action, open_action_cleanup, + output_file_args); + g_object_set_data (G_OBJECT (transaction), "output-file-args", output_file_args); - generation++; - g_object_set_data (G_OBJECT (transaction), "generation", - GINT_TO_POINTER (generation)); - return status; + pop_transaction_add_action (transaction, save_fd_action, save_fd_action_cleanup, + "output-fd"); + + return POP_ACTION_PROCESS_STATUS_FINISHED; } static PopActionRollbackStatus -test_action_cleanup (PopTransaction *transaction, - gpointer user_data) +open_files_action_cleanup (PopTransaction *transaction, + const char **files) { - g_print ("cleaning up!\n"); + OpenArguments *input_file_args, *output_file_args; + + input_file_args = g_object_get_data (G_OBJECT (transaction), + "input-file-args"); + g_slice_free (OpenArguments, input_file_args); + g_object_set_data (G_OBJECT (transaction), "input-file-args", NULL); + + output_file_args = g_object_get_data (G_OBJECT (transaction), + "output-file-args"); + g_slice_free (OpenArguments, output_file_args); + g_object_set_data (G_OBJECT (transaction), "output-file-args", NULL); + return POP_ACTION_ROLLBACK_STATUS_FINISHED; } +static void +on_transaction_finish (PopTransaction *transaction, + PopTransactionStatus status, + gpointer data) +{ + GMainLoop *loop; + + loop = (GMainLoop *) data; + g_print ("transaction completed with status %d\n", status); + + g_main_loop_quit (loop); +} + int main (int argc, char **argv) @@ -1240,40 +1335,33 @@ main (int argc, g_type_init (); + if (argc != 3) + { + g_printerr ("Usage: %s src dst\n", argv[0]); + return 1; + } + loop = g_main_loop_new (NULL, FALSE); - g_message ("creating instance of 'transaction' object..."); transaction = pop_transaction_new (); - g_message ("'transaction' object created successfully"); g_signal_connect (G_OBJECT (transaction), "finish", G_CALLBACK (on_transaction_finish), loop); + pop_transaction_add_action (transaction, open_files_action, + open_files_action_cleanup, + argv + 1); + +#if 0 + pop_transaction_add_action (transaction, copy_files_action, + copy_files_action_cleanup, NULL); +#endif - g_message ("adding simple test action..."); - pop_transaction_add_action (transaction, test_action, test_action_cleanup, - NULL); - g_message ("done adding simple test action..."); - - g_message ("adding duplicate test action..."); - pop_transaction_add_action (transaction, test_action, NULL, NULL); - g_message ("done adding test 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"); exit_code = 0; |