summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-05-06 01:41:18 -0400
committerRay Strode <rstrode@redhat.com>2007-05-06 01:41:18 -0400
commit8ca8f791e7d8b25022b428d14b58d26015c62837 (patch)
tree993d3b66151412fe5ef790f9da0bff63ea7f3681
parente3aa16afa3e6a6809ab70a95b841ecb36b42e0dd (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.c262
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;