+
+/* Set conditional monitoring mode only if we have non-empty condition in one
+ * of the tables at least */
+static inline void
+ovsdb_monitor_session_condition_set_mode(
+ struct ovsdb_monitor_session_condition *cond)
+{
+ cond->conditional = shash_count(&cond->tables) !=
+ cond->n_true_cnd;
+}
+
+/* Returnes an empty allocated session's condition state holder */
+struct ovsdb_monitor_session_condition *
+ovsdb_monitor_session_condition_create(void)
+{
+ struct ovsdb_monitor_session_condition *condition =
+ xzalloc(sizeof *condition);
+
+ condition->conditional = false;
+ shash_init(&condition->tables);
+ return condition;
+}
+
+void
+ovsdb_monitor_session_condition_destroy(
+ struct ovsdb_monitor_session_condition *condition)
+{
+ struct shash_node *node, *next;
+
+ if (!condition) {
+ return;
+ }
+
+ SHASH_FOR_EACH_SAFE (node, next, &condition->tables) {
+ struct ovsdb_monitor_table_condition *mtc = node->data;
+
+ ovsdb_condition_destroy(&mtc->new_condition);
+ ovsdb_condition_destroy(&mtc->old_condition);
+ shash_delete(&condition->tables, node);
+ free(mtc);
+ }
+ free(condition);
+}
+
+struct ovsdb_error *
+ovsdb_monitor_table_condition_create(
+ struct ovsdb_monitor_session_condition *condition,
+ const struct ovsdb_table *table,
+ const struct json *json_cnd)
+{
+ struct ovsdb_monitor_table_condition *mtc;
+ struct ovsdb_error *error;
+
+ mtc = xzalloc(sizeof *mtc);
+ mtc->table = table;
+ ovsdb_condition_init(&mtc->old_condition);
+ ovsdb_condition_init(&mtc->new_condition);
+
+ if (json_cnd) {
+ error = ovsdb_condition_from_json(table->schema,
+ json_cnd,
+ NULL,
+ &mtc->old_condition);
+ if (error) {
+ free(mtc);
+ return error;
+ }
+ }
+
+ shash_add(&condition->tables, table->schema->name, mtc);
+ /* On session startup old == new condition */
+ ovsdb_condition_clone(&mtc->new_condition, &mtc->old_condition);
+ if (ovsdb_condition_is_true(&mtc->old_condition)) {
+ condition->n_true_cnd++;
+ ovsdb_monitor_session_condition_set_mode(condition);
+ }
+
+ return NULL;
+}
+
+static bool
+ovsdb_monitor_get_table_conditions(
+ const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_session_condition *condition,
+ struct ovsdb_condition **old_condition,
+ struct ovsdb_condition **new_condition)
+{
+ if (!condition) {
+ return false;
+ }
+
+ struct ovsdb_monitor_table_condition *mtc =
+ shash_find_data(&condition->tables, mt->table->schema->name);
+
+ if (!mtc) {
+ return false;
+ }
+ *old_condition = &mtc->old_condition;
+ *new_condition = &mtc->new_condition;
+
+ return true;
+}
+
+static enum ovsdb_monitor_selection
+ovsdb_monitor_row_update_type_condition(
+ const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_session_condition *condition,
+ bool initial,
+ const struct ovsdb_datum *old,
+ const struct ovsdb_datum *new)
+{
+ struct ovsdb_condition *old_condition, *new_condition;
+ enum ovsdb_monitor_selection type =
+ ovsdb_monitor_row_update_type(initial, old, new);
+
+ if (ovsdb_monitor_get_table_conditions(mt,
+ condition,
+ &old_condition,
+ &new_condition)) {
+ bool old_cond = !old ? false
+ : ovsdb_condition_empty_or_match_any(old,
+ old_condition,
+ mt->columns_index_map);
+ bool new_cond = !new ? false
+ : ovsdb_condition_empty_or_match_any(new,
+ new_condition,
+ mt->columns_index_map);
+
+ if (!old_cond && !new_cond) {
+ type = OJMS_NONE;
+ }
+
+ switch (type) {
+ case OJMS_INITIAL:
+ case OJMS_INSERT:
+ if (!new_cond) {
+ type = OJMS_NONE;
+ }
+ break;
+ case OJMS_MODIFY:
+ type = !old_cond ? OJMS_INSERT : !new_cond
+ ? OJMS_DELETE : OJMS_MODIFY;
+ break;
+ case OJMS_DELETE:
+ if (!old_cond) {
+ type = OJMS_NONE;
+ }
+ break;
+ case OJMS_NONE:
+ break;
+ }
+ }
+ return type;
+}
+