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