ovsdb: Add replication support and refactor files in terms of replication.
[sliver-openvswitch.git] / ovsdb / transaction.c
index 21a46ec..d5e3601 100644 (file)
@@ -59,13 +59,6 @@ struct ovsdb_txn_row {
     struct ovsdb_row *new;      /* The new row. */
 };
 
-static const struct uuid *
-ovsdb_txn_row_get_uuid(const struct ovsdb_txn_row *txn_row)
-{
-    const struct ovsdb_row *row = txn_row->old ? txn_row->old : txn_row->new;
-    return ovsdb_row_get_uuid(row);
-}
-
 struct ovsdb_txn *
 ovsdb_txn_create(struct ovsdb *db)
 {
@@ -131,197 +124,43 @@ ovsdb_txn_row_commit(struct ovsdb_txn_row *txn_row)
     ovsdb_row_destroy(txn_row->old);
 }
 
-void
-ovsdb_txn_commit(struct ovsdb_txn *txn)
-{
-    txn->db->run_triggers = true;
-    ovsdb_txn_destroy(txn, ovsdb_txn_row_commit);
-}
-
-static void
-put_json_column(struct json *object, const struct ovsdb_row *row,
-                const struct ovsdb_column *column)
-{
-    json_object_put(object, column->name,
-                    ovsdb_datum_to_json(&row->fields[column->index],
-                                        &column->type));
-}
-
-static struct json *
-ovsdb_txn_row_to_json(const struct ovsdb_txn_row *txn_row)
-{
-    const struct ovsdb_row *old = txn_row->old;
-    const struct ovsdb_row *new = txn_row->new;
-    struct shash_node *node;
-    struct json *json;
-
-    if (!new) {
-        return json_null_create();
-    }
-
-    json = NULL;
-    SHASH_FOR_EACH (node, &new->table->schema->columns) {
-        struct ovsdb_column *column = node->data;
-        unsigned int index = column->index;
-
-        if (index != OVSDB_COL_UUID && column->persistent
-            && (!old || !ovsdb_datum_equals(&old->fields[index],
-                                            &new->fields[index],
-                                            &column->type)))
-        {
-            if (!json) {
-                json = json_object_create();
-            }
-            put_json_column(json, new, column);
-        }
-    }
-    return json;
-}
-
-static struct json *
-ovsdb_txn_table_to_json(const struct ovsdb_txn_table *txn_table)
-{
-    struct ovsdb_txn_row *txn_row;
-    struct json *txn_table_json;
-
-    txn_table_json = NULL;
-    HMAP_FOR_EACH (txn_row, struct ovsdb_txn_row, hmap_node,
-                   &txn_table->txn_rows) {
-        struct json *txn_row_json = ovsdb_txn_row_to_json(txn_row);
-        if (txn_row_json) {
-            char uuid[UUID_LEN + 1];
-
-            if (!txn_table_json) {
-                txn_table_json = json_object_create();
-            }
-
-            snprintf(uuid, sizeof uuid,
-                     UUID_FMT, UUID_ARGS(ovsdb_txn_row_get_uuid(txn_row)));
-            json_object_put(txn_table_json, uuid, txn_row_json);
-        }
-    }
-    return txn_table_json;
-}
-
-struct json *
-ovsdb_txn_to_json(const struct ovsdb_txn *txn)
-{
-    struct ovsdb_txn_table *txn_table;
-    struct json *txn_json;
-
-    txn_json = NULL;
-    HMAP_FOR_EACH (txn_table, struct ovsdb_txn_table, hmap_node,
-                   &txn->txn_tables) {
-        struct json *txn_table_json = ovsdb_txn_table_to_json(txn_table);
-        if (!txn_json) {
-            txn_json = json_object_create();
-        }
-        json_object_put(txn_json, txn_table->table->schema->name,
-                        txn_table_json);
-    }
-    return txn_json;
-}
-
-static struct ovsdb_error *
-ovsdb_txn_row_from_json(struct ovsdb_txn *txn, struct ovsdb_table *table,
-                        const struct uuid *row_uuid, struct json *json)
+struct ovsdb_error *
+ovsdb_txn_commit(struct ovsdb_txn *txn, bool durable)
 {
-    const struct ovsdb_row *row = ovsdb_table_get_row(table, row_uuid);
-    if (json->type == JSON_NULL) {
-        if (!row) {
-            return ovsdb_syntax_error(NULL, NULL, "transaction deletes "
-                                      "row "UUID_FMT" that does not exist",
-                                      UUID_ARGS(row_uuid));
-        }
-        ovsdb_txn_row_delete(txn, row);
-        return NULL;
-    } else if (row) {
-        return ovsdb_row_from_json(ovsdb_txn_row_modify(txn, row),
-                                   json, NULL, NULL);
-    } else {
-        struct ovsdb_error *error;
-        struct ovsdb_row *new;
+    struct ovsdb_replica *replica;
+    struct ovsdb_error *error;
 
-        new = ovsdb_row_create(table);
-        *ovsdb_row_get_uuid_rw(new) = *row_uuid;
-        error = ovsdb_row_from_json(new, json, NULL, NULL);
+    LIST_FOR_EACH (replica, struct ovsdb_replica, node, &txn->db->replicas) {
+        error = (replica->class->commit)(replica, txn, durable);
         if (error) {
-            ovsdb_row_destroy(new);
-        }
-
-        ovsdb_txn_row_insert(txn, new);
-
-        return error;
-    }
-}
-
-static struct ovsdb_error *
-ovsdb_txn_table_from_json(struct ovsdb_txn *txn, struct ovsdb_table *table,
-                          struct json *json)
-{
-    struct shash_node *node;
-
-    if (json->type != JSON_OBJECT) {
-        return ovsdb_syntax_error(json, NULL, "object expected");
-    }
-
-    SHASH_FOR_EACH (node, json->u.object) {
-        const char *uuid_string = node->name;
-        struct json *txn_row_json = node->data;
-        struct ovsdb_error *error;
-        struct uuid row_uuid;
+            /* We don't support two-phase commit so only the first replica is
+             * allowed to report an error. */
+            assert(&replica->node == txn->db->replicas.next);
 
-        if (!uuid_from_string(&row_uuid, uuid_string)) {
-            return ovsdb_syntax_error(json, NULL, "\"%s\" is not a valid UUID",
-                                      uuid_string);
-        }
-
-        error = ovsdb_txn_row_from_json(txn, table, &row_uuid, txn_row_json);
-        if (error) {
+            ovsdb_txn_abort(txn);
             return error;
         }
     }
 
+    txn->db->run_triggers = true;
+    ovsdb_txn_destroy(txn, ovsdb_txn_row_commit);
     return NULL;
 }
 
-struct ovsdb_error *
-ovsdb_txn_from_json(struct ovsdb *db, const struct json *json,
-                    struct ovsdb_txn **txnp)
+void
+ovsdb_txn_for_each_change(const struct ovsdb_txn *txn,
+                          ovsdb_txn_row_cb_func *cb, void *aux)
 {
-    struct ovsdb_error *error;
-    struct shash_node *node;
-    struct ovsdb_txn *txn;
+    struct ovsdb_txn_table *t;
+    struct ovsdb_txn_row *r;
 
-    *txnp = NULL;
-    if (json->type != JSON_OBJECT) {
-        return ovsdb_syntax_error(json, NULL, "object expected");
-    }
-
-    txn = ovsdb_txn_create(db);
-    SHASH_FOR_EACH (node, json->u.object) {
-        const char *table_name = node->name;
-        struct json *txn_table_json = node->data;
-        struct ovsdb_table *table;
-
-        table = shash_find_data(&db->tables, table_name);
-        if (!table) {
-            error = ovsdb_syntax_error(json, "unknown table",
-                                       "No table named %s.", table_name);
-            goto error;
-        }
-
-        error = ovsdb_txn_table_from_json(txn, table, txn_table_json);
-        if (error) {
-            goto error;
+    HMAP_FOR_EACH (t, struct ovsdb_txn_table, hmap_node, &txn->txn_tables) {
+        HMAP_FOR_EACH (r, struct ovsdb_txn_row, hmap_node, &t->txn_rows) {
+            if (!cb(r->old, r->new, aux)) {
+                break;
+            }
         }
-    }
-    *txnp = txn;
-    return NULL;
-
-error:
-    ovsdb_txn_abort(txn);
-    return error;
+   }
 }
 
 static struct ovsdb_txn_table *