ovsdb: Implement new "declare" operation.
authorBen Pfaff <blp@nicira.com>
Mon, 7 Dec 2009 19:47:48 +0000 (11:47 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 8 Dec 2009 01:10:28 +0000 (17:10 -0800)
lib/ovsdb-data.c
lib/ovsdb-data.h
ovsdb/SPECS
ovsdb/execution.c
tests/ovsdb-idl.at
tests/test-ovsdb.c

index 46298cb47694c2ae662b738b3df311c59112b998..df445d775c12d5eb91302286ef4506354b123189 100644 (file)
@@ -219,13 +219,13 @@ ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
         error1 = unwrap_json(json, "named-uuid", JSON_STRING, &value);
         if (!error1) {
             const char *name = json_string(value);
-            const struct uuid *named_uuid;
+            const struct ovsdb_symbol *symbol;
 
             ovsdb_error_destroy(error0);
 
-            named_uuid = ovsdb_symbol_table_get(symtab, name);
-            if (named_uuid) {
-                *uuid = *named_uuid;
+            symbol = ovsdb_symbol_table_get(symtab, name);
+            if (symbol) {
+                *uuid = symbol->uuid;
                 return NULL;
             } else {
                 return ovsdb_syntax_error(json, NULL,
@@ -728,7 +728,8 @@ ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
         struct shash_node *node, *next;
 
         SHASH_FOR_EACH_SAFE (node, next, &symtab->sh) {
-            free(node->data);
+            struct ovsdb_symbol *symbol = node->data;
+            free(symbol);
             shash_delete(&symtab->sh, node);
         }
         shash_destroy(&symtab->sh);
@@ -736,7 +737,7 @@ ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
     }
 }
 
-const struct uuid *
+struct ovsdb_symbol *
 ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
                        const char *name)
 {
@@ -745,12 +746,13 @@ ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
 
 void
 ovsdb_symbol_table_put(struct ovsdb_symbol_table *symtab, const char *name,
-                       const struct uuid *uuid)
+                       const struct uuid *uuid, bool used)
 {
-    struct uuid *entry = shash_find_data(&symtab->sh, name);
-    if (!entry) {
-        shash_add(&symtab->sh, name, xmemdup(uuid, sizeof *uuid));
-    } else {
-        *entry = *uuid;
-    }
+    struct ovsdb_symbol *symbol;
+
+    assert(!ovsdb_symbol_table_get(symtab, name));
+    symbol = xmalloc(sizeof *symbol);
+    symbol->uuid = *uuid;
+    symbol->used = used;
+    shash_add(&symtab->sh, name, symbol);
 }
index 35c4e3075ca10b56852081db599a44506d14fb36..b31aa5d496f07d10ed0cdd0af2ba3f2f58787d31 100644 (file)
@@ -118,11 +118,16 @@ ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum,
 /* A table mapping from names to data items.  Currently the data items are
  * always UUIDs; perhaps this will be expanded in the future. */
 
+struct ovsdb_symbol {
+    struct uuid uuid;           /* The UUID that the symbol represents. */
+    bool used;                  /* Already used as row UUID? */
+};
+
 struct ovsdb_symbol_table *ovsdb_symbol_table_create(void);
 void ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *);
-const struct uuid *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *,
-                                          const char *name);
+struct ovsdb_symbol *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *,
+                                            const char *name);
 void ovsdb_symbol_table_put(struct ovsdb_symbol_table *, const char *name,
-                            const struct uuid *);
+                            const struct uuid *, bool used);
 
 #endif /* ovsdb-data.h */
index 17b0840cacc7706790be4c8f94a9fb07e1cadf9d..93db15d4cc41191c75af22688ff69cef252db0a4 100644 (file)
@@ -599,7 +599,7 @@ Request object members:
     "op": "insert"          required
     "table": <table>        required
     "row": <row>            required
-    "uuid-name": <string>   optional
+    "uuid-name": <id>       optional
 
 Result object members:
 
@@ -611,10 +611,31 @@ Semantics:
     for all the columns in "table", those columns receive default
     values.
 
-    The new row receives a new, randomly generated UUID, which is
-    returned as the "uuid" member of the result.  If "uuid-name" is
-    supplied, then the UUID is made available under that name to this
-    operation and later operations within the same transaction.
+    If "uuid-name" is not supplied, the new row receives a new,
+    randomly generated UUID.
+
+    If "uuid-name" is supplied, then it is an error if <id> has
+    previously appeared as the "uuid-name" in an "insert" operation.
+
+    If "uuid-name" is supplied and its <id> previously appeared as the
+    "uuid-name" in a "declare" operation, then the new row receives
+    the UUID associated with that "uuid-name".
+
+    If "uuid-name" is supplied and its <id> has not previously
+    appeared as the "uuid-name" in a "declare" operation, then the new
+    row also receives a new, randomly generated UUID.  This UUID is
+    also made available under that name to this operation and later
+    operations within the same transaction.
+
+    The UUID for the new row is returned as the "uuid" member of the
+    result.
+
+Errors:
+
+    "error": "duplicate uuid-name"
+
+        The same "uuid-name" appeared on an earlier "insert" operation
+        within this transaction.
 
 select
 ......
@@ -797,3 +818,37 @@ Errors:
     "error": "aborted"
 
         This operation always fails with this error.
+
+declare
+.......
+
+Request object members:
+
+    "op": "declare"                    required
+    "uuid-name": <id>                  required
+
+Result object members:
+
+    none
+
+Semantics:
+
+    Predeclares a UUID named <id> that may be referenced in later
+    operations as ["named-uuid", <id>] or (at most once) in an
+    "insert" operation as "uuid-name".
+
+    It is an error if <id> has appeared as the "uuid-name" in a prior
+    "insert" or "declare" operation within this transaction.
+
+    The generated UUID is returned as the "uuid" member of the result.
+
+Result object members:
+
+    "uuid": <uuid>
+
+Errors:
+
+    "error": "duplicate uuid-name"
+
+        The same "uuid-name" appeared on an earlier "insert" or
+        "declare" operation within this transaction.
index 0bfe86fb31ce6a394685cab9dddf7966c086aa91..932bee2380bfe3b4853bb775bf583399f25186f3 100644 (file)
@@ -54,6 +54,7 @@ static ovsdb_operation_executor ovsdb_execute_delete;
 static ovsdb_operation_executor ovsdb_execute_wait;
 static ovsdb_operation_executor ovsdb_execute_commit;
 static ovsdb_operation_executor ovsdb_execute_abort;
+static ovsdb_operation_executor ovsdb_execute_declare;
 
 static ovsdb_operation_executor *
 lookup_executor(const char *name)
@@ -71,6 +72,7 @@ lookup_executor(const char *name)
         { "wait", ovsdb_execute_wait },
         { "commit", ovsdb_execute_commit },
         { "abort", ovsdb_execute_abort },
+        { "declare", ovsdb_execute_declare },
     };
 
     size_t i;
@@ -272,9 +274,25 @@ ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID | OP_OPTIONAL);
     error = ovsdb_parser_get_error(parser);
 
-    uuid_generate(&row_uuid);
     if (uuid_name) {
-        ovsdb_symbol_table_put(x->symtab, json_string(uuid_name), &row_uuid);
+        struct ovsdb_symbol *symbol;
+
+        symbol = ovsdb_symbol_table_get(x->symtab, json_string(uuid_name));
+        if (symbol) {
+            if (symbol->used) {
+                return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
+                                          "This \"uuid-name\" appeared on an "
+                                          "earlier \"insert\" operation.");
+            }
+            row_uuid = symbol->uuid;
+            symbol->used = true;
+        } else {
+            uuid_generate(&row_uuid);
+            ovsdb_symbol_table_put(x->symtab, json_string(uuid_name),
+                                   &row_uuid, true);
+        }
+    } else {
+        uuid_generate(&row_uuid);
     }
 
     if (!error) {
@@ -580,3 +598,29 @@ ovsdb_execute_wait(struct ovsdb_execution *x, struct ovsdb_parser *parser,
 
     return error;
 }
+
+static struct ovsdb_error *
+ovsdb_execute_declare(struct ovsdb_execution *x, struct ovsdb_parser *parser,
+                      struct json *result)
+{
+    const struct json *uuid_name;
+    struct uuid uuid;
+
+    uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID);
+    if (!uuid_name) {
+        return NULL;
+    }
+
+    if (ovsdb_symbol_table_get(x->symtab, json_string(uuid_name))) {
+        return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
+                                  "This \"uuid-name\" appeared on an "
+                                  "earlier \"declare\" or \"insert\" "
+                                  "operation.");
+    }
+
+    uuid_generate(&uuid);
+    ovsdb_symbol_table_put(x->symtab, json_string(uuid_name), &uuid, false);
+    json_object_put(result, "uuid", json_string_create_nocopy(
+                        xasprintf(UUID_FMT, UUID_ARGS(&uuid))));
+    return NULL;
+}
index cf9f1ba37079516d12fe60d8c535643f7f8b546b..a1717b8c41439d2d81b85fb5c7d8d40513c6f3b4 100644 (file)
@@ -143,18 +143,18 @@ OVSDB_CHECK_IDL([self-linking idl, consistent ops],
        "table": "link1",
        "row": {"i": 0, "k": ["named-uuid", "self"]},
        "uuid-name": "self"}]' \
-    '[{"op": "insert",
+    '[{"op": "declare",
+       "uuid-name": "row1"},
+      {"op": "declare",
+       "uuid-name": "row2"},
+      {"op": "insert",
        "table": "link1",
-       "row": {"i": 1},
+       "row": {"i": 1, "k": ["named-uuid", "row2"]},
        "uuid-name": "row1"},
       {"op": "insert",
        "table": "link1",
        "row": {"i": 2, "k": ["named-uuid", "row1"]},
-       "uuid-name": "row2"},
-      {"op": "update",
-       "table": "link1",
-       "where": [["i", "==", 1]],
-       "row": {"k": ["named-uuid", "row2"]}}]' \
+       "uuid-name": "row2"}]' \
     '[{"op": "update",
        "table": "link1",
        "where": [["i", "==", 1]],
@@ -166,7 +166,7 @@ OVSDB_CHECK_IDL([self-linking idl, consistent ops],
   [[000: empty
 001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
 002: i=0 k=0 ka=[] l2= uuid=<0>
-003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]},{"count":1}]}
+003: {"error":null,"result":[{"uuid":"<1>"},{"uuid":"<2>"},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
 004: i=0 k=0 ka=[] l2= uuid=<0>
 004: i=1 k=2 ka=[] l2= uuid=<1>
 004: i=2 k=1 ka=[] l2= uuid=<2>
index fb13df9c3dcf890021dad237683539b0207ab6e5..9819d03da5df7a370354d677743484a7c88a5757 100644 (file)
@@ -1346,7 +1346,8 @@ parse_uuids(const struct json *json, struct ovsdb_symbol_table *symtab,
 
     if (json->type == JSON_STRING && uuid_from_string(&uuid, json->u.string)) {
         char *name = xasprintf("#%d#", *n);
-        ovsdb_symbol_table_put(symtab, name, &uuid);
+        fprintf(stderr, "%s = "UUID_FMT"\n", name, UUID_ARGS(&uuid));
+        ovsdb_symbol_table_put(symtab, name, &uuid, false);
         free(name);
         *n += 1;
     } else if (json->type == JSON_ARRAY) {
@@ -1368,12 +1369,12 @@ static void
 substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab)
 {
     if (json->type == JSON_STRING) {
-        const struct uuid *uuid;
+        const struct ovsdb_symbol *symbol;
 
-        uuid = ovsdb_symbol_table_get(symtab, json->u.string);
-        if (uuid) {
+        symbol = ovsdb_symbol_table_get(symtab, json->u.string);
+        if (symbol) {
             free(json->u.string);
-            json->u.string = xasprintf(UUID_FMT, UUID_ARGS(uuid));
+            json->u.string = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid));
         }
     } else if (json->type == JSON_ARRAY) {
         size_t i;