* inclusive. */
struct ovsdb_monitor_json_cache_node {
struct hmap_node hmap_node; /* Elements in json cache. */
+ enum ovsdb_monitor_version version;
uint64_t from_txn;
struct json *json; /* Null, or a cloned of json */
};
static void ovsdb_monitor_table_track_changes(struct ovsdb_monitor_table *mt,
uint64_t unflushed);
+static uint32_t
+json_cache_hash(enum ovsdb_monitor_version version, uint64_t from_txn)
+{
+ uint32_t hash;
+
+ hash = hash_uint64(version);
+ hash = hash_uint64_basis(from_txn, hash);
+
+ return hash;
+}
+
static struct ovsdb_monitor_json_cache_node *
ovsdb_monitor_json_cache_search(const struct ovsdb_monitor *dbmon,
+ enum ovsdb_monitor_version version,
uint64_t from_txn)
{
struct ovsdb_monitor_json_cache_node *node;
- uint32_t hash = hash_uint64(from_txn);
+ uint32_t hash = json_cache_hash(version, from_txn);
HMAP_FOR_EACH_WITH_HASH(node, hmap_node, hash, &dbmon->json_cache) {
- if (node->from_txn == from_txn) {
+ if (node->from_txn == from_txn && node->version == version) {
return node;
}
}
static void
ovsdb_monitor_json_cache_insert(struct ovsdb_monitor *dbmon,
+ enum ovsdb_monitor_version version,
uint64_t from_txn, struct json *json)
{
struct ovsdb_monitor_json_cache_node *node;
- uint32_t hash;
+ uint32_t hash = json_cache_hash(version, from_txn);
node = xmalloc(sizeof *node);
- hash = hash_uint64(from_txn);
+ node->version = version;
node->from_txn = from_txn;
node->json = json ? json_clone(json) : NULL;
* 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,
+ bool initial, uint64_t *unflushed_,
enum ovsdb_monitor_version version)
{
struct ovsdb_monitor_json_cache_node *cache_node;
struct shash_node *node;
struct json *json;
- uint64_t prev_txn = *unflushed;
- uint64_t next_txn = dbmon->n_transactions + 1;
+ const uint64_t unflushed = *unflushed_;
+ const uint64_t next_unflushed = dbmon->n_transactions + 1;
/* 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, prev_txn);
+ cache_node = ovsdb_monitor_json_cache_search(dbmon, version, unflushed);
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,
+ json = ovsdb_monitor_compose_update(dbmon, initial, unflushed,
ovsdb_monitor_compose_row_update);
} else {
ovs_assert(version == OVSDB_MONITOR_V2);
- json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
+ json = ovsdb_monitor_compose_update(dbmon, initial, unflushed,
ovsdb_monitor_compose_row_update2);
}
- ovsdb_monitor_json_cache_insert(dbmon, prev_txn, json);
+ ovsdb_monitor_json_cache_insert(dbmon, version, unflushed, json);
}
/* Maintain transaction id of 'changes'. */
SHASH_FOR_EACH (node, &dbmon->tables) {
struct ovsdb_monitor_table *mt = node->data;
- ovsdb_monitor_table_untrack_changes(mt, prev_txn);
- ovsdb_monitor_table_track_changes(mt, next_txn);
+ ovsdb_monitor_table_untrack_changes(mt, unflushed);
+ ovsdb_monitor_table_track_changes(mt, next_unflushed);
}
- *unflushed = next_txn;
+ *unflushed_ = next_unflushed;
return json;
}
void
ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
- struct ovsdb_jsonrpc_monitor *jsonrpc_monitor)
+ struct ovsdb_jsonrpc_monitor *jsonrpc_monitor,
+ uint64_t unflushed)
{
struct jsonrpc_monitor_node *jm;
/* Find and remove the jsonrpc monitor from the list. */
LIST_FOR_EACH(jm, node, &dbmon->jsonrpc_monitors) {
if (jm->jsonrpc_monitor == jsonrpc_monitor) {
+ /* Release the tracked changes. */
+ struct shash_node *node;
+ SHASH_FOR_EACH (node, &dbmon->tables) {
+ struct ovsdb_monitor_table *mt = node->data;
+ ovsdb_monitor_table_untrack_changes(mt, unflushed);
+ }
list_remove(&jm->node);
free(jm);
struct ovsdb_monitor_aux aux;
ovsdb_monitor_init_aux(&aux, m);
+ /* Update ovsdb_monitor's transaction number for
+ * each transaction, before calling ovsdb_monitor_change_cb(). */
+ m->n_transactions++;
ovsdb_txn_for_each_change(txn, ovsdb_monitor_change_cb, &aux);
- if (aux.efficacy == OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE) {
+ switch(aux.efficacy) {
+ case OVSDB_CHANGES_NO_EFFECT:
+ /* The transaction is ignored by the monitor.
+ * Roll back the 'n_transactions' as if the transaction
+ * has never happened. */
+ m->n_transactions--;
+ break;
+ case OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE:
+ /* Nothing. */
+ break;
+ case OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE:
ovsdb_monitor_json_cache_flush(m);
- m->n_transactions++;
+ break;
}
return NULL;
}
}
+/* Add some memory usage statics for monitors into 'usage', for use with
+ * memory_report(). */
+void
+ovsdb_monitor_get_memory_usage(struct simap *usage)
+{
+ simap_put(usage, "monitors", hmap_count(&ovsdb_monitors));
+}
+
static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class = {
ovsdb_monitor_commit,
ovsdb_monitor_destroy_callback,