]> xenbits.xensource.com Git - xen.git/commitdiff
xenstore: add per-node generation counter
authorJuergen Gross <jgross@suse.com>
Mon, 5 Dec 2016 07:48:45 +0000 (08:48 +0100)
committerWei Liu <wei.liu2@citrix.com>
Mon, 5 Dec 2016 11:21:35 +0000 (11:21 +0000)
In order to be able to support reading the list of a node's children in
multiple chunks (needed for list sizes > 4096 bytes) without having to
allocate a temporary buffer we need some kind of generation counter for
each node. This will help to recognize a node has changed between
reading two chunks.

As removing a node and reintroducing it must result in different
generation counts each generation value has to be globally unique. This
can be ensured only by using a global 64 bit counter.

For handling of transactions there is already such a counter available,
it just has to be expanded to 64 bits and must be stored in each
modified node.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
tools/xenstore/include/xenstore_lib.h
tools/xenstore/xenstored_core.c
tools/xenstore/xenstored_core.h
tools/xenstore/xenstored_transaction.c

index efdf93580a18a686aa38e1f26703c1a23b44e661..0ffbae9eb5741be6782bfd2d99df947987487bca 100644 (file)
@@ -44,6 +44,7 @@ struct xs_permissions
 
 /* Header of the node record in tdb. */
 struct xs_tdb_record_hdr {
+       uint64_t generation;
        uint32_t num_perms;
        uint32_t datalen;
        uint32_t childlen;
index dfad0d5468cfa4135a5f84775ef7a3f1ba537c8a..95d6d7dc11de4652814944f1ce5eb28c6dc0320f 100644 (file)
@@ -442,6 +442,7 @@ static struct node *read_node(struct connection *conn, const void *ctx,
 
        /* Datalen, childlen, number of permissions */
        hdr = (void *)data.dptr;
+       node->generation = hdr->generation;
        node->num_perms = hdr->num_perms;
        node->datalen = hdr->datalen;
        node->childlen = hdr->childlen;
@@ -481,6 +482,7 @@ static bool write_node(struct connection *conn, struct node *node)
 
        data.dptr = talloc_size(node, data.dsize);
        hdr = (void *)data.dptr;
+       hdr->generation = node->generation;
        hdr->num_perms = node->num_perms;
        hdr->datalen = node->datalen;
        hdr->childlen = node->childlen;
index ecc614f5e32b575664d6fdf879877b909af6dc09..089625fb57b3a56ca39b4124aae608a540333338 100644 (file)
@@ -109,6 +109,9 @@ struct node {
        /* Parent (optional) */
        struct node *parent;
 
+       /* Generation count. */
+       uint64_t generation;
+
        /* Permissions. */
        unsigned int num_perms;
        struct xs_permissions *perms;
index b08b2eb4e67fe112b9e4b6cc6f32724de6da07cf..6c65dc510dbff0d36ce71bc9b5d3f3e28484c9df 100644 (file)
@@ -68,7 +68,10 @@ struct transaction
        uint32_t id;
 
        /* Generation when transaction started. */
-       unsigned int generation;
+       uint64_t generation;
+
+       /* Transaction internal generation. */
+       uint64_t trans_gen;
 
        /* TDB to work on, and filename */
        TDB_CONTEXT *tdb;
@@ -82,7 +85,7 @@ struct transaction
 };
 
 extern int quota_max_transaction;
-static unsigned int generation;
+static uint64_t generation;
 
 /* Return tdb context to use for this connection. */
 TDB_CONTEXT *tdb_transaction_context(struct transaction *trans)
@@ -99,12 +102,14 @@ void add_change_node(struct connection *conn, struct node *node, bool recurse)
 
        if (!conn || !conn->transaction) {
                /* They're changing the global database. */
-               generation++;
+               node->generation = generation++;
                return;
        }
 
        trans = conn->transaction;
 
+       node->generation = generation + trans->trans_gen++;
+
        list_for_each_entry(i, &trans->changes, list) {
                if (streq(i->node, node->name)) {
                        if (recurse)
@@ -161,7 +166,7 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in)
        }
 
        /* Attach transaction to input for autofree until it's complete */
-       trans = talloc(in, struct transaction);
+       trans = talloc_zero(in, struct transaction);
        INIT_LIST_HEAD(&trans->changes);
        INIT_LIST_HEAD(&trans->changed_domains);
        trans->generation = generation;
@@ -235,7 +240,7 @@ void do_transaction_end(struct connection *conn, struct buffered_data *in)
                /* Fire off the watches for everything that changed. */
                list_for_each_entry(i, &trans->changes, list)
                        fire_watches(conn, in, i->node, i->recurse);
-               generation++;
+               generation += trans->trans_gen;
        }
        send_ack(conn, XS_TRANSACTION_END);
 }