diff options
-rw-r--r-- | lib/jsonrpc.c | 13 | ||||
-rw-r--r-- | lib/jsonrpc.h | 1 | ||||
-rw-r--r-- | lib/ovsdb-cs.c | 25 | ||||
-rw-r--r-- | lib/svec.c | 11 | ||||
-rw-r--r-- | lib/svec.h | 1 | ||||
-rw-r--r-- | tests/ovsdb-idl.at | 24 | ||||
-rw-r--r-- | tests/test-ovsdb.c | 6 |
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++); |