[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-tools] [PATCH 1/3] Recover transaction on restart, give transactions IDs



# HG changeset patch
# User Rusty Russell <rusty@xxxxxxxxxxxxxxx>
# Node ID 6d2f8b0a18c4713286a16d22fd2a11d7ab4525b4
# Parent  5ea81e6405097b7ac25901ecdcd5fb19475508d8
Recover transactions on restart.
Give an ID to each transaction, and return that to client (they can use this to 
get it back).

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r 5ea81e640509 -r 6d2f8b0a18c4 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Sun Sep 25 10:47:22 2005
+++ b/tools/xenstore/xenstored_core.c   Mon Sep 26 04:30:14 2005
@@ -1409,9 +1409,10 @@
                manual_node("/", "tool");
                manual_node("/tool", "xenstored");
                manual_node("/tool/xenstored", NULL);
-       }
-
-       /* FIXME: Fsck */
+       } else {
+               /* FIXME: Fsck */
+               recover_transactions();
+       }
 }
 
 static void write_pidfile(const char *pidfile)
diff -r 5ea81e640509 -r 6d2f8b0a18c4 tools/xenstore/xenstored_transaction.c
--- a/tools/xenstore/xenstored_transaction.c    Sun Sep 25 10:47:22 2005
+++ b/tools/xenstore/xenstored_transaction.c    Mon Sep 26 04:30:14 2005
@@ -55,10 +55,11 @@
        /* Generation when transaction started. */
        unsigned int generation;
 
-       /* My owner (conn->transaction == me). */
+       /* My owner (conn->transaction == me).  NULL if unclaimed. */
        struct connection *conn;
 
        /* TDB to work on, and filename */
+       int id;
        TDB_CONTEXT *tdb;
        char *tdb_name;
 
@@ -108,35 +109,90 @@
        return 0;
 }
 
+/* Very dumb algorithm to get unique transaction id */
+static int get_transaction_id(void)
+{
+       int i = 0;
+       struct transaction *trans;
+
+again:
+       list_for_each_entry(trans, &transactions, list) {
+               if (trans->id == i) {
+                       i++;
+                       goto again;
+               }
+       }
+       return i;
+}
+
+static struct transaction *get_trans_by_id(int id)
+{
+       struct transaction *trans;
+
+       list_for_each_entry(trans, &transactions, list)
+               if (trans->id == id)
+                       return trans;
+       return NULL;
+}
+
+/* Caller fills in ->conn and ->tdb. */
+static struct transaction *new_trans(void *ctx, unsigned int gen, int id)
+{
+       struct transaction *trans;
+
+       trans = talloc(ctx, struct transaction);
+       INIT_LIST_HEAD(&trans->changes);
+       trans->generation = gen;
+       trans->id = id;
+       trans->tdb_name = talloc_asprintf(trans, "%s.%i", xs_daemon_tdb(), id);
+       list_add_tail(&trans->list, &transactions);
+       talloc_set_destructor(trans, destroy_transaction);
+       return trans;
+}
+
 void do_transaction_start(struct connection *conn, struct buffered_data *in)
 {
        struct transaction *trans;
+       char *vec[1];
+       char id[MAX_STRLEN(trans->id)];
+
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        if (conn->transaction) {
                send_error(conn, EBUSY);
                return;
        }
 
-       /* Attach transaction to input for autofree until it's complete */
-       trans = talloc(in, struct transaction);
-       INIT_LIST_HEAD(&trans->changes);
+       /* If given a name, they want transaction back. */
+       if (!streq(vec[0], "")) {
+               trans = get_trans_by_id(atoi(vec[0]));
+               if (!trans || trans->conn) {
+                       send_error(conn, ENOENT);
+                       return;
+               }
+       } else {
+               /* Attach transaction to input for autofree until complete */
+               trans = new_trans(in, generation, get_transaction_id());
+
+               trans->tdb = tdb_copy(tdb_context(conn), trans->tdb_name);
+               if (!trans->tdb) {
+                       send_error(conn, errno);
+                       return;
+               }
+               /* TDB lifetime is that of transaction */
+               talloc_steal(trans, trans->tdb);
+       }
+
+       /* Now we own it. */
        trans->conn = conn;
-       trans->generation = generation;
-       trans->tdb_name = talloc_asprintf(trans, "%s.%p",
-                                         xs_daemon_tdb(), trans);
-       trans->tdb = tdb_copy(tdb_context(conn), trans->tdb_name);
-       if (!trans->tdb) {
-               send_error(conn, errno);
-               return;
-       }
-       /* Make it close if we go away. */
-       talloc_steal(trans, trans->tdb);
-
-       /* Now we own it. */
        conn->transaction = talloc_steal(conn, trans);
-       list_add_tail(&trans->list, &transactions);
-       talloc_set_destructor(trans, destroy_transaction);
-       send_ack(conn, XS_TRANSACTION_START);
+
+       /* We return the transaction id as a string. */
+       sprintf(id, "%i", trans->id);
+       send_reply(conn, XS_TRANSACTION_START, id, strlen(id));
 }
 
 void do_transaction_end(struct connection *conn, const char *arg)
@@ -181,3 +237,37 @@
        send_ack(conn, XS_TRANSACTION_END);
 }
 
+/* Transactions sit in files: recover them. */
+void recover_transactions(void)
+{
+       DIR *dir;
+       struct dirent *dirent;
+       int id;
+       struct transaction *trans;
+       char *transdir;
+
+       transdir = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb());
+       if (strrchr(transdir, '/'))
+               *strchr(transdir, '/') = '\0';
+       else
+               transdir = talloc_strdup(transdir, ".");
+
+       dir = opendir(transdir);
+       if (!dir)
+               barf_perror("Could not open %s", transdir);
+
+       while ((dirent = readdir(dir)) != NULL) {
+               if (!strstarts(dirent->d_name, "tdb."))
+                       continue;
+
+               id = atoi(dirent->d_name + strlen("tdb."));
+               trans = new_trans(transdir, -1, id);
+               trans->conn = NULL;
+               trans->tdb = tdb_open(trans->tdb_name, 0, 0, O_RDWR, 0);
+               if (!trans->tdb) {
+                       eprintf("Could not reopen transaction %i: corrupt?",
+                               id);
+                       talloc_free(trans);
+               }
+       }
+}
diff -r 5ea81e640509 -r 6d2f8b0a18c4 tools/xenstore/xenstored_transaction.h
--- a/tools/xenstore/xenstored_transaction.h    Sun Sep 25 10:47:22 2005
+++ b/tools/xenstore/xenstored_transaction.h    Mon Sep 26 04:30:14 2005
@@ -32,4 +32,6 @@
 
 /* Return tdb context to use for this connection. */
 TDB_CONTEXT *tdb_transaction_context(struct transaction *trans);
+
+void recover_transactions(void);
 #endif /* _XENSTORED_TRANSACTION_H */

-- 
A bad analogy is like a leaky screwdriver -- Richard Braakman


_______________________________________________
Xen-tools mailing list
Xen-tools@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-tools


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.