[ovs-dev] [PATCH monitor_cond V3 04/10] ovsdb: generate update notifications for monitor_cond session

Liran Schour lirans at il.ibm.com
Wed Feb 3 13:53:28 UTC 2016


Hold session's conditions in ovsdb_monitor_session_condition. Pass it
to ovsdb_monitor for generating "update2" notifications.
Add functions that can generate "update2" notification for a
"monitor_cond" session.
json_cache is enabled only for session's with nulled or empty condition.
"monitor_cond" and "monitor_cond_change" are RFC 7047 extensions
described by ovsdb-server(1) manpage.

Signed-off-by: Liran Schour <lirans at il.ibm.com>

---
v2->v3:
* Document monitor_cond_update receives a single json condition
* Pass session's condition down to row_update function
* Do not classify modify as delete or insert since we send update
  due to cond_update with empty changes list
* Allow conditions with non-monitored columns
* Bug fix: allow json cache when session's condition is NULL
* Bug fix: allow json cahce when all table's conditions are empty
---
 ovsdb/condition.c       |  21 ++++
 ovsdb/condition.h       |   4 +
 ovsdb/jsonrpc-server.c  |  37 ++++++-
 ovsdb/monitor.c         | 261 ++++++++++++++++++++++++++++++++++++++++++++----
 ovsdb/monitor.h         |  40 +++++++-
 ovsdb/ovsdb-server.1.in | 230 +++++++++++++++++++++++++++++++++++++++---
 6 files changed, 551 insertions(+), 42 deletions(-)

diff --git a/ovsdb/condition.c b/ovsdb/condition.c
index 7321640..5edee5b 100644
--- a/ovsdb/condition.c
+++ b/ovsdb/condition.c
@@ -444,3 +444,24 @@ ovsdb_condition_clone(struct ovsdb_condition *to,
     }
     to->n_clauses = from->n_clauses;
 }
+
+const struct ovsdb_column **
+ovsdb_condition_get_columns(const struct ovsdb_condition *cond,
+                            size_t *n_columns)
+{
+    const struct ovsdb_column **columns;
+    size_t i;
+
+    if (!cond->n_clauses) {
+        *n_columns = 0;
+        return NULL;
+    }
+
+    columns = xmalloc(cond->n_clauses * sizeof *columns);
+    for (i = 0; i < cond->n_clauses; i++) {
+        columns[i] = cond->clauses[i].column;
+    }
+    *n_columns = i;
+
+    return columns;
+}
diff --git a/ovsdb/condition.h b/ovsdb/condition.h
index 318efba..e65b8c3 100644
--- a/ovsdb/condition.h
+++ b/ovsdb/condition.h
@@ -82,4 +82,8 @@ int ovsdb_condition_cmp(const struct ovsdb_condition *a,
 void ovsdb_condition_clone(struct ovsdb_condition *to,
                            const struct ovsdb_condition *from);
 
+const struct ovsdb_column **
+ovsdb_condition_get_columns(const struct ovsdb_condition *cond,
+                            size_t *n_columns);
+
 #endif /* ovsdb/condition.h */
diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index fcda8dc..fa5d5c4 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"
@@ -849,14 +850,16 @@ 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,
+                                                 request->id);
         }
     } else if (!strcmp(request->method, "monitor_cancel")) {
         reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params),
@@ -1048,6 +1051,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 *
@@ -1077,18 +1081,24 @@ 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,
+                                    struct ovsdb_monitor_session_condition *cond,
                                     const struct json *monitor_request)
 {
     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;
     struct ovsdb_parser parser;
     struct ovsdb_error *error;
 
     ovsdb_parser_init(&parser, monitor_request, "table %s", ts->name);
+    if (cond) {
+        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;
@@ -1155,6 +1165,12 @@ ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_monitor *dbmon,
             }
         }
     }
+    if (cond) {
+        error = ovsdb_monitor_table_condition_add(cond, table, where);
+        if (error) {
+            return error;
+        }
+    }
 
     return NULL;
 }
@@ -1193,6 +1209,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 (version == OVSDB_MONITOR_V2) {
+        m->condition = ovsdb_monitor_session_condition_create();
+    }
     m->unflushed = 0;
     m->version = version;
     hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0));
@@ -1221,6 +1240,7 @@ 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,
+                                                            m->condition,
                                                             array->elems[i]);
                 if (error) {
                     goto error;
@@ -1229,6 +1249,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
         } else {
             error = ovsdb_jsonrpc_parse_monitor_request(m->dbmon,
                                                         table,
+                                                        m->condition,
                                                         mr_value);
             if (error) {
                 goto error;
@@ -1253,6 +1274,11 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
         m->dbmon = dbmon;
     }
 
+    /* We only add conditions columns here to simplify ovsdb_monitor_add */
+    if (m->condition) {
+        ovsdb_monitor_add_all_condition_columns(m->dbmon, m->condition);
+    }
+
     ovsdb_monitor_get_initial(m->dbmon);
     json = ovsdb_jsonrpc_monitor_compose_update(m, true);
     json = json ? json : json_object_create();
@@ -1305,7 +1331,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
@@ -1328,6 +1354,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 7802560..1614d67 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 {
+    size_t n_empty_cnd;
+    struct shash tables;     /* Contains
+                              *   "struct ovsdb_monitor_table_condition *"s. */
+};
+
+/* Monitored table session's conditions */
+struct ovsdb_monitor_table_condition {
+    const struct ovsdb_table *table;
+    struct ovsdb_condition old_condition;
+    struct ovsdb_condition new_condition;
+};
+
 /*  Backend monitor.
  *
  *  ovsdb_monitor keep track of the ovsdb changes.
@@ -108,6 +123,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. */
@@ -129,9 +145,11 @@ struct ovsdb_monitor_table {
 };
 
 typedef struct json *
-(*compose_row_update_cb_func)(const struct ovsdb_monitor_table *mt,
-                              const struct ovsdb_monitor_row *row,
-                              bool initial, unsigned long int *changed);
+(*compose_row_update_cb_func)
+    (const struct ovsdb_monitor_table *mt,
+     const struct ovsdb_monitor_session_condition * condition,
+     const struct ovsdb_monitor_row *row,
+     bool initial, unsigned long int *changed);
 
 static void ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon);
 static struct ovsdb_monitor_changes * ovsdb_monitor_table_add_changes(
@@ -372,6 +390,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 =
@@ -390,9 +409,20 @@ ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
 {
     struct ovsdb_monitor_table *mt;
     struct ovsdb_monitor_column *c;
+    int i;
 
     mt = shash_find_data(&dbmon->tables, table->schema->name);
 
+    /* Check duplication only for non-monitored columns */
+    if (!monitored) {
+        for (i = 0; i < mt->n_columns; i++) {
+            if (mt->columns[i].column == column) {
+                /* column exists */
+                return;
+            }
+        }
+    }
+
     if (mt->n_columns >= mt->allocated_columns) {
         mt->columns = x2nrealloc(mt->columns, &mt->allocated_columns,
                                  sizeof *mt->columns);
@@ -409,6 +439,39 @@ ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
     }
 }
 
+static void
+ovsdb_monitor_condition_add_columns(struct ovsdb_monitor *dbmon,
+                                    const struct ovsdb_table *table,
+                                    struct ovsdb_condition *condition)
+{
+    size_t n_columns;
+    int i;
+    const struct ovsdb_column **columns =
+        ovsdb_condition_get_columns(condition, &n_columns);
+
+    for (i = 0; i < n_columns; i++) {
+        ovsdb_monitor_add_column(dbmon, table, columns[i],
+                                 OJMS_NONE, false);
+    }
+    if (n_columns) {
+        free(columns);
+    }
+}
+
+void
+ovsdb_monitor_add_all_condition_columns(
+                          struct ovsdb_monitor *dbmon,
+                          struct ovsdb_monitor_session_condition *cond)
+{
+    struct shash_node *node;
+
+    SHASH_FOR_EACH(node, &cond->tables) {
+        struct ovsdb_monitor_table_condition *mtc = node->data;
+
+        ovsdb_monitor_condition_add_columns(dbmon, mtc->table, &mtc->new_condition);
+    }
+}
+
 /* Check for duplicated column names. Return the first
  * duplicated column's name if found. Otherwise return
  * NULL.  */
@@ -519,6 +582,153 @@ 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);
+
+    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);
+}
+
+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);
+    mtc->table = table;
+    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 conditions expected");
+        }
+    }
+    ovsdb_condition_clone(&mtc->new_condition, &mtc->old_condition);
+    if (ovsdb_condition_empty(&mtc->old_condition)) {
+        condition->n_empty_cnd++;
+    }
+
+    return NULL;
+}
+
+static inline bool
+ovsdb_can_cache(const struct ovsdb_monitor_session_condition *condition)
+{
+    return shash_count(&condition->tables) == condition->n_empty_cnd;
+}
+
+static bool
+ovsdb_monitor_get_table_conditions(
+                      const struct ovsdb_monitor_table *mt,
+                      const struct ovsdb_monitor_session_condition *condition,
+                      struct ovsdb_condition **old_condition,
+                      struct ovsdb_condition **new_condition)
+{
+    if (!condition) {
+        return false;
+    }
+
+    struct ovsdb_monitor_table_condition *mtc =
+        shash_find_data(&condition->tables, mt->table->schema->name);
+
+    if (!mtc) {
+        return false;
+    }
+    *old_condition = &mtc->old_condition;
+    *new_condition = &mtc->new_condition;
+
+    return true;
+}
+
+static enum ovsdb_monitor_selection
+ovsdb_monitor_row_update_type_condition(
+                      const struct ovsdb_monitor_table *mt,
+                      const struct ovsdb_monitor_session_condition *condition,
+                      bool initial,
+                      const struct ovsdb_datum *old,
+                      const struct ovsdb_datum *new,
+                      const bool index_map)
+{
+    struct ovsdb_condition *old_condition, *new_condition;
+    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 (ovsdb_monitor_get_table_conditions(mt,
+                                           condition,
+                                           &old_condition,
+                                           &new_condition)) {
+        bool old_cond = !old ? false
+            : ovsdb_condition_evaluate_or_datum(old,
+                                                old_condition,
+                                                columns_index_map);
+        bool new_cond = !new ? false
+            : ovsdb_condition_evaluate_or_datum(new,
+                                                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,
@@ -563,6 +773,7 @@ ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt,
 static struct json *
 ovsdb_monitor_compose_row_update(
     const struct ovsdb_monitor_table *mt,
+    const struct ovsdb_monitor_session_condition *condition OVS_UNUSED,
     const struct ovsdb_monitor_row *row,
     bool initial, unsigned long int *changed)
 {
@@ -624,6 +835,7 @@ ovsdb_monitor_compose_row_update(
 static struct json *
 ovsdb_monitor_compose_row_update2(
     const struct ovsdb_monitor_table *mt,
+    const struct ovsdb_monitor_session_condition *condition,
     const struct ovsdb_monitor_row *row,
     bool initial, unsigned long int *changed)
 {
@@ -631,7 +843,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, condition, initial,
+                                                   row->old, row->new, true);
     if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) {
         return NULL;
     }
@@ -701,9 +914,11 @@ ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon)
  * RFC 7047) for all the outstanding changes within 'monitor', starting from
  * 'transaction'.  */
 static struct json*
-ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon,
-                             bool initial, uint64_t transaction,
-                             compose_row_update_cb_func row_update)
+ovsdb_monitor_compose_update(
+                      struct ovsdb_monitor *dbmon,
+                      bool initial, uint64_t transaction,
+                      const struct ovsdb_monitor_session_condition *condition,
+                      compose_row_update_cb_func row_update)
 {
     struct shash_node *node;
     struct json *json;
@@ -725,7 +940,7 @@ ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon,
         HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) {
             struct json *row_json;
 
-            row_json = (*row_update)(mt, row, initial, changed);
+            row_json = (*row_update)(mt, condition, row, initial, changed);
             if (row_json) {
                 char uuid[UUID_LEN + 1];
 
@@ -759,11 +974,13 @@ 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;
@@ -771,19 +988,27 @@ ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
 
     /* 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 && ovsdb_can_cache(condition))) {
+        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 {
         if (version == OVSDB_MONITOR_V1) {
-            json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
-                                        ovsdb_monitor_compose_row_update);
+            json =
+               ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
+                                            condition,
+                                            ovsdb_monitor_compose_row_update);
         } else {
             ovs_assert(version == OVSDB_MONITOR_V2);
-            json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
-                                        ovsdb_monitor_compose_row_update2);
+            json =
+               ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
+                                            condition,
+                                            ovsdb_monitor_compose_row_update2);
+        }
+        if (!condition || (condition && ovsdb_can_cache(condition))) {
+            ovsdb_monitor_json_cache_insert(dbmon, version, prev_txn, json);
         }
-        ovsdb_monitor_json_cache_insert(dbmon, version, prev_txn, json);
     }
 
     /* Maintain transaction id of 'changes'. */
diff --git a/ovsdb/monitor.h b/ovsdb/monitor.h
index 1f3dc6e..0529e5a 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. */
@@ -60,21 +63,50 @@ void ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
                               enum ovsdb_monitor_selection select,
                               bool monitored);
 
+void ovsdb_monitor_add_all_condition_columns(struct ovsdb_monitor *dbmon,
+                             struct ovsdb_monitor_session_condition *cond);
+
 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..27952b6 100644
--- a/ovsdb/ovsdb-server.1.in
+++ b/ovsdb/ovsdb-server.1.in
@@ -245,31 +245,228 @@ 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 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.
+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 condition
+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
+"where": [<condition>*]        optional
+.fi
+.RE
+.
+.IP
+The "columns" specify a new array of columns to be monitored
+(Currently unsupported).
+.
+.IP
+The "where" specify a new array of conditions to be applied to this monitoring
+session.
+.
+.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": null
+"error": null
+"id": same "id" as request
+.fi
+.RE
+.IP
+Subsequent <table-updates2> notifications are 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 rows that match the new condition and
+do not match the old condition.
+If deleted contents are requested by origin monitor request, <table-updates2>
+will contain any matched rows by old condition and not matched by the new
+condition.
+.
+.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 +481,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 +524,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





More information about the dev mailing list