> > Store the user monitor condition request in pre-json format in
> > ovsdb_idl_table in order to use it in ovsdb_idl_compose_monitor_request
> > routine and create a monitor condition request based on the
> > tables/columns available in db-schema.
> > 
> > Reported-at: https://issues.redhat.com/browse/FDP-3114
> > Signed-off-by: Lorenzo Bianconi <[email protected]>
> > ---
> > Changes in v3:
> > - Fix seqno reporting when the filtered condition is empty.

Hi Ilya,

thx for the review.

> > 
> > Changes in v2:
> > - Add missing unit-test.
> > - squash with patch 'ovsdb: Add ovsdb_cs_clear_condition routine to remove
> >   stable ovsdb_cs_db_table entries.'.
> > - fix the error condition reported by Ilya.
> > - Remove unnecessary ovsdb_cs_db_sync_condition() in
> >   ovsdb_cs_send_monitor_request().
> > - cosmetics.
> > ---
> >  lib/ovsdb-cs.c           |  51 ++++++++++++++----
> >  lib/ovsdb-cs.h           |   2 +
> >  lib/ovsdb-idl-provider.h |   3 ++
> >  lib/ovsdb-idl.c          | 110 +++++++++++++++++++++++++++++++++++++--
> >  tests/ovsdb-idl.at       |   3 ++
> >  tests/test-ovsdb.c       |   8 +++
> >  6 files changed, 165 insertions(+), 12 deletions(-)
> > 
> > diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c
> > index df33a835d..93f59492e 100644
> > --- a/lib/ovsdb-cs.c
> > +++ b/lib/ovsdb-cs.c
> > @@ -663,6 +663,18 @@ ovsdb_cs_wait(struct ovsdb_cs *cs)
> >  
> >  /* Network connection. */
> >  
> > +bool
> > +ovsdb_cs_is_remote_changed(struct ovsdb_cs *cs, const char *remote)
> > +{
> > +    if (cs &&
> > +        ((remote != NULL) != (cs->remote != NULL) ||
> > +         (remote && cs->remote && strcmp(remote, cs->remote)))) {
> > +        return true;
> > +    }
> > +
> > +    return false;
> > +}
> > +
> >  /* Changes the remote and creates a new session.  Keeps existing connection
> >   * if current remote is still valid.
> >   *
> > @@ -671,9 +683,7 @@ ovsdb_cs_wait(struct ovsdb_cs *cs)
> >  void
> >  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)))) {
> > +    if (ovsdb_cs_is_remote_changed(cs, remote)) {
> >          struct jsonrpc *rpc = NULL;
> >  
> >          /* Close the old session, if any. */
> > @@ -912,17 +922,40 @@ ovsdb_cs_db_get_table(struct ovsdb_cs_db *db, const 
> > char *table)
> >      return t;
> >  }
> >  
> > +static void
> > +ovsdb_cs_db_destroy_table(struct ovsdb_cs_db_table *table,
> > +                          struct ovsdb_cs_db *db)
> > +{
> > +    json_destroy(table->ack_cond);
> > +    json_destroy(table->req_cond);
> > +    json_destroy(table->new_cond);
> > +    hmap_remove(&db->tables, &table->hmap_node);
> > +    free(table->name);
> > +    free(table);
> > +}
> > +
> > +/* Destroy a given ovsdb_cs_db_table according to the table name. */
> > +void
> > +ovsdb_cs_clear_condition(struct ovsdb_cs *cs, const char *table)
> > +{
> > +    uint32_t hash = hash_string(table, 0);
> > +    struct ovsdb_cs_db *db = &cs->data;
> > +
> > +    struct ovsdb_cs_db_table *t;
> > +    HMAP_FOR_EACH_WITH_HASH (t, hmap_node, hash, &db->tables) {
> > +        if (!strcmp(t->name, table)) {
> > +            ovsdb_cs_db_destroy_table(t, db);
> 
> We should probbaly clear the last_id here, so the monitor reply clears
> the data from idl for the table that now doesn't exist.  But need to be
> careful and not actually clear the idl->server_schema_received or we
> risk to break the monitor_cond_since functionality whenever the client
> connects to an older database.

ack, I will fix it in v4

> 
> > +            return;
> > +        }
> > +    }
> > +}
> > +
> >  static void
> >  ovsdb_cs_db_destroy_tables(struct ovsdb_cs_db *db)
> >  {
> >      struct ovsdb_cs_db_table *table;
> >      HMAP_FOR_EACH_SAFE (table, hmap_node, &db->tables) {
> > -        json_destroy(table->ack_cond);
> > -        json_destroy(table->req_cond);
> > -        json_destroy(table->new_cond);
> > -        hmap_remove(&db->tables, &table->hmap_node);
> > -        free(table->name);
> > -        free(table);
> > +        ovsdb_cs_db_destroy_table(table, db);
> >      }
> >      hmap_destroy(&db->tables);
> >  }
> > diff --git a/lib/ovsdb-cs.h b/lib/ovsdb-cs.h
> > index bcc3dcd71..a46b806c0 100644
> > --- a/lib/ovsdb-cs.h
> > +++ b/lib/ovsdb-cs.h
> > @@ -122,6 +122,7 @@ void ovsdb_cs_run(struct ovsdb_cs *, struct ovs_list 
> > *events);
> >  void ovsdb_cs_wait(struct ovsdb_cs *);
> >  
> >  /* Network connection. */
> > +bool ovsdb_cs_is_remote_changed(struct ovsdb_cs *, const char *remote);
> >  void ovsdb_cs_set_remote(struct ovsdb_cs *, const char *remote, bool 
> > retry);
> >  
> >  void ovsdb_cs_enable_reconnect(struct ovsdb_cs *);
> > @@ -144,6 +145,7 @@ void ovsdb_cs_set_probe_interval(const struct ovsdb_cs 
> > *, int probe_interval);
> >  unsigned int ovsdb_cs_set_condition(struct ovsdb_cs *, const char *table,
> >                                      const struct json *condition);
> >  unsigned int ovsdb_cs_get_condition_seqno(const struct ovsdb_cs *);
> > +void ovsdb_cs_clear_condition(struct ovsdb_cs *, const char *table);
> >  
> >  /* Database change awareness. */
> >  void ovsdb_cs_set_db_change_aware(struct ovsdb_cs *, bool 
> > set_db_change_aware);
> > diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
> > index 6cf32fb50..9244bbcd5 100644
> > --- a/lib/ovsdb-idl-provider.h
> > +++ b/lib/ovsdb-idl-provider.h
> > @@ -130,6 +130,9 @@ struct ovsdb_idl_table {
> >                                * or not. */
> >      struct ovs_list indexes;    /* Contains "struct ovsdb_idl_index"s */
> >      struct ovs_list track_list; /* Tracked rows 
> > (ovsdb_idl_row.track_node). */
> > +
> > +    struct ovsdb_idl_condition req_cond; /* User requested monitor
> > +                                          * condition. */
> >  };
> >  
> >  struct ovsdb_idl_class {
> > diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> > index fe90deda7..6ad0eb36d 100644
> > --- a/lib/ovsdb-idl.c
> > +++ b/lib/ovsdb-idl.c
> > @@ -99,6 +99,7 @@ struct ovsdb_idl {
> >      struct ovs_list rows_to_reparse; /* Stores rows that might need to be
> >                                        * re-parsed due to insertion of a
> >                                        * referenced row. */
> > +    bool server_schema_received;
> 
> Need to add a comment here.

ack, I will fix it in v4

> 
> >  };
> >  
> >  static struct ovsdb_cs_ops ovsdb_idl_cs_ops;
> > @@ -205,6 +206,19 @@ 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 int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop,
> >                                           bool *may_need_wakeup);
> > +static void
> > +ovsdb_idl_condition_clone(struct ovsdb_idl_condition *dest,
> > +                          const struct ovsdb_idl_condition *source);
> > +static void
> > +ovsdb_idl_create_req_condition(struct ovsdb_idl *,
> > +                               const struct ovsdb_idl_table_class *,
> > +                               const struct ovsdb_idl_condition *);
> > +static void ovsdb_idl_destroy_req_condition(struct ovsdb_idl_table *);
> > +static bool ovsdb_idl_condition_is_set(struct ovsdb_idl_condition *);
> > +static unsigned int
> > +ovsdb_idl_set_condition__(struct ovsdb_idl *,
> > +                          const struct ovsdb_idl_table_class *,
> > +                          const struct ovsdb_idl_condition *);
> 
> ovsdb_idl_condition_clone, ovsdb_idl_create_req_condition and the
> ovsdb_idl_set_condition__ should not be on new lines, as these are
> prototypes and not implementations.

ack, I will fix it in v4

> 
> >  
> >  static void add_tracked_change_for_references(struct ovsdb_idl_row *);
> >  
> > @@ -266,6 +280,7 @@ ovsdb_idl_create_unconnected(const struct 
> > ovsdb_idl_class *class,
> >          .txn = NULL,
> >          .outstanding_txns = HMAP_INITIALIZER(&idl->outstanding_txns),
> >          .verify_write_only = false,
> > +        .server_schema_received = false,
> >          .deleted_untracked_rows
> >              = OVS_LIST_INITIALIZER(&idl->deleted_untracked_rows),
> >          .rows_to_reparse
> > @@ -298,6 +313,7 @@ ovsdb_idl_create_unconnected(const struct 
> > ovsdb_idl_class *class,
> >              = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
> >          table->idl = idl;
> >          table->in_server_schema = false;
> > +        ovsdb_idl_condition_init(&table->req_cond);
> >          shash_init(&table->schema_columns);
> >      }
> >  
> > @@ -311,6 +327,9 @@ ovsdb_idl_create_unconnected(const struct 
> > ovsdb_idl_class *class,
> >  void
> >  ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote, bool retry)
> >  {
> > +    if (ovsdb_cs_is_remote_changed(idl->cs, remote)) {
> > +        idl->server_schema_received = false;
> > +    }
> 
> I don't think this is needed.  And if it was needed, then we would 
> probbalyclear
> while receiving the RECONNECT event instead.  We're not clearing 
> 'in_server_schema'
> fileds, so should not clear this one as well.  If the reconnection happens we 
> will
> be seding a new monitor request that will get the schema, so everything 
> should work
> fine without setting to false on reconnections or remote changes.

ack, I will fix it in v4

> 
> >      ovsdb_cs_set_remote(idl->cs, remote, retry);
> >  }
> >  
> > @@ -372,6 +391,7 @@ ovsdb_idl_destroy(struct ovsdb_idl *idl)
> >  
> >              ovsdb_idl_schema_columns_clear(&table->schema_columns);
> >              shash_destroy(&table->schema_columns);
> > +            ovsdb_idl_destroy_req_condition(table);
> >  
> >              hmap_destroy(&table->rows);
> >              free(table->modes);
> > @@ -784,6 +804,7 @@ static struct json *
> >  ovsdb_idl_compose_monitor_request(const struct json *schema_json, void 
> > *idl_)
> >  {
> >      struct ovsdb_idl *idl = idl_;
> > +    idl->server_schema_received = true;
> 
> Should add an empty line between these two, or set the value closer to the 
> loop.

ack, I will fix it in v4

> 
> >  
> >      struct shash *schema = ovsdb_cs_parse_schema(schema_json);
> >      struct json *monitor_requests = json_object_create();
> > @@ -842,6 +863,7 @@ ovsdb_idl_compose_monitor_request(const struct json 
> > *schema_json, void *idl_)
> >                            idl->class_->database, table->class_->name);
> >                  json_destroy(columns);
> >                  table->in_server_schema = false;
> > +                ovsdb_cs_clear_condition(idl->cs, table->class_->name);
> >                  continue;
> >              } else if (schema && table_schema) {
> >                  table->in_server_schema = true;
> > @@ -852,6 +874,14 @@ ovsdb_idl_compose_monitor_request(const struct json 
> > *schema_json, void *idl_)
> >              json_object_put(monitor_requests, tc->name,
> >                              json_array_create_1(monitor_request));
> >          }
> > +
> > +        if (!table->in_server_schema) {
> > +            ovsdb_cs_clear_condition(idl->cs, table->class_->name);
> > +        } else if (ovsdb_idl_condition_is_set(&table->req_cond)) {
> > +            /* Update the monitor condition request according to the
> > +             * db schema. */
> > +            ovsdb_idl_set_condition__(idl, tc, &table->req_cond);
> 
> Hmm.  The ovsdb_idl_set_condition__() function doesn't filter, it uses the old
> filtered condition stored in the table->req_cond that was created before we
> received the new schema.  So, we can still set conditions here for tables that
> do not exist in on the server.

ack, in v4 I will move the filtering in ovsdb_idl_set_condition__()

> 
> > +        }
> >      }
> >      ovsdb_cs_free_schema(schema);
> >  
> > @@ -1156,6 +1186,45 @@ ovsdb_idl_condition_add_clause__(struct 
> > ovsdb_idl_condition *condition,
> >      hmap_insert(&condition->clauses, &clause->hmap_node, hash);
> >  }
> >  
> > +static void
> > +ovsdb_idl_destroy_req_condition(struct ovsdb_idl_table *table)
> > +{
> > +    ovsdb_idl_condition_destroy(&table->req_cond);
> > +}
> > +
> > +static bool
> > +ovsdb_idl_condition_is_set(struct ovsdb_idl_condition *condition)
> > +{
> > +    return !hmap_is_empty(&condition->clauses) || condition->is_true;
> > +}
> > +
> > +static void
> > +ovsdb_idl_condition_clone(struct ovsdb_idl_condition *dest,
> > +                          const struct ovsdb_idl_condition *source)
> > +{
> > +    ovsdb_idl_condition_init(dest);
> > +
> > +    struct ovsdb_idl_clause *clause;
> > +    HMAP_FOR_EACH (clause, hmap_node, &source->clauses) {
> > +        uint32_t hash = ovsdb_idl_clause_hash(clause);
> 
> Can use a hash of the current hmap node.

ack, I will fix it in v4

> 
> > +        ovsdb_idl_condition_add_clause__(dest, clause, hash);
> > +    }
> > +    dest->is_true = source->is_true;
> > +}
> > +
> > +static void
> > +ovsdb_idl_create_req_condition(struct ovsdb_idl *idl,
> > +                               const struct ovsdb_idl_table_class *tc,
> > +                               const struct ovsdb_idl_condition *condition)
> > +{
> > +    struct ovsdb_idl_table *table = shash_find_data(&idl->table_by_name,
> > +                                                    tc->name);
> > +    if (table) {
> > +        ovsdb_idl_destroy_req_condition(table);
> > +        ovsdb_idl_condition_clone(&table->req_cond, condition);
> > +    }
> > +}
> > +
> >  /* Adds a clause to the condition for replicating the table with class 
> > 'tc' in
> >   * 'idl'.
> >   *
> > @@ -1234,6 +1303,17 @@ ovsdb_idl_condition_to_json(const struct 
> > ovsdb_idl_condition *cnd)
> >      return json_array_create(clauses, n);
> >  }
> >  
> > +static unsigned int
> > +ovsdb_idl_set_condition__(struct ovsdb_idl *idl,
> > +                          const struct ovsdb_idl_table_class *tc,
> > +                          const struct ovsdb_idl_condition *condition)
> > +{
> > +    struct json *cond_json = ovsdb_idl_condition_to_json(condition);
> > +    unsigned int seqno = ovsdb_cs_set_condition(idl->cs, tc->name, 
> > cond_json);
> > +    json_destroy(cond_json);
> > +    return seqno;
> > +}
> > +
> >  /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
> >   * arranges to send the new condition to the database server.
> >   *
> > @@ -1245,9 +1325,33 @@ ovsdb_idl_set_condition(struct ovsdb_idl *idl,
> >                          const struct ovsdb_idl_table_class *tc,
> >                          const struct ovsdb_idl_condition *condition)
> >  {
> > -    struct json *cond_json = ovsdb_idl_condition_to_json(condition);
> > -    unsigned int seqno = ovsdb_cs_set_condition(idl->cs, tc->name, 
> > cond_json);
> > -    json_destroy(cond_json);
> > +    struct ovsdb_idl_condition filter_cond =
> > +        OVSDB_IDL_CONDITION_INIT(&filter_cond);
> > +
> > +    if (idl->server_schema_received && hmap_count(&condition->clauses)) {
> > +        struct ovsdb_idl_clause *clause;
> > +        HMAP_FOR_EACH (clause, hmap_node, &condition->clauses) {
> > +            struct ovsdb_idl_table *t =
> > +                ovsdb_idl_table_from_column(idl, clause->column);
> 
> This shoudld be done outside of the loop.  We can get the table directly
> from the table class - ovsdb_idl_table_from_class().

ack, I will fix it in v4

> 
> > +            if (!t || !t->in_server_schema) {
> > +                return ovsdb_idl_get_condition_seqno(idl);
> 
> We can't just return here, we still need to save these conditions, otherwise
> we will not send them on reconnection when the server schema changes.
> 
> > +            }
> > +
> > +            if (ovsdb_idl_server_has_column(idl, clause->column)) {
> > +                uint32_t hash = ovsdb_idl_clause_hash(clause);
> > +                ovsdb_idl_condition_add_clause__(&filter_cond, clause, 
> > hash);
> > +            }
> > +        }
> > +        condition = &filter_cond;
> > +    }
> > +
> > +    unsigned int seqno = ovsdb_idl_set_condition__(idl, tc, condition);
> > +    ovsdb_idl_create_req_condition(idl, tc, &filter_cond);
> 
> We should be saving the original conditions, not the filtered ones, because
> we need to filter every time we compose a new monitor request.

ack, I will fix it in v4

> 
> > +
> > +    if (hmap_count(&filter_cond.clauses)) {
> > +        ovsdb_idl_condition_destroy(&filter_cond);
> > +    }
> > +
> >      return seqno;
> >  }
> >  
> > diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
> > index 728d761d4..194afef13 100644
> > --- a/tests/ovsdb-idl.at
> > +++ b/tests/ovsdb-idl.at
> > @@ -2722,6 +2722,9 @@ unix:socket2 remote has col id in table simple7, 
> > type: string
> >  --- remote unix:socket2 done ---
> >  ], [stderr])
> >  
> > +# Check we do not have any errors related to conditional monitoring.
> > +AT_CHECK([grep -q "received error, error={\"details\":\"no table named 
> > link2\",\"error\":\"syntax error\"}" stderr], [1])
> > +
> >  OVSDB_SERVER_SHUTDOWN
> >  AT_CLEANUP
> 
> I think we need way more tests for this functionality, including a case where
> we connect to a server with an older schema that doesn't have some tables and
> some columns in the tables that exist, then re-connect to a server with the 
> new
> schema that has all, then re-connect back to one with the older schema.  The
> client sets conditions for all the tables before connecting to the first 
> server
> and doesn't change them afterwards.  We need to make sure that all the 
> conditions
> are properly filtered every time the cilent re-connects without touching the
> conditions.  Ant another test where client sets conditions for tables and
> columns that exist and for those that do not exist after the succesful 
> connection
> to make sure the filtering works outside of the monitor request.  Also maybe
> some tests to make sure the monitor-cond-since is respected anf the last-id is
> properly cleared when it needs to be and not cleared when it doesn't need to
> be cleared.

ack, I will add more test in v4.

Regards,
Lorenzo

> 
> THe commit message also could use a larger description of the problem and what
> this change is trying to achieve.
> 
> Best regards, Ilya Maximets.
> 
> >  
> > diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
> > index 95290ae78..037a78743 100644
> > --- a/tests/test-ovsdb.c
> > +++ b/tests/test-ovsdb.c
> > @@ -3596,6 +3596,12 @@ do_idl_table_column_check(struct ovs_cmdl_context 
> > *ctx)
> >          ovsdb_idl_set_remote(idl, ctx->argv[r], true);
> >          ovsdb_idl_force_reconnect(idl);
> >  
> > +        struct ovsdb_idl_condition cond_link2 =
> > +            OVSDB_IDL_CONDITION_INIT(&cond_link2);
> > +        idltest_link2_add_clause_i(&cond_link2, OVSDB_F_EQ, 1);
> > +
> > +        idltest_link2_set_condition(idl, &cond_link2);
> > +
> >          /* Wait for update. */
> >          for (;;) {
> >              ovsdb_idl_run(idl);
> > @@ -3661,6 +3667,8 @@ do_idl_table_column_check(struct ovs_cmdl_context 
> > *ctx)
> >                 type ? ", type: " : "", type ? type_s : "");
> >          free(type_s);
> >  
> > +        ovsdb_idl_condition_destroy(&cond_link2);
> > +
> >          printf("--- remote %s done ---\n", ctx->argv[r]);
> >      }
> >  
> 
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to