Store ovsdb monitor in global hmap. A newly created ovsdb monitor
object will first search the global hmap for a possible match. If
one is found, the existing ovsdb monitor is used instead.

With this patch, jsonrpc monitor and ovsdb monitor now have N:1 mapping.

Signed-off-by: Andy Zhou <az...@nicira.com>
---
 ovsdb/jsonrpc-server.c |  14 ++++-
 ovsdb/ovsdb-monitor.c  | 166 ++++++++++++++++++++++++++++++++++++++++++++++---
 ovsdb/ovsdb-monitor.h  |   9 ++-
 3 files changed, 175 insertions(+), 14 deletions(-)

diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index ba6df9d..5696393 100644
--- a/ovsdb/jsonrpc-server.c
+++ b/ovsdb/jsonrpc-server.c
@@ -1156,6 +1156,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session 
*s, struct ovsdb *db,
                              struct json *params)
 {
     struct ovsdb_jsonrpc_monitor *m = NULL;
+    struct ovsdb_monitor *dbmon = NULL;
     struct json *monitor_id, *monitor_requests;
     struct ovsdb_error *error = NULL;
     struct shash_node *node;
@@ -1233,7 +1234,13 @@ ovsdb_jsonrpc_monitor_create(struct 
ovsdb_jsonrpc_session *s, struct ovsdb *db,
         }
     }
 
-    ovsdb_monitor_add_jsonrpc_monitor(m->dbmon, m);
+    dbmon = ovsdb_monitor_add(m->dbmon);
+    if (dbmon != m->dbmon) {
+        /* Found an exsiting dbmon, reuse the current one. */
+        ovsdb_monitor_remove_jsonrpc_monitor(m->dbmon, m);
+        ovsdb_monitor_add_jsonrpc_monitor(dbmon, m);
+        m->dbmon =dbmon;
+    }
 
     ovsdb_monitor_get_initial(m->dbmon);
     json = ovsdb_jsonrpc_monitor_compose_update(m, true);
@@ -1292,7 +1299,10 @@ ovsdb_jsonrpc_monitor_compose_update(struct 
ovsdb_jsonrpc_monitor *m,
 
     json = ovsdb_monitor_compose_update(m->dbmon, initial,
                                         &m->unflushed);
-    ovsdb_monitor_renew_tracking_changes(m->dbmon, unflushed, m->unflushed);
+    if (unflushed != m->unflushed) {
+        ovsdb_monitor_renew_tracking_changes(m->dbmon, unflushed,
+                                             m->unflushed);
+    }
 
     return json;
 }
diff --git a/ovsdb/ovsdb-monitor.c b/ovsdb/ovsdb-monitor.c
index 70a8e26..210b33c 100644
--- a/ovsdb/ovsdb-monitor.c
+++ b/ovsdb/ovsdb-monitor.c
@@ -29,6 +29,7 @@
 #include "row.h"
 #include "simap.h"
 #include "table.h"
+#include "hash.h"
 #include "timeval.h"
 #include "transaction.h"
 #include "jsonrpc-server.h"
@@ -39,6 +40,7 @@
 VLOG_DEFINE_THIS_MODULE(ovsdb_monitor);
 
 static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class;
+static struct hmap ovsdb_monitors;
 
 /*  Backend monitor.
  *
@@ -52,6 +54,8 @@ struct ovsdb_monitor {
     struct ovs_list jsonrpc_monitors;  /* List front end jsonrpc monitors. */
     struct ovsdb *db;
     uint64_t n_transactions;      /* Count number of commited transactions. */
+
+    struct hmap_node hmap_node;   /* Elements within ovsdb_monitors.  */
 };
 
 struct jsonrpc_monitor_node {
@@ -255,6 +259,7 @@ ovsdb_monitor_create(struct ovsdb *db,
     dbmon->db = db;
     dbmon->n_transactions = 0;
     shash_init(&dbmon->tables);
+    hmap_node_nullify(&dbmon->hmap_node);
 
     ovsdb_monitor_add_jsonrpc_monitor(dbmon, jsonrpc_monitor);
     return dbmon;
@@ -336,7 +341,6 @@ ovsdb_monitor_table_add_changes(struct ovsdb_monitor_table 
*mt,
     list_push_back(&mt->changes_list, &changes->node);
 };
 
-
 static struct ovsdb_monitor_changes *
 ovsdb_monitor_table_find_changes(struct ovsdb_monitor_table *mt,
                                  uint64_t transaction)
@@ -364,7 +368,6 @@ ovsdb_monitor_table_untrack_changes(struct 
ovsdb_monitor_table *mt,
     changes = ovsdb_monitor_table_find_changes(mt, transaction);
 
     if (changes) {
-        ovs_assert(changes->transaction == transaction);
         if (--changes->n_refs == 0) {
             ovsdb_monitor_changes_destroy_rows(changes);
             list_remove(&changes->node);
@@ -383,7 +386,7 @@ ovsdb_monitor_table_track_changes(struct 
ovsdb_monitor_table *mt,
 
     changes = ovsdb_monitor_table_find_changes(mt, transaction);
     if (changes) {
-        ovs_assert(false);
+        changes->n_refs++;
     } else {
         ovsdb_monitor_table_add_changes(mt, transaction);
     }
@@ -503,7 +506,6 @@ ovsdb_monitor_compose_update(const struct ovsdb_monitor 
*dbmon,
     uint64_t from_txn;
 
     from_txn = initial ? 0 : *unflushed;
-
     *unflushed = dbmon->n_transactions + 1;
 
     max_columns = 0;
@@ -549,9 +551,6 @@ ovsdb_monitor_compose_update(const struct ovsdb_monitor 
*dbmon,
                 snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(&row->uuid));
                 json_object_put(table_json, uuid, row_json);
             }
-
-            hmap_remove(&changes->rows, &row->hmap_node);
-            ovsdb_monitor_row_destroy(mt, row);
         }
     }
 
@@ -624,6 +623,35 @@ ovsdb_monitor_changes_update(const struct ovsdb_row *old,
 }
 
 static bool
+ovsdb_monitor_initial_cb(const struct ovsdb_row *old,
+                         const struct ovsdb_row *new,
+                         const unsigned long int *changed OVS_UNUSED,
+                         void *aux_)
+{
+    struct ovsdb_monitor_aux *aux = aux_;
+    const struct ovsdb_monitor *m = aux->monitor;
+    struct ovsdb_table *table = new ? new->table : old->table;
+    struct ovsdb_monitor_table *mt;
+    struct ovsdb_monitor_changes *changes;
+
+    if (!aux->mt || table != aux->mt->table) {
+        aux->mt = shash_find_data(&m->tables, table->schema->name);
+        if (!aux->mt) {
+            /* We don't care about rows in this table at all.  Tell the caller
+             * to skip it.  */
+            return false;
+        }
+    }
+    mt = aux->mt;
+
+    changes = ovsdb_monitor_table_find_changes(mt, 0);
+    ovs_assert(changes);
+    ovsdb_monitor_changes_update(old, new, mt, changes);
+
+    return true;
+}
+
+static bool
 ovsdb_monitor_change_cb(const struct ovsdb_row *old,
                         const struct ovsdb_row *new,
                         const unsigned long int *changed OVS_UNUSED,
@@ -663,13 +691,18 @@ ovsdb_monitor_get_initial(const struct ovsdb_monitor 
*dbmon)
 
         if (mt->select & OJMS_INITIAL) {
             struct ovsdb_row *row;
+            struct ovsdb_monitor_changes *changes;
 
-            if (list_is_empty(&mt->changes_list)) {
+            changes = ovsdb_monitor_table_find_changes(mt, 0);
+            if (!changes) {
                 ovsdb_monitor_table_add_changes(mt, 0);
+                changes = ovsdb_monitor_table_find_changes(mt, 0);
+            } else {
+                changes->n_refs++;
             }
 
             HMAP_FOR_EACH (row, hmap_node, &mt->table->rows) {
-                ovsdb_monitor_change_cb(NULL, row, NULL, &aux);
+                ovsdb_monitor_initial_cb(NULL, row, NULL, &aux);
             }
         }
     }
@@ -681,6 +714,11 @@ ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor 
*dbmon,
 {
     struct jsonrpc_monitor_node *jm;
 
+    if (list_is_empty(&dbmon->jsonrpc_monitors)) {
+        ovsdb_monitor_destroy(dbmon);
+        return;
+    }
+
     /* Find and remove the jsonrpc monitor from the list.  */
     LIST_FOR_EACH(jm, node, &dbmon->jsonrpc_monitors) {
         if (jm->jsonrpc_monitor == jsonrpc_monitor) {
@@ -699,7 +737,109 @@ ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor 
*dbmon,
     }
 
     /* Should never reach here. jsonrpc_monitor should be on the list.  */
-    ovs_assert(true);
+    ovs_assert(false);
+}
+
+static bool
+ovsdb_monitor_table_equal(const struct ovsdb_monitor_table *a,
+                          const struct ovsdb_monitor_table *b)
+{
+    size_t i;
+
+    if ((a->table != b->table) ||
+        (a->select != b->select) ||
+        (a->n_columns != b->n_columns)) {
+        return false;
+    }
+
+    for (i = 0; i < a->n_columns; i++) {
+        if ((a->columns[i].column != b->columns[i].column) ||
+            (a->columns[i].select != b->columns[i].select)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool
+ovsdb_monitor_equal(const struct ovsdb_monitor *a,
+                    const struct ovsdb_monitor *b)
+{
+    struct shash_node *node;
+
+    if (shash_count(&a->tables) != shash_count(&b->tables)) {
+        return false;
+    }
+
+    SHASH_FOR_EACH(node, &a->tables) {
+        const struct ovsdb_monitor_table *mta = node->data;
+        const struct ovsdb_monitor_table *mtb;
+
+        mtb = shash_find_data(&b->tables, node->name);
+        if (!mtb) {
+            return false;
+        }
+
+        if (!ovsdb_monitor_table_equal(mta, mtb)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static size_t
+ovsdb_monitor_hash(const struct ovsdb_monitor *dbmon, size_t basis)
+{
+    const struct shash_node **nodes;
+    size_t i, j, n;
+
+    nodes = shash_sort(&dbmon->tables);
+    n = shash_count(&dbmon->tables);
+
+    for (i = 0; i < n; i++) {
+        struct ovsdb_monitor_table *mt = nodes[i]->data;
+
+        basis = hash_pointer(mt->table, basis);
+        basis = hash_3words(mt->select, mt->n_columns, basis);
+
+        for (j = 0; j < mt->n_columns; j++) {
+            basis = hash_pointer(mt->columns[j].column, basis);
+            basis = hash_2words(mt->columns[j].select, basis);
+        }
+    }
+    free(nodes);
+
+    return basis;
+}
+
+struct ovsdb_monitor *
+ovsdb_monitor_add(struct ovsdb_monitor *new_dbmon)
+{
+    struct ovsdb_monitor *dbmon;
+    size_t hash;
+    static bool init__ = false;
+
+    /* Init ovsdb_monitors once */
+    if (!init__) {
+        hmap_init(&ovsdb_monitors);
+        init__ = true;
+    }
+
+    /* New_dbmon should not be associated with only one jsonrpc
+     * connections.  */
+    ovs_assert(list_size(&new_dbmon->jsonrpc_monitors) == 1);
+
+    hash = ovsdb_monitor_hash(new_dbmon, 0);
+    HMAP_FOR_EACH_WITH_HASH(dbmon, hmap_node, hash, &ovsdb_monitors) {
+        if (ovsdb_monitor_equal(dbmon,  new_dbmon)) {
+            return dbmon;
+        }
+    }
+
+    hmap_insert_fast(&ovsdb_monitors, &new_dbmon->hmap_node, hash);
+    return new_dbmon;
 }
 
 /* Stop tracking changes since 'last_txn', and, start to
@@ -710,6 +850,8 @@ ovsdb_monitor_renew_tracking_changes(struct ovsdb_monitor 
*dbmon,
 {
     struct shash_node *node;
 
+    ovs_assert(prev_txn < next_txn);
+
     SHASH_FOR_EACH (node, &dbmon->tables) {
         struct ovsdb_monitor_table *mt = node->data;
 
@@ -725,6 +867,10 @@ ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon)
 
     list_remove(&dbmon->replica.node);
 
+    if (!hmap_node_is_null(&dbmon->hmap_node)) {
+        hmap_remove(&ovsdb_monitors, &dbmon->hmap_node);
+    }
+
     SHASH_FOR_EACH (node, &dbmon->tables) {
         struct ovsdb_monitor_table *mt = node->data;
         struct ovsdb_monitor_changes *changes, *next;
diff --git a/ovsdb/ovsdb-monitor.h b/ovsdb/ovsdb-monitor.h
index fb7bed5..90f696c 100644
--- a/ovsdb/ovsdb-monitor.h
+++ b/ovsdb/ovsdb-monitor.h
@@ -28,10 +28,15 @@ enum ovsdb_monitor_selection {
 
 
 struct ovsdb_monitor *ovsdb_monitor_create(struct ovsdb *db,
-                        struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
+                               struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
+
+struct ovsdb_monitor *ovsdb_monitor_add(struct ovsdb_monitor *dbmon);
 
 void ovsdb_monitor_add_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
-                        struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
+                                       struct ovsdb_jsonrpc_monitor 
*jsonrpc_monitor);
+
+void ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
+                       struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
 
 void ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
                                struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
-- 
1.9.1

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

Reply via email to