Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/815895/?format=api
{ "id": 815895, "url": "http://patchwork.ozlabs.org/api/patches/815895/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-43-blp@ovn.org/", "project": { "id": 47, "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api", "name": "Open vSwitch", "link_name": "openvswitch", "list_id": "ovs-dev.openvswitch.org", "list_email": "ovs-dev@openvswitch.org", "web_url": "http://openvswitch.org/", "scm_url": "git@github.com:openvswitch/ovs.git", "webscm_url": "https://github.com/openvswitch/ovs", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170919220125.32535-43-blp@ovn.org>", "list_archive_url": null, "date": "2017-09-19T22:01:15", "name": "[ovs-dev,RFC,42/52] ovsdb-server: Add support for a built-in _Server database.", "commit_ref": null, "pull_url": null, "state": "rfc", "archived": false, "hash": "0f485aefdddb329400a9c3d58484579c3edf3f59", "submitter": { "id": 67603, "url": "http://patchwork.ozlabs.org/api/people/67603/?format=api", "name": "Ben Pfaff", "email": "blp@ovn.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-43-blp@ovn.org/mbox/", "series": [ { "id": 3975, "url": "http://patchwork.ozlabs.org/api/series/3975/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=3975", "date": "2017-09-19T22:00:34", "name": "clustering implementation", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/3975/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/815895/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/815895/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<ovs-dev-bounces@openvswitch.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "dev@openvswitch.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "ovs-dev@mail.linuxfoundation.org" ], "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xxclc2d1hz9sMN\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 20 Sep 2017 08:21:00 +1000 (AEST)", "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id BD0BCD16;\n\tTue, 19 Sep 2017 22:02:45 +0000 (UTC)", "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 4DC35CE4\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:44 +0000 (UTC)", "from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 82E201A6\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:42 +0000 (UTC)", "from sigabrt.benpfaff.org (unknown [208.91.2.3])\n\t(Authenticated sender: blp@ovn.org)\n\tby relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 40D5D172097;\n\tWed, 20 Sep 2017 00:02:39 +0200 (CEST)" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Originating-IP": "208.91.2.3", "From": "Ben Pfaff <blp@ovn.org>", "To": "dev@openvswitch.org", "Date": "Tue, 19 Sep 2017 15:01:15 -0700", "Message-Id": "<20170919220125.32535-43-blp@ovn.org>", "X-Mailer": "git-send-email 2.10.2", "In-Reply-To": "<20170919220125.32535-1-blp@ovn.org>", "References": "<20170919220125.32535-1-blp@ovn.org>", "X-Spam-Status": "No, score=-0.2 required=5.0 tests=RCVD_IN_DNSWL_LOW,\n\tURI_NOVOWEL autolearn=disabled version=3.3.1", "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org", "Cc": "Ben Pfaff <blp@ovn.org>", "Subject": "[ovs-dev] [PATCH RFC 42/52] ovsdb-server: Add support for a\n\tbuilt-in _Server database.", "X-BeenThere": "ovs-dev@openvswitch.org", "X-Mailman-Version": "2.1.12", "Precedence": "list", "List-Id": "<ovs-dev.openvswitch.org>", "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>", "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>", "List-Post": "<mailto:ovs-dev@openvswitch.org>", "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>", "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "ovs-dev-bounces@openvswitch.org", "Errors-To": "ovs-dev-bounces@openvswitch.org" }, "content": "Initially this database only reports databases' names and schemas, but\nwhen clustering support is added in a later commit it will also report\nimportant aspects of clustering and cluster status.\n\nSigned-off-by: Ben Pfaff <blp@ovn.org>\n---\n Makefile.am | 8 ---\n NEWS | 3 ++\n build-aux/automake.mk | 12 ++++-\n build-aux/text2c | 16 ++++++\n ovsdb/.gitignore | 3 ++\n ovsdb/_server.ovsschema | 9 ++++\n ovsdb/_server.xml | 31 ++++++++++++\n ovsdb/automake.mk | 26 ++++++++++\n ovsdb/ovsdb-server.1.in | 5 ++\n ovsdb/ovsdb-server.c | 131 +++++++++++++++++++++++++++++++++++++++++++++---\n ovsdb/ovsdb-util.c | 93 +++++++++++++++++++++++++++++++---\n ovsdb/ovsdb-util.h | 9 ++++\n tests/ovsdb-server.at | 70 +++++++++++++-------------\n 13 files changed, 359 insertions(+), 57 deletions(-)\n create mode 100755 build-aux/text2c\n create mode 100644 ovsdb/_server.ovsschema\n create mode 100644 ovsdb/_server.xml", "diff": "diff --git a/Makefile.am b/Makefile.am\nindex 31d6331792af..e11de801e0b6 100644\n--- a/Makefile.am\n+++ b/Makefile.am\n@@ -81,14 +81,6 @@ EXTRA_DIST = \\\n \t.travis/osx-prepare.sh \\\n \tappveyor.yml \\\n \tboot.sh \\\n-\tbuild-aux/cccl \\\n-\tbuild-aux/cksum-schema-check \\\n-\tbuild-aux/calculate-schema-cksum \\\n-\tbuild-aux/dist-docs \\\n-\tbuild-aux/dpdkstrip.pl \\\n-\tbuild-aux/sodepends.pl \\\n-\tbuild-aux/soexpand.pl \\\n-\tbuild-aux/xml2nroff \\\n \t$(MAN_FRAGMENTS) \\\n \t$(MAN_ROOTS) \\\n \tVagrantfile \\\ndiff --git a/NEWS b/NEWS\nindex 8392ccc89a02..1ab0f1038c24 100644\n--- a/NEWS\n+++ b/NEWS\n@@ -1,5 +1,8 @@\n Post-v2.8.0\n --------------------\n+ - OVSDB:\n+ * ovsdb-server now always hosts a built-in database named _Server. See\n+ ovsdb-server(5) for more details.\n - ovs-vsctl and other commands that display data in tables now support a\n --max-column-width option to limit column width.\n - OVN:\ndiff --git a/build-aux/automake.mk b/build-aux/automake.mk\nindex 9500e3a69402..df5a884f8c23 100644\n--- a/build-aux/automake.mk\n+++ b/build-aux/automake.mk\n@@ -1,3 +1,13 @@\n-# This file is purely used for checking the style of the python build tools.\n+EXTRA_DIST += \\\n+\tbuild-aux/calculate-schema-cksum \\\n+\tbuild-aux/cccl \\\n+\tbuild-aux/cksum-schema-check \\\n+\tbuild-aux/dist-docs \\\n+\tbuild-aux/dpdkstrip.pl \\\n+\tbuild-aux/sodepends.pl \\\n+\tbuild-aux/soexpand.pl \\\n+\tbuild-aux/text2c \\\n+\tbuild-aux/xml2nroff\n+\n FLAKE8_PYFILES += \\\n $(srcdir)/build-aux/xml2nroff\ndiff --git a/build-aux/text2c b/build-aux/text2c\nnew file mode 100755\nindex 000000000000..cb1f256f1775\n--- /dev/null\n+++ b/build-aux/text2c\n@@ -0,0 +1,16 @@\n+#! /usr/bin/python\n+\n+import re\n+import sys\n+\n+\"\"\"This utility reads its input, which should be plain text, and\n+prints it back transformed into quoted strings that may be #included\n+into C source code.\"\"\"\n+\n+while True:\n+ line = sys.stdin.readline()\n+ if not line:\n+ break\n+\n+ s = line.replace(\"\\\\\", \"\\\\\\\\\").replace('\"', '\\\\\"').replace(\"\\n\", \"\\\\n\")\n+ print('\"' + s + '\"')\ndiff --git a/ovsdb/.gitignore b/ovsdb/.gitignore\nindex d715dee925b9..fbcefafc6e97 100644\n--- a/ovsdb/.gitignore\n+++ b/ovsdb/.gitignore\n@@ -1,3 +1,5 @@\n+/_server.ovsschema.inc\n+/_server.ovsschema.stamp\n /ovsdb-client\n /ovsdb-client.1\n /ovsdb-doc\n@@ -5,6 +7,7 @@\n /ovsdb-idlc\n /ovsdb-server\n /ovsdb-server.1\n+/ovsdb-server.5\n /ovsdb-tool\n /ovsdb-tool.1\n /libovsdb.pc\ndiff --git a/ovsdb/_server.ovsschema b/ovsdb/_server.ovsschema\nnew file mode 100644\nindex 000000000000..8997bae5fa36\n--- /dev/null\n+++ b/ovsdb/_server.ovsschema\n@@ -0,0 +1,9 @@\n+{\"name\": \"_Server\",\n+ \"version\": \"1.0.0\",\n+ \"cksum\": \"3931859656 185\",\n+ \"tables\": {\n+ \"Database\": {\n+ \"columns\": {\n+ \"name\": {\"type\": \"string\"},\n+ \"schema\": {\"type\": \"string\"}},\n+ \"isRoot\": true}}}\ndiff --git a/ovsdb/_server.xml b/ovsdb/_server.xml\nnew file mode 100644\nindex 000000000000..a55beb9bd6de\n--- /dev/null\n+++ b/ovsdb/_server.xml\n@@ -0,0 +1,31 @@\n+<?xml version=\"1.0\" encoding=\"utf-8\"?>\n+<database name=\"ovsdb-server\" title=\"ovsdb-server _Server schema\">\n+ <p>\n+ Every <code>ovsdb-server</code> (version 2.9 or later) always hosts an\n+ instance of this schema, which holds information on the status and\n+ configuration of the server itself. This database is read-only. This\n+ manpage describes the schema for this database.\n+ </p>\n+\n+ <table name=\"Database\" title=\"Databases.\">\n+ <p>\n+ This table describes the databases hosted by the database server, with\n+ one row per database. As its database configuration and status changes,\n+ the server automatically and immediately updates the table to match.\n+ </p>\n+ <p>\n+ Clients can use the <code>_uuid</code> column in this table as a\n+ generation number. The server generates a fresh <code>_uuid</code> every\n+ time it adds a database, so that removing and then re-adding a database\n+ to the server causes its row <code>_uuid</code> to change.\n+ </p>\n+\n+ <column name=\"name\">\n+ The database's name, as specified in its schema.\n+ </column>\n+\n+ <column name=\"schema\">\n+ The database schema, as a JSON string.\n+ </column>\n+ </table>\n+</database>\ndiff --git a/ovsdb/automake.mk b/ovsdb/automake.mk\nindex 50e5ab367eff..c1d402c43206 100644\n--- a/ovsdb/automake.mk\n+++ b/ovsdb/automake.mk\n@@ -117,3 +117,29 @@ EXTRA_DIST += ovsdb/ovsdb-dot.in ovsdb/dot2pic\n noinst_SCRIPTS += ovsdb/ovsdb-dot\n CLEANFILES += ovsdb/ovsdb-dot\n OVSDB_DOT = $(run_python) $(srcdir)/ovsdb/ovsdb-dot.in\n+\n+EXTRA_DIST += ovsdb/_server.ovsschema\n+CLEANFILES += ovsdb/_server.ovsschema.inc\n+ovsdb/ovsdb-server.o: ovsdb/_server.ovsschema.inc\n+ovsdb/_server.ovsschema.inc: ovsdb/_server.ovsschema $(srcdir)/build-aux/text2c\n+\t$(AM_V_GEN)$(run_python) $(srcdir)/build-aux/text2c < $< > $@.tmp\n+\t$(AM_V_at)mv $@.tmp $@\n+\n+# Version checking for _server.ovsschema.\n+ALL_LOCAL += ovsdb/_server.ovsschema.stamp\n+ovsdb/_server.ovsschema.stamp: ovsdb/_server.ovsschema\n+\t$(srcdir)/build-aux/cksum-schema-check $? $@\n+CLEANFILES += ovsdb/_server.ovsschema.stamp\n+\n+# _Server schema documentation\n+EXTRA_DIST += ovsdb/_server.xml\n+CLEANFILES += ovsdb/ovsdb-server.5\n+man_MANS += ovsdb/ovsdb-server.5\n+ovsdb/ovsdb-server.5: \\\n+\tovsdb/ovsdb-doc ovsdb/_server.xml ovsdb/_server.ovsschema \\\n+\t$(VSWITCH_PIC)\n+\t$(AM_V_GEN)$(OVSDB_DOC) \\\n+\t\t--version=$(VERSION) \\\n+\t\t$(srcdir)/ovsdb/_server.ovsschema \\\n+\t\t$(srcdir)/ovsdb/_server.xml > $@.tmp && \\\n+\tmv $@.tmp $@\ndiff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in\nindex f1c6466ccb75..455010c3f5fa 100644\n--- a/ovsdb/ovsdb-server.1.in\n+++ b/ovsdb/ovsdb-server.1.in\n@@ -36,6 +36,11 @@ Each OVSDB file may be specified on the command line as \\fIdatabase\\fR.\n If none is specified, the default is \\fB@DBDIR@/conf.db\\fR. The database\n files must already have been created and initialized using, for\n example, \\fBovsdb\\-tool create\\fR.\n+.PP\n+In addition to user-specified databases, \\fBovsdb\\-server\\fR version\n+2.9 and later also always hosts a built-in database named\n+\\fB_Server\\fR. Please see \\fBovsdb\\-server\\fR(5) for documentation on\n+this database's schema.\n .\n .SH \"ACTIVE and BACKUP\"\n \\fBovsdb\\-server\\fR runs either as a backup server, or as an active server.\ndiff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c\nindex 99ba6949f016..52eb21f89aa0 100644\n--- a/ovsdb/ovsdb-server.c\n+++ b/ovsdb/ovsdb-server.c\n@@ -65,6 +65,7 @@ struct db {\n char *filename;\n struct ovsdb_file *file;\n struct ovsdb *db;\n+ struct uuid row_uuid;\n };\n \n /* SSL configuration. */\n@@ -107,6 +108,7 @@ static unixctl_cb_func ovsdb_server_remove_database;\n static unixctl_cb_func ovsdb_server_list_databases;\n \n static char *open_db(struct server_config *config, const char *filename);\n+static void add_server_db(struct server_config *);\n static void close_db(struct db *db);\n \n static void parse_options(int *argc, char **argvp[],\n@@ -124,6 +126,7 @@ static void report_error_if_changed(char *error, char **last_errorp);\n static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,\n const struct sset *remotes,\n struct shash *all_dbs);\n+static void update_server_status(struct shash *all_dbs);\n \n static void save_config__(FILE *config_file, const struct sset *remotes,\n const struct sset *db_filenames,\n@@ -214,6 +217,8 @@ main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,\n update_remote_status(jsonrpc, remotes, all_dbs);\n }\n \n+ update_server_status(all_dbs);\n+\n memory_wait();\n if (*is_backup) {\n replication_wait();\n@@ -328,6 +333,7 @@ main(int argc, char *argv[])\n ovs_fatal(0, \"%s\", error);\n }\n }\n+ add_server_db(&server_config);\n \n error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes);\n if (!error) {\n@@ -490,6 +496,16 @@ close_db(struct db *db)\n free(db);\n }\n \n+static void\n+add_db(struct server_config *config, const char *name, struct db *db)\n+{\n+ db->row_uuid = UUID_ZERO;\n+ shash_add_assert(config->all_dbs, name, db);\n+ bool ok OVS_UNUSED = ovsdb_jsonrpc_server_add_db(config->jsonrpc,\n+ db->db);\n+ ovs_assert(ok);\n+}\n+\n static char *\n open_db(struct server_config *config, const char *filename)\n {\n@@ -525,6 +541,27 @@ open_db(struct server_config *config, const char *filename)\n return error;\n }\n \n+/* Add the internal _Server database to the server configuration. */\n+static void\n+add_server_db(struct server_config *config)\n+{\n+ struct json *schema_json = json_from_string(\n+#include \"ovsdb/_server.ovsschema.inc\"\n+ );\n+ ovs_assert(schema_json->type == JSON_OBJECT);\n+\n+ struct ovsdb_schema *schema;\n+ struct ovsdb_error *error OVS_UNUSED = ovsdb_schema_from_json(schema_json,\n+ &schema);\n+ ovs_assert(!error);\n+ json_destroy(schema_json);\n+\n+ struct db *db = xzalloc(sizeof *db);\n+ db->filename = xstrdup(\"<internal>\");\n+ db->db = ovsdb_create(schema);\n+ add_db(config, db->db->schema->name, db);\n+}\n+\n static char * OVS_WARN_UNUSED_RESULT\n parse_db_column__(const struct shash *all_dbs,\n const char *name_, char *name,\n@@ -875,6 +912,18 @@ update_remote_rows(const struct shash *all_dbs, const struct db *db_,\n }\n \n static void\n+commit_txn(struct ovsdb_txn *txn, const char *name)\n+{\n+ struct ovsdb_error *error = ovsdb_txn_commit(txn, false);\n+ if (error) {\n+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);\n+ char *msg = ovsdb_error_to_string_free(error);\n+ VLOG_ERR_RL(&rl, \"Failed to update %s: %s\", name, msg);\n+ free(msg);\n+ }\n+}\n+\n+static void\n update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,\n const struct sset *remotes,\n struct shash *all_dbs)\n@@ -890,14 +939,84 @@ update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,\n update_remote_rows(all_dbs, db, remote, jsonrpc, txn);\n }\n \n- struct ovsdb_error *error = ovsdb_txn_commit(txn, false);\n- if (error) {\n- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);\n- char *msg = ovsdb_error_to_string_free(error);\n- VLOG_ERR_RL(&rl, \"Failed to update remote status: %s\", msg);\n- free(msg);\n+ commit_txn(txn, node->name);\n+ }\n+}\n+\n+/* Updates 'row', a row in the _Server database's Database table, to match\n+ * 'db'. */\n+static void\n+update_database_status(struct ovsdb_row *row, struct db *db)\n+{\n+ ovsdb_util_write_string_column(row, \"name\", db->db->schema->name);\n+\n+ const struct uuid *row_uuid = ovsdb_row_get_uuid(row);\n+ if (!uuid_equals(row_uuid, &db->row_uuid)) {\n+ db->row_uuid = *row_uuid;\n+\n+ /* The schema can only change if the generation changes, so only update\n+ * it in that case. (Schemas are often kilobytes in size and expensive\n+ * to serialize, so presumably it's worth optimizing.) */\n+ struct json *json_schema = ovsdb_schema_to_json(db->db->schema);\n+ char *schema = json_to_string(json_schema, JSSF_SORT);\n+ ovsdb_util_write_string_column(row, \"schema\", schema);\n+ free(schema);\n+ json_destroy(json_schema);\n+ }\n+}\n+\n+/* Updates the Database table in the _Server database. */\n+static void\n+update_server_status(struct shash *all_dbs)\n+{\n+ struct db *server_db = shash_find_data(all_dbs, \"_Server\");\n+ struct ovsdb_table *database_table = shash_find_data(\n+ &server_db->db->tables, \"Database\");\n+ struct ovsdb_txn *txn = ovsdb_txn_create(server_db->db);\n+\n+ /* Update rows for databases that still exist.\n+ * Delete rows for databases that no longer exist. */\n+ const struct ovsdb_row *row, *next_row;\n+ HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &database_table->rows) {\n+ const char *name;\n+ ovsdb_util_read_string_column(row, \"name\", &name);\n+ struct db *db = shash_find_data(all_dbs, name);\n+ if (!db || !db->db) {\n+ ovsdb_txn_row_delete(txn, row);\n+ } else {\n+ update_database_status(ovsdb_txn_row_modify(txn, row), db);\n }\n }\n+\n+ /* Add rows for new databases.\n+ *\n+ * This is O(n**2) but usually there are only 2 or 3 databases. */\n+ struct shash_node *node;\n+ SHASH_FOR_EACH (node, all_dbs) {\n+ struct db *db = node->data;\n+\n+ if (!db->db) {\n+ continue;\n+ }\n+\n+ HMAP_FOR_EACH (row, hmap_node, &database_table->rows) {\n+ const char *name;\n+ ovsdb_util_read_string_column(row, \"name\", &name);\n+ if (!strcmp(name, node->name)) {\n+ goto next;\n+ }\n+ }\n+\n+ /* Add row. */\n+ struct ovsdb_row *row = ovsdb_row_create(database_table);\n+ uuid_generate(ovsdb_row_get_uuid_rw(row));\n+ update_database_status(row, db);\n+ ovsdb_txn_row_insert(txn, row);\n+\n+ next:;\n+ }\n+\n+ commit_txn(txn, \"_Server\");\n }\n \n /* Reconfigures ovsdb-server's remotes based on information in the database. */\ndiff --git a/ovsdb/ovsdb-util.c b/ovsdb/ovsdb-util.c\nindex 5ee5e4ddaf8d..06d25af49a18 100644\n--- a/ovsdb/ovsdb-util.c\n+++ b/ovsdb/ovsdb-util.c\n@@ -22,6 +22,38 @@\n \n VLOG_DEFINE_THIS_MODULE(ovsdb_util);\n \n+static void\n+ovsdb_util_clear_column(struct ovsdb_row *row, const char *column_name)\n+{\n+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);\n+ const struct ovsdb_table_schema *schema = row->table->schema;\n+ const struct ovsdb_column *column;\n+\n+ column = ovsdb_table_schema_get_column(schema, column_name);\n+ if (!column) {\n+ VLOG_DBG_RL(&rl, \"Table `%s' has no `%s' column\",\n+ schema->name, column_name);\n+ return;\n+ }\n+\n+ if (column->type.n_min) {\n+ if (!VLOG_DROP_DBG(&rl)) {\n+ char *type_name = ovsdb_type_to_english(&column->type);\n+ VLOG_DBG(\"Table `%s' column `%s' has type %s, which requires \"\n+ \"a value, when it was expected to be optional\",\n+ schema->name, column_name, type_name);\n+ free(type_name);\n+ }\n+ return;\n+ }\n+\n+ struct ovsdb_datum *datum = &row->fields[column->index];\n+ if (datum->n) {\n+ ovsdb_datum_destroy(datum, &column->type);\n+ ovsdb_datum_init_empty(datum);\n+ }\n+}\n+\n struct ovsdb_datum *\n ovsdb_util_get_datum(struct ovsdb_row *row, const char *column_name,\n const enum ovsdb_atomic_type key_type,\n@@ -164,29 +196,74 @@ ovsdb_util_read_bool_column(const struct ovsdb_row *row,\n return atom != NULL;\n }\n \n-void\n-ovsdb_util_write_bool_column(struct ovsdb_row *row, const char *column_name,\n- bool value)\n+bool\n+ovsdb_util_read_uuid_column(const struct ovsdb_row *row,\n+ const char *column_name, struct uuid *uuid)\n+{\n+ const union ovsdb_atom *atom;\n+\n+ atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_UUID);\n+ *uuid = atom ? atom->uuid : UUID_ZERO;\n+ return atom != NULL;\n+}\n+\n+static void\n+ovsdb_util_write_singleton(struct ovsdb_row *row, const char *column_name,\n+ const union ovsdb_atom *atom,\n+ enum ovsdb_atomic_type type)\n {\n const struct ovsdb_column *column;\n struct ovsdb_datum *datum;\n \n column = ovsdb_table_schema_get_column(row->table->schema, column_name);\n- datum = ovsdb_util_get_datum(row, column_name, OVSDB_TYPE_BOOLEAN,\n- OVSDB_TYPE_VOID, 1);\n+ datum = ovsdb_util_get_datum(row, column_name, type, OVSDB_TYPE_VOID, 1);\n if (!datum) {\n return;\n }\n \n- if (datum->n != 1) {\n+ if (datum->n == 1) {\n+ if (ovsdb_atom_equals(&datum->keys[0], atom, type)) {\n+ return;\n+ }\n+ } else {\n ovsdb_datum_destroy(datum, &column->type);\n-\n datum->n = 1;\n datum->keys = xmalloc(sizeof *datum->keys);\n datum->values = NULL;\n }\n+ ovsdb_atom_clone(&datum->keys[0], atom, type);\n+}\n \n- datum->keys[0].boolean = value;\n+void\n+ovsdb_util_write_bool_column(struct ovsdb_row *row, const char *column_name,\n+ bool value)\n+{\n+ const union ovsdb_atom atom = { .boolean = value };\n+ ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_BOOLEAN);\n+}\n+\n+void\n+ovsdb_util_write_uuid_column(struct ovsdb_row *row, const char *column_name,\n+ const struct uuid *uuid)\n+{\n+ if (uuid) {\n+ const union ovsdb_atom atom = { .uuid = *uuid };\n+ ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_UUID);\n+ } else {\n+ ovsdb_util_clear_column(row, column_name);\n+ }\n+}\n+\n+void\n+ovsdb_util_write_string_column(struct ovsdb_row *row, const char *column_name,\n+ const char *string)\n+{\n+ if (string) {\n+ const union ovsdb_atom atom = { .string = CONST_CAST(char *, string) };\n+ ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_STRING);\n+ } else {\n+ ovsdb_util_clear_column(row, column_name);\n+ }\n }\n \n void\ndiff --git a/ovsdb/ovsdb-util.h b/ovsdb/ovsdb-util.h\nindex abd81ff38cd2..a0404a3a7ff0 100644\n--- a/ovsdb/ovsdb-util.h\n+++ b/ovsdb/ovsdb-util.h\n@@ -38,6 +38,9 @@ bool ovsdb_util_read_integer_column(const struct ovsdb_row *row,\n bool ovsdb_util_read_string_column(const struct ovsdb_row *row,\n const char *column_name,\n const char **stringp);\n+void ovsdb_util_write_string_column(struct ovsdb_row *row,\n+ const char *column_name,\n+ const char *string);\n void ovsdb_util_write_string_string_column(struct ovsdb_row *row,\n const char *column_name,\n char **keys, char **values,\n@@ -48,5 +51,11 @@ bool ovsdb_util_read_bool_column(const struct ovsdb_row *row,\n void ovsdb_util_write_bool_column(struct ovsdb_row *row,\n const char *column_name,\n bool value);\n+bool ovsdb_util_read_uuid_column(const struct ovsdb_row *row,\n+ const char *column_name,\n+ struct uuid *);\n+void ovsdb_util_write_uuid_column(struct ovsdb_row *row,\n+ const char *column_name,\n+ const struct uuid *);\n \n #endif /* ovsdb/util.h */\ndiff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at\nindex 0f8c791128b1..ccbc1ac0b717 100644\n--- a/tests/ovsdb-server.at\n+++ b/tests/ovsdb-server.at\n@@ -147,20 +147,31 @@ AT_CHECK([ovsdb-client get-schema-version unix:socket ordinals], [0], [5.1.3\n OVSDB_SERVER_SHUTDOWN\n AT_CLEANUP\n \n+dnl CHECK_DBS([databases])\n+dnl\n+dnl Checks that ovsdb-server hosts the given 'databases', each of which\n+dnl needs to be followed by a newline.\n+m4_define([CHECK_DBS],\n+ [AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n+ [0], [_Server\n+$1])\n+AT_CHECK([ovsdb-client --no-headings dump _Server Database name | sort], [0], [dnl\n+Database table\n+_Server\n+$1])])\n+\n AT_SETUP([database multiplexing implementation])\n AT_KEYWORDS([ovsdb server positive])\n ordinal_schema > schema1\n constraint_schema > schema2\n AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])\n AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])\n-AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db1 db2], [0], [ignore], [ignore])\n-AT_CHECK(\n- [[ovsdb-client list-dbs unix:socket]], \n- [0], [constraints\n+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:db.sock db1 db2], [0], [ignore], [ignore])\n+CHECK_DBS([constraints\n ordinals\n-], [ignore], [test ! -e pid || kill `cat pid`])\n+])\n AT_CHECK(\n- [[ovstest test-jsonrpc request unix:socket get_schema [\\\"nonexistent\\\"]]], [0],\n+ [[ovstest test-jsonrpc request unix:db.sock get_schema [\\\"nonexistent\\\"]]], [0],\n [[{\"error\":{\"details\":\"get_schema request specifies unknown database nonexistent\",\"error\":\"unknown database\",\"syntax\":\"[\\\"nonexistent\\\"]\"},\"id\":0,\"result\":null}\n ]], [], [test ! -e pid || kill `cat pid`])\n OVSDB_SERVER_SHUTDOWN\n@@ -175,21 +186,19 @@ AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])\n AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])\n \n # Start ovsdb-server with just a single database - db1.\n-AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db1], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [ordinals\n+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:db.sock db1], [0])\n+CHECK_DBS([ordinals\n ])\n \n # Add the second database.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [constraints\n+CHECK_DBS([constraints\n ordinals\n ])\n \n # The databases are responsive.\n-AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ignore])\n-AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [0], [ignore], [ignore])\n+AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore])\n+AT_CHECK([ovsdb-client list-tables unix:db.sock ordinals], [0], [ignore], [ignore])\n \n # Add an already added database.\n if test $IS_WIN32 = \"yes\"; then\n@@ -215,25 +224,23 @@ ovs-appctl: ovsdb-server: server returned an error\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote db:ordinals,ordinals,name], [0])\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],\n [0], [db:ordinals,ordinals,name\n-punix:socket\n+punix:db.sock\n ])\n \n # Removing db1 has no effect on its remote.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [constraints\n+CHECK_DBS([constraints\n ])\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],\n [0], [db:ordinals,ordinals,name\n-punix:socket\n+punix:db.sock\n ])\n-AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [1], [ignore], [ignore])\n+AT_CHECK([ovsdb-client list-tables unix:db.sock ordinals], [1], [ignore], [ignore])\n \n # Remove db2.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db constraints], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [])\n-AT_CHECK([ovsdb-client list-tables unix:socket constraints], [1], [ignore], [ignore])\n+CHECK_DBS()\n+AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [1], [ignore], [ignore])\n \n # Remove a non-existent database.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [2],\n@@ -243,10 +250,9 @@ ovs-appctl: ovsdb-server: server returned an error\n \n # Add a removed database.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [constraints\n+CHECK_DBS([constraints\n ])\n-AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ignore])\n+AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore])\n OVS_APP_EXIT_AND_WAIT([ovsdb-server])\n AT_CLEANUP\n \n@@ -257,14 +263,13 @@ AT_SKIP_IF([test \"$IS_WIN32\" = \"yes\"])\n ordinal_schema > schema\n AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])\n on_exit 'kill `cat *.pid`'\n-AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1])\n+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db1])\n \n # Add the second database.\n constraint_schema > schema2\n AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [constraints\n+CHECK_DBS([constraints\n ordinals\n ])\n \n@@ -276,8 +281,7 @@ OVS_WAIT_WHILE([kill -0 `cat old.pid`])\n OVS_WAIT_UNTIL(\n [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])\n OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [constraints\n+CHECK_DBS([constraints\n ordinals\n ])\n OVS_APP_EXIT_AND_WAIT([ovsdb-server])\n@@ -292,12 +296,11 @@ AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])\n constraint_schema > schema2\n AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])\n on_exit 'kill `cat *.pid`'\n-AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1 db2])\n+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db1 db2])\n \n # Remove the second database.\n AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db constraints])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [ordinals\n+CHECK_DBS([ordinals\n ])\n \n # Kill the daemon process, making it look like a segfault,\n@@ -308,8 +311,7 @@ OVS_WAIT_WHILE([kill -0 `cat old.pid`])\n OVS_WAIT_UNTIL(\n [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])\n OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])\n-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],\n- [0], [ordinals\n+CHECK_DBS([ordinals\n ])\n OVS_APP_EXIT_AND_WAIT([ovsdb-server])\n AT_CLEANUP\n", "prefixes": [ "ovs-dev", "RFC", "42/52" ] }