diff mbox

[ovs-dev,15/15] ovsdb-idl: Check internal graph in OVSDB tests.

Message ID 1475723812-20932-15-git-send-email-blp@ovn.org
State Accepted
Headers show

Commit Message

Ben Pfaff Oct. 6, 2016, 3:16 a.m. UTC
Some upcoming tests will add extra trickiness to the IDL internal graph.
This worries me, because the IDL doesn't have any checks for its graph
consistency.  This commit adds some.

Signed-off-by: Ben Pfaff <blp@ovn.org>
---
 lib/ovsdb-idl.c    | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ovsdb-idl.h    |   2 +
 tests/test-ovsdb.c |   7 +++
 3 files changed, 131 insertions(+)

Comments

Andy Zhou Oct. 17, 2016, 8:44 p.m. UTC | #1
On Wed, Oct 5, 2016 at 8:16 PM, Ben Pfaff <blp@ovn.org> wrote:

> Some upcoming tests will add extra trickiness to the IDL internal graph.
> This worries me, because the IDL doesn't have any checks for its graph
> consistency.  This commit adds some.
>
> Signed-off-by: Ben Pfaff <blp@ovn.org>
>

For all 15 patches in the series,

Acked-by: Andy Zhou <azhou@ovn.org>
Ben Pfaff Oct. 19, 2016, 6:39 p.m. UTC | #2
On Mon, Oct 17, 2016 at 01:44:03PM -0700, Andy Zhou wrote:
> On Wed, Oct 5, 2016 at 8:16 PM, Ben Pfaff <blp@ovn.org> wrote:
> 
> > Some upcoming tests will add extra trickiness to the IDL internal graph.
> > This worries me, because the IDL doesn't have any checks for its graph
> > consistency.  This commit adds some.
> >
> > Signed-off-by: Ben Pfaff <blp@ovn.org>
> >
> 
> For all 15 patches in the series,
> 
> Acked-by: Andy Zhou <azhou@ovn.org>

Thanks Andy.  I applied these to master.
diff mbox

Patch

diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index b4d3c42..8ce228d 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -629,6 +629,128 @@  ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
 {
     jsonrpc_session_set_probe_interval(idl->session, probe_interval);
 }
+
+static size_t
+find_uuid_in_array(const struct uuid *target,
+                   const struct uuid *array, size_t n)
+{
+    for (size_t i = 0; i < n; i++) {
+        if (uuid_equals(&array[i], target)) {
+            return i;
+        }
+    }
+    return SIZE_MAX;
+}
+
+static size_t
+array_contains_uuid(const struct uuid *target,
+                    const struct uuid *array, size_t n)
+{
+    return find_uuid_in_array(target, array, n) != SIZE_MAX;
+}
+
+static bool
+remove_uuid_from_array(const struct uuid *target,
+                       struct uuid *array, size_t *n)
+{
+    size_t i = find_uuid_in_array(target, array, *n);
+    if (i != SIZE_MAX) {
+        array[i] = array[--*n];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static void
+add_row_references(const struct ovsdb_base_type *type,
+                   const union ovsdb_atom *atoms, size_t n_atoms,
+                   const struct uuid *exclude_uuid,
+                   struct uuid **dstsp, size_t *n_dstsp,
+                   size_t *allocated_dstsp)
+{
+    if (type->type != OVSDB_TYPE_UUID || !type->u.uuid.refTableName) {
+        return;
+    }
+
+    for (size_t i = 0; i < n_atoms; i++) {
+        const struct uuid *uuid = &atoms[i].uuid;
+        if (!uuid_equals(uuid, exclude_uuid)
+            && !array_contains_uuid(uuid, *dstsp, *n_dstsp)) {
+            if (*n_dstsp >= *allocated_dstsp) {
+                *dstsp = x2nrealloc(*dstsp, allocated_dstsp,
+                                    sizeof **dstsp);
+
+            }
+            (*dstsp)[*n_dstsp] = *uuid;
+            ++*n_dstsp;
+        }
+    }
+}
+
+/* Checks for consistency in 'idl''s graph of arcs between database rows.  Each
+ * reference from one row to a different row should be reflected as a "struct
+ * ovsdb_idl_arc" between those rows.
+ *
+ * This function is slow, big-O wise, and aborts if it finds an inconsistency,
+ * thus it is only for use in test programs. */
+void
+ovsdb_idl_check_consistency(const struct ovsdb_idl *idl)
+{
+    /* Consistency is broken while a transaction is in progress. */
+    if (!idl->txn) {
+        return;
+    }
+
+    bool ok = true;
+
+    struct uuid *dsts = NULL;
+    size_t allocated_dsts = 0;
+
+    for (size_t i = 0; i < idl->class->n_tables; i++) {
+        const struct ovsdb_idl_table *table = &idl->tables[i];
+        const struct ovsdb_idl_table_class *class = table->class;
+
+        const struct ovsdb_idl_row *row;
+        HMAP_FOR_EACH (row, hmap_node, &table->rows) {
+            size_t n_dsts = 0;
+            if (row->new) {
+                size_t n_columns = shash_count(&row->table->columns);
+                for (size_t j = 0; j < n_columns; j++) {
+                    const struct ovsdb_type *type = &class->columns[j].type;
+                    const struct ovsdb_datum *datum = &row->new[j];
+                    add_row_references(&type->key,
+                                       datum->keys, datum->n, &row->uuid,
+                                       &dsts, &n_dsts, &allocated_dsts);
+                    add_row_references(&type->value,
+                                       datum->values, datum->n, &row->uuid,
+                                       &dsts, &n_dsts, &allocated_dsts);
+                }
+            }
+            const struct ovsdb_idl_arc *arc;
+            LIST_FOR_EACH (arc, src_node, &row->src_arcs) {
+                if (!remove_uuid_from_array(&arc->dst->uuid,
+                                            dsts, &n_dsts)) {
+                    VLOG_ERR("unexpected arc from %s row "UUID_FMT" to %s "
+                             "row "UUID_FMT,
+                             table->class->name,
+                             UUID_ARGS(&row->uuid),
+                             arc->dst->table->class->name,
+                             UUID_ARGS(&arc->dst->uuid));
+                    ok = false;
+                }
+            }
+            for (size_t i = 0; i < n_dsts; i++) {
+                VLOG_ERR("%s row "UUID_FMT" missing arc to row "UUID_FMT,
+                         table->class->name, UUID_ARGS(&row->uuid),
+                         UUID_ARGS(&dsts[i]));
+                ok = false;
+            }
+        }
+    }
+    free(dsts);
+    ovs_assert(ok);
+}
 
 static unsigned char *
 ovsdb_idl_get_mode(struct ovsdb_idl *idl,
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index 28fe374..8786a41 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -75,6 +75,8 @@  bool ovsdb_idl_is_alive(const struct ovsdb_idl *);
 int ovsdb_idl_get_last_error(const struct ovsdb_idl *);
 
 void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval);
+
+void ovsdb_idl_check_consistency(const struct ovsdb_idl *);
 
 /* Choosing columns and tables to replicate. */
 
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index 7e3085b..6a7d467 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -2038,6 +2038,7 @@  idl_set(struct ovsdb_idl *idl, char *commands, int step)
     bool increment = false;
 
     txn = ovsdb_idl_txn_create(idl);
+    ovsdb_idl_check_consistency(idl);
     for (cmd = strtok_r(commands, ",", &save_ptr1); cmd;
          cmd = strtok_r(NULL, ",", &save_ptr1)) {
         char *save_ptr2 = NULL;
@@ -2144,14 +2145,17 @@  idl_set(struct ovsdb_idl *idl, char *commands, int step)
             increment = true;
         } else if (!strcmp(name, "abort")) {
             ovsdb_idl_txn_abort(txn);
+            ovsdb_idl_check_consistency(idl);
             break;
         } else if (!strcmp(name, "destroy")) {
             printf("%03d: destroy\n", step);
             ovsdb_idl_txn_destroy(txn);
+            ovsdb_idl_check_consistency(idl);
             return;
         } else {
             ovs_fatal(0, "unknown command %s", name);
         }
+        ovsdb_idl_check_consistency(idl);
     }
 
     status = ovsdb_idl_txn_commit_block(txn);
@@ -2163,6 +2167,7 @@  idl_set(struct ovsdb_idl *idl, char *commands, int step)
     }
     putchar('\n');
     ovsdb_idl_txn_destroy(txn);
+    ovsdb_idl_check_consistency(idl);
 }
 
 static const struct ovsdb_idl_table_class *
@@ -2422,6 +2427,7 @@  do_idl(struct ovs_cmdl_context *ctx)
             /* Wait for update. */
             for (;;) {
                 ovsdb_idl_run(idl);
+                ovsdb_idl_check_consistency(idl);
                 if (ovsdb_idl_get_seqno(idl) != seqno) {
                     break;
                 }
@@ -2474,6 +2480,7 @@  do_idl(struct ovs_cmdl_context *ctx)
     }
     for (;;) {
         ovsdb_idl_run(idl);
+        ovsdb_idl_check_consistency(idl);
         if (ovsdb_idl_get_seqno(idl) != seqno) {
             break;
         }