Andy Zhou <az...@ovn.org> wrote on 21/01/2016 02:03:51 PM:

> On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lir...@il.ibm.com> 
wrote:
> Hold session's conditions in ovsdb_monitor_session_conditon. Pass it
> to ovsdb_monitor for generating "update2" notifications.
> Add functions that can generate "update2" notification for a
> "monitor_cond" session.
> json_cache for will be enabled only for session's with empty condition.
> "monitor_cond" and "monitor_cond_change" are RFC 7047 extensions
> described by ovsdb-server(1) manpage.
> 
> s /conditon/condition/
Will fix this.

> 
> Signed-off-by: Liran Schour <lir...@il.ibm.com>
> ---
>  ovsdb/jsonrpc-server.c  |  59 +++++++++---
>  ovsdb/monitor.c         | 208 
++++++++++++++++++++++++++++++++++++++++--
>  ovsdb/monitor.h         |  37 +++++++-
>  ovsdb/ovsdb-server.1.in | 233 +++++++++++++++++++++++++++++++++++++
> +++++++----
>  4 files changed, 498 insertions(+), 39 deletions(-)
> 
> diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
> index 2065702..e4500da 100644
> --- a/ovsdb/jsonrpc-server.c
> +++ b/ovsdb/jsonrpc-server.c
> @@ -28,6 +28,7 @@
>  #include "ovsdb-error.h"
>  #include "ovsdb-parser.h"
>  #include "ovsdb.h"
> +#include "condition.h"
>  #include "poll-loop.h"
>  #include "reconnect.h"
>  #include "row.h"
> @@ -85,7 +86,7 @@ static void ovsdb_jsonrpc_trigger_complete_done(
>  /* Monitors. */
>  static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_create(
>      struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json 
*params,
> -    enum ovsdb_monitor_version, const struct json *request_id);
> +    enum ovsdb_monitor_version, bool, const struct json *request_id);
>  static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
>      struct ovsdb_jsonrpc_session *,
>      struct json_array *params,
> @@ -849,14 +850,18 @@ ovsdb_jsonrpc_session_got_request(struct 
> ovsdb_jsonrpc_session *s,
>              reply = execute_transaction(s, db, request);
>          }
>      } else if (!strcmp(request->method, "monitor") ||
> -               (monitor2_enable__ && !strcmp(request->method, 
"monitor2"))) {
> +               (monitor2_enable__ && !strcmp(request->method, 
"monitor2")) ||
> +               !strcmp(request->method, "monitor_cond")) {
>          struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
>          if (!reply) {
>              int l = strlen(request->method) - strlen("monitor");
>              enum ovsdb_monitor_version version = l ? OVSDB_MONITOR_V2
>                                                     : OVSDB_MONITOR_V1;
>              reply = ovsdb_jsonrpc_monitor_create(s, db, 
request->params,
> -                                                 version, request->id);
> +                                                 version,
> +                                                
 !strcmp(request->method,
> +                                                        
 "monitor_cond"),
> +                                                 request->id);
>          }
>      } else if (!strcmp(request->method, "monitor_cancel")) {
>          reply = ovsdb_jsonrpc_monitor_cancel(s, 
json_array(request->params),
> @@ -1048,6 +1053,7 @@ struct ovsdb_jsonrpc_monitor {
>      uint64_t unflushed;         /* The first transaction that has not 
been
>                                         flushed to the jsonrpc 
> remote client. */
>      enum ovsdb_monitor_version version;
> +    struct ovsdb_monitor_session_condition *condition;/* Session's 
> condition */
>  };
> 
>  static struct ovsdb_jsonrpc_monitor *
> @@ -1075,21 +1081,29 @@ parse_bool(struct ovsdb_parser *parser, 
> const char *name, bool default_value)
>  }
> 
>  static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
> -ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_monitor *dbmon,
> -                                    const struct ovsdb_table *table,
> -                                    const struct json *monitor_request,
> -                                    size_t *allocated_columns)
> +ovsdb_jsonrpc_parse_monitor_request(
> +                            struct ovsdb_monitor *dbmon,
> +                            const struct ovsdb_table *table,
> +                            bool conditional,
> +                            struct ovsdb_monitor_session_condition 
*cond,
> +                            const struct json *monitor_request,
> +                            size_t *allocated_columns)
> Can 'conditional' and 'cond' be combined into a single argument? 
>  cond == NULL  indicates conditional is false.

True. Will do that.

>  {
>      const struct ovsdb_table_schema *ts = table->schema;
>      enum ovsdb_monitor_selection select;
> -    const struct json *columns, *select_json;
> +    const struct json *columns, *select_json, *where = NULL;   
> Does where need to be set to NULL here? its value is always assigned
> when used.  
>      struct ovsdb_parser parser;
>      struct ovsdb_error *error;
> 
>      ovsdb_parser_init(&parser, monitor_request, "table %s", ts->name);
> +    if (conditional) {
> +        where = ovsdb_parser_member(&parser, "where", OP_ARRAY | 
> OP_OPTIONAL);
> +    }
>      columns = ovsdb_parser_member(&parser, "columns", OP_ARRAY | 
> OP_OPTIONAL);
> +
>      select_json = ovsdb_parser_member(&parser, "select",
>                                        OP_OBJECT | OP_OPTIONAL);
> +
>      error = ovsdb_parser_finish(&parser);
>      if (error) {
>          return error;
> @@ -1156,6 +1170,12 @@ ovsdb_jsonrpc_parse_monitor_request(struct 
> ovsdb_monitor *dbmon,
>              }
>          }
>      }
> +    if (conditional) {
> +        error = ovsdb_monitor_table_condition_add(cond, table, where);
> +        if (error) {
> +            return error;
> +        }
> +    }
> 
>      return NULL;
>  }
> @@ -1164,6 +1184,7 @@ static struct jsonrpc_msg *
>  ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, 
> struct ovsdb *db,
>                               struct json *params,
>                               enum ovsdb_monitor_version version,
> +                             bool conditional,
> Can version be used to figure out the value of 'conditional' here? 
Yes. Will do that.

>                               const struct json *request_id)
>  {
>      struct ovsdb_jsonrpc_monitor *m = NULL;
> @@ -1194,6 +1215,9 @@ ovsdb_jsonrpc_monitor_create(struct 
> ovsdb_jsonrpc_session *s, struct ovsdb *db,
>      m->session = s;
>      m->db = db;
>      m->dbmon = ovsdb_monitor_create(db, m);
> +    if (conditional) {
> +        m->condition = ovsdb_monitor_session_condition_create();
> +    }
>      m->unflushed = 0;
>      m->version = version;
>      hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0));
> @@ -1223,14 +1247,18 @@ ovsdb_jsonrpc_monitor_create(struct 
> ovsdb_jsonrpc_session *s, struct ovsdb *db,
> 
>              for (i = 0; i < array->n; i++) {
>                  error = ovsdb_jsonrpc_parse_monitor_request(
> -                    m->dbmon, table, array->elems[i], 
&allocated_columns);
> +                    m->dbmon, table, conditional, m->condition,
> +                    array->elems[i], &allocated_columns);
>                  if (error) {
>                      goto error;
>                  }
>              }
>          } else {
> -            error = ovsdb_jsonrpc_parse_monitor_request(
> -                m->dbmon, table, mr_value, &allocated_columns);
> +            error = ovsdb_jsonrpc_parse_monitor_request(m->dbmon, 
table,
> +                                                        conditional,
> +                                                        m->condition,
> +                                                        mr_value,
> +                                                        
&allocated_columns);
>              if (error) {
>                  goto error;
>              }
> @@ -1254,6 +1282,10 @@ ovsdb_jsonrpc_monitor_create(struct 
> ovsdb_jsonrpc_session *s, struct ovsdb *db,
>          m->dbmon = dbmon;
>      }
> 
> +    if (conditional) {
> +        /* Only now we can bind the session_condition to ovsdb_monitor. 
*/
> +        ovsdb_monitor_session_condition_bind(m->condition, dbmon);
> +    }
>      ovsdb_monitor_get_initial(m->dbmon);
>      json = ovsdb_jsonrpc_monitor_compose_update(m, true);
>      json = json ? json : json_object_create();
> @@ -1306,7 +1338,7 @@ ovsdb_jsonrpc_monitor_compose_update(struct 
> ovsdb_jsonrpc_monitor *m,
>                                       bool initial)
>  {
>      return ovsdb_monitor_get_update(m->dbmon, initial, &m->unflushed,
> -                                    m->version);
> +                                    m->condition, m->version);
>  }
> 
>  static bool
> @@ -1329,6 +1361,9 @@ ovsdb_jsonrpc_monitor_destroy(struct 
> ovsdb_jsonrpc_monitor *m)
>      json_destroy(m->monitor_id);
>      hmap_remove(&m->session->monitors, &m->node);
>      ovsdb_monitor_remove_jsonrpc_monitor(m->dbmon, m);
> +    if (m->condition) {
> +        ovsdb_monitor_session_condition_destroy(m->condition);
> +    }
>      free(m);
>  }
> 
> diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c
> index 51f4e09..5e3117a 100644
> --- a/ovsdb/monitor.c
> +++ b/ovsdb/monitor.c
> @@ -27,6 +27,7 @@
>  #include "ovsdb-parser.h"
>  #include "ovsdb.h"
>  #include "row.h"
> +#include "condition.h"
>  #include "simap.h"
>  #include "hash.h"
>  #include "table.h"
> @@ -41,6 +42,20 @@
>  static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class;
>  static struct hmap ovsdb_monitors = HMAP_INITIALIZER(&ovsdb_monitors);
> 
> +/* Keep state of session's conditions */
> +struct ovsdb_monitor_session_condition {
> +    bool can_cache;
> +    struct shash tables;     /* Contains
> +                              *   "struct 
> ovsdb_monitor_table_condition *"s. */
> +};
> +
> +/* Monitored table session's conditions */
> +struct ovsdb_monitor_table_condition {
> +    struct ovsdb_monitor_table *mt;
> +    struct ovsdb_condition old_condition;
> +    struct ovsdb_condition new_condition;
> +};
> +
>  /*  Backend monitor.
>   *
>   *  ovsdb_monitor keep track of the ovsdb changes.
> @@ -55,6 +70,8 @@ struct ovsdb_monitor {
>      uint64_t n_transactions;      /* Count number of committed 
> transactions. */
>      struct hmap_node hmap_node;   /* Elements within ovsdb_monitors.  
*/
>      struct hmap json_cache;       /* Contains 
> "ovsdb_monitor_json_cache_node"s.*/
> +    /* tmp pointer for composing update */
> +    const struct ovsdb_monitor_session_condition *condition;
>  };
> 
>  /* A json object of updates between 'from_txn' and 
'dbmon->n_transactions'
> @@ -107,6 +124,7 @@ struct ovsdb_monitor_changes {
>  /* A particular table being monitored. */
>  struct ovsdb_monitor_table {
>      const struct ovsdb_table *table;
> +    const struct ovsdb_monitor *dbmon;
> 
>      /* This is the union (bitwise-OR) of the 'select' values in all of 
the
>       * members of 'columns' below. */
> @@ -121,6 +139,10 @@ struct ovsdb_monitor_table {
> 
>      /* Contains 'ovsdb_monitor_changes' indexed by 'transaction'. */
>      struct hmap changes;
> +
> +    /* Temp pointers to conditions for composing update */
> +    struct ovsdb_condition *old_condition;
> +    struct ovsdb_condition *new_condition;
>  };
> 
>  typedef struct json *
> @@ -348,6 +370,7 @@ ovsdb_monitor_add_table(struct ovsdb_monitor *m,
> 
>      mt = xzalloc(sizeof *mt);
>      mt->table = table;
> +    mt->dbmon = m;
>      shash_add(&m->tables, table->schema->name, mt);
>      hmap_init(&mt->changes);
>      mt->columns_index_map =
> @@ -488,6 +511,162 @@ ovsdb_monitor_row_update_type(bool initial, 
> const bool old, const bool new)
>              : !new ? OJMS_DELETE
>              : OJMS_MODIFY;
>  }
> +
> +/* Returnes an empty allocated session's condition state holder */
> +struct ovsdb_monitor_session_condition *
> +ovsdb_monitor_session_condition_create(void)
> +{
> +    struct ovsdb_monitor_session_condition *condition;
> +
> +    condition = xzalloc(sizeof *condition);
> +    shash_init(&condition->tables);
> +    condition->can_cache = true;
> +
> +    return condition;
> +}
> +
> +void
> +ovsdb_monitor_session_condition_destroy(
> +                           struct ovsdb_monitor_session_condition 
*condition)
> +{
> +    struct shash_node *node, *next;
> +
> +    SHASH_FOR_EACH_SAFE (node, next, &condition->tables) {
> +        struct ovsdb_monitor_table_condition *mtc = node->data;
> +
> +        ovsdb_condition_destroy(&mtc->new_condition);
> +        ovsdb_condition_destroy(&mtc->old_condition);
> +        shash_delete(&condition->tables, node);
> +        free(mtc);
> +    }
> +    free(condition);
> +}
> +
> +/* Bind session's condition to a specific ovsdb_monitor */
> +void ovsdb_monitor_session_condition_bind(
> +                    const struct ovsdb_monitor_session_condition 
*condition,
> +                    const struct ovsdb_monitor *dbmon)
> +{
> +    struct shash_node *node;
> +
> +    SHASH_FOR_EACH (node, &condition->tables) {
> +        struct ovsdb_monitor_table_condition *mtc = node->data;
> +        struct ovsdb_monitor_table *mt;
> +
> +        mt = shash_find_data(&dbmon->tables, node->name);
> +        mtc->mt = mt;
> +    }
> +}
> +
> +struct ovsdb_error *
> +ovsdb_monitor_table_condition_add(
> +                         struct ovsdb_monitor_session_condition 
*condition,
> +                         const struct ovsdb_table *table,
> +                         const struct json *json_cnd)
> +{
> +    struct ovsdb_monitor_table_condition *mtc;
> +    struct ovsdb_error *error;
> +
> +    mtc = xzalloc(sizeof *mtc);
> +    shash_add(&condition->tables, table->schema->name, mtc);
> +    ovsdb_condition_init(&mtc->old_condition);
> +    ovsdb_condition_init(&mtc->new_condition);
> +
> +    if (json_cnd) {
> +        error = ovsdb_condition_from_json(table->schema,
> +                                          json_cnd,
> +                                          NULL,
> +                                          &mtc->old_condition);
> +        if (error) {
> +            return ovsdb_syntax_error(json_cnd,
> +                                      NULL, "array of conditons 
expected");
> s/conditons/conditions/
Will fix this.
 
> +        }
> +    }
> +    ovsdb_condition_clone(&mtc->new_condition, &mtc->old_condition);
> +
> +    if (!ovsdb_condition_empty(&mtc->old_condition)) {
> +        condition->can_cache = false;
> +    }
> +
> +    return NULL;
> +}
> +
> +/* Set session's condition in this ovsdb_monitor */
> +static void
> +ovsdb_monitor_set_condition(
> +                   struct ovsdb_monitor *dbmon,
> +                   const struct ovsdb_monitor_session_condition 
*condition)
> +{
> +    struct shash_node *node;
> +
> +    if (condition) {
> +        dbmon->condition = condition;
> +        SHASH_FOR_EACH (node, &condition->tables) {
> +            struct ovsdb_monitor_table_condition *mtc = node->data;
> +
> +            mtc->mt->old_condition = &mtc->old_condition;
> +            mtc->mt->new_condition = &mtc->new_condition;
> +        }
> +    }
> +}
> +
> +static void
> +ovsdb_monitor_unset_condition(struct ovsdb_monitor *dbmon)
> +{
> +    dbmon->condition = NULL;
> +}
> +
> +static enum ovsdb_monitor_selection
> +ovsdb_monitor_row_update_type_condition(const struct 
ovsdb_monitor_table *mt,
> +                                        bool initial,
> +                                        const struct ovsdb_datum *old,
> +                                        const struct ovsdb_datum *new,
> +                                        const bool index_map)
> +{
> +    unsigned int *columns_index_map = index_map ? mt->columns_index_map
> +                                      : NULL;
> +    enum ovsdb_monitor_selection type =
> +        ovsdb_monitor_row_update_type(initial, old, new);
> +
> +    if (mt->dbmon->condition &&
> +        (!ovsdb_condition_empty(mt->old_condition) &&
> +         !ovsdb_condition_empty(mt->new_condition))) {
> +        bool old_cond = !old ? false
> +            : ovsdb_condition_evaluate_or_datum(old,
> +                                                mt->old_condition,
> +                                                columns_index_map);
> +        bool new_cond = !new ? false
> +            : ovsdb_condition_evaluate_or_datum(new,
> +                                                mt->new_condition,
> +                                                columns_index_map);
> +
> +        if (!old_cond && !new_cond) {
> +            type = OJMS_NONE;
> +        }
> +
> +        switch (type) {
> +        case OJMS_INITIAL:
> +        case OJMS_INSERT:
> +            if (!new_cond) {
> +                type = OJMS_NONE;
> +            }
> +            break;
> +        case OJMS_MODIFY:
> +            type = !old_cond ? OJMS_INSERT : !new_cond
> +                ? OJMS_DELETE : OJMS_MODIFY;
> +            break;
> +        case OJMS_DELETE:
> +            if (!old_cond) {
> +                type = OJMS_NONE;
> +            }
> +            break;
> +        case OJMS_NONE:
> +            break;
> +        }
> +    }
> +    return type;
> +}
> +
>  static bool
>  ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt,
>                                const struct ovsdb_monitor_row *row,
> @@ -600,7 +779,8 @@ ovsdb_monitor_compose_row_update2(
>      struct json *row_update2, *diff_json;
>      size_t i;
> 
> -    type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
> +    type = ovsdb_monitor_row_update_type_condition(mt, initial,
> +                                                   row->old, row->new, 
true);
>      if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) {
>          return NULL;
>      }
> @@ -728,19 +908,24 @@ ovsdb_monitor_compose_update(struct 
> ovsdb_monitor *dbmon,
>   * be used as part of the initial reply to a "monitor" request, 
> false if it is
>   * going to be used as part of an "update" notification. */
>  struct json *
> -ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
> -                         bool initial, uint64_t *unflushed,
> -                         enum ovsdb_monitor_version version)
> +ovsdb_monitor_get_update(
> +             struct ovsdb_monitor *dbmon,
> +             bool initial, uint64_t *unflushed,
> +             const struct ovsdb_monitor_session_condition *condition,
> +             enum ovsdb_monitor_version version)
>  {
> -    struct ovsdb_monitor_json_cache_node *cache_node;
> +    struct ovsdb_monitor_json_cache_node *cache_node = NULL;
>      struct shash_node *node;
>      struct json *json;
>      uint64_t prev_txn = *unflushed;
>      uint64_t next_txn = dbmon->n_transactions + 1;
> 
> +    ovsdb_monitor_set_condition(dbmon, condition);
> Urgh, this does not look clean... 
>
Agree. Will pass the session condition pointer down to the 
compose_row_update functions where it is needed and remove the 
set_condition and unset_condition functions.
 
>      /* Return a clone of cached json if one exists. Otherwise,
>       * generate a new one and add it to the cache.  */
> -    cache_node = ovsdb_monitor_json_cache_search(dbmon, version, 
prev_txn);
> +    if (condition && condition->can_cache) {
> +        cache_node = ovsdb_monitor_json_cache_search(dbmon, 
> version, prev_txn);
> +    }
>      if (cache_node) {
>          json = cache_node->json ? json_clone(cache_node->json) : NULL;
>      } else {
> @@ -752,7 +937,9 @@ ovsdb_monitor_get_update(struct ovsdb_monitor 
*dbmon,
>              json = ovsdb_monitor_compose_update(dbmon, initial, 
prev_txn,
>                                         
 ovsdb_monitor_compose_row_update2);
>          }
> -        ovsdb_monitor_json_cache_insert(dbmon, version, prev_txn, 
json);
> +        if (condition && condition->can_cache) {
> +            ovsdb_monitor_json_cache_insert(dbmon, version, prev_txn, 
json);
> +        }
>      }
> 
>      /* Maintain transaction id of 'changes'. */
> @@ -763,6 +950,7 @@ ovsdb_monitor_get_update(struct ovsdb_monitor 
*dbmon,
>          ovsdb_monitor_table_track_changes(mt, next_txn);
>      }
>      *unflushed = next_txn;
> +    ovsdb_monitor_unset_condition(dbmon);
> 
>      return json;
>  }
> @@ -890,6 +1078,11 @@ ovsdb_monitor_changes_classify(enum 
> ovsdb_monitor_selection type,
>          return OVSDB_CHANGES_NO_EFFECT;
>      }
> 
> +    /* On conditional monitor MODIFY might be INSERT or DELETE */
> +    if (type == OJMS_MODIFY) {
> +        type |= OJMS_INSERT | OJMS_DELETE;
> +    }
> +
> This logic is not obvious to me.  It seems to cause extra cache 
> flushes in case no conditions are specified, which means
> modify will not be changed into insert nor delete.  In case those 
> changes can happen, they don't use json_cache anyways.
> Did I miss something? 
>
You are right in the perspective of the json_cache. But we use efficacy 
also to decide if we need to insert this row to changes. This patch series 
taking into consideration sending update notification due to condition 
change will include none empty changes list. In that case at the moment of 
recording a change in a row with type modify, we do not know if it will be 
treated as an insert or delete at update notification.
However when I look again at the code I see that if we force cond_update 
to be sent from the a JSONRPC session of the existing monitor session, 
then we can guarantee that changes list is being flushed an empty when we 
build the new update notification and we will not get encountered with 
rows of type modify that will end up as insert or delete.
Will modify the code according to that and simplify the logic of 
cond_update according to that. Thanks.
   
>      return (mt->select & type)
>                  ?  OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE
>                  :  OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE;
> @@ -922,6 +1115,7 @@ ovsdb_monitor_change_cb(const struct ovsdb_row 
*old,
>          enum ovsdb_monitor_selection type;
> 
>          type = ovsdb_monitor_row_update_type(false, old, new);
> +
> Is this intentional?
No, this is a typo.
  
>          efficacy = ovsdb_monitor_changes_classify(type, mt, changed);
>          if (efficacy > OVSDB_CHANGES_NO_EFFECT) {
>              ovsdb_monitor_changes_update(old, new, mt, changes);
> diff --git a/ovsdb/monitor.h b/ovsdb/monitor.h
> index d6e9635..d4063f7 100644
> --- a/ovsdb/monitor.h
> +++ b/ovsdb/monitor.h
> @@ -19,8 +19,11 @@
> 
>  struct ovsdb_monitor;
>  struct ovsdb_jsonrpc_monitor;
> +struct ovsdb_monitor_session_condition;
> +struct ovsdb_condition;
> 
>  enum ovsdb_monitor_selection {
> +    OJMS_NONE = 0,              /* None for this iteration */
>      OJMS_INITIAL = 1 << 0,      /* All rows when monitor is created. */
>      OJMS_INSERT = 1 << 1,       /* New rows. */
>      OJMS_DELETE = 1 << 2,       /* Deleted rows. */
> @@ -64,17 +67,43 @@ const char * OVS_WARN_UNUSED_RESULT
>  ovsdb_monitor_table_check_duplicates(struct ovsdb_monitor *,
>                            const struct ovsdb_table *);
> 
> -struct json *ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
> -                                      bool initial,
> -                                      uint64_t *unflushed_transaction,
> -                                      enum ovsdb_monitor_version 
version);
> +struct json *ovsdb_monitor_get_update(
> +               struct ovsdb_monitor *dbmon,
> +               bool initial,
> +               uint64_t *unflushed_transaction,
> +               const struct ovsdb_monitor_session_condition *condition,
> +               enum ovsdb_monitor_version version);
> 
>  void ovsdb_monitor_table_add_select(struct ovsdb_monitor *dbmon,
>                                      const struct ovsdb_table *table,
>                                      enum ovsdb_monitor_selection 
select);
> 
> +struct ovsdb_condition *
> +ovsdb_monitor_table_get_condition(struct ovsdb_monitor *dbmon,
> +                                  const struct ovsdb_table *table);
> +
> +void ovsdb_monitor_table_set_conditional(struct ovsdb_monitor *dbmon,
> +                                         const struct ovsdb_table 
*table);
> +
>  bool ovsdb_monitor_needs_flush(struct ovsdb_monitor *dbmon,
>                                 uint64_t next_transaction);
> 
>  void ovsdb_monitor_get_initial(const struct ovsdb_monitor *dbmon);
> +
> +struct ovsdb_monitor_session_condition *
> +ovsdb_monitor_session_condition_create(void);
> +
> +void
> +ovsdb_monitor_session_condition_destroy(
> +                          struct ovsdb_monitor_session_condition 
*condition);
> +struct ovsdb_error *
> +ovsdb_monitor_table_condition_add(
> +                          struct ovsdb_monitor_session_condition 
*condition,
> +                          const struct ovsdb_table *table,
> +                          const struct json *json_cnd);
> +
> +void ovsdb_monitor_session_condition_bind(
> +                           const struct ovsdb_monitor_session_condition 
*,
> +                           const struct ovsdb_monitor *);
> +
>  #endif
> diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in
> index 6c85729..bf25492 100644
> --- a/ovsdb/ovsdb-server.1.in
> +++ b/ovsdb/ovsdb-server.1.in
> @@ -245,31 +245,231 @@ notifications (see below) to the request, it 
> must be unique among all
>  active monitors.  \fBovsdb\-server\fR rejects attempt to create two
>  monitors with the same identifier.
>  .
> -.IP "4.1.12. Monitor2"
> -A new monitor method added in Open vSwitch version 2.5. Monitor2 allows
> -for more efficient update notifications (described below).
> +.IP "4.1.12. Monitor_cond"
> +A new monitor method added in Open vSwitch version 2.5. The 
monitor_cond
> +request enables a client to replicate subsets of tables within an OVSDB
> +database by requesting notifications of changes to rows matching one of
> +the conditions specified in "where" by receiving the specified contents
> +of these rows when table updates occur. Monitor_cond also allows a more
> +efficient update notifications by receiving table-updates2 
notifications
> +(described below).
> +.
>  .IP
> -The monitor method described in Section 4.1.5 also applies to
> -monitor2, with the following exceptions.
> +The monitor method described in Section 4.1.5 also applies to 
monitor_cond,
> +with the following exceptions:
>  .
>  .RS
>  .IP \(bu
> -RPC request method becomes "monitor2".
> +RPC request method becomes "monitor_cond".
>  .IP \(bu
> -Replay result follows <table-updates2>, described in Section 4.1.13.
> +Replay result follows <table-updates2>, described in Section 4.1.14.
>  .IP \(bu
>  Subsequent changes are sent to the client using the "update2" monitor
> -notification, described in Section 4.1.13
> +notification, described in Section 4.1.14
> +.IP \(bu
> +Update notifications are being sent only for rows matching 
[<conditions>*].
> +<condition> is specified in Section 5.1 in the RFC with the following
> +change: A condition can be either a 3-element JSON array as deescribed 
in
> +the RFC or a boolean value. In case of an empty array an implicit true
> +boolean value will be considered, and all rows will be monitored.
> +.RE
> +.
> +.IP
> +The request object has the following members:
> +.
> +.PP
> +.RS
> +.nf
> +"method": "monitor_cond"
> +"params": [<db-name>, <json-value>, <monitor-cond-requests>]
> +"id": <nonnull-json-value>
> +.fi
> +.RE
> +.
> +.IP
> +The <json-value> parameter is used to match subsequent update 
notifications
> +(see below) to this request. The <monitor-cond-requests> object maps 
the name
> +of the table to an array of <monitor-cond-request>.
> +.
> +.IP
> +Each <monitor-cond-request> is an object with the following members:
> +.
> +.PP
> +.RS
> +.nf
> +"columns": [<column>*]            optional
> +"where": [<condition>*]           optional
> +"select": <monitor-select>        optional
> +.fi
> +.RE
> +.
> +.IP
> +The "columns", if present, define the columns within the table to 
> be monitored
> +that match conditions. If not present all columns are being monitored.
> +.
> +.IP
> +The "where" if present is a JSON array of <condition> and boolean 
> values. If not
> +present or condition is an empty array, implicit True will be 
considered and
> +updates on all rows will be sent. <condition> is specified in Section 
5.1 in
> +the RFC with the following change: A condition can be either a 
3-element JSON
> +array as described in the RFC or a boolean value. In case of an 
> empty array an
> +implicit true boolean value will be considered, and all rows will 
> be monitored.
> +.
> +.IP
> +<monitor-select> is an object with the following members:
> +.
> +.PP
> +.RS
> +.nf
> +"initial": <boolean>              optional
> +"insert": <boolean>               optional
> +"delete": <boolean>               optional
> +"modify": <boolean>               optional
> +.fi
> +.RE
> +.
> +.IP
> +The contents of this object specify how the columns or table are to be
> +monitored as explained in more detail below.
> +.
> +.IP
> +The response object has the following members:
> +.
> +.PP
> +.RS
> +.nf
> +"result": <table-updates2>
> +"error": null
> +"id": same "id" as request
> +.fi
> +.RE
> +.
> +.IP
> +The <table-updates2> object is described in detail in Section 4.1.14. 
It
> +contains the contents of the tables for which "initial" rows are 
selected.
> +If no tables initial contents are requested, then "result" is an 
> empty object.
> +,
> +.IP
> +Subsequently, when changes to a specified table that match one of 
> the conditions
> +in monitor-cond-request are committed, the changes are 
> automatically sent to the
> +client using the "update2" monitor notification (see Section 4.1.14). 
This
> +monitoring persists until the JSON-RPC session terminates or until the 
client
> +sends a "monitor_cancel" JSON-RPC request.
> +.
> +.IP
> +Each <monitor-cond-request> specifies one or more conditions and 
> the manner in
> +which the rows that match the conditions are to be monitored. The 
> circumstances in
> +which an "update" notification is sent for a row within the table 
> are determined by
> +<monitor-select>:
> +.
> +.RS
> +.IP \(bu
> +If "initial" is omitted or true, every row in the original table 
> that matches one of
> +the conditions is sent as part of the response to the "monitor_cond" 
request.
> +.IP \(bu
> +If "insert" is omitted or true, "update" notifications are sent forrows 
newly
> +inserted into the table that match conditions or for rows modified 
> in the table
> +so that their old version does not match the condition and new version 
does.
> +(new row in the client's replica table)
> +.IP \(bu
> +If "delete" is omitted or true, "update" notifications are sent for
> rows deleted
> +from the table that match conditions or for rows modified in the 
> table so that
> +their old version does match the conditions and new version does 
> not. (deleted row
> +in the client's replica)
> +.IP \(bu
> +If "modify" is omitted or true, "update" notifications are sent 
> whenever a row in
> +the table that matches conditions in both old and new version is 
modified.
> +.RE
> +.
> +.IP
> +Both monitor and monitor_cond sessions can exist concurrently. However,
> +monitor and monitor_cond shares the same <json-value> parameter space; 
it
> +must be unique among all monitor and monitor_cond sessions.
> +.
> +.IP "4.1.13. Monitor_cond_update"
> +The "monitor_cond_update" request enables a client to change an 
existing
> +"monitor_cond" replication of the database by specifying a new set of
> +conditions and columns for each replicated table. Currently changing 
the
> +columns set is not supported.
> +.
> +.IP
> +The request object has the following members:
> +.
> +.IP
> +.RS
> +.nf
> +"method": "monitor_cond_update"
> +"params": [<json-value>, <json-value>, <monitor-cond-update-requests>]
> +"id": <nonnull-json-value>
> +.fi
> +.RE
> +.
> +.IP
> +The <json-value> parameter should have a value of an existing 
conditional
> +monitoring session from this client. The second <json-value> in params 
array
> +is the requested value for this session. This value is valid only after
> +"monitor_cond_update" is committed. A user can use these values to 
> distinguish
> +between update messages before conditions update and after. The
> +<monitor-cond-update-requests> object maps the name of the table to
> an array of
> +<monitor-cond-update-request>.
> +.
> +.IP
> +Each <monitor-cond-update-request> is an object with the following 
members:
> +.
> +.IP
> +.RS
> +.nf
> +"columns": [<column>*]         optional
> +"added": [<condition>*]        optional
> +"removed": [<condition>*]      optional
> +.fi
>  .RE
>  .
>  .IP
> -Both monitor and monitor2 sessions can exist concurrently. However,
> -monitor and monitor2 shares the same <json-value> parameter space; it
> -must be unique among all monitor and monitor2 sessions.
> +The "columns" specify a new array of columns to be monitored
> +(Currently unsupported).
> +.
> +.IP
> +The "added" specify a new array of conditions to be added to the 
> existing array
> +of conditions for this table.
> "added" clause can not match any clauses within the existing clauses?   
> +.
> +.IP
> +The "removed" specify an array of existing conditions to be removedfrom 
this
> +replication.
> "removed" has to match existing, but not match any clause in "added" ?  
> +.
> +.IP
> +<condition> is specified in Section 5.1 in the RFC with the following 
change:
> +A condition can be either a 3-element JSON array as described in the 
RFC or a
> +boolean value. In case of an empty array an implicit true boolean 
> value will be
> +considered, and all rows will be monitored.
> +.
> +.IP
> +The response object has the following members:
> +.
> +.IP
> +.RS
> +.nf
> +"result": <table-updates>
> <table-updates2>? 
> Should we honor the original monitor's 'initial' flag?  I thought 
> one the reasons for supporting
> condition updates is to avoid getting the initial state. If not, we 
> should probably document it.
>
Initial state will include only the condition's matched rows. I will 
document it.
  
> +"error": null
> +"id": same "id" as request
> +.fi
> +.RE
> +.IP
> +The <table-updates2> object is described in detail in Section 4.1.14 in 
the
> +RFC. If insert contents are requested by origin monitor_cond request,
> +<table-updates2> will contain any newly matched rows by "added" 
conditions.
> +If deleted contents are requested by origin monitor request, 
<table-updates2>
> +will contain any matched rows by "removed" conditions.
> Keep on using the "removed" conditions does not make sense to me. What 
for?
>
The update notification due to cond_update should include as deleted rows 
that matched by the "removed" conditions. It should notify the client that 
these rows are being deleted from replica due to the cond_update. Should I 
clarify the documentation on this?
 
> +.
> +.IP
> +Changes according to the new conditions are automatically sent to the 
client
> +using the "update2" monitor notification. Updates as a result of a 
condition
> +change, will be sent only after the client received a response to the
> +"monitor_cond_update" request.
>  .
> -.IP "4.1.13. Update2 notification"
> +.IP "4.1.14. Update2 notification"
>  The "update2" notification is sent by the server to the client to 
report
> -changes in tables that are being monitored following a "monitor2" 
request
> +changes in tables that are being monitored following a "monitor_cond" 
request
>  as described above. The notification has the following members:
>  .
>  .RS
> @@ -284,7 +484,8 @@ as described above. The notification has the 
> following members:
>  The <json-value> in "params" is the same as the value passed as the
>  <json-value>  in "params" for the corresponding "monitor" request.
>  <table-updates2> is an object that maps from a table name to a 
> <table-update2>.
> -A <table-update2> is an object that maps from row's UUID to a <row-
> update2> object. A <row-update2> is an object with one of the 
> following members:
> +A <table-update2> is an object that maps from row's UUID to a 
<row-update2>
> +object. A <row-update2> is an object with one of the following members:
>  .
>  .RS
>  .IP "\(dqinitial\(dq: <row>"
> @@ -326,8 +527,8 @@ elements, <row> includes the value from the new 
column.
>  .
>  .IP
>  Initial views of rows are not presented in update2 notifications,
> -but in the response object to the monitor2 request. The formatting of 
the
> -<table-updates2> object, however, is the same in either case.
> +but in the response object to the monitor_cond request. The formatting
> +of the <table-updates2> object, however, is the same in either case.
>  .
>  .IP "5.1. Notation"
>  For <condition>, RFC 7047 only allows the use of \fB!=\fR, \fB==\fR,
> --
> 2.1.4
> 
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to