return NULL;
}
-/* Stop currently tracking changes to table 'mt' since 'transaction'.
- *
- * Return 'true' if the 'transaction' is being tracked. 'false' otherwise. */
+/* Stop currently tracking changes to table 'mt' since 'transaction'. */
static void
ovsdb_monitor_table_untrack_changes(struct ovsdb_monitor_table *mt,
uint64_t transaction)
free(changes);
}
+static enum ovsdb_monitor_selection
+ovsdb_monitor_row_update_type(bool initial, const bool old, const bool new)
+{
+ return initial ? OJMS_INITIAL
+ : !old ? OJMS_INSERT
+ : !new ? OJMS_DELETE
+ : OJMS_MODIFY;
+}
+
/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
* 'mt', or NULL if no row update should be sent.
*
struct json *row_json;
size_t i;
- type = (initial ? OJMS_INITIAL
- : !row->old ? OJMS_INSERT
- : !row->new ? OJMS_DELETE
- : OJMS_MODIFY);
+ type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
if (!(mt->select & type)) {
return NULL;
}
mt->select |= select;
}
+ /*
+ * If a row's change type (insert, delete or modify) matches that of
+ * the monitor, they should be sent to the monitor's clients as updates.
+ * Of cause, the monitor should also internally update with this change.
+ *
+ * When a change type does not require client side update, the monitor
+ * may still need to keep track of certain changes in order to generate
+ * correct future updates. For example, the monitor internal state should
+ * be updated whenever a new row is inserted, in order to generate the
+ * correct initial state, regardless if a insert change type is being
+ * monitored.
+ *
+ * On the other hand, if a transaction only contains changes to columns
+ * that are not monitored, this transaction can be safely ignored by the
+ * monitor.
+ *
+ * Thus, the order of the declaration is important:
+ * 'OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE' always implies
+ * 'OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE', but not vice versa. */
+enum ovsdb_monitor_changes_efficacy {
+ OVSDB_CHANGES_NO_EFFECT, /* Monitor does not care about this
+ change. */
+ OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE, /* Monitor internal updates. */
+ OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE, /* Client needs to be updated. */
+};
+
struct ovsdb_monitor_aux {
const struct ovsdb_monitor *monitor;
struct ovsdb_monitor_table *mt;
+ enum ovsdb_monitor_changes_efficacy efficacy;
};
static void
{
aux->monitor = m;
aux->mt = NULL;
+ aux->efficacy = OVSDB_CHANGES_NO_EFFECT;
}
static void
}
}
+static bool
+ovsdb_monitor_columns_changed(const struct ovsdb_monitor_table *mt,
+ const unsigned long int *changed)
+{
+ size_t i;
+
+ for (i = 0; i < mt->n_columns; i++) {
+ size_t column_index = mt->columns[i].column->index;
+
+ if (bitmap_is_set(changed, column_index)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Return the efficacy of a row's change to a monitor table.
+ *
+ * Please see the block comment above 'ovsdb_monitor_changes_efficacy'
+ * definition form more information. */
+static enum ovsdb_monitor_changes_efficacy
+ovsdb_monitor_changes_classify(enum ovsdb_monitor_selection type,
+ const struct ovsdb_monitor_table *mt,
+ const unsigned long int *changed)
+{
+ if (type == OJMS_MODIFY &&
+ !ovsdb_monitor_columns_changed(mt, changed)) {
+ return OVSDB_CHANGES_NO_EFFECT;
+ }
+
+ return (mt->select & type)
+ ? OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE
+ : OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE;
+}
+
static bool
ovsdb_monitor_change_cb(const struct ovsdb_row *old,
const struct ovsdb_row *new,
- const unsigned long int *changed OVS_UNUSED,
+ const unsigned long int *changed,
void *aux_)
{
struct ovsdb_monitor_aux *aux = aux_;
mt = aux->mt;
HMAP_FOR_EACH(changes, hmap_node, &mt->changes) {
- ovsdb_monitor_changes_update(old, new, mt, changes);
+ enum ovsdb_monitor_changes_efficacy efficacy;
+ enum ovsdb_monitor_selection type;
+
+ type = ovsdb_monitor_row_update_type(false, old, new);
+ efficacy = ovsdb_monitor_changes_classify(type, mt, changed);
+ if (efficacy > OVSDB_CHANGES_NO_EFFECT) {
+ ovsdb_monitor_changes_update(old, new, mt, changes);
+ }
+
+ if (aux->efficacy < efficacy) {
+ aux->efficacy = efficacy;
+ }
}
+
return true;
}
hmap_remove(&mt->changes, &changes->hmap_node);
ovsdb_monitor_changes_destroy(changes);
}
+ hmap_destroy(&mt->changes);
free(mt->columns);
free(mt);
}
struct ovsdb_monitor *m = ovsdb_monitor_cast(replica);
struct ovsdb_monitor_aux aux;
- ovsdb_monitor_json_cache_flush(m);
ovsdb_monitor_init_aux(&aux, m);
ovsdb_txn_for_each_change(txn, ovsdb_monitor_change_cb, &aux);
- m->n_transactions++;
+
+ if (aux.efficacy == OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE) {
+ ovsdb_monitor_json_cache_flush(m);
+ m->n_transactions++;
+ }
return NULL;
}