ovsdb-tool now accepts multiple schema files for all applicable options.
If these schema can be joined together without compatibility error,
the joined schema will be used as the runtime DB schema.

When storing joined schemata into a database file, A JSON array will
be store as its first record, with every individual schema as the
element of the array. The joined schema is not stored into the file.
Since one can be rebuilt by rejoining the schmeata represented by
the JSON array.

Signed-off-by: Andy Zhou <az...@nicira.com>
---
 ovsdb/file.c         |  85 ++++++++++++++----------
 ovsdb/file.h         |  14 ++--
 ovsdb/ovsdb-server.c |   2 +-
 ovsdb/ovsdb-tool.c   | 178 +++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 199 insertions(+), 80 deletions(-)

diff --git a/ovsdb/file.c b/ovsdb/file.c
index 8c3c31b..041b538 100644
--- a/ovsdb/file.c
+++ b/ovsdb/file.c
@@ -64,7 +64,7 @@ static struct ovsdb_error *ovsdb_file_txn_commit(struct json 
*,
                                                  struct ovsdb_log *);
 
 static struct ovsdb_error *ovsdb_file_open__(const char *file_name,
-                                             const struct ovsdb_schema *,
+                                             struct shash *schemata,
                                              bool read_only, struct ovsdb **,
                                              struct ovsdb_file **);
 static struct ovsdb_error *ovsdb_file_txn_from_json(
@@ -85,20 +85,28 @@ static struct ovsdb_error *ovsdb_file_create(struct ovsdb *,
  * '*filep' to an ovsdb_file that represents the open file.  This ovsdb_file
  * persists until '*dbp' is destroyed.
  *
+ * If 'schemata' is nonnull, it needs to be an empty shash. On success,
+ * it contains the schemata read from the log file. Caller is repsonsible
+ * for freeing memory.
+ *
  * On success, returns NULL.  On failure, returns an ovsdb_error (which the
  * caller must destroy) and sets '*dbp' and '*filep' to NULL. */
 struct ovsdb_error *
 ovsdb_file_open(const char *file_name, bool read_only,
-                struct ovsdb **dbp, struct ovsdb_file **filep)
+                struct ovsdb **dbp, struct ovsdb_file **filep,
+                struct shash *schemata)
 {
-    return ovsdb_file_open__(file_name, NULL, read_only, dbp, filep);
+    if (schemata) {
+        ovs_assert(shash_count(schemata) == 0);
+    }
+    return ovsdb_file_open__(file_name, schemata, read_only, dbp, filep);
 }
 
-/* Opens database 'file_name' with an alternate schema.  The specified 'schema'
- * is used to interpret the data in 'file_name', ignoring the schema actually
- * stored in the file.  Data in the file for tables or columns that do not
- * exist in 'schema' are ignored, but the ovsdb file format must otherwise be
- * observed, including column constraints.
+/* Opens database 'file_name' with an alternate schemata.  The specified
+ * 'schemata' * is used to interpret the data in 'file_name', ignoring the
+ * schemata actually stored in the file.  Data in the file for tables or
+ * columns that do not exist in 'schemata' are ignored, but the ovsdb file
+ * format must otherwise be observed, including column constraints.
  *
  * This function can be useful for upgrading or downgrading databases to
  * "almost-compatible" formats.
@@ -110,23 +118,22 @@ ovsdb_file_open(const char *file_name, bool read_only,
  * null pointer.  On failure, returns an ovsdb_error (which the caller must
  * destroy) and sets '*dbp' to NULL. */
 struct ovsdb_error *
-ovsdb_file_open_as_schema(const char *file_name,
-                          const struct ovsdb_schema *schema,
-                          struct ovsdb **dbp)
+ovsdb_file_open_as_schemata(const char *file_name,
+                            struct shash *schemata,
+                            struct ovsdb **dbp)
 {
-    return ovsdb_file_open__(file_name, schema, true, dbp, NULL);
+    return ovsdb_file_open__(file_name, schemata, true, dbp, NULL);
 }
 
 static struct ovsdb_error *
 ovsdb_file_open_log(const char *file_name, enum ovsdb_log_open_mode open_mode,
-                    struct ovsdb_log **logp, struct ovsdb_schema **schemap)
+                    struct ovsdb_log **logp, struct shash *schemata)
 {
-    struct ovsdb_schema *schema = NULL;
     struct ovsdb_log *log = NULL;
     struct ovsdb_error *error;
     struct json *json = NULL;
 
-    ovs_assert(logp || schemap);
+    ovs_assert(logp || schemata);
 
     error = ovsdb_log_open(file_name, open_mode, -1, &log);
     if (error) {
@@ -142,8 +149,8 @@ ovsdb_file_open_log(const char *file_name, enum 
ovsdb_log_open_mode open_mode,
         goto error;
     }
 
-    if (schemap) {
-        error = ovsdb_schema_from_json(json, &schema);
+    if (ovsdb_schemata_is_empty(schemata)) {
+        error = ovsdb_schemata_from_json(json, schemata);
         if (error) {
             error = ovsdb_wrap_error(error,
                                      "failed to parse \"%s\" as ovsdb schema",
@@ -158,9 +165,6 @@ ovsdb_file_open_log(const char *file_name, enum 
ovsdb_log_open_mode open_mode,
     } else {
         ovsdb_log_close(log);
     }
-    if (schemap) {
-        *schemap = schema;
-    }
     return NULL;
 
 error:
@@ -169,44 +173,57 @@ error:
     if (logp) {
         *logp = NULL;
     }
-    if (schemap) {
-        *schemap = NULL;
-    }
     return error;
 }
 
 static struct ovsdb_error *
 ovsdb_file_open__(const char *file_name,
-                  const struct ovsdb_schema *alternate_schema,
+                  struct shash *schemata,
                   bool read_only, struct ovsdb **dbp,
                   struct ovsdb_file **filep)
 {
     enum ovsdb_log_open_mode open_mode;
     unsigned int n_transactions;
-    struct ovsdb_schema *schema = NULL;
+    struct ovsdb_schema *joined_schema;
     struct ovsdb_error *error;
     struct ovsdb_log *log;
     struct json *json;
     struct ovsdb *db = NULL;
+    bool convert = ovsdb_schemata_is_non_empty(schemata);
+    struct shash local_schemata = SHASH_INITIALIZER(&local_schemata);
+
+    /* If caller passed in non empty 'schemata',  we will use it
+     * instead of the schemata stored int the log file.  Otherwise,
+     * it will be the container for storing the schemata read from
+     * the log file.  */
+    if (!schemata) {
+        /* Caller don't need the schmeta information, we use 'local_schemata'
+         * to read it from the db file. */
+        schemata = &local_schemata;
+    }
 
     /* In read-only mode there is no ovsdb_file so 'filep' must be null. */
     ovs_assert(!(read_only && filep));
 
     open_mode = read_only ? OVSDB_LOG_READ_ONLY : OVSDB_LOG_READ_WRITE;
-    error = ovsdb_file_open_log(file_name, open_mode, &log,
-                                alternate_schema ? NULL : &schema);
+    error = ovsdb_file_open_log(file_name, open_mode, &log, schemata);
+    if (error) {
+        goto error;
+    }
+
+    error = ovsdb_schemata_join(schemata, &joined_schema);
     if (error) {
         goto error;
     }
 
-    db = ovsdb_create(schema ? schema : ovsdb_schema_clone(alternate_schema));
+    /* 'db' will take the ownership of joined_schema */
+    db = ovsdb_create(joined_schema);
 
     n_transactions = 0;
     while ((error = ovsdb_log_read(log, &json)) == NULL && json) {
         struct ovsdb_txn *txn;
 
-        error = ovsdb_file_txn_from_json(db, json, alternate_schema != NULL,
-                                         &txn);
+        error = ovsdb_file_txn_from_json(db, json, convert, &txn);
         json_destroy(json);
         if (error) {
             ovsdb_log_unread(log);
@@ -246,6 +263,7 @@ ovsdb_file_open__(const char *file_name,
     }
 
     *dbp = db;
+    ovsdb_schemata_destroy(&local_schemata);
     return NULL;
 
 error:
@@ -253,6 +271,7 @@ error:
     if (filep) {
         *filep = NULL;
     }
+    ovsdb_schemata_destroy(&local_schemata);
     ovsdb_destroy(db);
     ovsdb_log_close(log);
     return error;
@@ -484,10 +503,10 @@ ovsdb_file_save_copy(const char *file_name, int locking,
  * schema.  On failure, returns an ovsdb_error (which the caller must destroy)
  * and sets '*dbp' to NULL. */
 struct ovsdb_error *
-ovsdb_file_read_schema(const char *file_name, struct ovsdb_schema **schemap)
+ovsdb_file_read_schemata(const char *file_name, struct shash *schemata)
 {
-    ovs_assert(schemap != NULL);
-    return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL, schemap);
+    ovs_assert(schemata && ovsdb_schemata_is_empty(schemata));
+    return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL, schemata);
 }
 
 /* Replica implementation. */
diff --git a/ovsdb/file.h b/ovsdb/file.h
index ee67b12..aaa9c8c 100644
--- a/ovsdb/file.h
+++ b/ovsdb/file.h
@@ -18,6 +18,7 @@
 
 #include <stdbool.h>
 #include "compiler.h"
+#include "shash.h"
 #include "log.h"
 
 struct ovsdb;
@@ -25,12 +26,13 @@ struct ovsdb_file;
 struct ovsdb_schema;
 
 struct ovsdb_error *ovsdb_file_open(const char *file_name, bool read_only,
-                                    struct ovsdb **, struct ovsdb_file **)
+                                    struct ovsdb **, struct ovsdb_file **,
+                                    struct shash *schemata)
     OVS_WARN_UNUSED_RESULT;
 
-struct ovsdb_error *ovsdb_file_open_as_schema(const char *file_name,
-                                              const struct ovsdb_schema *,
-                                              struct ovsdb **)
+struct ovsdb_error *ovsdb_file_open_as_schemata(const char *file_name,
+                                                struct shash *schemata,
+                                                struct ovsdb **)
     OVS_WARN_UNUSED_RESULT;
 
 struct ovsdb_error *ovsdb_file_save_copy(const char *file_name, int locking,
@@ -40,8 +42,8 @@ struct ovsdb_error *ovsdb_file_save_copy(const char 
*file_name, int locking,
 
 struct ovsdb_error *ovsdb_file_compact(struct ovsdb_file *);
 
-struct ovsdb_error *ovsdb_file_read_schema(const char *file_name,
-                                           struct ovsdb_schema **)
+struct ovsdb_error *ovsdb_file_read_schemata(const char *file_name,
+                                           struct shash *schemata)
     OVS_WARN_UNUSED_RESULT;
 
 #endif /* ovsdb/file.h */
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index cd13b0d..c52af17 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -407,7 +407,7 @@ open_db(struct server_config *config, const char *filename)
     db = xzalloc(sizeof *db);
     db->filename = xstrdup(filename);
 
-    db_error = ovsdb_file_open(db->filename, false, &db->db, &db->file);
+    db_error = ovsdb_file_open(db->filename, false, &db->db, &db->file, NULL);
     if (db_error) {
         error = ovsdb_error_to_string(db_error);
     } else if (!ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db)) {
diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c
index 32883e2..a91d8b2 100644
--- a/ovsdb/ovsdb-tool.c
+++ b/ovsdb/ovsdb-tool.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,7 +38,9 @@
 #include "socket-util.h"
 #include "table.h"
 #include "timeval.h"
+#include "sset.h"
 #include "util.h"
+#include "shash.h"
 #include "openvswitch/vlog.h"
 
 /* -m, --more: Verbosity level for "show-log" command output. */
@@ -56,12 +58,14 @@ int
 main(int argc, char *argv[])
 {
     struct ovs_cmdl_context ctx = { .argc = 0, };
+
     set_program_name(argv[0]);
     parse_options(argc, argv);
     fatal_ignore_sigpipe();
     ctx.argc = argc - optind;
     ctx.argv = argv + optind;
     ovs_cmdl_run_command(&ctx, get_all_commands());
+
     return 0;
 }
 
@@ -188,20 +192,33 @@ check_ovsdb_error(struct ovsdb_error *error)
         ovs_fatal(0, "%s", ovsdb_error_to_string(error));
     }
 }
+
+static void
+parse_schema_file_names(const char *file_names, struct sset *names)
+{
+   ovsdb_parse_schema_file_names(file_names, names, default_schema());
+   ovs_assert(!sset_is_empty(names));
+}
+
 
 static void
 do_create(struct ovs_cmdl_context *ctx)
 {
     const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
-    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : 
default_schema();
-    struct ovsdb_schema *schema;
+    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL;
     struct ovsdb_log *log;
     struct json *json;
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
+    struct sset schema_names = SSET_INITIALIZER(&schema_names);
 
-    /* Read schema from file and convert to JSON. */
-    check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema));
-    json = ovsdb_schema_to_json(schema);
-    ovsdb_schema_destroy(schema);
+    /* Read schema from file(s) and convert to JSON. */
+    parse_schema_file_names(schema_file_name, &schema_names);
+
+    check_ovsdb_error(ovsdb_schemata_from_files(&schema_names, &schemata));
+    sset_destroy(&schema_names);
+
+    json = ovsdb_schemata_to_json(&schemata);
+    ovsdb_schemata_destroy(&schemata);
 
     /* Create database file. */
     check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_CREATE,
@@ -215,7 +232,7 @@ do_create(struct ovs_cmdl_context *ctx)
 
 static void
 compact_or_convert(const char *src_name_, const char *dst_name_,
-                   const struct ovsdb_schema *new_schema,
+                   struct shash *new_schemata,
                    const char *comment)
 {
     char *src_name, *dst_name;
@@ -249,9 +266,9 @@ compact_or_convert(const char *src_name_, const char 
*dst_name_,
     }
 
     /* Save a copy. */
-    check_ovsdb_error(new_schema
-                      ? ovsdb_file_open_as_schema(src_name, new_schema, &db)
-                      : ovsdb_file_open(src_name, true, &db, NULL));
+    check_ovsdb_error(ovsdb_schemata_is_null_or_empty(new_schemata)
+                      ? ovsdb_file_open(src_name, true, &db, NULL, 
new_schemata)
+                      : ovsdb_file_open_as_schemata(src_name, new_schemata, 
&db));
     check_ovsdb_error(ovsdb_file_save_copy(dst_name, false, comment, db));
     ovsdb_destroy(db);
 
@@ -287,72 +304,153 @@ static void
 do_convert(struct ovs_cmdl_context *ctx)
 {
     const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db();
-    const char *schema = ctx->argc >= 3 ? ctx->argv[2] : default_schema();
+    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL;
     const char *target = ctx->argc >= 4 ? ctx->argv[3] : NULL;
-    struct ovsdb_schema *new_schema;
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
+    struct sset schema_names = SSET_INITIALIZER(&schema_names);
 
-    check_ovsdb_error(ovsdb_schema_from_file(schema, &new_schema));
-    compact_or_convert(db, target, new_schema,
+    parse_schema_file_names(schema_file_name, &schema_names);
+    check_ovsdb_error(ovsdb_schemata_from_files(&schema_names, &schemata));
+    sset_destroy(&schema_names);
+
+    compact_or_convert(db, target, &schemata,
                        "converted by ovsdb-tool "VERSION);
-    ovsdb_schema_destroy(new_schema);
+    ovsdb_schemata_destroy(&schemata);
 }
 
 static void
 do_needs_conversion(struct ovs_cmdl_context *ctx)
 {
     const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
-    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : 
default_schema();
-    struct ovsdb_schema *schema1, *schema2;
-
-    check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema1));
-    check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema2));
-    puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes");
-    ovsdb_schema_destroy(schema1);
-    ovsdb_schema_destroy(schema2);
+    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL;
+    struct shash schemata1 = SHASH_INITIALIZER(&schemata1);
+    struct shash schemata2 = SHASH_INITIALIZER(&schemata2);
+    struct shash_node *node1, *node2;
+    bool need_conversion = false;
+    struct sset schema_names = SSET_INITIALIZER(&schema_names);
+
+
+    /* Read schema from file(s) and convert to JSON. */
+    parse_schema_file_names(schema_file_name, &schema_names);
+    check_ovsdb_error(ovsdb_schemata_from_files(&schema_names, &schemata1));
+    sset_destroy(&schema_names);
+
+    check_ovsdb_error(ovsdb_file_read_schemata(db_file_name, &schemata2));
+
+    SHASH_FOR_EACH (node1, &schemata1) {
+        struct ovsdb_schema *schema1 = node1->data;
+
+        node2 = shash_find(&schemata2, schema1->name);
+        if (node2) {
+            const struct ovsdb_schema *schema2 = node2->data;
+
+            need_conversion = ovsdb_schema_equal(schema1, schema2);
+        }
+
+        if (!need_conversion) {
+            break;
+        }
+    }
+
+    puts(need_conversion ? "no" : "yes");
+
+    ovsdb_schemata_destroy(&schemata1);
+    ovsdb_schemata_destroy(&schemata2);
 }
 
 static void
 do_db_version(struct ovs_cmdl_context *ctx)
 {
     const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
     struct ovsdb_schema *schema;
 
-    check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema));
-    puts(schema->version);
-    ovsdb_schema_destroy(schema);
+    check_ovsdb_error(ovsdb_file_read_schemata(db_file_name, &schemata));
+
+    if (shash_count(&schemata) == 1) {
+        schema = shash_first(&schemata)->data;
+        puts(schema->version);
+    } else {
+        struct shash_node *node;
+        SHASH_FOR_EACH (node, &schemata) {
+            schema = node->data;
+            printf("%s:%s\n", schema->name, schema->version);
+        }
+    }
+
+    ovsdb_schemata_destroy(&schemata);
 }
 
 static void
 do_db_cksum(struct ovs_cmdl_context *ctx)
 {
     const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
     struct ovsdb_schema *schema;
 
-    check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema));
-    puts(schema->cksum);
-    ovsdb_schema_destroy(schema);
+    check_ovsdb_error(ovsdb_file_read_schemata(db_file_name, &schemata));
+
+    if (shash_count(&schemata) == 1) {
+        schema = shash_first(&schemata)->data;
+        puts(schema->cksum);
+    } else {
+        struct shash_node *node;
+        SHASH_FOR_EACH (node, &schemata) {
+            schema = node->data;
+            printf("%s:%s\n", schema->name, schema->cksum);
+        }
+    }
+    ovsdb_schemata_destroy(&schemata);
 }
 
 static void
 do_schema_version(struct ovs_cmdl_context *ctx)
 {
     const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : 
default_schema();
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
     struct ovsdb_schema *schema;
-
-    check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema));
-    puts(schema->version);
-    ovsdb_schema_destroy(schema);
+    struct sset schema_names = SSET_INITIALIZER(&schema_names);
+
+    parse_schema_file_names(schema_file_name, &schema_names);
+    check_ovsdb_error(ovsdb_schemata_from_files(&schema_names, &schemata));
+    sset_destroy(&schema_names);
+
+    if (shash_count(&schemata) == 1) {
+        schema = shash_first(&schemata)->data;
+        puts(schema->version);
+    } else {
+        struct shash_node *node;
+        SHASH_FOR_EACH (node, &schemata) {
+            schema = node->data;
+            printf("%s:%s\n", schema->name, schema->version);
+        }
+    }
+    ovsdb_schemata_destroy(&schemata);
 }
 
 static void
 do_schema_cksum(struct ovs_cmdl_context *ctx)
 {
-    const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : 
default_schema();
+    const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : NULL;
+    struct shash schemata = SHASH_INITIALIZER(&schemata);
     struct ovsdb_schema *schema;
-
-    check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema));
-    puts(schema->cksum);
-    ovsdb_schema_destroy(schema);
+    struct sset schema_names = SSET_INITIALIZER(&schema_names);
+
+    parse_schema_file_names(schema_file_name, &schema_names);
+    check_ovsdb_error(ovsdb_schemata_from_files(&schema_names, &schemata));
+    sset_destroy(&schema_names);
+
+    if (shash_count(&schemata) == 1) {
+        schema = shash_first(&schemata)->data;
+        puts(schema->cksum);
+    } else {
+        struct shash_node *node;
+        SHASH_FOR_EACH (node, &schemata) {
+            schema = node->data;
+            printf("%s:%s\n", schema->name, schema->cksum);
+        }
+    }
+    ovsdb_schemata_destroy(&schemata);
 }
 
 static void
@@ -363,7 +461,7 @@ transact(bool read_only, int argc, char *argv[])
     struct json *request, *result;
     struct ovsdb *db;
 
-    check_ovsdb_error(ovsdb_file_open(db_file_name, read_only, &db, NULL));
+    check_ovsdb_error(ovsdb_file_open(db_file_name, read_only, &db, NULL, 
NULL));
 
     request = parse_json(transaction);
     result = ovsdb_execute(db, NULL, request, 0, NULL);
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to