]> xenbits.xensource.com Git - people/aperard/xen-unstable.git/commitdiff
tools/xenstore: add framework to commit accounting data on success only
authorJuergen Gross <jgross@suse.com>
Tue, 30 May 2023 08:24:14 +0000 (10:24 +0200)
committerJulien Grall <jgrall@amazon.com>
Wed, 7 Jun 2023 11:10:31 +0000 (12:10 +0100)
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@suse.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
tools/xenstore/xenstored_core.c
tools/xenstore/xenstored_core.h
tools/xenstore/xenstored_domain.c
tools/xenstore/xenstored_domain.h

index 3ca68681e34028159858c3e96f4aa25c08061336..8392bdec9bc3f082107859580c43c37879b781e8 100644 (file)
@@ -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);
index c59b06551f543b3909fdb6a49ef57ff9db000d45..1f811f38cb037476c2316ce4800c451f9ef513f8 100644 (file)
@@ -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;
 
index 698b2e5e236b8010232312fab55837bec5adf472..923a3082d743ce5e4f7a397d6e3122324dcc5a33 100644 (file)
@@ -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;
@@ -1069,6 +1069,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;
 
@@ -1089,6 +1090,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,
@@ -1105,6 +1122,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)
index 9d05eb01da885e9ceff998a371ee8a002532006d..e40657216b8e631020d5bf0fa92304764f7c1466 100644 (file)
  * 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 */