[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 3/4] xenstore: rework of transaction handling
On Thu, Mar 30, 2017 at 03:11:48PM +0200, Juergen Gross wrote: [...] > + > +/* > + * A node has been accessed. > + * > + * Modifying accesses (write, delete) always update the generation (global > and > + * node->generation). > + * > + * Accesses in a transaction will be added to the list of accessed nodes > + * if not already done. Read type accesses will copy the node to the > + * transaction specific data base part, write type accesses go there > + * anyway. > + * > + * If not NULL, key will be supplied with name and length of name of the node > + * to be accessed in the data base. > + */ > +int access_node(struct connection *conn, struct node *node, > + enum node_access_type type, TDB_DATA *key) > +{ > + struct accessed_node *i = NULL; > struct transaction *trans; > + TDB_DATA local_key; > + const char *trans_name = NULL; > + int ret; > + bool introduce = false; > > - if (!conn || !conn->transaction) { > + if (type != NODE_ACCESS_READ) { > /* They're changing the global database. */ This comment should be moved below. > node->generation = generation++; > - return; > + if (conn && !conn->transaction) > + wrl_apply_debit_direct(conn); > + } > + > + if (!conn || !conn->transaction) { > + if (key) > + set_tdb_key(node->name, key); > + return 0; > } > > trans = conn->transaction; > > - node->generation = generation + trans->trans_gen++; > + trans_name = transaction_get_node_name(node, trans, node->name); > + if (!trans_name) > + goto nomem; > > - list_for_each_entry(i, &trans->changes, list) { > - if (streq(i->node, node->name)) { > - if (recurse) > - i->recurse = recurse; > - return; > - } > - } > - > - i = talloc(trans, struct changed_node); > + i = find_accessed_node(trans, node->name); > if (!i) { > - /* All we can do is let the transaction fail. */ > - generation++; > - return; > + i = talloc_zero(trans, struct accessed_node); > + if (!i) > + goto nomem; > + i->node = talloc_strdup(i, node->name); > + if (!i->node) > + goto nomem; > + > + introduce = true; > + i->ta_node = false; > + > + /* We have to verify read nodes only if we didn't write them. */ > + if (type == NODE_ACCESS_READ) { > + i->generation = node->generation; > + i->check_gen = true; > + if (node->generation != NO_GENERATION) { > + set_tdb_key(trans_name, &local_key); > + ret = write_node_raw(conn, &local_key, node); > + if (ret) > + goto err; > + i->ta_node = true; > + } > + } I think the current code structure is a bit confusing. For write types, the call to write_node_raw is outside of this function but for read type it is inside this function. > + list_add_tail(&i->list, &trans->accessed); > } > - i->node = talloc_strdup(i, node->name); > - if (!i->node) { > - /* All we can do is let the transaction fail. */ > - generation++; > + > + if (type != NODE_ACCESS_READ) > + i->modified = true; > + > + if (introduce && type == NODE_ACCESS_DELETE) > + /* Nothing to delete. */ > + return -1; > + > + if (key) { > + set_tdb_key(trans_name, key); > + if (type == NODE_ACCESS_WRITE) > + i->ta_node = true; > + if (type == NODE_ACCESS_DELETE) > + i->ta_node = false; The same caveat made me wonder if ta_node was really what it meant to be because I couldn't find where write_node_raw was. Can I suggest you make them consistent? Either lift the write_node_raw for read to read_node or push down the write_node_raw in delete_node and write_node here? If I misunderstand how this works, please tell me... > + } > + > + return 0; > + > +nomem: > + ret = ENOMEM; > +err: > + talloc_free((void *)trans_name); > + talloc_free(i); > + trans->fail = true; > + errno = ret; > + return ret; > +} > + > +/* > + * Finalize transaction: > + * Walk through accessed nodes and check generation against global data. > + * If all entries match, read the transaction entries and write them without > + * transaction prepended. Delete all transaction specific nodes in the data > + * base. > + */ [...] > @@ -269,7 +525,7 @@ void transaction_entry_inc(struct transaction *trans, > unsigned int domid) > d = talloc(trans, struct changed_domain); > if (!d) { > /* Let the transaction fail. */ > - generation++; > + trans->fail = true; > return; > } > d->domid = domid; > @@ -290,7 +546,7 @@ void transaction_entry_dec(struct transaction *trans, > unsigned int domid) > d = talloc(trans, struct changed_domain); > if (!d) { > /* Let the transaction fail. */ > - generation++; > + trans->fail = true; > return; > } > d->domid = domid; > @@ -313,6 +569,29 @@ void conn_delete_all_transactions(struct connection > *conn) > conn->transaction_started = 0; > } > > +int check_transactions(int (*func)(void *, const char *), void *par) > +{ I think you can make the func take hashtable * and the second parameter hashtable *. You can then avoid changing remember_string. Or even better, you don't need to take a callback function at all because AFAICT only remember_string is called. > + struct connection *conn; > + struct transaction *trans; > + char *tname; > + > + list_for_each_entry(conn, &connections, list) { > + list_for_each_entry(trans, &conn->transaction_list, list) { > + tname = talloc_asprintf(trans, "%"PRIu64, > + trans->generation); > + if (!tname) > + return ENOMEM; > + > + if (!func(par, tname)) > + return ENOMEM; > + I guess a bigger question is why calling remember_string here would constitute a check on all transactions. Sorry this is taking a bit long. I am still struggling with the code. I haven't got around to check if the code matches the algorithm yet. I expect a few iterations are needed. Wei. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |