]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/monitor.c
ovsdb-monitor: Refactor ovsdb monitor implementation.
[mirror_ovs.git] / ovsdb / monitor.c
CommitLineData
2fa1df7b 1/*
c1efab9b 2 * Copyright (c) 2015, 2017 Nicira, Inc.
2fa1df7b
AZ
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include <errno.h>
20
21#include "bitmap.h"
22#include "column.h"
3e8a2ad1 23#include "openvswitch/dynamic-string.h"
ee89ea7b 24#include "openvswitch/json.h"
2fa1df7b
AZ
25#include "jsonrpc.h"
26#include "ovsdb-error.h"
27#include "ovsdb-parser.h"
28#include "ovsdb.h"
29#include "row.h"
71cdf7cd 30#include "condition.h"
2fa1df7b 31#include "simap.h"
7e911055 32#include "hash.h"
2fa1df7b 33#include "table.h"
6e5a9216 34#include "hash.h"
2fa1df7b
AZ
35#include "timeval.h"
36#include "transaction.h"
37#include "jsonrpc-server.h"
38#include "monitor.h"
ee89ea7b 39#include "util.h"
2fa1df7b
AZ
40#include "openvswitch/vlog.h"
41
71cdf7cd 42VLOG_DEFINE_THIS_MODULE(ovsdb_monitor);
2fa1df7b 43
6e5a9216 44static struct hmap ovsdb_monitors = HMAP_INITIALIZER(&ovsdb_monitors);
2fa1df7b 45
71cdf7cd
LS
46/* Keep state of session's conditions */
47struct ovsdb_monitor_session_condition {
e4ef6881 48 bool conditional; /* True iff every table's condition is true. */
71cdf7cd
LS
49 struct shash tables; /* Contains
50 * "struct ovsdb_monitor_table_condition *"s. */
51};
52
53/* Monitored table session's conditions */
54struct ovsdb_monitor_table_condition {
55 const struct ovsdb_table *table;
56 struct ovsdb_monitor_table *mt;
57 struct ovsdb_condition old_condition;
58 struct ovsdb_condition new_condition;
59};
60
2fa1df7b
AZ
61/* Backend monitor.
62 *
63 * ovsdb_monitor keep track of the ovsdb changes.
64 */
65
66/* A collection of tables being monitored. */
67struct ovsdb_monitor {
009bf21f 68 struct ovs_list list_node; /* In struct ovsdb's "monitors" list. */
2fa1df7b 69 struct shash tables; /* Holds "struct ovsdb_monitor_table"s. */
d9412837 70 struct ovs_list jsonrpc_monitors; /* Contains "jsonrpc_monitor_node"s. */
2fa1df7b 71 struct ovsdb *db;
222bed54
HZ
72
73 /* Contains "ovsdb_monitor_change_set". Each change set contains changes
74 * from some start point up to the latest committed transaction. There can
75 * be different change sets for the same struct ovsdb_monitor because there
76 * are different clients pending on changes starting from different points.
77 * The different change sets are maintained as a list. */
78 struct ovs_list change_sets;
79
80 /* The new change set that is to be populated for future transactions. */
81 struct ovsdb_monitor_change_set *new_change_set;
82
83 /* The change set that starts from the first transaction of the DB, which
84 * is used for populating the initial data for new clients. */
85 struct ovsdb_monitor_change_set *init_change_set;
86
87 struct hmap_node hmap_node; /* Elements within ovsdb_monitors. */
88 struct hmap json_cache; /* Contains "ovsdb_monitor_json_cache_node"s.*/
4c280978
AZ
89};
90
222bed54
HZ
91/* A json object of updates for the ovsdb_monitor_change_set and the given
92 * monitor version. */
4c280978
AZ
93struct ovsdb_monitor_json_cache_node {
94 struct hmap_node hmap_node; /* Elements in json cache. */
a32b4433 95 enum ovsdb_monitor_version version;
222bed54 96 struct uuid change_set_uuid;
4c280978 97 struct json *json; /* Null, or a cloned of json */
2fa1df7b
AZ
98};
99
d9412837 100struct jsonrpc_monitor_node {
d9412837 101 struct ovs_list node;
ad376c93 102 struct ovsdb_jsonrpc_monitor *jsonrpc_monitor;
d9412837
AZ
103};
104
2fa1df7b
AZ
105/* A particular column being monitored. */
106struct ovsdb_monitor_column {
107 const struct ovsdb_column *column;
108 enum ovsdb_monitor_selection select;
6150a75f 109 bool monitored;
2fa1df7b
AZ
110};
111
112/* A row that has changed in a monitored table. */
113struct ovsdb_monitor_row {
222bed54 114 struct hmap_node hmap_node; /* In ovsdb_monitor_change_set_for_table. */
2fa1df7b
AZ
115 struct uuid uuid; /* UUID of row that changed. */
116 struct ovsdb_datum *old; /* Old data, NULL for an inserted row. */
117 struct ovsdb_datum *new; /* New data, NULL for a deleted row. */
118};
119
222bed54
HZ
120/* Contains a set of changes that are not yet flushed to all the jsonrpc
121 * connections.
1158f320 122 *
222bed54
HZ
123 * 'n_refs' represent the number of jsonrpc connections that depend on this
124 * change set (have not received updates). Generate the update for the last
125 * jsonprc connection will also destroy the whole "struct
126 * ovsdb_monitor_change_set" object.
127 */
128struct ovsdb_monitor_change_set {
129 /* Element in change_sets of ovsdb_monitor. */
130 struct ovs_list list_node;
131
132 /* Internally generated uuid that identifies this data structure. */
133 struct uuid uuid;
134
135 /* Contains struct ovsdb_monitor_change_set_for_table. */
136 struct ovs_list change_set_for_tables;
137
138 int n_refs;
139};
140
141/* Contains 'struct ovsdb_monitor_row's for rows in a specific table
142 * of struct ovsdb_monitor_change_set. It can also be searched from
143 * member 'change_sets' of struct ovsdb_monitor_table. */
144struct ovsdb_monitor_change_set_for_table {
145 /* Element in ovsdb_monitor_tables' change_sets list. */
146 struct ovs_list list_in_mt;
147
148 /* Element in ovsdb_monitor_change_sets' change_set_for_tables list. */
149 struct ovs_list list_in_change_set;
150
1158f320 151 struct ovsdb_monitor_table *mt;
222bed54
HZ
152 struct ovsdb_monitor_change_set *mcs;
153
154 /* Contains struct ovsdb_monitor_row. */
1158f320 155 struct hmap rows;
e0f42d4a
HZ
156
157 /* Save the mt->n_columns that is used when creating the changes.
158 * It can be different from the current mt->n_columns because
159 * mt->n_columns can be increased when there are condition changes
160 * from any of the clients sharing the dbmon. */
161 size_t n_columns;
1158f320
AZ
162};
163
2fa1df7b
AZ
164/* A particular table being monitored. */
165struct ovsdb_monitor_table {
166 const struct ovsdb_table *table;
167
168 /* This is the union (bitwise-OR) of the 'select' values in all of the
169 * members of 'columns' below. */
170 enum ovsdb_monitor_selection select;
171
172 /* Columns being monitored. */
173 struct ovsdb_monitor_column *columns;
174 size_t n_columns;
6150a75f
LS
175 size_t n_monitored_columns;
176 size_t allocated_columns;
2fa1df7b 177
ec1eadce
LS
178 /* Columns in ovsdb_monitor_row have different indexes then in
179 * ovsdb_row. This field maps between column->index to the index in the
180 * ovsdb_monitor_row. It is used for condition evaluation. */
181 unsigned int *columns_index_map;
182
222bed54
HZ
183 /* Contains 'ovsdb_monitor_change_set_for_table'. */
184 struct ovs_list change_sets;
2fa1df7b
AZ
185};
186
845a1187
LS
187enum ovsdb_monitor_row_type {
188 OVSDB_ROW,
189 OVSDB_MONITOR_ROW
190};
191
52553aea 192typedef struct json *
71cdf7cd
LS
193(*compose_row_update_cb_func)
194 (const struct ovsdb_monitor_table *mt,
195 const struct ovsdb_monitor_session_condition * condition,
845a1187
LS
196 enum ovsdb_monitor_row_type row_type,
197 const void *,
e0f42d4a
HZ
198 bool initial, unsigned long int *changed,
199 size_t n_columns);
52553aea 200
be084595 201static void ovsdb_monitor_destroy(struct ovsdb_monitor *);
222bed54
HZ
202static struct ovsdb_monitor_change_set * ovsdb_monitor_add_change_set(
203 struct ovsdb_monitor *, bool init_only);
204static void ovsdb_monitor_change_set_destroy(
205 struct ovsdb_monitor_change_set *);
206static void ovsdb_monitor_track_new_change_set(struct ovsdb_monitor *);
d9412837 207
a32b4433 208static uint32_t
222bed54
HZ
209json_cache_hash(enum ovsdb_monitor_version version,
210 struct ovsdb_monitor_change_set *change_set)
a32b4433 211{
222bed54 212 return hash_uint64_basis(version, uuid_hash(&change_set->uuid));
a32b4433
HZ
213}
214
4c280978
AZ
215static struct ovsdb_monitor_json_cache_node *
216ovsdb_monitor_json_cache_search(const struct ovsdb_monitor *dbmon,
a32b4433 217 enum ovsdb_monitor_version version,
222bed54 218 struct ovsdb_monitor_change_set *change_set)
4c280978
AZ
219{
220 struct ovsdb_monitor_json_cache_node *node;
222bed54 221 uint32_t hash = json_cache_hash(version, change_set);
4c280978
AZ
222
223 HMAP_FOR_EACH_WITH_HASH(node, hmap_node, hash, &dbmon->json_cache) {
222bed54
HZ
224 if (uuid_equals(&node->change_set_uuid, &change_set->uuid) &&
225 node->version == version) {
4c280978
AZ
226 return node;
227 }
228 }
229
230 return NULL;
231}
232
233static void
234ovsdb_monitor_json_cache_insert(struct ovsdb_monitor *dbmon,
a32b4433 235 enum ovsdb_monitor_version version,
222bed54
HZ
236 struct ovsdb_monitor_change_set *change_set,
237 struct json *json)
4c280978
AZ
238{
239 struct ovsdb_monitor_json_cache_node *node;
222bed54 240 uint32_t hash = json_cache_hash(version, change_set);
4c280978
AZ
241
242 node = xmalloc(sizeof *node);
243
a32b4433 244 node->version = version;
222bed54 245 node->change_set_uuid = change_set->uuid;
4c280978
AZ
246 node->json = json ? json_clone(json) : NULL;
247
248 hmap_insert(&dbmon->json_cache, &node->hmap_node, hash);
249}
250
251static void
252ovsdb_monitor_json_cache_flush(struct ovsdb_monitor *dbmon)
253{
4ec3d7c7 254 struct ovsdb_monitor_json_cache_node *node;
4c280978 255
4ec3d7c7 256 HMAP_FOR_EACH_POP(node, hmap_node, &dbmon->json_cache) {
4c280978
AZ
257 json_destroy(node->json);
258 free(node);
259 }
260}
261
222bed54
HZ
262/* Free all versions of json cache for a given change_set.*/
263static void
264ovsdb_monitor_json_cache_destroy(struct ovsdb_monitor *dbmon,
265 struct ovsdb_monitor_change_set *change_set)
266{
267 enum ovsdb_monitor_version v;
268 for (v = OVSDB_MONITOR_V1; v < OVSDB_MONITOR_VERSION_MAX; v++) {
269 struct ovsdb_monitor_json_cache_node *node
270 = ovsdb_monitor_json_cache_search(dbmon, v, change_set);
271 if (node) {
272 hmap_remove(&dbmon->json_cache, &node->hmap_node);
273 json_destroy(node->json);
274 free(node);
275 }
276 }
277}
278
2fa1df7b
AZ
279static int
280compare_ovsdb_monitor_column(const void *a_, const void *b_)
281{
282 const struct ovsdb_monitor_column *a = a_;
283 const struct ovsdb_monitor_column *b = b_;
284
6150a75f
LS
285 /* put all monitored columns at the begining */
286 if (a->monitored != b->monitored) {
287 return a->monitored ? -1 : 1;
288 }
289
2fa1df7b
AZ
290 return a->column < b->column ? -1 : a->column > b->column;
291}
292
1158f320 293/* Finds and returns the ovsdb_monitor_row in 'mt->changes->rows' for the
2fa1df7b
AZ
294 * given 'uuid', or NULL if there is no such row. */
295static struct ovsdb_monitor_row *
222bed54
HZ
296ovsdb_monitor_changes_row_find(
297 const struct ovsdb_monitor_change_set_for_table *changes,
298 const struct uuid *uuid)
2fa1df7b
AZ
299{
300 struct ovsdb_monitor_row *row;
301
1158f320 302 HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid),
7e911055 303 &changes->rows) {
2fa1df7b
AZ
304 if (uuid_equals(uuid, &row->uuid)) {
305 return row;
306 }
307 }
308 return NULL;
309}
310
e0f42d4a 311/* Allocates an array of 'n_columns' ovsdb_datums and initializes them as
2fa1df7b
AZ
312 * copies of the data in 'row' drawn from the columns represented by
313 * mt->columns[]. Returns the array.
314 *
315 * If 'row' is NULL, returns NULL. */
316static struct ovsdb_datum *
317clone_monitor_row_data(const struct ovsdb_monitor_table *mt,
e0f42d4a
HZ
318 const struct ovsdb_row *row,
319 size_t n_columns)
2fa1df7b
AZ
320{
321 struct ovsdb_datum *data;
322 size_t i;
323
324 if (!row) {
325 return NULL;
326 }
327
e0f42d4a
HZ
328 data = xmalloc(n_columns * sizeof *data);
329 for (i = 0; i < n_columns; i++) {
2fa1df7b
AZ
330 const struct ovsdb_column *c = mt->columns[i].column;
331 const struct ovsdb_datum *src = &row->fields[c->index];
332 struct ovsdb_datum *dst = &data[i];
333 const struct ovsdb_type *type = &c->type;
334
335 ovsdb_datum_clone(dst, src, type);
336 }
337 return data;
338}
339
e0f42d4a 340/* Replaces the n_columns ovsdb_datums in row[] by copies of the data from
2fa1df7b
AZ
341 * in 'row' drawn from the columns represented by mt->columns[]. */
342static void
343update_monitor_row_data(const struct ovsdb_monitor_table *mt,
344 const struct ovsdb_row *row,
e0f42d4a
HZ
345 struct ovsdb_datum *data,
346 size_t n_columns)
2fa1df7b
AZ
347{
348 size_t i;
349
e0f42d4a 350 for (i = 0; i < n_columns; i++) {
2fa1df7b
AZ
351 const struct ovsdb_column *c = mt->columns[i].column;
352 const struct ovsdb_datum *src = &row->fields[c->index];
353 struct ovsdb_datum *dst = &data[i];
354 const struct ovsdb_type *type = &c->type;
355
356 if (!ovsdb_datum_equals(src, dst, type)) {
357 ovsdb_datum_destroy(dst, type);
358 ovsdb_datum_clone(dst, src, type);
359 }
360 }
361}
362
e0f42d4a 363/* Frees all of the n_columns ovsdb_datums in data[], using the types taken
2fa1df7b
AZ
364 * from mt->columns[], plus 'data' itself. */
365static void
366free_monitor_row_data(const struct ovsdb_monitor_table *mt,
e0f42d4a
HZ
367 struct ovsdb_datum *data,
368 size_t n_columns)
2fa1df7b
AZ
369{
370 if (data) {
371 size_t i;
372
e0f42d4a 373 for (i = 0; i < n_columns; i++) {
2fa1df7b
AZ
374 const struct ovsdb_column *c = mt->columns[i].column;
375
376 ovsdb_datum_destroy(&data[i], &c->type);
377 }
378 free(data);
379 }
380}
381
382/* Frees 'row', which must have been created from 'mt'. */
383static void
384ovsdb_monitor_row_destroy(const struct ovsdb_monitor_table *mt,
e0f42d4a
HZ
385 struct ovsdb_monitor_row *row,
386 size_t n_columns)
2fa1df7b
AZ
387{
388 if (row) {
e0f42d4a
HZ
389 free_monitor_row_data(mt, row->old, n_columns);
390 free_monitor_row_data(mt, row->new, n_columns);
2fa1df7b
AZ
391 free(row);
392 }
393}
394
ec1eadce
LS
395static void
396ovsdb_monitor_columns_sort(struct ovsdb_monitor *dbmon)
397{
398 int i;
399 struct shash_node *node;
400
401 SHASH_FOR_EACH (node, &dbmon->tables) {
402 struct ovsdb_monitor_table *mt = node->data;
403
404 qsort(mt->columns, mt->n_columns, sizeof *mt->columns,
405 compare_ovsdb_monitor_column);
406 for (i = 0; i < mt->n_columns; i++) {
407 /* re-set index map due to sort */
408 mt->columns_index_map[mt->columns[i].column->index] = i;
409 }
410 }
411}
412
6e5a9216 413void
36247a75
AZ
414ovsdb_monitor_add_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
415 struct ovsdb_jsonrpc_monitor *jsonrpc_monitor)
416{
417 struct jsonrpc_monitor_node *jm;
418
419 jm = xzalloc(sizeof *jm);
420 jm->jsonrpc_monitor = jsonrpc_monitor;
417e7e66 421 ovs_list_push_back(&dbmon->jsonrpc_monitors, &jm->node);
36247a75
AZ
422}
423
2fa1df7b
AZ
424struct ovsdb_monitor *
425ovsdb_monitor_create(struct ovsdb *db,
426 struct ovsdb_jsonrpc_monitor *jsonrpc_monitor)
427{
428 struct ovsdb_monitor *dbmon;
429
430 dbmon = xzalloc(sizeof *dbmon);
431
009bf21f 432 ovs_list_push_back(&db->monitors, &dbmon->list_node);
417e7e66 433 ovs_list_init(&dbmon->jsonrpc_monitors);
2fa1df7b 434 dbmon->db = db;
222bed54 435 ovs_list_init(&dbmon->change_sets);
2fa1df7b 436 shash_init(&dbmon->tables);
6e5a9216 437 hmap_node_nullify(&dbmon->hmap_node);
4c280978 438 hmap_init(&dbmon->json_cache);
2fa1df7b 439
36247a75 440 ovsdb_monitor_add_jsonrpc_monitor(dbmon, jsonrpc_monitor);
2fa1df7b
AZ
441 return dbmon;
442}
443
444void
445ovsdb_monitor_add_table(struct ovsdb_monitor *m,
446 const struct ovsdb_table *table)
447{
448 struct ovsdb_monitor_table *mt;
ec1eadce
LS
449 int i;
450 size_t n_columns = shash_count(&table->schema->columns);
2fa1df7b
AZ
451
452 mt = xzalloc(sizeof *mt);
453 mt->table = table;
2fa1df7b 454 shash_add(&m->tables, table->schema->name, mt);
222bed54 455 ovs_list_init(&mt->change_sets);
ec1eadce
LS
456 mt->columns_index_map =
457 xmalloc(sizeof *mt->columns_index_map * n_columns);
458 for (i = 0; i < n_columns; i++) {
459 mt->columns_index_map[i] = -1;
460 }
2fa1df7b
AZ
461}
462
ec1eadce 463const char *
2fa1df7b
AZ
464ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
465 const struct ovsdb_table *table,
466 const struct ovsdb_column *column,
467 enum ovsdb_monitor_selection select,
6150a75f 468 bool monitored)
2fa1df7b
AZ
469{
470 struct ovsdb_monitor_table *mt;
471 struct ovsdb_monitor_column *c;
472
473 mt = shash_find_data(&dbmon->tables, table->schema->name);
474
ec1eadce
LS
475 /* Check for column duplication. Return duplicated column name. */
476 if (mt->columns_index_map[column->index] != -1) {
477 return column->name;
478 }
479
6150a75f
LS
480 if (mt->n_columns >= mt->allocated_columns) {
481 mt->columns = x2nrealloc(mt->columns, &mt->allocated_columns,
2fa1df7b
AZ
482 sizeof *mt->columns);
483 }
484
485 mt->select |= select;
ec1eadce 486 mt->columns_index_map[column->index] = mt->n_columns;
2fa1df7b
AZ
487 c = &mt->columns[mt->n_columns++];
488 c->column = column;
489 c->select = select;
6150a75f
LS
490 c->monitored = monitored;
491 if (monitored) {
492 mt->n_monitored_columns++;
493 }
2fa1df7b
AZ
494
495 return NULL;
496}
497
71cdf7cd
LS
498static void
499ovsdb_monitor_condition_add_columns(struct ovsdb_monitor *dbmon,
500 const struct ovsdb_table *table,
501 struct ovsdb_condition *condition)
502{
503 size_t n_columns;
504 int i;
505 const struct ovsdb_column **columns =
506 ovsdb_condition_get_columns(condition, &n_columns);
507
508 for (i = 0; i < n_columns; i++) {
509 ovsdb_monitor_add_column(dbmon, table, columns[i],
510 OJMS_NONE, false);
511 }
512
513 free(columns);
514}
515
516/* Bind this session's condition to ovsdb_monitor */
517void
518ovsdb_monitor_condition_bind(struct ovsdb_monitor *dbmon,
519 struct ovsdb_monitor_session_condition *cond)
520{
521 struct shash_node *node;
522
523 SHASH_FOR_EACH(node, &cond->tables) {
524 struct ovsdb_monitor_table_condition *mtc = node->data;
525 struct ovsdb_monitor_table *mt =
526 shash_find_data(&dbmon->tables, mtc->table->schema->name);
527
528 mtc->mt = mt;
529 ovsdb_monitor_condition_add_columns(dbmon, mtc->table,
530 &mtc->new_condition);
531 }
532}
533
845a1187
LS
534bool
535ovsdb_monitor_table_exists(struct ovsdb_monitor *m,
536 const struct ovsdb_table *table)
537{
538 return shash_find_data(&m->tables, table->schema->name);
539}
540
222bed54
HZ
541static struct ovsdb_monitor_change_set *
542ovsdb_monitor_add_change_set(struct ovsdb_monitor *dbmon,
543 bool init_only)
1158f320 544{
222bed54
HZ
545 struct ovsdb_monitor_change_set *change_set = xzalloc(sizeof *change_set);
546 change_set->uuid = uuid_random();
547 ovs_list_push_back(&(dbmon->change_sets), &change_set->list_node);
548 ovs_list_init(&change_set->change_set_for_tables);
549 change_set->n_refs = 1;
6e5a9216 550
222bed54
HZ
551 struct shash_node *node;
552 SHASH_FOR_EACH (node, &dbmon->tables) {
553 struct ovsdb_monitor_table *mt = node->data;
554 if (!init_only || (mt->select & OJMS_INITIAL)) {
555 struct ovsdb_monitor_change_set_for_table *mcst =
556 xzalloc(sizeof *mcst);
557 mcst->mt = mt;
558 mcst->n_columns = mt->n_columns;
559 mcst->mcs = change_set;
560 hmap_init(&mcst->rows);
561 ovs_list_push_back(&mt->change_sets, &mcst->list_in_mt);
562 ovs_list_push_back(&change_set->change_set_for_tables,
563 &mcst->list_in_change_set);
7e911055
AZ
564 }
565 }
566
222bed54
HZ
567 return change_set;
568};
1158f320 569
1158f320 570static void
222bed54
HZ
571ovsdb_monitor_untrack_change_set(struct ovsdb_monitor *dbmon,
572 struct ovsdb_monitor_change_set *mcs)
1158f320 573{
222bed54
HZ
574 ovs_assert(mcs);
575 if (--mcs->n_refs == 0) {
576 if (mcs == dbmon->init_change_set) {
577 dbmon->init_change_set = NULL;
578 } else if (mcs == dbmon->new_change_set) {
579 dbmon->new_change_set = NULL;
1158f320 580 }
222bed54
HZ
581 ovsdb_monitor_json_cache_destroy(dbmon, mcs);
582 ovsdb_monitor_change_set_destroy(mcs);
1158f320
AZ
583 }
584}
585
1158f320 586static void
222bed54 587ovsdb_monitor_track_new_change_set(struct ovsdb_monitor *dbmon)
1158f320 588{
222bed54 589 struct ovsdb_monitor_change_set *change_set = dbmon->new_change_set;
7e911055 590
222bed54
HZ
591 if (change_set) {
592 change_set->n_refs++;
7e911055 593 } else {
222bed54
HZ
594 change_set = ovsdb_monitor_add_change_set(dbmon, false);
595 dbmon->new_change_set = change_set;
7e911055 596 }
1158f320
AZ
597}
598
599static void
222bed54 600ovsdb_monitor_change_set_destroy(struct ovsdb_monitor_change_set *mcs)
1158f320 601{
222bed54 602 ovs_list_remove(&mcs->list_node);
1158f320 603
222bed54
HZ
604 struct ovsdb_monitor_change_set_for_table *mcst, *next_mcst;
605 LIST_FOR_EACH_SAFE (mcst, next_mcst, list_in_change_set,
606 &mcs->change_set_for_tables) {
607 ovs_list_remove(&mcst->list_in_change_set);
608 ovs_list_remove(&mcst->list_in_mt);
609
610 struct ovsdb_monitor_row *row, *next;
611 HMAP_FOR_EACH_SAFE (row, next, hmap_node, &mcst->rows) {
612 hmap_remove(&mcst->rows, &row->hmap_node);
613 ovsdb_monitor_row_destroy(mcst->mt, row, mcst->n_columns);
614 }
615 hmap_destroy(&mcst->rows);
616
617 free(mcst);
1158f320 618 }
222bed54 619 free(mcs);
1158f320
AZ
620}
621
23cbedb7
AZ
622static enum ovsdb_monitor_selection
623ovsdb_monitor_row_update_type(bool initial, const bool old, const bool new)
624{
625 return initial ? OJMS_INITIAL
626 : !old ? OJMS_INSERT
627 : !new ? OJMS_DELETE
628 : OJMS_MODIFY;
629}
71cdf7cd
LS
630
631/* Set conditional monitoring mode only if we have non-empty condition in one
632 * of the tables at least */
633static inline void
634ovsdb_monitor_session_condition_set_mode(
635 struct ovsdb_monitor_session_condition *cond)
636{
e4ef6881
BP
637 struct shash_node *node;
638
639 SHASH_FOR_EACH (node, &cond->tables) {
640 struct ovsdb_monitor_table_condition *mtc = node->data;
641
642 if (!ovsdb_condition_is_true(&mtc->new_condition)) {
643 cond->conditional = true;
644 return;
645 }
646 }
647 cond->conditional = false;
71cdf7cd
LS
648}
649
650/* Returnes an empty allocated session's condition state holder */
651struct ovsdb_monitor_session_condition *
652ovsdb_monitor_session_condition_create(void)
653{
654 struct ovsdb_monitor_session_condition *condition =
655 xzalloc(sizeof *condition);
656
657 condition->conditional = false;
658 shash_init(&condition->tables);
659 return condition;
660}
661
662void
663ovsdb_monitor_session_condition_destroy(
664 struct ovsdb_monitor_session_condition *condition)
665{
666 struct shash_node *node, *next;
667
668 if (!condition) {
669 return;
670 }
671
672 SHASH_FOR_EACH_SAFE (node, next, &condition->tables) {
673 struct ovsdb_monitor_table_condition *mtc = node->data;
674
675 ovsdb_condition_destroy(&mtc->new_condition);
676 ovsdb_condition_destroy(&mtc->old_condition);
677 shash_delete(&condition->tables, node);
678 free(mtc);
679 }
d3c8a7e8 680 shash_destroy(&condition->tables);
71cdf7cd
LS
681 free(condition);
682}
683
684struct ovsdb_error *
685ovsdb_monitor_table_condition_create(
686 struct ovsdb_monitor_session_condition *condition,
687 const struct ovsdb_table *table,
688 const struct json *json_cnd)
689{
690 struct ovsdb_monitor_table_condition *mtc;
691 struct ovsdb_error *error;
692
693 mtc = xzalloc(sizeof *mtc);
694 mtc->table = table;
695 ovsdb_condition_init(&mtc->old_condition);
696 ovsdb_condition_init(&mtc->new_condition);
697
698 if (json_cnd) {
699 error = ovsdb_condition_from_json(table->schema,
700 json_cnd,
701 NULL,
702 &mtc->old_condition);
703 if (error) {
704 free(mtc);
705 return error;
706 }
707 }
708
709 shash_add(&condition->tables, table->schema->name, mtc);
710 /* On session startup old == new condition */
711 ovsdb_condition_clone(&mtc->new_condition, &mtc->old_condition);
5707b87d 712 ovsdb_monitor_session_condition_set_mode(condition);
71cdf7cd
LS
713
714 return NULL;
715}
716
717static bool
718ovsdb_monitor_get_table_conditions(
719 const struct ovsdb_monitor_table *mt,
720 const struct ovsdb_monitor_session_condition *condition,
721 struct ovsdb_condition **old_condition,
722 struct ovsdb_condition **new_condition)
723{
724 if (!condition) {
725 return false;
726 }
727
728 struct ovsdb_monitor_table_condition *mtc =
729 shash_find_data(&condition->tables, mt->table->schema->name);
730
731 if (!mtc) {
732 return false;
733 }
734 *old_condition = &mtc->old_condition;
735 *new_condition = &mtc->new_condition;
736
737 return true;
738}
739
845a1187
LS
740struct ovsdb_error *
741ovsdb_monitor_table_condition_update(
742 struct ovsdb_monitor *dbmon,
743 struct ovsdb_monitor_session_condition *condition,
744 const struct ovsdb_table *table,
745 const struct json *cond_json)
746{
c1efab9b
BP
747 if (!condition) {
748 return NULL;
749 }
750
845a1187
LS
751 struct ovsdb_monitor_table_condition *mtc =
752 shash_find_data(&condition->tables, table->schema->name);
753 struct ovsdb_error *error;
f0d7ae19 754 struct ovsdb_condition cond = OVSDB_CONDITION_INITIALIZER(&cond);
845a1187 755
845a1187
LS
756 error = ovsdb_condition_from_json(table->schema, cond_json,
757 NULL, &cond);
758 if (error) {
759 return error;
760 }
761 ovsdb_condition_destroy(&mtc->new_condition);
762 ovsdb_condition_clone(&mtc->new_condition, &cond);
763 ovsdb_condition_destroy(&cond);
764 ovsdb_monitor_condition_add_columns(dbmon,
765 table,
766 &mtc->new_condition);
767
768 return NULL;
769}
770
771static void
772ovsdb_monitor_table_condition_updated(struct ovsdb_monitor_table *mt,
773 struct ovsdb_monitor_session_condition *condition)
774{
775 struct ovsdb_monitor_table_condition *mtc =
776 shash_find_data(&condition->tables, mt->table->schema->name);
777
778 if (mtc) {
779 /* If conditional monitoring - set old condition to new condition */
780 if (ovsdb_condition_cmp_3way(&mtc->old_condition,
781 &mtc->new_condition)) {
845a1187
LS
782 ovsdb_condition_destroy(&mtc->old_condition);
783 ovsdb_condition_clone(&mtc->old_condition, &mtc->new_condition);
784 ovsdb_monitor_session_condition_set_mode(condition);
785 }
786 }
787}
788
71cdf7cd
LS
789static enum ovsdb_monitor_selection
790ovsdb_monitor_row_update_type_condition(
791 const struct ovsdb_monitor_table *mt,
792 const struct ovsdb_monitor_session_condition *condition,
793 bool initial,
845a1187 794 enum ovsdb_monitor_row_type row_type,
71cdf7cd
LS
795 const struct ovsdb_datum *old,
796 const struct ovsdb_datum *new)
797{
798 struct ovsdb_condition *old_condition, *new_condition;
799 enum ovsdb_monitor_selection type =
800 ovsdb_monitor_row_update_type(initial, old, new);
801
802 if (ovsdb_monitor_get_table_conditions(mt,
803 condition,
804 &old_condition,
805 &new_condition)) {
806 bool old_cond = !old ? false
807 : ovsdb_condition_empty_or_match_any(old,
845a1187
LS
808 old_condition,
809 row_type == OVSDB_MONITOR_ROW ?
810 mt->columns_index_map :
811 NULL);
71cdf7cd
LS
812 bool new_cond = !new ? false
813 : ovsdb_condition_empty_or_match_any(new,
845a1187
LS
814 new_condition,
815 row_type == OVSDB_MONITOR_ROW ?
816 mt->columns_index_map :
817 NULL);
71cdf7cd
LS
818
819 if (!old_cond && !new_cond) {
820 type = OJMS_NONE;
821 }
822
823 switch (type) {
824 case OJMS_INITIAL:
825 case OJMS_INSERT:
826 if (!new_cond) {
827 type = OJMS_NONE;
828 }
829 break;
830 case OJMS_MODIFY:
831 type = !old_cond ? OJMS_INSERT : !new_cond
832 ? OJMS_DELETE : OJMS_MODIFY;
833 break;
834 case OJMS_DELETE:
835 if (!old_cond) {
836 type = OJMS_NONE;
837 }
838 break;
839 case OJMS_NONE:
840 break;
841 }
842 }
843 return type;
844}
845
52553aea
AZ
846static bool
847ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt,
845a1187
LS
848 enum ovsdb_monitor_row_type row_type,
849 const struct ovsdb_datum *old,
850 const struct ovsdb_datum *new,
52553aea 851 enum ovsdb_monitor_selection type,
e0f42d4a
HZ
852 unsigned long int *changed,
853 size_t n_columns)
52553aea
AZ
854{
855 if (!(mt->select & type)) {
856 return true;
857 }
858
859 if (type == OJMS_MODIFY) {
860 size_t i, n_changes;
861
862 n_changes = 0;
e0f42d4a
HZ
863 memset(changed, 0, bitmap_n_bytes(n_columns));
864 for (i = 0; i < n_columns; i++) {
52553aea 865 const struct ovsdb_column *c = mt->columns[i].column;
845a1187
LS
866 size_t index = row_type == OVSDB_ROW ? c->index : i;
867 if (!ovsdb_datum_equals(&old[index], &new[index], &c->type)) {
52553aea
AZ
868 bitmap_set1(changed, i);
869 n_changes++;
870 }
871 }
872 if (!n_changes) {
873 /* No actual changes: presumably a row changed and then
874 * changed back later. */
875 return true;
876 }
877 }
878
879 return false;
880}
23cbedb7 881
2fa1df7b
AZ
882/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
883 * 'mt', or NULL if no row update should be sent.
884 *
885 * The caller should specify 'initial' as true if the returned JSON is going to
886 * be used as part of the initial reply to a "monitor" request, false if it is
887 * going to be used as part of an "update" notification.
888 *
889 * 'changed' must be a scratch buffer for internal use that is at least
e0f42d4a 890 * bitmap_n_bytes(n_columns) bytes long. */
2fa1df7b
AZ
891static struct json *
892ovsdb_monitor_compose_row_update(
893 const struct ovsdb_monitor_table *mt,
71cdf7cd 894 const struct ovsdb_monitor_session_condition *condition OVS_UNUSED,
845a1187
LS
895 enum ovsdb_monitor_row_type row_type OVS_UNUSED,
896 const void *_row,
e0f42d4a
HZ
897 bool initial, unsigned long int *changed,
898 size_t n_columns OVS_UNUSED)
2fa1df7b 899{
845a1187 900 const struct ovsdb_monitor_row *row = _row;
2fa1df7b
AZ
901 enum ovsdb_monitor_selection type;
902 struct json *old_json, *new_json;
903 struct json *row_json;
904 size_t i;
905
845a1187 906 ovs_assert(row_type == OVSDB_MONITOR_ROW);
23cbedb7 907 type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
845a1187 908 if (ovsdb_monitor_row_skip_update(mt, row_type, row->old,
e0f42d4a
HZ
909 row->new, type, changed,
910 mt->n_columns)) {
2fa1df7b
AZ
911 return NULL;
912 }
913
2fa1df7b
AZ
914 row_json = json_object_create();
915 old_json = new_json = NULL;
916 if (type & (OJMS_DELETE | OJMS_MODIFY)) {
917 old_json = json_object_create();
918 json_object_put(row_json, "old", old_json);
919 }
920 if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
921 new_json = json_object_create();
922 json_object_put(row_json, "new", new_json);
923 }
6150a75f 924 for (i = 0; i < mt->n_monitored_columns; i++) {
2fa1df7b
AZ
925 const struct ovsdb_monitor_column *c = &mt->columns[i];
926
6150a75f 927 if (!c->monitored || !(type & c->select)) {
2fa1df7b
AZ
928 /* We don't care about this type of change for this
929 * particular column (but we will care about it for some
930 * other column). */
931 continue;
932 }
933
934 if ((type == OJMS_MODIFY && bitmap_is_set(changed, i))
935 || type == OJMS_DELETE) {
936 json_object_put(old_json, c->column->name,
937 ovsdb_datum_to_json(&row->old[i],
938 &c->column->type));
939 }
940 if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
941 json_object_put(new_json, c->column->name,
942 ovsdb_datum_to_json(&row->new[i],
943 &c->column->type));
944 }
945 }
946
947 return row_json;
948}
949
52553aea
AZ
950/* Returns JSON for a <row-update2> (as described in ovsdb-server(1) mapage)
951 * for 'row' within * 'mt', or NULL if no row update should be sent.
952 *
953 * The caller should specify 'initial' as true if the returned JSON is
845a1187 954 * going to be used as part of the initial reply to a "monitor_cond" request,
52553aea
AZ
955 * false if it is going to be used as part of an "update2" notification.
956 *
957 * 'changed' must be a scratch buffer for internal use that is at least
e0f42d4a 958 * bitmap_n_bytes(n_columns) bytes long. */
52553aea
AZ
959static struct json *
960ovsdb_monitor_compose_row_update2(
961 const struct ovsdb_monitor_table *mt,
71cdf7cd 962 const struct ovsdb_monitor_session_condition *condition,
845a1187
LS
963 enum ovsdb_monitor_row_type row_type,
964 const void *_row,
e0f42d4a
HZ
965 bool initial, unsigned long int *changed,
966 size_t n_columns)
52553aea
AZ
967{
968 enum ovsdb_monitor_selection type;
969 struct json *row_update2, *diff_json;
845a1187 970 const struct ovsdb_datum *old, *new;
52553aea
AZ
971 size_t i;
972
845a1187
LS
973 if (row_type == OVSDB_MONITOR_ROW) {
974 old = ((const struct ovsdb_monitor_row *)_row)->old;;
975 new = ((const struct ovsdb_monitor_row *)_row)->new;
976 } else {
977 old = new = ((const struct ovsdb_row *)_row)->fields;
978 }
979
71cdf7cd 980 type = ovsdb_monitor_row_update_type_condition(mt, condition, initial,
845a1187 981 row_type, old, new);
e0f42d4a
HZ
982 if (ovsdb_monitor_row_skip_update(mt, row_type, old, new, type, changed,
983 n_columns)) {
52553aea
AZ
984 return NULL;
985 }
986
987 row_update2 = json_object_create();
988 if (type == OJMS_DELETE) {
989 json_object_put(row_update2, "delete", json_null_create());
990 } else {
991 diff_json = json_object_create();
992 const char *op;
993
6150a75f 994 for (i = 0; i < mt->n_monitored_columns; i++) {
52553aea 995 const struct ovsdb_monitor_column *c = &mt->columns[i];
845a1187 996 size_t index = row_type == OVSDB_ROW ? c->column->index : i;
6150a75f 997 if (!c->monitored || !(type & c->select)) {
52553aea
AZ
998 /* We don't care about this type of change for this
999 * particular column (but we will care about it for some
1000 * other column). */
1001 continue;
1002 }
1003
1004 if (type == OJMS_MODIFY) {
1005 struct ovsdb_datum diff;
1006
1007 if (!bitmap_is_set(changed, i)) {
1008 continue;
1009 }
1010
845a1187 1011 ovsdb_datum_diff(&diff ,&old[index], &new[index],
52553aea
AZ
1012 &c->column->type);
1013 json_object_put(diff_json, c->column->name,
1014 ovsdb_datum_to_json(&diff, &c->column->type));
1015 ovsdb_datum_destroy(&diff, &c->column->type);
1016 } else {
845a1187 1017 if (!ovsdb_datum_is_default(&new[index], &c->column->type)) {
52553aea 1018 json_object_put(diff_json, c->column->name,
845a1187 1019 ovsdb_datum_to_json(&new[index],
52553aea
AZ
1020 &c->column->type));
1021 }
1022 }
1023 }
1024
1025 op = type == OJMS_INITIAL ? "initial"
1026 : type == OJMS_MODIFY ? "modify" : "insert";
1027 json_object_put(row_update2, op, diff_json);
1028 }
1029
1030 return row_update2;
1031}
1032
6cef8e87
AZ
1033static size_t
1034ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon)
1035{
1036 struct shash_node *node;
1037 size_t max_columns = 0;
1038
1039 SHASH_FOR_EACH (node, &dbmon->tables) {
1040 struct ovsdb_monitor_table *mt = node->data;
1041
1042 max_columns = MAX(max_columns, mt->n_columns);
1043 }
1044
1045 return max_columns;
1046}
1047
845a1187
LS
1048static void
1049ovsdb_monitor_add_json_row(struct json **json, const char *table_name,
1050 struct json **table_json, struct json *row_json,
1051 const struct uuid *row_uuid)
1052{
1053 char uuid[UUID_LEN + 1];
1054
1055 /* Create JSON object for transaction overall. */
1056 if (!*json) {
1057 *json = json_object_create();
1058 }
1059
1060 /* Create JSON object for transaction on this table. */
1061 if (!*table_json) {
1062 *table_json = json_object_create();
1063 json_object_put(*json, table_name, *table_json);
1064 }
1065
1066 /* Add JSON row to JSON table. */
1067 snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(row_uuid));
1068 json_object_put(*table_json, uuid, row_json);
1069}
1070
2fa1df7b 1071/* Constructs and returns JSON for a <table-updates> object (as described in
4c280978
AZ
1072 * RFC 7047) for all the outstanding changes within 'monitor', starting from
1073 * 'transaction'. */
1074static struct json*
71cdf7cd
LS
1075ovsdb_monitor_compose_update(
1076 struct ovsdb_monitor *dbmon,
222bed54 1077 bool initial, struct ovsdb_monitor_change_set *mcs,
71cdf7cd
LS
1078 const struct ovsdb_monitor_session_condition *condition,
1079 compose_row_update_cb_func row_update)
2fa1df7b 1080{
2fa1df7b 1081 struct json *json;
6cef8e87
AZ
1082 size_t max_columns = ovsdb_monitor_max_columns(dbmon);
1083 unsigned long int *changed = xmalloc(bitmap_n_bytes(max_columns));
2fa1df7b
AZ
1084
1085 json = NULL;
222bed54
HZ
1086 struct ovsdb_monitor_change_set_for_table *mcst;
1087 LIST_FOR_EACH (mcst, list_in_change_set, &mcs->change_set_for_tables) {
2fa1df7b
AZ
1088 struct ovsdb_monitor_row *row, *next;
1089 struct json *table_json = NULL;
222bed54 1090 struct ovsdb_monitor_table *mt = mcst->mt;
2fa1df7b 1091
222bed54 1092 HMAP_FOR_EACH_SAFE (row, next, hmap_node, &mcst->rows) {
70ec021a
AS
1093 struct json *row_json;
1094 row_json = (*row_update)(mt, condition, OVSDB_MONITOR_ROW, row,
222bed54 1095 initial, changed, mcst->n_columns);
70ec021a
AS
1096 if (row_json) {
1097 ovsdb_monitor_add_json_row(&json, mt->table->schema->name,
1098 &table_json, row_json,
1099 &row->uuid);
1100 }
1101 }
1102 }
845a1187 1103 free(changed);
2fa1df7b 1104
845a1187
LS
1105 return json;
1106}
2fa1df7b 1107
845a1187
LS
1108static struct json*
1109ovsdb_monitor_compose_cond_change_update(
1110 struct ovsdb_monitor *dbmon,
1111 struct ovsdb_monitor_session_condition *condition)
1112{
1113 struct shash_node *node;
1114 struct json *json = NULL;
1115 size_t max_columns = ovsdb_monitor_max_columns(dbmon);
1116 unsigned long int *changed = xmalloc(bitmap_n_bytes(max_columns));
2fa1df7b 1117
845a1187
LS
1118 SHASH_FOR_EACH (node, &dbmon->tables) {
1119 struct ovsdb_monitor_table *mt = node->data;
1120 struct ovsdb_row *row;
1121 struct json *table_json = NULL;
1122 struct ovsdb_condition *old_condition, *new_condition;
1123
1124 if (!ovsdb_monitor_get_table_conditions(mt,
1125 condition,
1126 &old_condition,
1127 &new_condition) ||
1128 !ovsdb_condition_cmp_3way(old_condition, new_condition)) {
1129 /* Nothing to update on this table */
1130 continue;
1131 }
2fa1df7b 1132
845a1187
LS
1133 /* Iterate over all rows in table */
1134 HMAP_FOR_EACH (row, hmap_node, &mt->table->rows) {
1135 struct json *row_json;
1136
1137 row_json = ovsdb_monitor_compose_row_update2(mt, condition,
1138 OVSDB_ROW, row,
e0f42d4a
HZ
1139 false, changed,
1140 mt->n_columns);
845a1187
LS
1141 if (row_json) {
1142 ovsdb_monitor_add_json_row(&json, mt->table->schema->name,
1143 &table_json, row_json,
1144 ovsdb_row_get_uuid(row));
2fa1df7b 1145 }
2fa1df7b 1146 }
845a1187 1147 ovsdb_monitor_table_condition_updated(mt, condition);
4c280978
AZ
1148 }
1149 free(changed);
1150
1151 return json;
1152}
1153
1154/* Returns JSON for a <table-updates> object (as described in RFC 7047)
222bed54
HZ
1155 * for all the outstanding changes in dbmon that are tracked by the change set
1156 * *p_mcs.
1157 *
845a1187
LS
1158 * If cond_updated is true all rows in the db that match conditions will be
1159 * sent.
4c280978
AZ
1160 *
1161 * The caller should specify 'initial' as true if the returned JSON is going to
1162 * be used as part of the initial reply to a "monitor" request, false if it is
1163 * going to be used as part of an "update" notification. */
1164struct json *
71cdf7cd
LS
1165ovsdb_monitor_get_update(
1166 struct ovsdb_monitor *dbmon,
845a1187 1167 bool initial, bool cond_updated,
845a1187 1168 struct ovsdb_monitor_session_condition *condition,
be084595 1169 enum ovsdb_monitor_version version,
222bed54 1170 struct ovsdb_monitor_change_set **p_mcs)
4c280978 1171{
71cdf7cd 1172 struct ovsdb_monitor_json_cache_node *cache_node = NULL;
4c280978 1173 struct json *json;
222bed54 1174 struct ovsdb_monitor_change_set *mcs = *p_mcs;
4c280978 1175
222bed54 1176 ovs_assert(cond_updated ? mcs == dbmon->new_change_set : true);
845a1187 1177
4c280978
AZ
1178 /* Return a clone of cached json if one exists. Otherwise,
1179 * generate a new one and add it to the cache. */
845a1187 1180 if (!condition || (!condition->conditional && !cond_updated)) {
71cdf7cd 1181 cache_node = ovsdb_monitor_json_cache_search(dbmon, version,
222bed54 1182 mcs);
71cdf7cd 1183 }
4c280978
AZ
1184 if (cache_node) {
1185 json = cache_node->json ? json_clone(cache_node->json) : NULL;
1186 } else {
52553aea 1187 if (version == OVSDB_MONITOR_V1) {
71cdf7cd 1188 json =
222bed54 1189 ovsdb_monitor_compose_update(dbmon, initial, mcs,
71cdf7cd
LS
1190 condition,
1191 ovsdb_monitor_compose_row_update);
52553aea
AZ
1192 } else {
1193 ovs_assert(version == OVSDB_MONITOR_V2);
845a1187 1194 if (!cond_updated) {
222bed54 1195 json = ovsdb_monitor_compose_update(dbmon, initial, mcs,
70ec021a
AS
1196 condition,
1197 ovsdb_monitor_compose_row_update2);
1198
1199 if (!condition || !condition->conditional) {
222bed54 1200 ovsdb_monitor_json_cache_insert(dbmon, version, mcs,
70ec021a
AS
1201 json);
1202 }
1203 } else {
845a1187
LS
1204 /* Compose update on whole db due to condition update.
1205 Session must be flushed (change list is empty)*/
70ec021a
AS
1206 json =
1207 ovsdb_monitor_compose_cond_change_update(dbmon, condition);
1208 }
1209 }
4c280978
AZ
1210 }
1211
222bed54
HZ
1212 /* Maintain tracking change set. */
1213 ovsdb_monitor_untrack_change_set(dbmon, mcs);
1214 ovsdb_monitor_track_new_change_set(dbmon);
1215 *p_mcs = dbmon->new_change_set;
4c280978 1216
2fa1df7b
AZ
1217 return json;
1218}
1219
1220bool
59c35e11 1221ovsdb_monitor_needs_flush(struct ovsdb_monitor *dbmon,
222bed54 1222 struct ovsdb_monitor_change_set *change_set)
2fa1df7b 1223{
222bed54
HZ
1224 ovs_assert(change_set);
1225 return (change_set != dbmon->new_change_set);
2fa1df7b
AZ
1226}
1227
1228void
1229ovsdb_monitor_table_add_select(struct ovsdb_monitor *dbmon,
1230 const struct ovsdb_table *table,
1231 enum ovsdb_monitor_selection select)
1232{
1233 struct ovsdb_monitor_table * mt;
1234
1235 mt = shash_find_data(&dbmon->tables, table->schema->name);
1236 mt->select |= select;
1237}
1238
58de87cc
AZ
1239 /*
1240 * If a row's change type (insert, delete or modify) matches that of
1241 * the monitor, they should be sent to the monitor's clients as updates.
1242 * Of cause, the monitor should also internally update with this change.
1243 *
1244 * When a change type does not require client side update, the monitor
1245 * may still need to keep track of certain changes in order to generate
1246 * correct future updates. For example, the monitor internal state should
1247 * be updated whenever a new row is inserted, in order to generate the
1248 * correct initial state, regardless if a insert change type is being
1249 * monitored.
1250 *
1251 * On the other hand, if a transaction only contains changes to columns
1252 * that are not monitored, this transaction can be safely ignored by the
1253 * monitor.
1254 *
1255 * Thus, the order of the declaration is important:
1256 * 'OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE' always implies
1257 * 'OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE', but not vice versa. */
1258enum ovsdb_monitor_changes_efficacy {
1259 OVSDB_CHANGES_NO_EFFECT, /* Monitor does not care about this
1260 change. */
1261 OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE, /* Monitor internal updates. */
1262 OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE, /* Client needs to be updated. */
1263};
1264
2fa1df7b
AZ
1265struct ovsdb_monitor_aux {
1266 const struct ovsdb_monitor *monitor;
1267 struct ovsdb_monitor_table *mt;
a0cba5c2 1268 enum ovsdb_monitor_changes_efficacy efficacy;
2fa1df7b
AZ
1269};
1270
1271static void
1272ovsdb_monitor_init_aux(struct ovsdb_monitor_aux *aux,
1273 const struct ovsdb_monitor *m)
1274{
1275 aux->monitor = m;
1276 aux->mt = NULL;
a0cba5c2 1277 aux->efficacy = OVSDB_CHANGES_NO_EFFECT;
2fa1df7b
AZ
1278}
1279
7e911055
AZ
1280static void
1281ovsdb_monitor_changes_update(const struct ovsdb_row *old,
1282 const struct ovsdb_row *new,
1283 const struct ovsdb_monitor_table *mt,
222bed54 1284 struct ovsdb_monitor_change_set_for_table *mcst)
2fa1df7b 1285{
2fa1df7b
AZ
1286 const struct uuid *uuid = ovsdb_row_get_uuid(new ? new : old);
1287 struct ovsdb_monitor_row *change;
2fa1df7b 1288
222bed54 1289 change = ovsdb_monitor_changes_row_find(mcst, uuid);
2fa1df7b 1290 if (!change) {
1158f320 1291 change = xzalloc(sizeof *change);
222bed54 1292 hmap_insert(&mcst->rows, &change->hmap_node, uuid_hash(uuid));
2fa1df7b 1293 change->uuid = *uuid;
222bed54
HZ
1294 change->old = clone_monitor_row_data(mt, old, mcst->n_columns);
1295 change->new = clone_monitor_row_data(mt, new, mcst->n_columns);
2fa1df7b
AZ
1296 } else {
1297 if (new) {
20853442
AZ
1298 if (!change->new) {
1299 /* Reinsert the row that was just deleted.
1300 *
1301 * This path won't be hit without replication. Whenever OVSDB
1302 * server inserts a new row, It always generates a new UUID
1303 * that is different from the row just deleted.
1304 *
1305 * With replication, this path can be hit in a corner
1306 * case when two OVSDB servers are set up to replicate
1307 * each other. Not that is a useful set up, but can
1308 * happen in practice.
1309 *
1310 * An example of how this path can be hit is documented below.
1311 * The details is not as important to the correctness of the
1312 * logic, but added here to convince ourselves that this path
1313 * can be hit.
1314 *
1315 * Imagine two OVSDB servers that replicates from each
1316 * other. For each replication session, there is a
1317 * corresponding monitor at the other end of the replication
1318 * JSONRPC connection.
1319 *
1320 * The events can lead to a back to back deletion and
1321 * insertion operation of the same row for the monitor of
1322 * the first server are:
1323 *
1324 * 1. A row is inserted in the first OVSDB server.
1325 * 2. The row is then replicated to the remote OVSDB server.
1326 * 3. The row is now deleted by the local OVSDB server. This
1327 * deletion operation is replicated to the local monitor
1328 * of the OVSDB server.
1329 * 4. The monitor now receives the same row, as an insertion,
1330 * from the replication server. Because of
1331 * replication, the row carries the same UUID as the row
1332 * just deleted.
1333 */
222bed54 1334 change->new = clone_monitor_row_data(mt, new, mcst->n_columns);
20853442 1335 } else {
222bed54 1336 update_monitor_row_data(mt, new, change->new, mcst->n_columns);
20853442 1337 }
2fa1df7b 1338 } else {
222bed54 1339 free_monitor_row_data(mt, change->new, mcst->n_columns);
2fa1df7b
AZ
1340 change->new = NULL;
1341
1342 if (!change->old) {
1343 /* This row was added then deleted. Forget about it. */
222bed54 1344 hmap_remove(&mcst->rows, &change->hmap_node);
2fa1df7b
AZ
1345 free(change);
1346 }
1347 }
1348 }
7e911055
AZ
1349}
1350
58de87cc
AZ
1351static bool
1352ovsdb_monitor_columns_changed(const struct ovsdb_monitor_table *mt,
1353 const unsigned long int *changed)
1354{
1355 size_t i;
1356
1357 for (i = 0; i < mt->n_columns; i++) {
1358 size_t column_index = mt->columns[i].column->index;
1359
1360 if (bitmap_is_set(changed, column_index)) {
1361 return true;
1362 }
1363 }
1364
1365 return false;
1366}
1367
1368/* Return the efficacy of a row's change to a monitor table.
1369 *
1370 * Please see the block comment above 'ovsdb_monitor_changes_efficacy'
1371 * definition form more information. */
1372static enum ovsdb_monitor_changes_efficacy
1373ovsdb_monitor_changes_classify(enum ovsdb_monitor_selection type,
1374 const struct ovsdb_monitor_table *mt,
1375 const unsigned long int *changed)
1376{
1377 if (type == OJMS_MODIFY &&
1378 !ovsdb_monitor_columns_changed(mt, changed)) {
1379 return OVSDB_CHANGES_NO_EFFECT;
1380 }
1381
71cdf7cd
LS
1382 if (type == OJMS_MODIFY) {
1383 /* Condition might turn a modify operation to insert or delete */
1384 type |= OJMS_INSERT | OJMS_DELETE;
1385 }
1386
58de87cc
AZ
1387 return (mt->select & type)
1388 ? OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE
1389 : OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE;
1390}
1391
7e911055
AZ
1392static bool
1393ovsdb_monitor_change_cb(const struct ovsdb_row *old,
1394 const struct ovsdb_row *new,
3a22387b 1395 const unsigned long int *changed,
7e911055
AZ
1396 void *aux_)
1397{
1398 struct ovsdb_monitor_aux *aux = aux_;
1399 const struct ovsdb_monitor *m = aux->monitor;
1400 struct ovsdb_table *table = new ? new->table : old->table;
1401 struct ovsdb_monitor_table *mt;
222bed54 1402 struct ovsdb_monitor_change_set_for_table *mcst;
7e911055
AZ
1403
1404 if (!aux->mt || table != aux->mt->table) {
1405 aux->mt = shash_find_data(&m->tables, table->schema->name);
1406 if (!aux->mt) {
1407 /* We don't care about rows in this table at all. Tell the caller
1408 * to skip it. */
1409 return false;
1410 }
1411 }
1412 mt = aux->mt;
1413
71cdf7cd
LS
1414 enum ovsdb_monitor_selection type =
1415 ovsdb_monitor_row_update_type(false, old, new);
1416 enum ovsdb_monitor_changes_efficacy efficacy =
1417 ovsdb_monitor_changes_classify(type, mt, changed);
58de87cc 1418
222bed54
HZ
1419 if (efficacy > OVSDB_CHANGES_NO_EFFECT) {
1420 LIST_FOR_EACH (mcst, list_in_mt, &mt->change_sets) {
1421 ovsdb_monitor_changes_update(old, new, mt, mcst);
58de87cc 1422 }
71cdf7cd
LS
1423 }
1424 if (aux->efficacy < efficacy) {
1425 aux->efficacy = efficacy;
7e911055 1426 }
58de87cc 1427
2fa1df7b
AZ
1428 return true;
1429}
1430
61b63013 1431void
222bed54
HZ
1432ovsdb_monitor_get_initial(struct ovsdb_monitor *dbmon,
1433 struct ovsdb_monitor_change_set **p_mcs)
2fa1df7b 1434{
222bed54
HZ
1435 if (!dbmon->init_change_set) {
1436 struct ovsdb_monitor_change_set *change_set =
1437 ovsdb_monitor_add_change_set(dbmon, true);
1438 dbmon->init_change_set = change_set;
1439
1440 struct ovsdb_monitor_change_set_for_table *mcst;
1441 LIST_FOR_EACH (mcst, list_in_change_set,
1442 &change_set->change_set_for_tables) {
1443 if (mcst->mt->select & OJMS_INITIAL) {
1444 struct ovsdb_row *row;
1445 HMAP_FOR_EACH (row, hmap_node, &mcst->mt->table->rows) {
1446 ovsdb_monitor_changes_update(NULL, row, mcst->mt, mcst);
6e5a9216 1447 }
2fa1df7b
AZ
1448 }
1449 }
222bed54
HZ
1450 } else {
1451 dbmon->init_change_set->n_refs++;
2fa1df7b 1452 }
222bed54
HZ
1453
1454 *p_mcs = dbmon->init_change_set;
2fa1df7b
AZ
1455}
1456
1457void
d9412837 1458ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
f76def25 1459 struct ovsdb_jsonrpc_monitor *jsonrpc_monitor,
222bed54 1460 struct ovsdb_monitor_change_set *change_set)
d9412837
AZ
1461{
1462 struct jsonrpc_monitor_node *jm;
1463
417e7e66 1464 if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) {
6e5a9216
AZ
1465 ovsdb_monitor_destroy(dbmon);
1466 return;
1467 }
1468
d9412837
AZ
1469 /* Find and remove the jsonrpc monitor from the list. */
1470 LIST_FOR_EACH(jm, node, &dbmon->jsonrpc_monitors) {
1471 if (jm->jsonrpc_monitor == jsonrpc_monitor) {
f76def25 1472 /* Release the tracked changes. */
222bed54
HZ
1473 if (change_set) {
1474 ovsdb_monitor_untrack_change_set(dbmon, change_set);
f76def25 1475 }
417e7e66 1476 ovs_list_remove(&jm->node);
d9412837
AZ
1477 free(jm);
1478
1479 /* Destroy ovsdb monitor if this is the last user. */
417e7e66 1480 if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) {
d9412837
AZ
1481 ovsdb_monitor_destroy(dbmon);
1482 }
1483
1484 return;
1485 };
1486 }
1487
1488 /* Should never reach here. jsonrpc_monitor should be on the list. */
1489 OVS_NOT_REACHED();
1490}
1491
6e5a9216
AZ
1492static bool
1493ovsdb_monitor_table_equal(const struct ovsdb_monitor_table *a,
1494 const struct ovsdb_monitor_table *b)
1495{
1496 size_t i;
1497
6150a75f
LS
1498 ovs_assert(b->n_columns == b->n_monitored_columns);
1499
6e5a9216
AZ
1500 if ((a->table != b->table) ||
1501 (a->select != b->select) ||
6150a75f 1502 (a->n_monitored_columns != b->n_monitored_columns)) {
6e5a9216
AZ
1503 return false;
1504 }
1505
6150a75f
LS
1506 /* Compare only monitored columns that must be sorted already */
1507 for (i = 0; i < a->n_monitored_columns; i++) {
6e5a9216
AZ
1508 if ((a->columns[i].column != b->columns[i].column) ||
1509 (a->columns[i].select != b->columns[i].select)) {
1510 return false;
1511 }
1512 }
6e5a9216
AZ
1513 return true;
1514}
1515
1516static bool
1517ovsdb_monitor_equal(const struct ovsdb_monitor *a,
1518 const struct ovsdb_monitor *b)
1519{
1520 struct shash_node *node;
1521
1522 if (shash_count(&a->tables) != shash_count(&b->tables)) {
1523 return false;
1524 }
1525
1526 SHASH_FOR_EACH(node, &a->tables) {
1527 const struct ovsdb_monitor_table *mta = node->data;
1528 const struct ovsdb_monitor_table *mtb;
1529
1530 mtb = shash_find_data(&b->tables, node->name);
1531 if (!mtb) {
1532 return false;
1533 }
1534
1535 if (!ovsdb_monitor_table_equal(mta, mtb)) {
1536 return false;
1537 }
1538 }
1539
1540 return true;
1541}
1542
1543static size_t
1544ovsdb_monitor_hash(const struct ovsdb_monitor *dbmon, size_t basis)
1545{
1546 const struct shash_node **nodes;
1547 size_t i, j, n;
1548
1549 nodes = shash_sort(&dbmon->tables);
1550 n = shash_count(&dbmon->tables);
1551
1552 for (i = 0; i < n; i++) {
1553 struct ovsdb_monitor_table *mt = nodes[i]->data;
1554
1555 basis = hash_pointer(mt->table, basis);
1556 basis = hash_3words(mt->select, mt->n_columns, basis);
1557
1558 for (j = 0; j < mt->n_columns; j++) {
1559 basis = hash_pointer(mt->columns[j].column, basis);
1560 basis = hash_2words(mt->columns[j].select, basis);
1561 }
1562 }
1563 free(nodes);
1564
1565 return basis;
1566}
1567
1568struct ovsdb_monitor *
1569ovsdb_monitor_add(struct ovsdb_monitor *new_dbmon)
1570{
1571 struct ovsdb_monitor *dbmon;
1572 size_t hash;
1573
1574 /* New_dbmon should be associated with only one jsonrpc
1575 * connections. */
417e7e66 1576 ovs_assert(ovs_list_is_singleton(&new_dbmon->jsonrpc_monitors));
6e5a9216 1577
ec1eadce
LS
1578 ovsdb_monitor_columns_sort(new_dbmon);
1579
6e5a9216
AZ
1580 hash = ovsdb_monitor_hash(new_dbmon, 0);
1581 HMAP_FOR_EACH_WITH_HASH(dbmon, hmap_node, hash, &ovsdb_monitors) {
1582 if (ovsdb_monitor_equal(dbmon, new_dbmon)) {
1583 return dbmon;
1584 }
1585 }
1586
1587 hmap_insert(&ovsdb_monitors, &new_dbmon->hmap_node, hash);
1588 return new_dbmon;
1589}
1590
d9412837 1591static void
2fa1df7b
AZ
1592ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon)
1593{
1594 struct shash_node *node;
1595
009bf21f 1596 ovs_list_remove(&dbmon->list_node);
2fa1df7b 1597
6e5a9216
AZ
1598 if (!hmap_node_is_null(&dbmon->hmap_node)) {
1599 hmap_remove(&ovsdb_monitors, &dbmon->hmap_node);
1600 }
1601
4c280978
AZ
1602 ovsdb_monitor_json_cache_flush(dbmon);
1603 hmap_destroy(&dbmon->json_cache);
1604
222bed54
HZ
1605 struct ovsdb_monitor_change_set *cs, *cs_next;
1606 LIST_FOR_EACH_SAFE (cs, cs_next, list_node, &dbmon->change_sets) {
1607 ovsdb_monitor_change_set_destroy(cs);
1608 }
1609
2fa1df7b
AZ
1610 SHASH_FOR_EACH (node, &dbmon->tables) {
1611 struct ovsdb_monitor_table *mt = node->data;
222bed54 1612 ovs_assert(ovs_list_is_empty(&mt->change_sets));
2fa1df7b 1613 free(mt->columns);
ec1eadce 1614 free(mt->columns_index_map);
2fa1df7b
AZ
1615 free(mt);
1616 }
1617 shash_destroy(&dbmon->tables);
1618 free(dbmon);
1619}
1620
120fb2ca 1621static void
009bf21f 1622ovsdb_monitor_commit(struct ovsdb_monitor *m, const struct ovsdb_txn *txn)
2fa1df7b 1623{
2fa1df7b
AZ
1624 struct ovsdb_monitor_aux aux;
1625
1626 ovsdb_monitor_init_aux(&aux, m);
1627 ovsdb_txn_for_each_change(txn, ovsdb_monitor_change_cb, &aux);
a0cba5c2 1628
222bed54
HZ
1629 if (aux.efficacy > OVSDB_CHANGES_NO_EFFECT) {
1630 /* The transaction is has impact to the monitor.
1631 * Reset new_change_set, so that a new change set will be
1632 * created for future trackings. */
1633 m->new_change_set = NULL;
1634
1635 if (aux.efficacy == OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE) {
1636 ovsdb_monitor_json_cache_flush(m);
1637 }
a0cba5c2 1638 }
2fa1df7b
AZ
1639}
1640
009bf21f
BP
1641void
1642ovsdb_monitors_commit(struct ovsdb *db, const struct ovsdb_txn *txn)
2fa1df7b 1643{
009bf21f 1644 struct ovsdb_monitor *m;
2fa1df7b 1645
009bf21f
BP
1646 LIST_FOR_EACH (m, list_node, &db->monitors) {
1647 ovsdb_monitor_commit(m, txn);
1648 }
1649}
1650
1651void
1652ovsdb_monitors_remove(struct ovsdb *db)
1653{
1654 struct ovsdb_monitor *m, *next_m;
1655
1656 LIST_FOR_EACH_SAFE (m, next_m, list_node, &db->monitors) {
1657 struct jsonrpc_monitor_node *jm, *next_jm;
1658
1659 /* Delete all front-end monitors. Removing the last front-end monitor
1660 * will also destroy the corresponding ovsdb_monitor. */
1661 LIST_FOR_EACH_SAFE (jm, next_jm, node, &m->jsonrpc_monitors) {
53178986 1662 ovsdb_jsonrpc_monitor_destroy(jm->jsonrpc_monitor, false);
009bf21f 1663 }
d9412837 1664 }
2fa1df7b
AZ
1665}
1666
e0c73ed1
AZ
1667/* Add some memory usage statics for monitors into 'usage', for use with
1668 * memory_report(). */
1669void
1670ovsdb_monitor_get_memory_usage(struct simap *usage)
1671{
8302b6d1 1672 struct ovsdb_monitor *dbmon;
e0c73ed1 1673 simap_put(usage, "monitors", hmap_count(&ovsdb_monitors));
8302b6d1
AZ
1674
1675 HMAP_FOR_EACH(dbmon, hmap_node, &ovsdb_monitors) {
1676 simap_increase(usage, "json-caches", hmap_count(&dbmon->json_cache));
1677 }
e0c73ed1 1678}
53178986
BP
1679
1680void
1681ovsdb_monitor_prereplace_db(struct ovsdb *db)
1682{
1683 struct ovsdb_monitor *m, *next_m;
1684
1685 LIST_FOR_EACH_SAFE (m, next_m, list_node, &db->monitors) {
1686 struct jsonrpc_monitor_node *jm, *next_jm;
1687
1688 /* Delete all front-end monitors. Removing the last front-end monitor
1689 * will also destroy the corresponding ovsdb_monitor. */
1690 LIST_FOR_EACH_SAFE (jm, next_jm, node, &m->jsonrpc_monitors) {
1691 ovsdb_jsonrpc_monitor_destroy(jm->jsonrpc_monitor, true);
1692 }
1693 }
1694}