summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/jsonrpc.c13
-rw-r--r--lib/jsonrpc.h1
-rw-r--r--lib/ovsdb-cs.c25
-rw-r--r--lib/svec.c11
-rw-r--r--lib/svec.h1
-rw-r--r--tests/ovsdb-idl.at24
-rw-r--r--tests/test-ovsdb.c6
7 files changed, 77 insertions, 4 deletions
diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c
index 926cbcb86..7e333ae25 100644
--- a/lib/jsonrpc.c
+++ b/lib/jsonrpc.c
@@ -952,6 +952,19 @@ jsonrpc_session_steal(struct jsonrpc_session *s)
return rpc;
}
+void
+jsonrpc_session_replace(struct jsonrpc_session *s, struct jsonrpc *rpc)
+{
+ if (s->rpc) {
+ jsonrpc_close(s->rpc);
+ }
+ s->rpc = rpc;
+ if (s->rpc) {
+ reconnect_set_name(s->reconnect, jsonrpc_get_name(s->rpc));
+ reconnect_connected(s->reconnect, time_msec());
+ }
+}
+
static void
jsonrpc_session_disconnect(struct jsonrpc_session *s)
{
diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h
index d75d66b86..034a30b71 100644
--- a/lib/jsonrpc.h
+++ b/lib/jsonrpc.h
@@ -114,6 +114,7 @@ struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *,
void jsonrpc_session_close(struct jsonrpc_session *);
struct jsonrpc *jsonrpc_session_steal(struct jsonrpc_session *);
+void jsonrpc_session_replace(struct jsonrpc_session *, struct jsonrpc *);
void jsonrpc_session_run(struct jsonrpc_session *);
void jsonrpc_session_wait(struct jsonrpc_session *);
diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c
index 911b71dd4..22630955d 100644
--- a/lib/ovsdb-cs.c
+++ b/lib/ovsdb-cs.c
@@ -660,7 +660,8 @@ ovsdb_cs_wait(struct ovsdb_cs *cs)
/* Network connection. */
-/* Changes the remote and creates a new session.
+/* Changes the remote and creates a new session. Keeps existing connection
+ * if current remote is still valid.
*
* If 'retry' is true, the connection to the remote will automatically retry
* when it fails. If 'retry' is false, the connection is one-time. */
@@ -670,9 +671,12 @@ ovsdb_cs_set_remote(struct ovsdb_cs *cs, const char *remote, bool retry)
if (cs
&& ((remote != NULL) != (cs->remote != NULL)
|| (remote && cs->remote && strcmp(remote, cs->remote)))) {
+ struct jsonrpc *rpc = NULL;
+
/* Close the old session, if any. */
if (cs->session) {
- jsonrpc_session_close(cs->session);
+ /* Save the current open connection and close the session. */
+ rpc = jsonrpc_session_steal(cs->session);
cs->session = NULL;
free(cs->remote);
@@ -682,17 +686,30 @@ ovsdb_cs_set_remote(struct ovsdb_cs *cs, const char *remote, bool retry)
/* Open new session, if any. */
if (remote) {
struct svec remotes = SVEC_EMPTY_INITIALIZER;
+ struct uuid old_cid = cs->cid;
+
ovsdb_session_parse_remote(remote, &remotes, &cs->cid);
if (cs->shuffle_remotes) {
svec_shuffle(&remotes);
}
cs->session = jsonrpc_session_open_multiple(&remotes, retry);
- svec_destroy(&remotes);
- cs->state_seqno = UINT_MAX;
+ /* Use old connection, if cluster id didn't change and the remote
+ * is still on the list, to avoid unnecessary re-connection. */
+ if (rpc && uuid_equals(&old_cid, &cs->cid)
+ && svec_contains_unsorted(&remotes, jsonrpc_get_name(rpc))) {
+ jsonrpc_session_replace(cs->session, rpc);
+ cs->state_seqno = jsonrpc_session_get_seqno(cs->session);
+ rpc = NULL;
+ } else {
+ cs->state_seqno = UINT_MAX;
+ }
+ svec_destroy(&remotes);
cs->remote = xstrdup(remote);
}
+
+ jsonrpc_close(rpc);
}
}
diff --git a/lib/svec.c b/lib/svec.c
index c1b986bab..6ea96384b 100644
--- a/lib/svec.c
+++ b/lib/svec.c
@@ -247,6 +247,17 @@ svec_contains(const struct svec *svec, const char *name)
return svec_find(svec, name) != SIZE_MAX;
}
+bool
+svec_contains_unsorted(const struct svec *svec, const char *name)
+{
+ for (size_t i = 0; i < svec->n; i++) {
+ if (!strcmp(svec->names[i], name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
size_t
svec_find(const struct svec *svec, const char *name)
{
diff --git a/lib/svec.h b/lib/svec.h
index b4e1343a9..cd95871cc 100644
--- a/lib/svec.h
+++ b/lib/svec.h
@@ -50,6 +50,7 @@ void svec_shuffle(struct svec *);
void svec_diff(const struct svec *a, const struct svec *b,
struct svec *a_only, struct svec *both, struct svec *b_only);
bool svec_contains(const struct svec *, const char *);
+bool svec_contains_unsorted(const struct svec *, const char *);
size_t svec_find(const struct svec *, const char *);
bool svec_is_sorted(const struct svec *);
bool svec_is_unique(const struct svec *);
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index 62181dd4d..e32f9ec89 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -2282,3 +2282,27 @@ OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect],
008: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
009: done
]])
+
+dnl This test checks that IDL keeps the existing connection to the server if
+dnl it's still on a list of remotes after update.
+OVSDB_CHECK_IDL_C([simple idl, initially empty, set remotes],
+ [],
+ [['set-remote unix:socket' \
+ '+set-remote unix:bad_socket,unix:socket' \
+ '+set-remote unix:bad_socket' \
+ '+set-remote unix:socket' \
+ 'set-remote unix:bad_socket,unix:socket' \
+ '+set-remote unix:socket' \
+ '+reconnect']],
+ [[000: empty
+001: new remotes: unix:socket, is connected: true
+002: new remotes: unix:bad_socket,unix:socket, is connected: true
+003: new remotes: unix:bad_socket, is connected: false
+004: new remotes: unix:socket, is connected: false
+005: empty
+006: new remotes: unix:bad_socket,unix:socket, is connected: true
+007: new remotes: unix:socket, is connected: true
+008: reconnect
+009: empty
+010: done
+]])
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index a886f971e..93329cd4c 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -2621,6 +2621,7 @@ do_idl(struct ovs_cmdl_context *ctx)
setvbuf(stdout, NULL, _IONBF, 0);
symtab = ovsdb_symbol_table_create();
+ const char remote_s[] = "set-remote ";
const char cond_s[] = "condition ";
if (ctx->argc > 2 && strstr(ctx->argv[2], cond_s)) {
update_conditions(idl, ctx->argv[2] + strlen(cond_s));
@@ -2664,6 +2665,11 @@ do_idl(struct ovs_cmdl_context *ctx)
if (!strcmp(arg, "reconnect")) {
print_and_log("%03d: reconnect", step++);
ovsdb_idl_force_reconnect(idl);
+ } else if (!strncmp(arg, remote_s, strlen(remote_s))) {
+ ovsdb_idl_set_remote(idl, arg + strlen(remote_s), true);
+ print_and_log("%03d: new remotes: %s, is connected: %s", step++,
+ arg + strlen(remote_s),
+ ovsdb_idl_is_connected(idl) ? "true" : "false");
} else if (!strncmp(arg, cond_s, strlen(cond_s))) {
update_conditions(idl, arg + strlen(cond_s));
print_and_log("%03d: change conditions", step++);