From patchwork Mon Jan 1 05:16:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 854293 X-Patchwork-Delegate: jpettit@nicira.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3z95CX58fYz9t84 for ; Mon, 1 Jan 2018 16:21:44 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C2374CE4; Mon, 1 Jan 2018 05:17:07 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 3F576CDB for ; Mon, 1 Jan 2018 05:17:06 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5439A14B for ; Mon, 1 Jan 2018 05:17:03 +0000 (UTC) X-Originating-IP: 173.228.112.64 Received: from sigabrt.gateway.sonic.net (173-228-112-64.dsl.dynamic.fusionbroadband.com [173.228.112.64]) (Authenticated sender: blp@ovn.org) by relay2-d.mail.gandi.net (Postfix) with ESMTPSA id 2F80FC5A44; Mon, 1 Jan 2018 06:17:00 +0100 (CET) From: Ben Pfaff To: dev@openvswitch.org Date: Sun, 31 Dec 2017 21:16:35 -0800 Message-Id: <20180101051640.13043-10-blp@ovn.org> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20180101051640.13043-1-blp@ovn.org> References: <20180101051640.13043-1-blp@ovn.org> X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Ben Pfaff Subject: [ovs-dev] [PATCH 10/15] ovsdb-server: Add new RPC "set_db_change_aware". X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The _Server database recently added to ovsdb-server can be used to dump out information about databases, but monitoring updates to _Server is not yet very useful because for historical reasons ovsdb-server drops all of its OVSDB connections whenever databases are added or removed or otherwise change in some major way. It is not a good idea to change this behavior for all clients, because some of them rely on it, but this commit introduces a new RPC that allows clients that understand _Server to suppress the connection-closing behavior. Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- Documentation/ref/ovsdb-server.7.rst | 43 ++++++++ ovsdb/_server.xml | 34 ++++++ ovsdb/jsonrpc-server.c | 195 +++++++++++++++++++++++++++-------- ovsdb/jsonrpc-server.h | 4 +- ovsdb/ovsdb-client.c | 28 ++++- ovsdb/ovsdb-server.c | 11 +- tests/ovsdb-server.at | 40 ++++++- 7 files changed, 299 insertions(+), 56 deletions(-) diff --git a/Documentation/ref/ovsdb-server.7.rst b/Documentation/ref/ovsdb-server.7.rst index cc625f6016fb..2ed392feed1f 100644 --- a/Documentation/ref/ovsdb-server.7.rst +++ b/Documentation/ref/ovsdb-server.7.rst @@ -146,6 +146,19 @@ notifications (see below) to the request, it must be unique among all active monitors. ``ovsdb-server`` rejects attempt to create two monitors with the same identifier. +4.1.7 Monitor Cancellation +-------------------------- + +When a database monitored by a session is removed, and database change +awareness is enabled for the session (see Section 4.1.16), the database server +spontaneously cancels all monitors (including conditional monitors described in +Section 4.1.12) for the removed database. For each canceled monitor, it issues +a notification in the following form:: + + "method": "monitor_canceled" + "params": [] + "id": null + 4.1.12 Monitor_cond ------------------- @@ -371,6 +384,36 @@ The response object contains the following members:: running OVSDB server process. A fresh UUID is generated when the process restarts. +4.1.16 Database Change Awareness +-------------------------------- + +RFC 7047 does not provide a way for a client to find out about some kinds of +configuration changes, such as about databases added or removed while a client +is connected to the server, or databases changing between read/write and +read-only due to a transition between active and backup roles. Traditionally, +``ovsdb-server`` disconnects all of its clients when this happens, because this +prompts a well-written client to reassess what is available from the server +when it reconnects. + +OVS 2.9 provides a way for clients to keep track of these kinds of changes, by +monitoring the ``Database`` table in the ``_Server`` database introduced in +this release (see ``ovsdb-server(5)`` for details). By itself, this does not +suppress ``ovsdb-server`` disconnection behavior, because a client might +monitor this database without understanding its special semantics. Instead, +``ovsdb-server`` provides a special request:: + + "method": "set_db_change_aware" + "params": [] + "id": + +If the boolean in the request is true, it suppresses the connection-closing +behavior for the current connection, and false restores the default behavior. +The reply is always the same:: + + "result": {} + "error": null + "id": same "id" as request + 5.1 Notation ------------ diff --git a/ovsdb/_server.xml b/ovsdb/_server.xml index a55beb9bd6de..8ef782fb97b2 100644 --- a/ovsdb/_server.xml +++ b/ovsdb/_server.xml @@ -13,6 +13,40 @@ one row per database. As its database configuration and status changes, the server automatically and immediately updates the table to match.

+ +

+ The OVSDB protocol specified in RFC 7047 does not provide a way for an + OVSDB client to find out about some kinds of configuration changes, such + as about databases added or removed while a client is connected to the + server, or databases changing between read/write and read-only due to a + transition between active and backup roles. This table provides a + solution: clients can monitor the table's contents to find out about + important changes. +

+ +

+ Traditionally, ovsdb-server disconnects all of its clients + when a significant configuration change occurs, because this prompts a + well-written client to reassess what is available from the server when it + reconnects. Because this table provides an alternative and more + efficient way to find out about those changes, OVS 2.9 also introduces + the set_db_change_aware RPC, documented in + ovsdb-server(1), to allow clients to suppress this + disconnection behavior. +

+ +

+ When a database is removed from the server, in addition to + Database table updates, the server sends cancel + messages, as described in RFC 7047 section 4.1.4, in reply to outstanding + transactions for the removed database. The server also cancels any + outstanding monitoring initiated by monitor or + monitor_cond requested on the removed database, sending the + monitor_canceled RPC described in + ovsdb-server(5). Only clients that disable disconnection + with set_db_change_aware receive these messages. +

+

Clients can use the _uuid column in this table as a generation number. The server generates a fresh _uuid every diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 27586cddd8b3..d51a56854517 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -57,12 +57,15 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); /* Sessions. */ static struct ovsdb_jsonrpc_session *ovsdb_jsonrpc_session_create( struct ovsdb_jsonrpc_remote *, struct jsonrpc_session *, bool); +static void ovsdb_jsonrpc_session_preremove_db(struct ovsdb_jsonrpc_remote *, + struct ovsdb *); static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *); static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *); static void ovsdb_jsonrpc_session_get_memory_usage_all( const struct ovsdb_jsonrpc_remote *, struct simap *usage); static void ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *); -static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *); +static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *, + bool force); static void ovsdb_jsonrpc_session_set_all_options( struct ovsdb_jsonrpc_remote *, const struct ovsdb_jsonrpc_options *); static bool ovsdb_jsonrpc_active_session_get_status( @@ -83,6 +86,8 @@ static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *, static struct ovsdb_jsonrpc_trigger *ovsdb_jsonrpc_trigger_find( struct ovsdb_jsonrpc_session *, const struct json *id, size_t hash); static void ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *); +static void ovsdb_jsonrpc_trigger_preremove_db(struct ovsdb_jsonrpc_session *, + struct ovsdb *); static void ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *); static void ovsdb_jsonrpc_trigger_complete_done( struct ovsdb_jsonrpc_session *); @@ -99,6 +104,8 @@ static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel( struct ovsdb_jsonrpc_session *, struct json_array *params, const struct json *request_id); +static void ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *, + struct ovsdb *); static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *); static void ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *); static bool ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *); @@ -157,34 +164,25 @@ ovsdb_jsonrpc_server_create(bool read_only) bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db) { - /* The OVSDB protocol doesn't have a way to notify a client that a - * database has been added. If some client tried to use the database - * that we're adding and failed, then forcing it to reconnect seems like - * a reasonable way to make it try again. - * - * If this is too big of a hammer in practice, we could be more selective, - * e.g. disconnect only connections that actually tried to use a database - * with 'db''s name. */ - ovsdb_jsonrpc_server_reconnect(svr); - + ovsdb_jsonrpc_server_reconnect(svr, false); return ovsdb_server_add_db(&svr->up, db); } -/* Removes 'db' from the set of databases served out by 'svr'. Returns - * true if successful, false if there is no database associated with 'db'. */ -bool +/* Removes 'db' from the set of databases served out by 'svr'. */ +void ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db) { - /* There might be pointers to 'db' from 'svr', such as monitors or - * outstanding transactions. Disconnect all JSON-RPC connections to avoid - * accesses to freed memory. - * - * If this is too big of a hammer in practice, we could be more selective, - * e.g. disconnect only connections that actually reference 'db'. */ - ovsdb_jsonrpc_server_reconnect(svr); + struct shash_node *node; + SHASH_FOR_EACH (node, &svr->remotes) { + struct ovsdb_jsonrpc_remote *remote = node->data; + + ovsdb_jsonrpc_session_preremove_db(remote, db); + } + + ovsdb_jsonrpc_server_reconnect(svr, false); - return ovsdb_server_remove_db(&svr->up, db); + ovsdb_server_remove_db(&svr->up, db); } void @@ -333,17 +331,20 @@ ovsdb_jsonrpc_server_free_remote_status( free(status->locks_lost); } -/* Forces all of the JSON-RPC sessions managed by 'svr' to disconnect and - * reconnect. */ +/* Makes all of the JSON-RPC sessions managed by 'svr' to disconnect. (They + * will then generally reconnect.). + * + * If 'force' is true, disconnects all sessions. Otherwise, disconnects only + * sesions that aren't database change aware. */ void -ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *svr) +ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *svr, bool force) { struct shash_node *node; SHASH_FOR_EACH (node, &svr->remotes) { struct ovsdb_jsonrpc_remote *remote = node->data; - ovsdb_jsonrpc_session_reconnect_all(remote); + ovsdb_jsonrpc_session_reconnect_all(remote, force); } } @@ -359,7 +360,7 @@ ovsdb_jsonrpc_server_set_read_only(struct ovsdb_jsonrpc_server *svr, { if (svr->read_only != read_only) { svr->read_only = read_only; - ovsdb_jsonrpc_server_reconnect(svr); + ovsdb_jsonrpc_server_reconnect(svr, false); } } @@ -432,6 +433,20 @@ struct ovsdb_jsonrpc_session { struct ovsdb_session up; struct ovsdb_jsonrpc_remote *remote; + /* RFC 7047 does not contemplate how to alert clients to changes to the set + * of databases, e.g. databases that are added or removed while the + * database server is running. Traditionally, ovsdb-server disconnects all + * of its clients when this happens; a well-written client will reassess + * what is available from the server upon reconnection. + * + * OVS 2.9 introduces a way for clients to monitor changes to the databases + * being served, through the Database table in the _Server database that + * OVSDB adds in this version. ovsdb-server suppresses the connection + * close for clients that identify themselves as taking advantage of this + * mechanism. + */ + bool db_change_aware; + /* Triggers. */ struct hmap triggers; /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */ @@ -478,6 +493,20 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote, return s; } +/* Database 'db' is about to be removed from the database server. To prepare, + * this function removes all references to 'db' from session 's'. */ +static void +ovsdb_jsonrpc_session_preremove_db(struct ovsdb_jsonrpc_remote *remote, + struct ovsdb *db) +{ + struct ovsdb_jsonrpc_session *s; + + LIST_FOR_EACH (s, node, &remote->sessions) { + ovsdb_jsonrpc_monitor_preremove_db(s, db); + ovsdb_jsonrpc_trigger_preremove_db(s, db); + } +} + static void ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s) { @@ -606,17 +635,23 @@ ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote) } } -/* Forces all of the JSON-RPC sessions managed by 'remote' to disconnect and - * reconnect. */ +/* Makes all of the JSON-RPC sessions managed by 'remove' to disconnect. (They + * will then generally reconnect.). + * + * If 'force' is true, disconnects all sessions. Otherwise, disconnects only + * sesions that aren't database change aware. */ static void -ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote) +ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote, + bool force) { struct ovsdb_jsonrpc_session *s, *next; LIST_FOR_EACH_SAFE (s, next, node, &remote->sessions) { - jsonrpc_session_force_reconnect(s->js); - if (!jsonrpc_session_is_alive(s->js)) { - ovsdb_jsonrpc_session_close(s); + if (force || !s->db_change_aware) { + jsonrpc_session_force_reconnect(s->js); + if (!jsonrpc_session_is_alive(s->js)) { + ovsdb_jsonrpc_session_close(s); + } } } } @@ -859,6 +894,17 @@ ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *waiter) } static struct jsonrpc_msg * +syntax_error_reply(const struct jsonrpc_msg *request, const char *details) +{ + struct ovsdb_error *error = ovsdb_syntax_error( + request->params, NULL, "%s: %s", request->method, details); + struct jsonrpc_msg *msg = jsonrpc_create_error(ovsdb_error_to_json(error), + request->id); + ovsdb_error_destroy(error); + return msg; +} + +static struct jsonrpc_msg * ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s, struct jsonrpc_msg *request) { @@ -872,24 +918,21 @@ ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s, error = ovsdb_jsonrpc_session_parse_lock_name(request, &lock_name); if (error) { - goto error; + return jsonrpc_create_error(ovsdb_error_to_json_free(error), + request->id); } /* Report error if this session has not issued a "lock" or "steal" for this * lock. */ waiter = ovsdb_session_get_lock_waiter(&s->up, lock_name); if (!waiter) { - error = ovsdb_syntax_error( - request->params, NULL, "\"unlock\" without \"lock\" or \"steal\""); - goto error; + return syntax_error_reply(request, + "\"unlock\" without \"lock\" or \"steal\""); } ovsdb_jsonrpc_session_unlock__(waiter); return jsonrpc_create_reply(json_object_create(), request->id); - -error: - return jsonrpc_create_error(ovsdb_error_to_json_free(error), request->id); } static struct jsonrpc_msg * @@ -903,6 +946,21 @@ execute_transaction(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, return NULL; } +static struct jsonrpc_msg * +ovsdb_jsonrpc_session_set_db_change_aware(struct ovsdb_jsonrpc_session *s, + const struct jsonrpc_msg *request) +{ + const struct json_array *params = json_array(request->params); + if (params->n != 1 + || (params->elems[0]->type != JSON_TRUE && + params->elems[0]->type != JSON_FALSE)) { + return syntax_error_reply(request, "true or false parameter expected"); + } + + s->db_change_aware = json_boolean(params->elems[0]); + return jsonrpc_create_reply(json_object_create(), request->id); +} + static void ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s, struct jsonrpc_msg *request) @@ -963,6 +1021,8 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s, reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_STEAL); } else if (!strcmp(request->method, "unlock")) { reply = ovsdb_jsonrpc_session_unlock(s, request); + } else if (!strcmp(request->method, "set_db_change_aware")) { + reply = ovsdb_jsonrpc_session_set_db_change_aware(s, request); } else if (!strcmp(request->method, "echo")) { reply = jsonrpc_create_reply(json_clone(request->params), request->id); } else { @@ -1098,14 +1158,34 @@ ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *t) } static void -ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s) +ovsdb_jsonrpc_trigger_remove__(struct ovsdb_jsonrpc_session *s, + struct ovsdb *db) { struct ovsdb_jsonrpc_trigger *t, *next; HMAP_FOR_EACH_SAFE (t, next, hmap_node, &s->triggers) { - ovsdb_jsonrpc_trigger_complete(t); + if (!db || t->trigger.db == db) { + ovsdb_jsonrpc_trigger_complete(t); + } } } +/* Database 'db' is about to be removed from the database server. To prepare, + * this function removes all references from triggers in 's' to 'db'. */ +static void +ovsdb_jsonrpc_trigger_preremove_db(struct ovsdb_jsonrpc_session *s, + struct ovsdb *db) +{ + ovs_assert(db); + ovsdb_jsonrpc_trigger_remove__(s, db); +} + +/* Removes all triggers from 's'. */ +static void +ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s) +{ + ovsdb_jsonrpc_trigger_remove__(s, NULL); +} + static void ovsdb_jsonrpc_trigger_complete_done(struct ovsdb_jsonrpc_session *s) { @@ -1525,15 +1605,42 @@ ovsdb_jsonrpc_monitor_cancel(struct ovsdb_jsonrpc_session *s, } static void -ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s) +ovsdb_jsonrpc_monitor_remove__(struct ovsdb_jsonrpc_session *s, + struct ovsdb *db) { struct ovsdb_jsonrpc_monitor *m, *next; HMAP_FOR_EACH_SAFE (m, next, node, &s->monitors) { - ovsdb_jsonrpc_monitor_destroy(m); + if (!db || m->db == db) { + if (db && jsonrpc_session_is_connected(s->js) + && s->db_change_aware) { + struct jsonrpc_msg *notify = jsonrpc_create_notify( + "monitor_canceled", + json_array_create_1(json_clone(m->monitor_id))); + ovsdb_jsonrpc_session_send(s, notify); + } + ovsdb_jsonrpc_monitor_destroy(m); + } } } +/* Database 'db' is about to be removed from the database server. To prepare, + * this function removes all references from monitors in 's' to 'db'. */ +static void +ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s, + struct ovsdb *db) +{ + ovs_assert(db); + ovsdb_jsonrpc_monitor_remove__(s, db); +} + +/* Cancels all monitors in 's'. */ +static void +ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s) +{ + ovsdb_jsonrpc_monitor_remove__(s, NULL); +} + static struct json * ovsdb_jsonrpc_monitor_compose_update(struct ovsdb_jsonrpc_monitor *m, bool initial) diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index a3acc75f8d4f..50a8b879c5a9 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -27,7 +27,7 @@ struct uuid; struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(bool read_only); bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *, struct ovsdb *); -bool ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *, +void ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *, struct ovsdb *); void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *); @@ -64,7 +64,7 @@ bool ovsdb_jsonrpc_server_get_remote_status( void ovsdb_jsonrpc_server_free_remote_status( struct ovsdb_jsonrpc_remote_status *); -void ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *); +void ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *, bool force); void ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *); void ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *); diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 0ab4d66f1b29..600c5070db78 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -74,6 +74,13 @@ struct ovsdb_client_command { /* --timestamp: Print a timestamp before each update on "monitor" command? */ static bool timestamp; +/* --db-change-aware, --no-db-change-aware: Enable db_change_aware feature for + * "monitor" command? + * + * (This option is undocumented because it is expected to be useful only for + * testing that the db_change_aware feature actually works.) */ +static int db_change_aware; + /* --force: Ignore schema differences for "restore" command? */ static bool force; @@ -199,6 +206,8 @@ parse_options(int argc, char *argv[]) {"version", no_argument, NULL, 'V'}, {"timestamp", no_argument, NULL, OPT_TIMESTAMP}, {"force", no_argument, NULL, OPT_FORCE}, + {"db-change-aware", no_argument, &db_change_aware, 1}, + {"no-db-change-aware", no_argument, &db_change_aware, 0}, VLOG_LONG_OPTIONS, DAEMON_LONG_OPTIONS, #ifdef HAVE_OPENSSL @@ -1021,7 +1030,6 @@ do_monitor__(struct jsonrpc *rpc, const char *database, const char *table_name = argv[0]; struct unixctl_server *unixctl; struct ovsdb_schema *schema; - struct jsonrpc_msg *request; struct json *monitor, *monitor_requests, *request_id; bool exiting = false; bool blocked = false; @@ -1089,11 +1097,29 @@ do_monitor__(struct jsonrpc *rpc, const char *database, free(nodes); } + if (db_change_aware) { + struct jsonrpc_msg *request = jsonrpc_create_request( + "set_db_change_aware", + json_array_create_1(json_boolean_create(true)), + NULL); + struct jsonrpc_msg *reply; + int error = jsonrpc_transact_block(rpc, request, &reply); + if (error) { + ovs_fatal(error, "%s: error setting db_change_aware", server); + } + if (reply->type == JSONRPC_ERROR) { + ovs_fatal(0, "%s: set_db_change_aware failed (%s)", + server, json_to_string(reply->error, 0)); + } + jsonrpc_msg_destroy(reply); + } + monitor = json_array_create_3(json_string_create(database), json_null_create(), monitor_requests); const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond" : "monitor"; + struct jsonrpc_msg *request; request = jsonrpc_create_request(method, monitor, NULL); request_id = json_clone(request->id); jsonrpc_send(rpc, request); diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index dd0cdfe6a38b..1e36b27958f8 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -1240,7 +1240,7 @@ ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn, struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_; ovsdb_jsonrpc_disable_monitor_cond(); - ovsdb_jsonrpc_server_reconnect(jsonrpc); + ovsdb_jsonrpc_server_reconnect(jsonrpc, true); unixctl_command_reply(conn, NULL); } @@ -1298,7 +1298,7 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *jsonrpc_) { struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_; - ovsdb_jsonrpc_server_reconnect(jsonrpc); + ovsdb_jsonrpc_server_reconnect(jsonrpc, true); unixctl_command_reply(conn, NULL); } @@ -1400,12 +1400,9 @@ ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED, static void remove_db(struct server_config *config, struct shash_node *node) { - struct db *db; - bool ok; + struct db *db = node->data; - db = node->data; - ok = ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db); - ovs_assert(ok); + ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db); close_db(db); shash_delete(config->all_dbs, node); diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 07ceda92496d..2e3d8ad14636 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -169,14 +169,31 @@ AT_CLEANUP AT_SETUP([ovsdb-server/add-db and remove-db]) AT_KEYWORDS([ovsdb server positive]) -on_exit 'kill `cat ovsdb-server.pid`' +on_exit 'kill `cat *.pid`' ordinal_schema > schema1 constraint_schema > schema2 AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore]) AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore]) # Start ovsdb-server with just a single database - db1. -AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:db.sock db1], [0]) +AT_CHECK([ovsdb-server -vfile -vvlog:off --log-file --detach --no-chdir --pidfile --remote=punix:db.sock db1], [0]) +CHECK_DBS([ordinals +]) + +# Remove the database. +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [0]) +CHECK_DBS([]) + +# Start monitoring processes. +AT_CHECK([ovsdb-client --detach --pidfile=ovsdb-client-1.pid --no-db-change-aware --no-headings monitor _Server Database name > db-change-unaware.stdout 2> db-change-unaware.stderr]) +AT_CHECK([ovsdb-client --detach --pidfile=ovsdb-client-2.pid --db-change-aware --no-headings monitor _Server Database name > db-change-aware.stdout 2> db-change-aware.stderr]) +AT_CAPTURE_FILE([db-change-unaware.stdout]) +AT_CAPTURE_FILE([db-change-unaware.stderr]) +AT_CAPTURE_FILE([db-change-aware.stdout]) +AT_CAPTURE_FILE([db-change-aware.stderr]) + +# Add the first database back. +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db1], [0]) CHECK_DBS([ordinals ]) @@ -243,6 +260,25 @@ AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0]) CHECK_DBS([constraints ]) AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore]) + +# Check the monitoring results. +AT_CHECK([uuidfilt db-change-aware.stdout], [0], [dnl +<0> initial _Server + +<1> insert ordinals + +<2> insert constraints + +<1> delete ordinals + +<2> delete constraints + +<3> insert constraints +]) +AT_CHECK([uuidfilt db-change-unaware.stdout], [0], [dnl +<0> initial _Server +]) + OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP