diff mbox series

[ovs-dev,v2,1/2] ovsdb-idl: New function ovsdb_idl_create_unconnected().

Message ID 20180618183650.17439-1-blp@ovn.org
State Accepted
Headers show
Series [ovs-dev,v2,1/2] ovsdb-idl: New function ovsdb_idl_create_unconnected(). | expand

Commit Message

Ben Pfaff June 18, 2018, 6:36 p.m. UTC
This new function makes it possible to create an instance of the IDL
without connecting it to a remote OVSDB server.  The caller can then
connect and disconnect using ovsdb_idl_set_remote(); the ability to
disconnect is a new feature.

With this patch, the ovsdb_idl 'session' member can be null whereas
previously it was always nonnull.  The scattered changes throughout
ovsdb-idl are to cope with this new possibility.

An upcoming patch will introduce the first user of this new feature.

Signed-off-by: Ben Pfaff <blp@ovn.org>
---
v1->v2: No change.

 lib/ovsdb-idl.c | 118 +++++++++++++++++++++++++++++++++++++++++---------------
 lib/ovsdb-idl.h |   2 +
 2 files changed, 88 insertions(+), 32 deletions(-)

Comments

Mark Michelson July 26, 2018, 8:56 p.m. UTC | #1
Better late than never

Acked-by: Mark Michelson <mmichels@redhat.com>

On 06/18/2018 02:36 PM, Ben Pfaff wrote:
> This new function makes it possible to create an instance of the IDL
> without connecting it to a remote OVSDB server.  The caller can then
> connect and disconnect using ovsdb_idl_set_remote(); the ability to
> disconnect is a new feature.
> 
> With this patch, the ovsdb_idl 'session' member can be null whereas
> previously it was always nonnull.  The scattered changes throughout
> ovsdb-idl are to cope with this new possibility.
> 
> An upcoming patch will introduce the first user of this new feature.
> 
> Signed-off-by: Ben Pfaff <blp@ovn.org>
> ---
> v1->v2: No change.
> 
>   lib/ovsdb-idl.c | 118 +++++++++++++++++++++++++++++++++++++++++---------------
>   lib/ovsdb-idl.h |   2 +
>   2 files changed, 88 insertions(+), 32 deletions(-)
> 
> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> index e0991f940f79..86e28d810603 100644
> --- a/lib/ovsdb-idl.c
> +++ b/lib/ovsdb-idl.c
> @@ -233,6 +233,7 @@ struct ovsdb_idl {
>        * function currently returns then the session has reconnected and the
>        * state machine must restart.  */
>       struct jsonrpc_session *session; /* Connection to the server. */
> +    char *remote;                    /* 'session' remote name. */
>       enum ovsdb_idl_state state;      /* Current session state. */
>       unsigned int state_seqno;        /* See above. */
>       struct json *request_id;         /* JSON ID for request awaiting reply. */
> @@ -365,18 +366,6 @@ static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
>   static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
>   static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
>   
> -static void
> -ovsdb_idl_open_session(struct ovsdb_idl *idl, const char *remote, bool retry)
> -{
> -    ovs_assert(!idl->data.txn);
> -    jsonrpc_session_close(idl->session);
> -
> -    struct svec remotes = SVEC_EMPTY_INITIALIZER;
> -    ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
> -    idl->session = jsonrpc_session_open_multiple(&remotes, retry);
> -    svec_destroy(&remotes);
> -}
> -
>   static void
>   ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
>                     struct ovsdb_idl *parent, bool monitor_everything_by_default)
> @@ -443,13 +432,38 @@ ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
>   struct ovsdb_idl *
>   ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
>                    bool monitor_everything_by_default, bool retry)
> +{
> +    struct ovsdb_idl *idl = ovsdb_idl_create_unconnected(
> +        class, monitor_everything_by_default);
> +    ovsdb_idl_set_remote(idl, remote, retry);
> +    return idl;
> +}
> +
> +/* Creates and returns a connection to an in-memory replica of the remote
> + * database whose schema is described by 'class'.  (Ordinarily 'class' is
> + * compiled from an OVSDB schema automatically by ovsdb-idlc.)
> + *
> + * Use ovsdb_idl_set_remote() to configure the database to which to connect.
> + * Until a remote is configured, no data can be retrieved.
> + *
> + * If 'monitor_everything_by_default' is true, then everything in the remote
> + * database will be replicated by default.  ovsdb_idl_omit() and
> + * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
> + * monitoring.
> + *
> + * If 'monitor_everything_by_default' is false, then no columns or tables will
> + * be replicated by default.  ovsdb_idl_add_column() and ovsdb_idl_add_table()
> + * must be used to choose some columns or tables to replicate.
> + */
> +struct ovsdb_idl *
> +ovsdb_idl_create_unconnected(const struct ovsdb_idl_class *class,
> +                             bool monitor_everything_by_default)
>   {
>       struct ovsdb_idl *idl;
>   
>       idl = xzalloc(sizeof *idl);
>       ovsdb_idl_db_init(&idl->server, &serverrec_idl_class, idl, true);
>       ovsdb_idl_db_init(&idl->data, class, idl, monitor_everything_by_default);
> -    ovsdb_idl_open_session(idl, remote, retry);
>       idl->state_seqno = UINT_MAX;
>       idl->request_id = NULL;
>       idl->leader_only = true;
> @@ -471,14 +485,38 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
>       return idl;
>   }
>   
> -/* Changes the remote and creates a new session. */
> +/* Changes the remote and creates a new session.
> + *
> + * If 'retry' is true, the connection to the remote will automatically retry
> + * when it fails.  If 'retry' is false, the connection is one-time. */
>   void
> -ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
> -                     bool retry)
> +ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote, bool retry)
>   {
> -    if (idl) {
> -        ovsdb_idl_open_session(idl, remote, retry);
> -        idl->state_seqno = UINT_MAX;
> +    if (idl
> +        && ((remote != NULL) != (idl->remote != NULL)
> +            || (remote && idl->remote && strcmp(remote, idl->remote)))) {
> +        ovs_assert(!idl->data.txn);
> +
> +        /* Close the old session, if any. */
> +        if (idl->session) {
> +            jsonrpc_session_close(idl->session);
> +            idl->session = NULL;
> +
> +            free(idl->remote);
> +            idl->remote = NULL;
> +        }
> +
> +        /* Open new session, if any. */
> +        if (remote) {
> +            struct svec remotes = SVEC_EMPTY_INITIALIZER;
> +            ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
> +            idl->session = jsonrpc_session_open_multiple(&remotes, retry);
> +            svec_destroy(&remotes);
> +
> +            idl->state_seqno = UINT_MAX;
> +
> +            idl->remote = xstrdup(remote);
> +        }
>       }
>   }
>   
> @@ -588,7 +626,7 @@ ovsdb_idl_state_to_string(enum ovsdb_idl_state state)
>   static void
>   ovsdb_idl_retry_at(struct ovsdb_idl *idl, const char *where)
>   {
> -    if (jsonrpc_session_get_n_remotes(idl->session) > 1) {
> +    if (idl->session && jsonrpc_session_get_n_remotes(idl->session) > 1) {
>           ovsdb_idl_force_reconnect(idl);
>           ovsdb_idl_transition_at(idl, IDL_S_RETRY, where);
>       } else {
> @@ -601,7 +639,7 @@ ovsdb_idl_transition_at(struct ovsdb_idl *idl, enum ovsdb_idl_state new_state,
>                           const char *where)
>   {
>       VLOG_DBG("%s: %s -> %s at %s",
> -             jsonrpc_session_get_name(idl->session),
> +             idl->session ? jsonrpc_session_get_name(idl->session) : "void",
>                ovsdb_idl_state_to_string(idl->state),
>                ovsdb_idl_state_to_string(new_state),
>                where);
> @@ -619,7 +657,9 @@ ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request)
>   {
>       json_destroy(idl->request_id);
>       idl->request_id = json_clone(request->id);
> -    jsonrpc_session_send(idl->session, request);
> +    if (idl->session) {
> +        jsonrpc_session_send(idl->session, request);
> +    }
>   }
>   
>   static void
> @@ -787,6 +827,11 @@ ovsdb_idl_process_msg(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
>   void
>   ovsdb_idl_run(struct ovsdb_idl *idl)
>   {
> +    if (!idl->session) {
> +        ovsdb_idl_txn_abort_all(idl);
> +        return;
> +    }
> +
>       int i;
>   
>       ovs_assert(!idl->data.txn);
> @@ -826,6 +871,9 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
>   void
>   ovsdb_idl_wait(struct ovsdb_idl *idl)
>   {
> +    if (!idl->session) {
> +        return;
> +    }
>       jsonrpc_session_wait(idl->session);
>       jsonrpc_session_recv_wait(idl->session);
>   }
> @@ -892,7 +940,9 @@ ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
>   void
>   ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
>   {
> -    jsonrpc_session_enable_reconnect(idl->session);
> +    if (idl->session) {
> +        jsonrpc_session_enable_reconnect(idl->session);
> +    }
>   }
>   
>   /* Forces 'idl' to drop its connection to the database and reconnect.  In the
> @@ -900,7 +950,9 @@ ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
>   void
>   ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
>   {
> -    jsonrpc_session_force_reconnect(idl->session);
> +    if (idl->session) {
> +        jsonrpc_session_force_reconnect(idl->session);
> +    }
>   }
>   
>   /* Some IDL users should only write to write-only columns.  Furthermore,
> @@ -918,7 +970,7 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
>   bool
>   ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
>   {
> -    return jsonrpc_session_is_alive(idl->session) &&
> +    return idl->session && jsonrpc_session_is_alive(idl->session) &&
>              idl->state != IDL_S_ERROR;
>   }
>   
> @@ -930,10 +982,7 @@ ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
>   int
>   ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
>   {
> -    int err;
> -
> -    err = jsonrpc_session_get_last_error(idl->session);
> -
> +    int err = idl->session ? jsonrpc_session_get_last_error(idl->session) : 0;
>       if (err) {
>           return err;
>       } else if (idl->state == IDL_S_ERROR) {
> @@ -949,7 +998,9 @@ ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
>   void
>   ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
>   {
> -    jsonrpc_session_set_probe_interval(idl->session, probe_interval);
> +    if (idl->session) {
> +        jsonrpc_session_set_probe_interval(idl->session, probe_interval);
> +    }
>   }
>   
>   static size_t
> @@ -4006,7 +4057,8 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
>       if (!any_updates) {
>           txn->status = TXN_UNCHANGED;
>           json_destroy(operations);
> -    } else if (!jsonrpc_session_send(
> +    } else if (txn->db->idl->session
> +               && !jsonrpc_session_send(
>                      txn->db->idl->session,
>                      jsonrpc_create_request(
>                          "transact", operations, &txn->request_id))) {
> @@ -4696,7 +4748,9 @@ ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
>           if (!msg) {
>               break;
>           }
> -        jsonrpc_session_send(idl->session, msg);
> +        if (idl->session) {
> +            jsonrpc_session_send(idl->session, msg);
> +        }
>       }
>   }
>   
> diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
> index ea18b22f5480..382981cb44c6 100644
> --- a/lib/ovsdb-idl.h
> +++ b/lib/ovsdb-idl.h
> @@ -60,6 +60,8 @@ struct ovsdb_idl *ovsdb_idl_create(const char *remote,
>                                      const struct ovsdb_idl_class *,
>                                      bool monitor_everything_by_default,
>                                      bool retry);
> +struct ovsdb_idl *ovsdb_idl_create_unconnected(
> +    const struct ovsdb_idl_class *, bool monitor_everything_by_default);
>   void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *, bool);
>   void ovsdb_idl_destroy(struct ovsdb_idl *);
>   
>
Ben Pfaff Oct. 4, 2018, 8:29 p.m. UTC | #2
Thanks.  I applied this series to master.

On Thu, Jul 26, 2018 at 04:56:32PM -0400, Mark Michelson wrote:
> Better late than never
> 
> Acked-by: Mark Michelson <mmichels@redhat.com>
> 
> On 06/18/2018 02:36 PM, Ben Pfaff wrote:
> >This new function makes it possible to create an instance of the IDL
> >without connecting it to a remote OVSDB server.  The caller can then
> >connect and disconnect using ovsdb_idl_set_remote(); the ability to
> >disconnect is a new feature.
> >
> >With this patch, the ovsdb_idl 'session' member can be null whereas
> >previously it was always nonnull.  The scattered changes throughout
> >ovsdb-idl are to cope with this new possibility.
> >
> >An upcoming patch will introduce the first user of this new feature.
> >
> >Signed-off-by: Ben Pfaff <blp@ovn.org>
> >---
> >v1->v2: No change.
> >
> >  lib/ovsdb-idl.c | 118 +++++++++++++++++++++++++++++++++++++++++---------------
> >  lib/ovsdb-idl.h |   2 +
> >  2 files changed, 88 insertions(+), 32 deletions(-)
> >
> >diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> >index e0991f940f79..86e28d810603 100644
> >--- a/lib/ovsdb-idl.c
> >+++ b/lib/ovsdb-idl.c
> >@@ -233,6 +233,7 @@ struct ovsdb_idl {
> >       * function currently returns then the session has reconnected and the
> >       * state machine must restart.  */
> >      struct jsonrpc_session *session; /* Connection to the server. */
> >+    char *remote;                    /* 'session' remote name. */
> >      enum ovsdb_idl_state state;      /* Current session state. */
> >      unsigned int state_seqno;        /* See above. */
> >      struct json *request_id;         /* JSON ID for request awaiting reply. */
> >@@ -365,18 +366,6 @@ static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
> >  static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
> >  static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
> >-static void
> >-ovsdb_idl_open_session(struct ovsdb_idl *idl, const char *remote, bool retry)
> >-{
> >-    ovs_assert(!idl->data.txn);
> >-    jsonrpc_session_close(idl->session);
> >-
> >-    struct svec remotes = SVEC_EMPTY_INITIALIZER;
> >-    ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
> >-    idl->session = jsonrpc_session_open_multiple(&remotes, retry);
> >-    svec_destroy(&remotes);
> >-}
> >-
> >  static void
> >  ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
> >                    struct ovsdb_idl *parent, bool monitor_everything_by_default)
> >@@ -443,13 +432,38 @@ ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
> >  struct ovsdb_idl *
> >  ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
> >                   bool monitor_everything_by_default, bool retry)
> >+{
> >+    struct ovsdb_idl *idl = ovsdb_idl_create_unconnected(
> >+        class, monitor_everything_by_default);
> >+    ovsdb_idl_set_remote(idl, remote, retry);
> >+    return idl;
> >+}
> >+
> >+/* Creates and returns a connection to an in-memory replica of the remote
> >+ * database whose schema is described by 'class'.  (Ordinarily 'class' is
> >+ * compiled from an OVSDB schema automatically by ovsdb-idlc.)
> >+ *
> >+ * Use ovsdb_idl_set_remote() to configure the database to which to connect.
> >+ * Until a remote is configured, no data can be retrieved.
> >+ *
> >+ * If 'monitor_everything_by_default' is true, then everything in the remote
> >+ * database will be replicated by default.  ovsdb_idl_omit() and
> >+ * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
> >+ * monitoring.
> >+ *
> >+ * If 'monitor_everything_by_default' is false, then no columns or tables will
> >+ * be replicated by default.  ovsdb_idl_add_column() and ovsdb_idl_add_table()
> >+ * must be used to choose some columns or tables to replicate.
> >+ */
> >+struct ovsdb_idl *
> >+ovsdb_idl_create_unconnected(const struct ovsdb_idl_class *class,
> >+                             bool monitor_everything_by_default)
> >  {
> >      struct ovsdb_idl *idl;
> >      idl = xzalloc(sizeof *idl);
> >      ovsdb_idl_db_init(&idl->server, &serverrec_idl_class, idl, true);
> >      ovsdb_idl_db_init(&idl->data, class, idl, monitor_everything_by_default);
> >-    ovsdb_idl_open_session(idl, remote, retry);
> >      idl->state_seqno = UINT_MAX;
> >      idl->request_id = NULL;
> >      idl->leader_only = true;
> >@@ -471,14 +485,38 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
> >      return idl;
> >  }
> >-/* Changes the remote and creates a new session. */
> >+/* Changes the remote and creates a new session.
> >+ *
> >+ * If 'retry' is true, the connection to the remote will automatically retry
> >+ * when it fails.  If 'retry' is false, the connection is one-time. */
> >  void
> >-ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
> >-                     bool retry)
> >+ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote, bool retry)
> >  {
> >-    if (idl) {
> >-        ovsdb_idl_open_session(idl, remote, retry);
> >-        idl->state_seqno = UINT_MAX;
> >+    if (idl
> >+        && ((remote != NULL) != (idl->remote != NULL)
> >+            || (remote && idl->remote && strcmp(remote, idl->remote)))) {
> >+        ovs_assert(!idl->data.txn);
> >+
> >+        /* Close the old session, if any. */
> >+        if (idl->session) {
> >+            jsonrpc_session_close(idl->session);
> >+            idl->session = NULL;
> >+
> >+            free(idl->remote);
> >+            idl->remote = NULL;
> >+        }
> >+
> >+        /* Open new session, if any. */
> >+        if (remote) {
> >+            struct svec remotes = SVEC_EMPTY_INITIALIZER;
> >+            ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
> >+            idl->session = jsonrpc_session_open_multiple(&remotes, retry);
> >+            svec_destroy(&remotes);
> >+
> >+            idl->state_seqno = UINT_MAX;
> >+
> >+            idl->remote = xstrdup(remote);
> >+        }
> >      }
> >  }
> >@@ -588,7 +626,7 @@ ovsdb_idl_state_to_string(enum ovsdb_idl_state state)
> >  static void
> >  ovsdb_idl_retry_at(struct ovsdb_idl *idl, const char *where)
> >  {
> >-    if (jsonrpc_session_get_n_remotes(idl->session) > 1) {
> >+    if (idl->session && jsonrpc_session_get_n_remotes(idl->session) > 1) {
> >          ovsdb_idl_force_reconnect(idl);
> >          ovsdb_idl_transition_at(idl, IDL_S_RETRY, where);
> >      } else {
> >@@ -601,7 +639,7 @@ ovsdb_idl_transition_at(struct ovsdb_idl *idl, enum ovsdb_idl_state new_state,
> >                          const char *where)
> >  {
> >      VLOG_DBG("%s: %s -> %s at %s",
> >-             jsonrpc_session_get_name(idl->session),
> >+             idl->session ? jsonrpc_session_get_name(idl->session) : "void",
> >               ovsdb_idl_state_to_string(idl->state),
> >               ovsdb_idl_state_to_string(new_state),
> >               where);
> >@@ -619,7 +657,9 @@ ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request)
> >  {
> >      json_destroy(idl->request_id);
> >      idl->request_id = json_clone(request->id);
> >-    jsonrpc_session_send(idl->session, request);
> >+    if (idl->session) {
> >+        jsonrpc_session_send(idl->session, request);
> >+    }
> >  }
> >  static void
> >@@ -787,6 +827,11 @@ ovsdb_idl_process_msg(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
> >  void
> >  ovsdb_idl_run(struct ovsdb_idl *idl)
> >  {
> >+    if (!idl->session) {
> >+        ovsdb_idl_txn_abort_all(idl);
> >+        return;
> >+    }
> >+
> >      int i;
> >      ovs_assert(!idl->data.txn);
> >@@ -826,6 +871,9 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
> >  void
> >  ovsdb_idl_wait(struct ovsdb_idl *idl)
> >  {
> >+    if (!idl->session) {
> >+        return;
> >+    }
> >      jsonrpc_session_wait(idl->session);
> >      jsonrpc_session_recv_wait(idl->session);
> >  }
> >@@ -892,7 +940,9 @@ ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
> >  void
> >  ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
> >  {
> >-    jsonrpc_session_enable_reconnect(idl->session);
> >+    if (idl->session) {
> >+        jsonrpc_session_enable_reconnect(idl->session);
> >+    }
> >  }
> >  /* Forces 'idl' to drop its connection to the database and reconnect.  In the
> >@@ -900,7 +950,9 @@ ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
> >  void
> >  ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
> >  {
> >-    jsonrpc_session_force_reconnect(idl->session);
> >+    if (idl->session) {
> >+        jsonrpc_session_force_reconnect(idl->session);
> >+    }
> >  }
> >  /* Some IDL users should only write to write-only columns.  Furthermore,
> >@@ -918,7 +970,7 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
> >  bool
> >  ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
> >  {
> >-    return jsonrpc_session_is_alive(idl->session) &&
> >+    return idl->session && jsonrpc_session_is_alive(idl->session) &&
> >             idl->state != IDL_S_ERROR;
> >  }
> >@@ -930,10 +982,7 @@ ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
> >  int
> >  ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
> >  {
> >-    int err;
> >-
> >-    err = jsonrpc_session_get_last_error(idl->session);
> >-
> >+    int err = idl->session ? jsonrpc_session_get_last_error(idl->session) : 0;
> >      if (err) {
> >          return err;
> >      } else if (idl->state == IDL_S_ERROR) {
> >@@ -949,7 +998,9 @@ ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
> >  void
> >  ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
> >  {
> >-    jsonrpc_session_set_probe_interval(idl->session, probe_interval);
> >+    if (idl->session) {
> >+        jsonrpc_session_set_probe_interval(idl->session, probe_interval);
> >+    }
> >  }
> >  static size_t
> >@@ -4006,7 +4057,8 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
> >      if (!any_updates) {
> >          txn->status = TXN_UNCHANGED;
> >          json_destroy(operations);
> >-    } else if (!jsonrpc_session_send(
> >+    } else if (txn->db->idl->session
> >+               && !jsonrpc_session_send(
> >                     txn->db->idl->session,
> >                     jsonrpc_create_request(
> >                         "transact", operations, &txn->request_id))) {
> >@@ -4696,7 +4748,9 @@ ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
> >          if (!msg) {
> >              break;
> >          }
> >-        jsonrpc_session_send(idl->session, msg);
> >+        if (idl->session) {
> >+            jsonrpc_session_send(idl->session, msg);
> >+        }
> >      }
> >  }
> >diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
> >index ea18b22f5480..382981cb44c6 100644
> >--- a/lib/ovsdb-idl.h
> >+++ b/lib/ovsdb-idl.h
> >@@ -60,6 +60,8 @@ struct ovsdb_idl *ovsdb_idl_create(const char *remote,
> >                                     const struct ovsdb_idl_class *,
> >                                     bool monitor_everything_by_default,
> >                                     bool retry);
> >+struct ovsdb_idl *ovsdb_idl_create_unconnected(
> >+    const struct ovsdb_idl_class *, bool monitor_everything_by_default);
> >  void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *, bool);
> >  void ovsdb_idl_destroy(struct ovsdb_idl *);
> >
>
diff mbox series

Patch

diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index e0991f940f79..86e28d810603 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -233,6 +233,7 @@  struct ovsdb_idl {
      * function currently returns then the session has reconnected and the
      * state machine must restart.  */
     struct jsonrpc_session *session; /* Connection to the server. */
+    char *remote;                    /* 'session' remote name. */
     enum ovsdb_idl_state state;      /* Current session state. */
     unsigned int state_seqno;        /* See above. */
     struct json *request_id;         /* JSON ID for request awaiting reply. */
@@ -365,18 +366,6 @@  static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
 
-static void
-ovsdb_idl_open_session(struct ovsdb_idl *idl, const char *remote, bool retry)
-{
-    ovs_assert(!idl->data.txn);
-    jsonrpc_session_close(idl->session);
-
-    struct svec remotes = SVEC_EMPTY_INITIALIZER;
-    ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
-    idl->session = jsonrpc_session_open_multiple(&remotes, retry);
-    svec_destroy(&remotes);
-}
-
 static void
 ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
                   struct ovsdb_idl *parent, bool monitor_everything_by_default)
@@ -443,13 +432,38 @@  ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
 struct ovsdb_idl *
 ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
                  bool monitor_everything_by_default, bool retry)
+{
+    struct ovsdb_idl *idl = ovsdb_idl_create_unconnected(
+        class, monitor_everything_by_default);
+    ovsdb_idl_set_remote(idl, remote, retry);
+    return idl;
+}
+
+/* Creates and returns a connection to an in-memory replica of the remote
+ * database whose schema is described by 'class'.  (Ordinarily 'class' is
+ * compiled from an OVSDB schema automatically by ovsdb-idlc.)
+ *
+ * Use ovsdb_idl_set_remote() to configure the database to which to connect.
+ * Until a remote is configured, no data can be retrieved.
+ *
+ * If 'monitor_everything_by_default' is true, then everything in the remote
+ * database will be replicated by default.  ovsdb_idl_omit() and
+ * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
+ * monitoring.
+ *
+ * If 'monitor_everything_by_default' is false, then no columns or tables will
+ * be replicated by default.  ovsdb_idl_add_column() and ovsdb_idl_add_table()
+ * must be used to choose some columns or tables to replicate.
+ */
+struct ovsdb_idl *
+ovsdb_idl_create_unconnected(const struct ovsdb_idl_class *class,
+                             bool monitor_everything_by_default)
 {
     struct ovsdb_idl *idl;
 
     idl = xzalloc(sizeof *idl);
     ovsdb_idl_db_init(&idl->server, &serverrec_idl_class, idl, true);
     ovsdb_idl_db_init(&idl->data, class, idl, monitor_everything_by_default);
-    ovsdb_idl_open_session(idl, remote, retry);
     idl->state_seqno = UINT_MAX;
     idl->request_id = NULL;
     idl->leader_only = true;
@@ -471,14 +485,38 @@  ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
     return idl;
 }
 
-/* Changes the remote and creates a new session. */
+/* Changes the remote and creates a new session.
+ *
+ * If 'retry' is true, the connection to the remote will automatically retry
+ * when it fails.  If 'retry' is false, the connection is one-time. */
 void
-ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
-                     bool retry)
+ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote, bool retry)
 {
-    if (idl) {
-        ovsdb_idl_open_session(idl, remote, retry);
-        idl->state_seqno = UINT_MAX;
+    if (idl
+        && ((remote != NULL) != (idl->remote != NULL)
+            || (remote && idl->remote && strcmp(remote, idl->remote)))) {
+        ovs_assert(!idl->data.txn);
+
+        /* Close the old session, if any. */
+        if (idl->session) {
+            jsonrpc_session_close(idl->session);
+            idl->session = NULL;
+
+            free(idl->remote);
+            idl->remote = NULL;
+        }
+
+        /* Open new session, if any. */
+        if (remote) {
+            struct svec remotes = SVEC_EMPTY_INITIALIZER;
+            ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
+            idl->session = jsonrpc_session_open_multiple(&remotes, retry);
+            svec_destroy(&remotes);
+
+            idl->state_seqno = UINT_MAX;
+
+            idl->remote = xstrdup(remote);
+        }
     }
 }
 
@@ -588,7 +626,7 @@  ovsdb_idl_state_to_string(enum ovsdb_idl_state state)
 static void
 ovsdb_idl_retry_at(struct ovsdb_idl *idl, const char *where)
 {
-    if (jsonrpc_session_get_n_remotes(idl->session) > 1) {
+    if (idl->session && jsonrpc_session_get_n_remotes(idl->session) > 1) {
         ovsdb_idl_force_reconnect(idl);
         ovsdb_idl_transition_at(idl, IDL_S_RETRY, where);
     } else {
@@ -601,7 +639,7 @@  ovsdb_idl_transition_at(struct ovsdb_idl *idl, enum ovsdb_idl_state new_state,
                         const char *where)
 {
     VLOG_DBG("%s: %s -> %s at %s",
-             jsonrpc_session_get_name(idl->session),
+             idl->session ? jsonrpc_session_get_name(idl->session) : "void",
              ovsdb_idl_state_to_string(idl->state),
              ovsdb_idl_state_to_string(new_state),
              where);
@@ -619,7 +657,9 @@  ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request)
 {
     json_destroy(idl->request_id);
     idl->request_id = json_clone(request->id);
-    jsonrpc_session_send(idl->session, request);
+    if (idl->session) {
+        jsonrpc_session_send(idl->session, request);
+    }
 }
 
 static void
@@ -787,6 +827,11 @@  ovsdb_idl_process_msg(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
 void
 ovsdb_idl_run(struct ovsdb_idl *idl)
 {
+    if (!idl->session) {
+        ovsdb_idl_txn_abort_all(idl);
+        return;
+    }
+
     int i;
 
     ovs_assert(!idl->data.txn);
@@ -826,6 +871,9 @@  ovsdb_idl_run(struct ovsdb_idl *idl)
 void
 ovsdb_idl_wait(struct ovsdb_idl *idl)
 {
+    if (!idl->session) {
+        return;
+    }
     jsonrpc_session_wait(idl->session);
     jsonrpc_session_recv_wait(idl->session);
 }
@@ -892,7 +940,9 @@  ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
 void
 ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
 {
-    jsonrpc_session_enable_reconnect(idl->session);
+    if (idl->session) {
+        jsonrpc_session_enable_reconnect(idl->session);
+    }
 }
 
 /* Forces 'idl' to drop its connection to the database and reconnect.  In the
@@ -900,7 +950,9 @@  ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
 void
 ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
 {
-    jsonrpc_session_force_reconnect(idl->session);
+    if (idl->session) {
+        jsonrpc_session_force_reconnect(idl->session);
+    }
 }
 
 /* Some IDL users should only write to write-only columns.  Furthermore,
@@ -918,7 +970,7 @@  ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
 bool
 ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
 {
-    return jsonrpc_session_is_alive(idl->session) &&
+    return idl->session && jsonrpc_session_is_alive(idl->session) &&
            idl->state != IDL_S_ERROR;
 }
 
@@ -930,10 +982,7 @@  ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
 int
 ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
 {
-    int err;
-
-    err = jsonrpc_session_get_last_error(idl->session);
-
+    int err = idl->session ? jsonrpc_session_get_last_error(idl->session) : 0;
     if (err) {
         return err;
     } else if (idl->state == IDL_S_ERROR) {
@@ -949,7 +998,9 @@  ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
 void
 ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
 {
-    jsonrpc_session_set_probe_interval(idl->session, probe_interval);
+    if (idl->session) {
+        jsonrpc_session_set_probe_interval(idl->session, probe_interval);
+    }
 }
 
 static size_t
@@ -4006,7 +4057,8 @@  ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
     if (!any_updates) {
         txn->status = TXN_UNCHANGED;
         json_destroy(operations);
-    } else if (!jsonrpc_session_send(
+    } else if (txn->db->idl->session
+               && !jsonrpc_session_send(
                    txn->db->idl->session,
                    jsonrpc_create_request(
                        "transact", operations, &txn->request_id))) {
@@ -4696,7 +4748,9 @@  ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
         if (!msg) {
             break;
         }
-        jsonrpc_session_send(idl->session, msg);
+        if (idl->session) {
+            jsonrpc_session_send(idl->session, msg);
+        }
     }
 }
 
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index ea18b22f5480..382981cb44c6 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -60,6 +60,8 @@  struct ovsdb_idl *ovsdb_idl_create(const char *remote,
                                    const struct ovsdb_idl_class *,
                                    bool monitor_everything_by_default,
                                    bool retry);
+struct ovsdb_idl *ovsdb_idl_create_unconnected(
+    const struct ovsdb_idl_class *, bool monitor_everything_by_default);
 void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *, bool);
 void ovsdb_idl_destroy(struct ovsdb_idl *);