+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;
+
+ /* New_dbmon should be associated with only one jsonrpc
+ * connections. */
+ ovs_assert(list_is_singleton(&new_dbmon->jsonrpc_monitors));
+
+ 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(&ovsdb_monitors, &new_dbmon->hmap_node, hash);
+ return new_dbmon;
+}
+