By verifying that singleton tables (that is, tables that should have exactly
one row) are empty when they emit transactions that insert into them,
ovs-vsctl and similar tools tolerate initialization races, where more than one
client at a time tries to initialize a singleton table.

The upshot is that if you create a database and then run multiple ovs-vsctl
(etc.) commands against it in parallel (without first initializing it
serially), then without this patch sometimes you will sometimes get failures
but this patch avoids them.

Signed-off-by: Ben Pfaff <b...@ovn.org>
---
 lib/ovsdb-idl-provider.h |  1 +
 lib/ovsdb-idl.c          | 24 ++++++++++++++++++++----
 ovsdb/ovsdb-idlc.in      |  8 ++++++--
 3 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
index d15ab1db58a6..b0ebed44f83a 100644
--- a/lib/ovsdb-idl-provider.h
+++ b/lib/ovsdb-idl-provider.h
@@ -101,6 +101,7 @@ struct ovsdb_idl_column {
 struct ovsdb_idl_table_class {
     char *name;
     bool is_root;
+    bool is_singleton;
     const struct ovsdb_idl_column *columns;
     size_t n_columns;
     size_t allocation_size;
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 12009f568575..e2f9af7f61d4 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -3538,12 +3538,28 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
             }
         } else if (row->old_datum != row->new_datum) {
             struct json *row_json;
-            struct json *op;
             size_t idx;
 
-            op = json_object_create();
-            json_object_put_string(op, "op", row->old_datum ? "update"
-                                                            : "insert");
+            if (!row->old_datum && class->is_singleton) {
+                /* We're inserting a row into a table that allows only a
+                 * single row.  (This is a fairly common OVSDB pattern for
+                 * storing global data.)  Verify that the table is empty
+                 * before inserting the row, so that we get a clear
+                 * verification-related failure if there was an insertion
+                 * race with another client. */
+                struct json *op = json_object_create();
+                json_array_add(operations, op);
+                json_object_put_string(op, "op", "wait");
+                json_object_put_string(op, "table", class->name);
+                json_object_put(op, "where", json_array_create_empty());
+                json_object_put(op, "timeout", json_integer_create(0));
+                json_object_put_string(op, "until", "==");
+                json_object_put(op, "rows", json_array_create_empty());
+            }
+
+            struct json *op = json_object_create();
+            json_object_put_string(op, "op",
+                                   row->old_datum ? "update" : "insert");
             json_object_put_string(op, "table", class->name);
             if (row->old_datum) {
                 json_object_put(op, "where", where_uuid_equals(&row->uuid));
diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index c3973e4f5982..d07d527877a6 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -1298,9 +1298,13 @@ void
             is_root = "true"
         else:
             is_root = "false"
-        print("    {\"%s\", %s," % (tableName, is_root))
+        if table.max_rows == 1:
+            is_singleton = "true"
+        else:
+            is_singleton = "false"
+        print("    {\"%s\", %s, %s," % (tableName, is_root, is_singleton))
         print("     %s_columns, ARRAY_SIZE(%s_columns)," % (
-            structName, structName))
+              structName, structName))
         print("     sizeof(struct %s), %s_init__}," % (structName, structName))
     print("};")
 
-- 
2.10.2

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to