On 15 June 2015 at 19:35, Andy Zhou <[email protected]> wrote: > ovsdb-tool now accepts multiple schema files for all applicable options.
If these schema can be joined together without compatibility error, > s/schema/[schemas|schemata] > 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 > s/store/stored > 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. > This file also requires updates to man pages. > > Signed-off-by: Andy Zhou <[email protected]> > --- > 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' > typo "schmeta" > + * 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; > For example, ovsdb_file_open_log()->ovsdb_schemata_from_json() might have already called ovsdb_schemata_destroy() for you in case of error. So this would potentially lead to double free. Is it right? > + 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" > Alphabetical order? > #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"); > Do you have this reverse way? ovsdb-tool man page says this: needs-conversion db schema Reads the schema embedded in db and the standalone schema in schema and compares them. If the schemas are the same, prints no on stdout; if they differ, print yes. in your case I think "need_conversion" actually should be renamed to "schemas_are_equal" because "need_conversion" is negation of that? > + > + 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 > [email protected] > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
