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/

>
> 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.

>  {
>      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?


>                               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/

> +        }
> +    }
> +    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...

     /* 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?


>      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?

>          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 for rows
> 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 removed from
> 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.


> +"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?

+.
> +.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