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

[PATCH v5 04/14] tools/xenstore: add framework to commit accounting data on success only



Instead of modifying accounting data and undo those modifications in
case of an error during further processing, add a framework for
collecting the needed changes and commit them only when the whole
operation has succeeded.

This scheme can reuse large parts of the per transaction accounting.
The changed_domain handling can be reused, but the array size of the
accounting data should be possible to be different for both use cases.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
V3:
- call acc_commit() earlier (Julien Grall)
- add assert() to acc_commit()
- use fixed sized acc array in struct changed_domain (Julien Grall)
V5:
- set conn->in to NULL only locally in acc_commit() (Julien Grall)
- define ACC_CHD_N in enum (Julien Grall)
---
 tools/xenstore/xenstored_core.c   |  7 ++++
 tools/xenstore/xenstored_core.h   |  3 ++
 tools/xenstore/xenstored_domain.c | 54 ++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_domain.h |  6 +++-
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 3ca68681e3..8392bdec9b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1023,6 +1023,9 @@ static void send_error(struct connection *conn, int error)
                        break;
                }
        }
+
+       acc_drop(conn);
+
        send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
                          strlen(xsd_errors[i].errstring) + 1);
 }
@@ -1034,6 +1037,9 @@ void send_reply(struct connection *conn, enum 
xsd_sockmsg_type type,
 
        assert(type != XS_WATCH_EVENT);
 
+       /* Commit accounting now, as later errors won't undo any changes. */
+       acc_commit(conn);
+
        if ( len > XENSTORE_PAYLOAD_MAX ) {
                send_error(conn, E2BIG);
                return;
@@ -2195,6 +2201,7 @@ struct connection *new_connection(const struct 
interface_funcs *funcs)
        new->is_stalled = false;
        new->transaction_started = 0;
        INIT_LIST_HEAD(&new->out_list);
+       INIT_LIST_HEAD(&new->acc_list);
        INIT_LIST_HEAD(&new->ref_list);
        INIT_LIST_HEAD(&new->watches);
        INIT_LIST_HEAD(&new->transaction_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c59b06551f..1f811f38cb 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -139,6 +139,9 @@ struct connection
        struct list_head out_list;
        uint64_t timeout_msec;
 
+       /* Not yet committed accounting data (valid if in != NULL). */
+       struct list_head acc_list;
+
        /* Referenced requests no longer pending. */
        struct list_head ref_list;
 
diff --git a/tools/xenstore/xenstored_domain.c 
b/tools/xenstore/xenstored_domain.c
index 30fb9acec6..e59e40088e 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -100,7 +100,7 @@ struct changed_domain
        unsigned int domid;
 
        /* Accounting data. */
-       int acc[ACC_TR_N];
+       int acc[ACC_CHD_N];
 };
 
 static struct hashtable *domhash;
@@ -1070,6 +1070,7 @@ static int domain_acc_add(struct connection *conn, 
unsigned int domid,
                          enum accitem what, int add, bool no_dom_alloc)
 {
        struct domain *d;
+       struct changed_domain *cd;
        struct list_head *head;
        int ret;
 
@@ -1090,6 +1091,22 @@ static int domain_acc_add(struct connection *conn, 
unsigned int domid,
                }
        }
 
+       /* Temporary accounting data until final commit? */
+       if (conn && conn->in && what < ACC_REQ_N) {
+               /* Consider transaction local data. */
+               ret = 0;
+               if (conn->transaction && what < ACC_TR_N) {
+                       head = transaction_get_changed_domains(
+                               conn->transaction);
+                       cd = acc_find_changed_domain(head, domid);
+                       if (cd)
+                               ret = cd->acc[what];
+               }
+               ret += acc_add_changed_dom(conn->in, &conn->acc_list, what,
+                                          add, domid);
+               return errno ? -1 : domain_acc_add_valid(d, what, ret);
+       }
+
        if (conn && conn->transaction && what < ACC_TR_N) {
                head = transaction_get_changed_domains(conn->transaction);
                ret = acc_add_changed_dom(conn->transaction, head, what,
@@ -1106,6 +1123,41 @@ static int domain_acc_add(struct connection *conn, 
unsigned int domid,
        return d->acc[what];
 }
 
+void acc_drop(struct connection *conn)
+{
+       struct changed_domain *cd;
+
+       while ((cd = list_top(&conn->acc_list, struct changed_domain, list))) {
+               list_del(&cd->list);
+               talloc_free(cd);
+       }
+}
+
+void acc_commit(struct connection *conn)
+{
+       struct changed_domain *cd;
+       enum accitem what;
+       struct buffered_data *in = conn->in;
+
+       /*
+        * Make sure domain_acc_add() below can't add additional data to
+        * to be committed accounting records.
+        */
+       conn->in = NULL;
+
+       while ((cd = list_top(&conn->acc_list, struct changed_domain, list))) {
+               list_del(&cd->list);
+               for (what = 0; what < ACC_REQ_N; what++)
+                       if (cd->acc[what])
+                               domain_acc_add(conn, cd->domid, what,
+                                              cd->acc[what], true);
+
+               talloc_free(cd);
+       }
+
+       conn->in = in;
+}
+
 int domain_nbentry_inc(struct connection *conn, unsigned int domid)
 {
        return (domain_acc_add(conn, domid, ACC_NODES, 1, false) < 0)
diff --git a/tools/xenstore/xenstored_domain.h 
b/tools/xenstore/xenstored_domain.h
index 9d05eb01da..e40657216b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -25,8 +25,10 @@
  * a per transaction array.
  */
 enum accitem {
-       ACC_NODES,
+       ACC_REQ_N,              /* Number of elements per request. */
+       ACC_NODES = ACC_REQ_N,
        ACC_TR_N,               /* Number of elements per transaction. */
+       ACC_CHD_N = ACC_TR_N,   /* max(ACC_REQ_N, ACC_TR_N), for changed dom. */
        ACC_N = ACC_TR_N,       /* Number of elements per domain. */
 };
 
@@ -113,6 +115,8 @@ int domain_get_quota(const void *ctx, struct connection 
*conn,
  * If "update" is true, "chk_quota" is ignored.
  */
 int acc_fix_domains(struct list_head *head, bool chk_quota, bool update);
+void acc_drop(struct connection *conn);
+void acc_commit(struct connection *conn);
 
 /* Write rate limiting */
 
-- 
2.35.3




 


Rackspace

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