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