# 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
|