[ovs-dev] [PATCH 10/13] ovsdb-idl: Allow clients to modify records without using structs.

Ben Pfaff blp at nicira.com
Mon Jan 25 18:18:56 UTC 2010


The IDL is intended to allow clients easier access to data in the database
by providing an extra layer of abstraction.  However, ovs-vsctl needs to
also provide generic access to database tables, rows, and columns, and
until now the IDL has not allowed this.  In particular, there was no way
to modify the value of a database column by providing a "struct
ovsdb_datum" with the new value and then have that reflected in the IDL
structs, although the other direction was possible.

This commit fixes that problem, which requires a bit of refactoring of the
IDL layer.  It also exposes the interface for iterating through table
records to clients directly, by moving it from the "private" IDL header to
the public one.
---
 lib/ovsdb-idl-provider.h |   14 +---
 lib/ovsdb-idl.c          |  158 ++++++++++++++++++++++++++++++----------
 lib/ovsdb-idl.h          |   20 +++++-
 ovsdb/ovsdb-idlc.in      |  184 ++++++++++++++++++++++++++--------------------
 4 files changed, 245 insertions(+), 131 deletions(-)

diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
index 8bc6f3e..45ea869 100644
--- a/lib/ovsdb-idl-provider.h
+++ b/lib/ovsdb-idl-provider.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009 Nicira Networks.
+/* Copyright (c) 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,6 +41,8 @@ struct ovsdb_idl_row {
 struct ovsdb_idl_column {
     char *name;
     struct ovsdb_type type;
+    void (*parse)(struct ovsdb_idl_row *, const struct ovsdb_datum *);
+    void (*unparse)(struct ovsdb_idl_row *);
 };
 
 struct ovsdb_idl_table_class {
@@ -48,8 +50,6 @@ struct ovsdb_idl_table_class {
     const struct ovsdb_idl_column *columns;
     size_t n_columns;
     size_t allocation_size;
-    void (*parse)(struct ovsdb_idl_row *);
-    void (*unparse)(struct ovsdb_idl_row *);
 };
 
 struct ovsdb_idl_table {
@@ -69,14 +69,6 @@ struct ovsdb_idl_row *ovsdb_idl_get_row_arc(
     struct ovsdb_idl_table_class *dst_table,
     const struct uuid *dst_uuid);
 
-struct ovsdb_idl_row *ovsdb_idl_first_row(
-    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
-
-struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *);
-
-void ovsdb_idl_txn_write(struct ovsdb_idl_row *,
-                         const struct ovsdb_idl_column *,
-                         struct ovsdb_datum *);
 void ovsdb_idl_txn_verify(const struct ovsdb_idl_row *,
                           const struct ovsdb_idl_column *);
 void ovsdb_idl_txn_delete(struct ovsdb_idl_row *);
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 736707b..7bbe6bf 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -115,6 +115,8 @@ static struct ovsdb_idl_row *ovsdb_idl_row_create(struct ovsdb_idl_table *,
                                                   const struct uuid *);
 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row *);
 
+static void ovsdb_idl_row_parse(struct ovsdb_idl_row *);
+static void ovsdb_idl_row_unparse(struct ovsdb_idl_row *);
 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row *);
 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row *);
 
@@ -199,7 +201,7 @@ ovsdb_idl_clear(struct ovsdb_idl *idl)
             struct ovsdb_idl_arc *arc, *next_arc;
 
             if (!ovsdb_idl_row_is_orphan(row)) {
-                (row->table->class->unparse)(row);
+                ovsdb_idl_row_unparse(row);
                 ovsdb_idl_row_clear_old(row);
             }
             hmap_remove(&table->rows, &row->hmap_node);
@@ -535,6 +537,30 @@ ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
 }
 
 static void
+ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
+{
+    const struct ovsdb_idl_table_class *class = row->table->class;
+    size_t i;
+
+    for (i = 0; i < class->n_columns; i++) {
+        const struct ovsdb_idl_column *c = &class->columns[i];
+        (c->parse)(row, &row->old[i]);
+    }
+}
+
+static void
+ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
+{
+    const struct ovsdb_idl_table_class *class = row->table->class;
+    size_t i;
+
+    for (i = 0; i < class->n_columns; i++) {
+        const struct ovsdb_idl_column *c = &class->columns[i];
+        (c->unparse)(row);
+    }
+}
+
+static void
 ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
 {
     assert(row->old == row->new);
@@ -597,9 +623,10 @@ ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row, bool destroy_dsts)
 
     /* This is trickier than it looks.  ovsdb_idl_row_clear_arcs() will destroy
      * 'arc', so we need to use the "safe" variant of list traversal.  However,
-     * calling ref->table->class->parse will add an arc equivalent to 'arc' to
-     * row->arcs.  That could be a problem for traversal, but it adds it at the
-     * beginning of the list to prevent us from stumbling upon it again.
+     * calling an ovsdb_idl_column's 'parse' function will add an arc
+     * equivalent to 'arc' to row->arcs.  That could be a problem for
+     * traversal, but it adds it at the beginning of the list to prevent us
+     * from stumbling upon it again.
      *
      * (If duplicate arcs were possible then we would need to make sure that
      * 'next' didn't also point into 'arc''s destination, but we forbid
@@ -608,9 +635,9 @@ ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row, bool destroy_dsts)
                         &row->dst_arcs) {
         struct ovsdb_idl_row *ref = arc->src;
 
-        (ref->table->class->unparse)(ref);
+        ovsdb_idl_row_unparse(ref);
         ovsdb_idl_row_clear_arcs(ref, destroy_dsts);
-        (ref->table->class->parse)(ref);
+        ovsdb_idl_row_parse(ref);
     }
 }
 
@@ -656,7 +683,7 @@ ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
         ovsdb_datum_init_default(&row->old[i], &class->columns[i].type);
     }
     ovsdb_idl_row_update(row, row_json);
-    (class->parse)(row);
+    ovsdb_idl_row_parse(row);
 
     ovsdb_idl_row_reparse_backrefs(row, false);
 }
@@ -664,7 +691,7 @@ ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
 static void
 ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
 {
-    (row->table->class->unparse)(row);
+    ovsdb_idl_row_unparse(row);
     ovsdb_idl_row_clear_arcs(row, true);
     ovsdb_idl_row_clear_old(row);
     if (list_is_empty(&row->dst_arcs)) {
@@ -677,10 +704,10 @@ ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
 static void
 ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
 {
-    (row->table->class->unparse)(row);
+    ovsdb_idl_row_unparse(row);
     ovsdb_idl_row_clear_arcs(row, true);
     ovsdb_idl_row_update(row, row_json);
-    (row->table->class->parse)(row);
+    ovsdb_idl_row_parse(row);
 }
 
 static bool
@@ -697,7 +724,7 @@ may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
      *
      * We only need to test whether the first arc in dst->dst_arcs originates
      * at 'src', since we add all of the arcs from a given source in a clump
-     * (in a single call to a row's ->parse function) and new arcs are always
+     * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
      * added at the front of the dst_arcs list. */
     if (list_is_empty(&dst->dst_arcs)) {
         return true;
@@ -725,22 +752,44 @@ ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
 
     dst_table = ovsdb_idl_table_from_class(idl, dst_table_class);
     dst = ovsdb_idl_get_row(dst_table, dst_uuid);
-    if (!dst) {
-        dst = ovsdb_idl_row_create(dst_table, dst_uuid);
-    }
+    if (idl->txn) {
+        /* We're being called from ovsdb_idl_txn_write().  We must not update
+         * any arcs, because the transaction will be backed out at commit or
+         * abort time and we don't want our graph screwed up.
+         *
+         * Just return the destination row, if there is one and it has not been
+         * deleted. */
+        if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new)) {
+            return dst;
+        }
+        return NULL;
+    } else {
+        /* We're being called from some other context.  Update the graph. */
+        if (!dst) {
+            dst = ovsdb_idl_row_create(dst_table, dst_uuid);
+        }
 
-    /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
-    if (may_add_arc(src, dst)) {
-        /* The arc *must* be added at the front of the dst_arcs list.  See
-         * ovsdb_idl_row_reparse_backrefs() for details. */
-        arc = xmalloc(sizeof *arc);
-        list_push_front(&src->src_arcs, &arc->src_node);
-        list_push_front(&dst->dst_arcs, &arc->dst_node);
-        arc->src = src;
-        arc->dst = dst;
+        /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
+        if (may_add_arc(src, dst)) {
+            /* The arc *must* be added at the front of the dst_arcs list.  See
+             * ovsdb_idl_row_reparse_backrefs() for details. */
+            arc = xmalloc(sizeof *arc);
+            list_push_front(&src->src_arcs, &arc->src_node);
+            list_push_front(&dst->dst_arcs, &arc->dst_node);
+            arc->src = src;
+            arc->dst = dst;
+        }
+
+        return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
     }
+}
 
-    return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
+const struct ovsdb_idl_row *
+ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
+                           const struct ovsdb_idl_table_class *tc,
+                           const struct uuid *uuid)
+{
+    return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
 }
 
 static struct ovsdb_idl_row *
@@ -757,7 +806,7 @@ next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
     return NULL;
 }
 
-struct ovsdb_idl_row *
+const struct ovsdb_idl_row *
 ovsdb_idl_first_row(const struct ovsdb_idl *idl,
                     const struct ovsdb_idl_table_class *table_class)
 {
@@ -766,7 +815,7 @@ ovsdb_idl_first_row(const struct ovsdb_idl *idl,
     return next_real_row(table, hmap_first(&table->rows));
 }
 
-struct ovsdb_idl_row *
+const struct ovsdb_idl_row *
 ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
 {
     struct ovsdb_idl_table *table = row->table;
@@ -952,12 +1001,22 @@ ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
 {
     struct ovsdb_idl_row *row, *next;
 
+    /* This must happen early.  Otherwise, ovsdb_idl_row_parse() will call an
+     * ovsdb_idl_column's 'parse' function, which will call
+     * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
+     * transaction and fail to update the graph.  */
+    txn->idl->txn = NULL;
+
     HMAP_FOR_EACH_SAFE (row, next, struct ovsdb_idl_row, txn_node,
                         &txn->txn_rows) {
-        if (row->old && row->written) {
-            (row->table->class->unparse)(row);
-            ovsdb_idl_row_clear_arcs(row, false);
-            (row->table->class->parse)(row);
+        if (row->old) {
+            if (row->written) {
+                ovsdb_idl_row_unparse(row);
+                ovsdb_idl_row_clear_arcs(row, false);
+                ovsdb_idl_row_parse(row);
+            }
+        } else {
+            hmap_remove(&row->table->rows, &row->hmap_node);
         }
         ovsdb_idl_row_clear_new(row);
 
@@ -1063,9 +1122,10 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
             BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
                 const struct ovsdb_idl_column *column = &class->columns[idx];
 
-                if (!row->old || !ovsdb_datum_equals(&row->old[idx],
-                                                     &row->new[idx],
-                                                     &column->type)) {
+                if (row->old
+                    ? !ovsdb_datum_equals(&row->old[idx], &row->new[idx],
+                                          &column->type)
+                    : !ovsdb_datum_is_default(&row->new[idx], &column->type)) {
                     json_object_put(row_json, column->name,
                                     substitute_uuids(
                                         ovsdb_datum_to_json(&row->new[idx],
@@ -1139,7 +1199,6 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
         txn->status = TXN_INCOMPLETE;
     }
 
-    txn->idl->txn = NULL;
     ovsdb_idl_txn_disassemble(txn);
     return txn->status;
 }
@@ -1169,14 +1228,33 @@ ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
 }
 
 void
-ovsdb_idl_txn_write(struct ovsdb_idl_row *row,
+ovsdb_idl_txn_read(const struct ovsdb_idl_row *row,
+                   const struct ovsdb_idl_column *column,
+                   struct ovsdb_datum *datum)
+{
+    const struct ovsdb_idl_table_class *class = row->table->class;
+    size_t column_idx = column - class->columns;
+
+    assert(row->new != NULL);
+    if (row->written && bitmap_is_set(row->written, column_idx)) {
+        ovsdb_datum_clone(datum, &row->new[column_idx], &column->type);
+    } else if (row->old) {
+        ovsdb_datum_clone(datum, &row->old[column_idx], &column->type);
+    } else {
+        ovsdb_datum_init_default(datum, &column->type);
+    }
+}
+
+void
+ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
                     const struct ovsdb_idl_column *column,
                     struct ovsdb_datum *datum)
 {
+    struct ovsdb_idl_row *row = (struct ovsdb_idl_row *) row_;
     const struct ovsdb_idl_table_class *class = row->table->class;
     size_t column_idx = column - class->columns;
 
-    assert(row->new);
+    assert(row->new != NULL);
     if (hmap_node_is_null(&row->txn_node)) {
         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
                     uuid_hash(&row->uuid));
@@ -1193,6 +1271,8 @@ ovsdb_idl_txn_write(struct ovsdb_idl_row *row,
         bitmap_set1(row->written, column_idx);
     }
     row->new[column_idx] = *datum;
+    (column->unparse)(row);
+    (column->parse)(row, &row->new[column_idx]);
 }
 
 void
@@ -1203,7 +1283,7 @@ ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
     const struct ovsdb_idl_table_class *class = row->table->class;
     size_t column_idx = column - class->columns;
 
-    assert(row->new);
+    assert(row->new != NULL);
     if (!row->old
         || (row->written && bitmap_is_set(row->written, column_idx))) {
         return;
@@ -1222,10 +1302,11 @@ ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
 void
 ovsdb_idl_txn_delete(struct ovsdb_idl_row *row)
 {
-    assert(row->new);
+    assert(row->new != NULL);
     if (!row->old) {
         ovsdb_idl_row_clear_new(row);
         assert(!row->prereqs);
+        hmap_remove(&row->table->rows, &row->hmap_node);
         hmap_remove(&row->table->idl->txn->txn_rows, &row->txn_node);
         free(row);
         return;
@@ -1247,6 +1328,7 @@ ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
     row->table = ovsdb_idl_table_from_class(txn->idl, class);
     row->new = xmalloc(class->n_columns * sizeof *row->new);
     row->written = bitmap_allocate(class->n_columns);
+    hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
     hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
     return row;
 }
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index 88514b9..975dfc1 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009 Nicira Networks.
+/* Copyright (c) 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,11 @@
 #include <stdint.h>
 
 struct json;
+struct ovsdb_datum;
 struct ovsdb_idl_class;
+struct ovsdb_idl_column;
+struct ovsdb_idl_table_class;
+struct uuid;
 
 struct ovsdb_idl *ovsdb_idl_create(const char *remote,
                                    const struct ovsdb_idl_class *);
@@ -33,6 +37,13 @@ unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *);
 bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *);
 void ovsdb_idl_force_reconnect(struct ovsdb_idl *);
 
+const struct ovsdb_idl_row *ovsdb_idl_get_row_for_uuid(
+    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *,
+    const struct uuid *);
+const struct ovsdb_idl_row *ovsdb_idl_first_row(
+    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
+const struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *);
+
 enum ovsdb_idl_txn_status {
     TXN_UNCHANGED,              /* Transaction didn't include any changes. */
     TXN_INCOMPLETE,             /* Commit in progress, please wait. */
@@ -57,4 +68,11 @@ enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *);
 int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *);
 void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *);
 
+void ovsdb_idl_txn_read(const struct ovsdb_idl_row *,
+                        const struct ovsdb_idl_column *,
+                        struct ovsdb_datum *);
+void ovsdb_idl_txn_write(const struct ovsdb_idl_row *,
+                         const struct ovsdb_idl_column *,
+                         struct ovsdb_datum *);
+
 #endif /* ovsdb-idl.h */
diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index 10be351..62fe318 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -202,18 +202,16 @@ def cBaseType(prefix, type, refTable=None):
                 'boolean': 'bool ',
                 'string': 'char *'}[type]
 
-def cCopyType(indent, dstVar, dst, src, type, refTable=None):
+def cCopyType(indent, dst, src, type, refTable=None):
     args = {'indent': indent,
-            'dstVar': dstVar,
             'dst': dst,
             'src': src}
     if type == 'uuid' and refTable:
-        return ("%(indent)s%(dstVar)s = %(src)s;\n" +
-                "%(indent)s%(dst)s = %(src)s->header_.uuid;") % args
+        return ("%(indent)s%(dst)s = %(src)s->header_.uuid;") % args
     elif type == 'string':
-        return "%(indent)s%(dstVar)s = %(dst)s = xstrdup(%(src)s);" % args
+        return "%(indent)s%(dst)s = xstrdup(%(src)s);" % args
     else:
-        return "%(dstVar)s = %(dst)s = %(src)s;" % args
+        return "%(indent)s%(dst)s = %(src)s;" % args
 
 def typeIsOptionalPointer(type):
     return (type.min == 0 and type.max == 1 and not type.value
@@ -226,6 +224,18 @@ def cDeclComment(type):
     else:
         return ""
 
+def cInitDefault(var, type, refTable, isOptional):
+    if type == 'uuid' and refTable:
+        return "%s = NULL;" % var
+    elif type == 'string' and not isOptional:
+        return "%s = \"\";" % var
+    else:
+        return {'integer': '%s = 0;',
+                'real': '%s = 0.0;',
+                'uuid': 'uuid_zero(&%s);',
+                'boolean': '%s = false;',
+                'string': '%s = NULL;'}[type] % var
+
 def constify(cType, const):
     if (const
         and cType.endswith('*') and not cType.endswith('**')
@@ -280,19 +290,36 @@ def printCIDLHeader(schemaFile):
 #include <stdint.h>
 #include "ovsdb-idl-provider.h"
 #include "uuid.h"''' % {'prefix': prefix.upper()}
+
     for tableName, table in schema.tables.iteritems():
-        print
-        print "/* %s table. */" % tableName
         structName = "%s%s" % (prefix, tableName.lower())
+
+        print ""
+        print "/* %s table. */" % tableName
         print "struct %s {" % structName
         print "\tstruct ovsdb_idl_row header_;"
         for columnName, column in table.columns.iteritems():
             print "\n\t/* %s column. */" % columnName
             for member in cMembers(prefix, columnName, column, False):
                 print "\t%(type)s%(name)s;%(comment)s" % member
-        print '''\
-};
+        print "};"
+
+        # Column indexes.
+        printEnum(["%s_COL_%s" % (structName.upper(), columnName.upper())
+                   for columnName in table.columns]
+                  + ["%s_N_COLUMNS" % structName.upper()])
+
+        print
+        for columnName in table.columns:
+            print "#define %(s)s_col_%(c)s (%(s)s_columns[%(S)s_COL_%(C)s])" % {
+                's': structName,
+                'S': structName.upper(),
+                'c': columnName,
+                'C': columnName.upper()}
 
+        print "\nextern struct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (structName, structName.upper())
+
+        print '''
 const struct %(s)s *%(s)s_first(const struct ovsdb_idl *);
 const struct %(s)s *%(s)s_next(const struct %(s)s *);
 #define %(S)s_FOR_EACH(ROW, IDL) for ((ROW) = %(s)s_first(IDL); (ROW); (ROW) = %(s)s_next(ROW))
@@ -312,6 +339,17 @@ struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
                     in cMembers(prefix, columnName, column, True)]
             print '%s);' % ', '.join(args)
 
+    # Table indexes.
+    printEnum(["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in schema.tables] + ["%sN_TABLES" % prefix.upper()])
+    print
+    for tableName in schema.tables:
+        print "#define %(p)stable_%(t)s (%(p)stable_classes[%(P)sTABLE_%(T)s])" % {
+            'p': prefix,
+            'P': prefix.upper(),
+            't': tableName.lower(),
+            'T': tableName.upper()}
+    print "\nextern struct ovsdb_idl_table_class %stable_classes[%sN_TABLES];" % (prefix, prefix.upper())
+
     print "\nextern struct ovsdb_idl_class %sidl_class;" % prefix
     print "\n#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()}
 
@@ -336,16 +374,12 @@ def printCIDLSource(schemaFile):
 #include <limits.h>
 #include "ovsdb-data.h"''' % schema.idlHeader
 
-    # Table indexes.
-    printEnum(["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in schema.tables] + ["%sN_TABLES" % prefix.upper()])
-    print "\nstatic struct ovsdb_idl_table_class %stable_classes[%sN_TABLES];" % (prefix, prefix.upper())
-
     # Cast functions.
     for tableName, table in schema.tables.iteritems():
         structName = "%s%s" % (prefix, tableName.lower())
         print '''
 static struct %(s)s *
-%(s)s_cast(struct ovsdb_idl_row *row)
+%(s)s_cast(const struct ovsdb_idl_row *row)
 {
     return row ? CONTAINER_OF(row, struct %(s)s, header_) : NULL;
 }\
@@ -360,31 +394,18 @@ static struct %(s)s *
         else:
             print "/* %s table. */" % (tableName)
 
-        # Column indexes.
-        printEnum(["%s_COL_%s" % (structName.upper(), columnName.upper())
-                   for columnName in table.columns]
-                  + ["%s_N_COLUMNS" % structName.upper()])
-
-        print "\nstatic struct ovsdb_idl_column %s_columns[];" % structName
-
-        # Parse function.
-        print '''
+        # Parse functions.
+        for columnName, column in table.columns.iteritems():
+            print '''
 static void
-%s_parse(struct ovsdb_idl_row *row_)
+%(s)s_parse_%(c)s(struct ovsdb_idl_row *row_, const struct ovsdb_datum *datum)
 {
-    struct %s *row = %s_cast(row_);
-    const struct ovsdb_datum *datum;
-    size_t i UNUSED;
-
-    memset(row_ + 1, 0, sizeof *row - sizeof *row_);''' % (structName, structName, structName)
-
+    struct %(s)s *row = %(s)s_cast(row_);''' % {'s': structName,
+                                                'c': columnName}
 
-        for columnName, column in table.columns.iteritems():
             type = column.type
             refKey = type.key == "uuid" and type.keyRefTable
             refValue = type.value == "uuid" and type.valueRefTable
-            print
-            print "    datum = &row_->old[%s_COL_%s];" % (structName.upper(), columnName.upper())
             if type.value:
                 keyVar = "row->key_%s" % columnName
                 valueVar = "row->value_%s" % columnName
@@ -392,7 +413,9 @@ static void
                 keyVar = "row->%s" % columnName
                 valueVar = None
 
-            if (type.min == 1 and type.max == 1) or typeIsOptionalPointer(type):
+            if ((type.min == 1 and type.max == 1) or
+                typeIsOptionalPointer(type)):
+                print
                 print "    if (datum->n >= 1) {"
                 if not refKey:
                     print "        %s = datum->keys[0].%s;" % (keyVar, type.key)
@@ -404,20 +427,23 @@ static void
                         print "        %s = datum->values[0].%s;" % (valueVar, type.value)
                     else:
                         print "        %s = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->values[0].uuid));" % (valueVar, prefix, type.valueRefTable.lower(), prefix, prefix.upper(), type.valueRefTable.upper())
-                if (not typeIsOptionalPointer(type) and
-                    (type.key == "string" or type.value == "string")):
-                    print "    } else {"
-                    if type.key == "string":
-                        print "        %s = \"\";" % keyVar
-                    if type.value == "string":
-                        print "        %s = \"\";" % valueVar
+                print "    } else {"
+                print "        %s" % cInitDefault(keyVar, type.key, type.keyRefTable, type.min == 0)
+                if valueVar:
+                    print "        %s" % cInitDefault(valueVar, type.value, type.valueRefTable, type.min == 0)
                 print "    }"
-
             else:
                 if type.max != 'unlimited':
-                    nMax = "MIN(%d, datum->n)" % type.max
+                    print "    size_t n = MIN(%d, datum->n);" % type.max
+                    nMax = "n"
                 else:
                     nMax = "datum->n"
+                print "    size_t i;"
+                print
+                print "    %s = NULL;" % keyVar
+                if valueVar:
+                    print "    %s = NULL;" % valueVar
+                print "    row->n_%s = 0;" % columnName
                 print "    for (i = 0; i < %s; i++) {" % nMax
                 refs = []
                 if refKey:
@@ -449,20 +475,18 @@ static void
                 if refs:
                     print "        }"
                 print "    }"
-        print "}"
+            print "}"
 
-        # Unparse function.
-        nArrays = 0
+        # Unparse functions.
         for columnName, column in table.columns.iteritems():
             type = column.type
             if (type.min != 1 or type.max != 1) and not typeIsOptionalPointer(type):
-                if not nArrays:
-                    print '''
+                print '''
 static void
-%s_unparse(struct ovsdb_idl_row *row_)
+%(s)s_unparse_%(c)s(struct ovsdb_idl_row *row_)
 {
-    struct %s *row = %s_cast(row_);
-''' % (structName, structName, structName)
+    struct %(s)s *row = %(s)s_cast(row_);
+''' % {'s': structName, 'c': columnName}
                 if type.value:
                     keyVar = "row->key_%s" % columnName
                     valueVar = "row->value_%s" % columnName
@@ -472,14 +496,15 @@ static void
                 print "    free(%s);" % keyVar
                 if valueVar:
                     print "    free(%s);" % valueVar
-                nArrays += 1
-        if not nArrays:
-            print '''
+                print '}'
+            else:
+                print '''
 static void
-%s_unparse(struct ovsdb_idl_row *row UNUSED)
-{''' % (structName)
-        print "}"
-
+%(s)s_unparse_%(c)s(struct ovsdb_idl_row *row UNUSED)
+{
+    /* Nothing to do. */
+}''' % {'s': structName, 'c': columnName}
+ 
         # First, next functions.
         print '''
 const struct %(s)s *
@@ -542,20 +567,19 @@ void
             else:
                 if len(members) > 1:
                     nVar = members[1]['name']
-            print '%(s)s_set_%(c)s(const struct %(s)s *row_, %(args)s)' % \
+            print '%(s)s_set_%(c)s(const struct %(s)s *row, %(args)s)' % \
                 {'s': structName, 'c': columnName,
                  'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
             print "{"
-            print "    struct %(s)s *row = (struct %(s)s *) row_;" % {'s': structName}
             print "    struct ovsdb_datum datum;"
             if type.min == 1 and type.max == 1:
                 print
                 print "    datum.n = 1;"
                 print "    datum.keys = xmalloc(sizeof *datum.keys);"
-                print cCopyType("    ", "row->%s" % keyVar, "datum.keys[0].%s" % type.key, keyVar, type.key, type.keyRefTable)
+                print cCopyType("    ", "datum.keys[0].%s" % type.key, keyVar, type.key, type.keyRefTable)
                 if type.value:
                     print "    datum.values = xmalloc(sizeof *datum.values);"
-                    print cCopyType("    ", "row->%s" % valueVar, "datum.values[0].%s" % type.value, valueVar, type.value, type.valueRefTable)
+                    print cCopyType("    ", "datum.values[0].%s" % type.value, valueVar, type.value, type.valueRefTable)
                 else:
                     print "    datum.values = NULL;"
             elif typeIsOptionalPointer(type):
@@ -563,22 +587,15 @@ void
                 print "    if (%s) {" % keyVar
                 print "        datum.n = 1;"
                 print "        datum.keys = xmalloc(sizeof *datum.keys);"
-                print cCopyType("        ", "row->%s" % keyVar, "datum.keys[0].%s" % type.key, keyVar, type.key, type.keyRefTable)
+                print cCopyType("        ", "datum.keys[0].%s" % type.key, keyVar, type.key, type.keyRefTable)
                 print "    } else {"
                 print "        datum.n = 0;"
                 print "        datum.keys = NULL;"
-                print "        row->%s = NULL;" % keyVar
                 print "    }"
                 print "    datum.values = NULL;"
             else:
                 print "    size_t i;"
                 print
-                print "    free(row->%s);" % keyVar
-                print "    row->%s = %s ? xmalloc(%s * sizeof *row->%s) : NULL;" % (keyVar, nVar, nVar, keyVar)
-                print "    row->%s = %s;" % (nVar, nVar)
-                if type.value:
-                    print "    free(row->%s);" % valueVar
-                    print "    row->%s = xmalloc(%s * sizeof *row->%s);" % (valueVar, nVar, valueVar)
                 print "    datum.n = %s;" % nVar
                 print "    datum.keys = xmalloc(%s * sizeof *datum.keys);" % nVar
                 if type.value:
@@ -586,9 +603,9 @@ void
                 else:
                     print "    datum.values = NULL;"
                 print "    for (i = 0; i < %s; i++) {" % nVar
-                print cCopyType("        ", "row->%s[i]" % keyVar, "datum.keys[i].%s" % type.key, "%s[i]" % keyVar, type.key, type.keyRefTable)
+                print cCopyType("        ", "datum.keys[i].%s" % type.key, "%s[i]" % keyVar, type.key, type.keyRefTable)
                 if type.value:
-                    print cCopyType("        ", "row->%s[i]" % valueVar, "datum.values[i].%s" % type.value, "%s[i]" % valueVar, type.value, type.valueRefTable)
+                    print cCopyType("        ", "datum.values[i].%s" % type.value, "%s[i]" % valueVar, type.value, type.valueRefTable)
                 print "    }"
             print "    ovsdb_idl_txn_write(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \
                 % {'s': structName,
@@ -597,7 +614,7 @@ void
             print "}"
 
         # Table columns.
-        print "\nstatic struct ovsdb_idl_column %s_columns[%s_N_COLUMNS] = {" % (
+        print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS] = {" % (
             structName, structName.upper())
         for columnName, column in table.columns.iteritems():
             type = column.type
@@ -610,22 +627,27 @@ void
                 max = "UINT_MAX"
             else:
                 max = type.max
-            print "    {\"%s\", {OVSDB_TYPE_%s, OVSDB_TYPE_%s, %d, %s}}," % (
-                columnName, type.key.upper(), valueTypeName,
-                type.min, max)
+            print """\
+    {"%(c)s",
+     {OVSDB_TYPE_%(kt)s, OVSDB_TYPE_%(vt)s, %(min)s, %(max)s},
+     %(s)s_parse_%(c)s,
+     %(s)s_unparse_%(c)s},""" % {'c': columnName,
+                                 's': structName,
+                                 'kt': type.key.upper(),
+                                 'vt': valueTypeName,
+                                 'min': type.min,
+                                 'max': max}
         print "};"
 
     # Table classes.
     print ""
-    print "static struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper())
+    print "struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper())
     for tableName, table in schema.tables.iteritems():
         structName = "%s%s" % (prefix, tableName.lower())
         print "    {\"%s\"," % tableName
         print "     %s_columns, ARRAY_SIZE(%s_columns)," % (
             structName, structName)
-        print "     sizeof(struct %s)," % structName
-        print "     %s_parse," % structName
-        print "     %s_unparse}," % structName
+        print "     sizeof(struct %s)}," % structName
     print "};"
 
     # IDL class.
-- 
1.6.3.3





More information about the dev mailing list