]>
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" |
2fa1df7b AZ |
24 | #include "json.h" |
25 | #include "jsonrpc.h" | |
26 | #include "ovsdb-error.h" | |
27 | #include "ovsdb-parser.h" | |
28 | #include "ovsdb.h" | |
29 | #include "row.h" | |
30 | #include "simap.h" | |
7e911055 | 31 | #include "hash.h" |
2fa1df7b | 32 | #include "table.h" |
6e5a9216 | 33 | #include "hash.h" |
2fa1df7b AZ |
34 | #include "timeval.h" |
35 | #include "transaction.h" | |
36 | #include "jsonrpc-server.h" | |
37 | #include "monitor.h" | |
38 | #include "openvswitch/vlog.h" | |
39 | ||
40 | ||
41 | static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class; | |
6e5a9216 | 42 | static struct hmap ovsdb_monitors = HMAP_INITIALIZER(&ovsdb_monitors); |
2fa1df7b AZ |
43 | |
44 | /* Backend monitor. | |
45 | * | |
46 | * ovsdb_monitor keep track of the ovsdb changes. | |
47 | */ | |
48 | ||
49 | /* A collection of tables being monitored. */ | |
50 | struct ovsdb_monitor { | |
51 | struct ovsdb_replica replica; | |
52 | struct shash tables; /* Holds "struct ovsdb_monitor_table"s. */ | |
d9412837 | 53 | struct ovs_list jsonrpc_monitors; /* Contains "jsonrpc_monitor_node"s. */ |
2fa1df7b | 54 | struct ovsdb *db; |
59c35e11 | 55 | uint64_t n_transactions; /* Count number of committed transactions. */ |
6e5a9216 | 56 | struct hmap_node hmap_node; /* Elements within ovsdb_monitors. */ |
4c280978 AZ |
57 | struct hmap json_cache; /* Contains "ovsdb_monitor_json_cache_node"s.*/ |
58 | }; | |
59 | ||
60 | /* A json object of updates between 'from_txn' and 'dbmon->n_transactions' | |
61 | * inclusive. */ | |
62 | struct ovsdb_monitor_json_cache_node { | |
63 | struct hmap_node hmap_node; /* Elements in json cache. */ | |
a32b4433 | 64 | enum ovsdb_monitor_version version; |
4c280978 AZ |
65 | uint64_t from_txn; |
66 | struct json *json; /* Null, or a cloned of json */ | |
2fa1df7b AZ |
67 | }; |
68 | ||
d9412837 AZ |
69 | struct jsonrpc_monitor_node { |
70 | struct ovsdb_jsonrpc_monitor *jsonrpc_monitor; | |
71 | struct ovs_list node; | |
72 | }; | |
73 | ||
2fa1df7b AZ |
74 | /* A particular column being monitored. */ |
75 | struct ovsdb_monitor_column { | |
76 | const struct ovsdb_column *column; | |
77 | enum ovsdb_monitor_selection select; | |
78 | }; | |
79 | ||
80 | /* A row that has changed in a monitored table. */ | |
81 | struct ovsdb_monitor_row { | |
82 | struct hmap_node hmap_node; /* In ovsdb_jsonrpc_monitor_table.changes. */ | |
83 | struct uuid uuid; /* UUID of row that changed. */ | |
84 | struct ovsdb_datum *old; /* Old data, NULL for an inserted row. */ | |
85 | struct ovsdb_datum *new; /* New data, NULL for a deleted row. */ | |
86 | }; | |
87 | ||
1158f320 AZ |
88 | /* Contains 'struct ovsdb_monitor_row's for rows that have been |
89 | * updated but not yet flushed to all the jsonrpc connection. | |
90 | * | |
91 | * 'n_refs' represent the number of jsonrpc connections that have | |
92 | * not received updates. Generate the update for the last jsonprc | |
93 | * connection will also destroy the whole "struct ovsdb_monitor_changes" | |
94 | * object. | |
95 | * | |
96 | * 'transaction' stores the first update's transaction id. | |
97 | * */ | |
98 | struct ovsdb_monitor_changes { | |
99 | struct ovsdb_monitor_table *mt; | |
100 | struct hmap rows; | |
101 | int n_refs; | |
102 | uint64_t transaction; | |
7e911055 AZ |
103 | struct hmap_node hmap_node; /* Element in ovsdb_monitor_tables' changes |
104 | hmap. */ | |
1158f320 AZ |
105 | }; |
106 | ||
2fa1df7b AZ |
107 | /* A particular table being monitored. */ |
108 | struct ovsdb_monitor_table { | |
109 | const struct ovsdb_table *table; | |
110 | ||
111 | /* This is the union (bitwise-OR) of the 'select' values in all of the | |
112 | * members of 'columns' below. */ | |
113 | enum ovsdb_monitor_selection select; | |
114 | ||
115 | /* Columns being monitored. */ | |
116 | struct ovsdb_monitor_column *columns; | |
117 | size_t n_columns; | |
118 | ||
ec1eadce LS |
119 | /* Columns in ovsdb_monitor_row have different indexes then in |
120 | * ovsdb_row. This field maps between column->index to the index in the | |
121 | * ovsdb_monitor_row. It is used for condition evaluation. */ | |
122 | unsigned int *columns_index_map; | |
123 | ||
7e911055 AZ |
124 | /* Contains 'ovsdb_monitor_changes' indexed by 'transaction'. */ |
125 | struct hmap changes; | |
2fa1df7b AZ |
126 | }; |
127 | ||
52553aea AZ |
128 | typedef struct json * |
129 | (*compose_row_update_cb_func)(const struct ovsdb_monitor_table *mt, | |
130 | const struct ovsdb_monitor_row *row, | |
131 | bool initial, unsigned long int *changed); | |
132 | ||
d9412837 | 133 | static void ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon); |
6e5a9216 AZ |
134 | static struct ovsdb_monitor_changes * ovsdb_monitor_table_add_changes( |
135 | struct ovsdb_monitor_table *mt, uint64_t next_txn); | |
7e911055 AZ |
136 | static struct ovsdb_monitor_changes *ovsdb_monitor_table_find_changes( |
137 | struct ovsdb_monitor_table *mt, uint64_t unflushed); | |
1158f320 AZ |
138 | static void ovsdb_monitor_changes_destroy( |
139 | struct ovsdb_monitor_changes *changes); | |
140 | static void ovsdb_monitor_table_track_changes(struct ovsdb_monitor_table *mt, | |
7e911055 | 141 | uint64_t unflushed); |
d9412837 | 142 | |
a32b4433 HZ |
143 | static uint32_t |
144 | json_cache_hash(enum ovsdb_monitor_version version, uint64_t from_txn) | |
145 | { | |
146 | uint32_t hash; | |
147 | ||
148 | hash = hash_uint64(version); | |
149 | hash = hash_uint64_basis(from_txn, hash); | |
150 | ||
151 | return hash; | |
152 | } | |
153 | ||
4c280978 AZ |
154 | static struct ovsdb_monitor_json_cache_node * |
155 | ovsdb_monitor_json_cache_search(const struct ovsdb_monitor *dbmon, | |
a32b4433 | 156 | enum ovsdb_monitor_version version, |
4c280978 AZ |
157 | uint64_t from_txn) |
158 | { | |
159 | struct ovsdb_monitor_json_cache_node *node; | |
a32b4433 | 160 | uint32_t hash = json_cache_hash(version, from_txn); |
4c280978 AZ |
161 | |
162 | HMAP_FOR_EACH_WITH_HASH(node, hmap_node, hash, &dbmon->json_cache) { | |
a32b4433 | 163 | if (node->from_txn == from_txn && node->version == version) { |
4c280978 AZ |
164 | return node; |
165 | } | |
166 | } | |
167 | ||
168 | return NULL; | |
169 | } | |
170 | ||
171 | static void | |
172 | ovsdb_monitor_json_cache_insert(struct ovsdb_monitor *dbmon, | |
a32b4433 | 173 | enum ovsdb_monitor_version version, |
4c280978 AZ |
174 | uint64_t from_txn, struct json *json) |
175 | { | |
176 | struct ovsdb_monitor_json_cache_node *node; | |
a32b4433 | 177 | uint32_t hash = json_cache_hash(version, from_txn); |
4c280978 AZ |
178 | |
179 | node = xmalloc(sizeof *node); | |
180 | ||
a32b4433 | 181 | node->version = version; |
4c280978 AZ |
182 | node->from_txn = from_txn; |
183 | node->json = json ? json_clone(json) : NULL; | |
184 | ||
185 | hmap_insert(&dbmon->json_cache, &node->hmap_node, hash); | |
186 | } | |
187 | ||
188 | static void | |
189 | ovsdb_monitor_json_cache_flush(struct ovsdb_monitor *dbmon) | |
190 | { | |
4ec3d7c7 | 191 | struct ovsdb_monitor_json_cache_node *node; |
4c280978 | 192 | |
4ec3d7c7 | 193 | HMAP_FOR_EACH_POP(node, hmap_node, &dbmon->json_cache) { |
4c280978 AZ |
194 | json_destroy(node->json); |
195 | free(node); | |
196 | } | |
197 | } | |
198 | ||
2fa1df7b AZ |
199 | static int |
200 | compare_ovsdb_monitor_column(const void *a_, const void *b_) | |
201 | { | |
202 | const struct ovsdb_monitor_column *a = a_; | |
203 | const struct ovsdb_monitor_column *b = b_; | |
204 | ||
205 | return a->column < b->column ? -1 : a->column > b->column; | |
206 | } | |
207 | ||
208 | static struct ovsdb_monitor * | |
209 | ovsdb_monitor_cast(struct ovsdb_replica *replica) | |
210 | { | |
211 | ovs_assert(replica->class == &ovsdb_jsonrpc_replica_class); | |
212 | return CONTAINER_OF(replica, struct ovsdb_monitor, replica); | |
213 | } | |
214 | ||
1158f320 | 215 | /* Finds and returns the ovsdb_monitor_row in 'mt->changes->rows' for the |
2fa1df7b AZ |
216 | * given 'uuid', or NULL if there is no such row. */ |
217 | static struct ovsdb_monitor_row * | |
7e911055 AZ |
218 | ovsdb_monitor_changes_row_find(const struct ovsdb_monitor_changes *changes, |
219 | const struct uuid *uuid) | |
2fa1df7b AZ |
220 | { |
221 | struct ovsdb_monitor_row *row; | |
222 | ||
1158f320 | 223 | HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), |
7e911055 | 224 | &changes->rows) { |
2fa1df7b AZ |
225 | if (uuid_equals(uuid, &row->uuid)) { |
226 | return row; | |
227 | } | |
228 | } | |
229 | return NULL; | |
230 | } | |
231 | ||
232 | /* Allocates an array of 'mt->n_columns' ovsdb_datums and initializes them as | |
233 | * copies of the data in 'row' drawn from the columns represented by | |
234 | * mt->columns[]. Returns the array. | |
235 | * | |
236 | * If 'row' is NULL, returns NULL. */ | |
237 | static struct ovsdb_datum * | |
238 | clone_monitor_row_data(const struct ovsdb_monitor_table *mt, | |
239 | const struct ovsdb_row *row) | |
240 | { | |
241 | struct ovsdb_datum *data; | |
242 | size_t i; | |
243 | ||
244 | if (!row) { | |
245 | return NULL; | |
246 | } | |
247 | ||
248 | data = xmalloc(mt->n_columns * sizeof *data); | |
249 | for (i = 0; i < mt->n_columns; i++) { | |
250 | const struct ovsdb_column *c = mt->columns[i].column; | |
251 | const struct ovsdb_datum *src = &row->fields[c->index]; | |
252 | struct ovsdb_datum *dst = &data[i]; | |
253 | const struct ovsdb_type *type = &c->type; | |
254 | ||
255 | ovsdb_datum_clone(dst, src, type); | |
256 | } | |
257 | return data; | |
258 | } | |
259 | ||
260 | /* Replaces the mt->n_columns ovsdb_datums in row[] by copies of the data from | |
261 | * in 'row' drawn from the columns represented by mt->columns[]. */ | |
262 | static void | |
263 | update_monitor_row_data(const struct ovsdb_monitor_table *mt, | |
264 | const struct ovsdb_row *row, | |
265 | struct ovsdb_datum *data) | |
266 | { | |
267 | size_t i; | |
268 | ||
269 | for (i = 0; i < mt->n_columns; i++) { | |
270 | const struct ovsdb_column *c = mt->columns[i].column; | |
271 | const struct ovsdb_datum *src = &row->fields[c->index]; | |
272 | struct ovsdb_datum *dst = &data[i]; | |
273 | const struct ovsdb_type *type = &c->type; | |
274 | ||
275 | if (!ovsdb_datum_equals(src, dst, type)) { | |
276 | ovsdb_datum_destroy(dst, type); | |
277 | ovsdb_datum_clone(dst, src, type); | |
278 | } | |
279 | } | |
280 | } | |
281 | ||
282 | /* Frees all of the mt->n_columns ovsdb_datums in data[], using the types taken | |
283 | * from mt->columns[], plus 'data' itself. */ | |
284 | static void | |
285 | free_monitor_row_data(const struct ovsdb_monitor_table *mt, | |
286 | struct ovsdb_datum *data) | |
287 | { | |
288 | if (data) { | |
289 | size_t i; | |
290 | ||
291 | for (i = 0; i < mt->n_columns; i++) { | |
292 | const struct ovsdb_column *c = mt->columns[i].column; | |
293 | ||
294 | ovsdb_datum_destroy(&data[i], &c->type); | |
295 | } | |
296 | free(data); | |
297 | } | |
298 | } | |
299 | ||
300 | /* Frees 'row', which must have been created from 'mt'. */ | |
301 | static void | |
302 | ovsdb_monitor_row_destroy(const struct ovsdb_monitor_table *mt, | |
303 | struct ovsdb_monitor_row *row) | |
304 | { | |
305 | if (row) { | |
306 | free_monitor_row_data(mt, row->old); | |
307 | free_monitor_row_data(mt, row->new); | |
308 | free(row); | |
309 | } | |
310 | } | |
311 | ||
ec1eadce LS |
312 | static void |
313 | ovsdb_monitor_columns_sort(struct ovsdb_monitor *dbmon) | |
314 | { | |
315 | int i; | |
316 | struct shash_node *node; | |
317 | ||
318 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
319 | struct ovsdb_monitor_table *mt = node->data; | |
320 | ||
321 | qsort(mt->columns, mt->n_columns, sizeof *mt->columns, | |
322 | compare_ovsdb_monitor_column); | |
323 | for (i = 0; i < mt->n_columns; i++) { | |
324 | /* re-set index map due to sort */ | |
325 | mt->columns_index_map[mt->columns[i].column->index] = i; | |
326 | } | |
327 | } | |
328 | } | |
329 | ||
6e5a9216 | 330 | void |
36247a75 AZ |
331 | ovsdb_monitor_add_jsonrpc_monitor(struct ovsdb_monitor *dbmon, |
332 | struct ovsdb_jsonrpc_monitor *jsonrpc_monitor) | |
333 | { | |
334 | struct jsonrpc_monitor_node *jm; | |
335 | ||
336 | jm = xzalloc(sizeof *jm); | |
337 | jm->jsonrpc_monitor = jsonrpc_monitor; | |
417e7e66 | 338 | ovs_list_push_back(&dbmon->jsonrpc_monitors, &jm->node); |
36247a75 AZ |
339 | } |
340 | ||
2fa1df7b AZ |
341 | struct ovsdb_monitor * |
342 | ovsdb_monitor_create(struct ovsdb *db, | |
343 | struct ovsdb_jsonrpc_monitor *jsonrpc_monitor) | |
344 | { | |
345 | struct ovsdb_monitor *dbmon; | |
346 | ||
347 | dbmon = xzalloc(sizeof *dbmon); | |
348 | ||
349 | ovsdb_replica_init(&dbmon->replica, &ovsdb_jsonrpc_replica_class); | |
350 | ovsdb_add_replica(db, &dbmon->replica); | |
417e7e66 | 351 | ovs_list_init(&dbmon->jsonrpc_monitors); |
2fa1df7b | 352 | dbmon->db = db; |
59c35e11 | 353 | dbmon->n_transactions = 0; |
2fa1df7b | 354 | shash_init(&dbmon->tables); |
6e5a9216 | 355 | hmap_node_nullify(&dbmon->hmap_node); |
4c280978 | 356 | hmap_init(&dbmon->json_cache); |
2fa1df7b | 357 | |
36247a75 | 358 | ovsdb_monitor_add_jsonrpc_monitor(dbmon, jsonrpc_monitor); |
2fa1df7b AZ |
359 | return dbmon; |
360 | } | |
361 | ||
362 | void | |
363 | ovsdb_monitor_add_table(struct ovsdb_monitor *m, | |
364 | const struct ovsdb_table *table) | |
365 | { | |
366 | struct ovsdb_monitor_table *mt; | |
ec1eadce LS |
367 | int i; |
368 | size_t n_columns = shash_count(&table->schema->columns); | |
2fa1df7b AZ |
369 | |
370 | mt = xzalloc(sizeof *mt); | |
371 | mt->table = table; | |
2fa1df7b | 372 | shash_add(&m->tables, table->schema->name, mt); |
7e911055 | 373 | hmap_init(&mt->changes); |
ec1eadce LS |
374 | mt->columns_index_map = |
375 | xmalloc(sizeof *mt->columns_index_map * n_columns); | |
376 | for (i = 0; i < n_columns; i++) { | |
377 | mt->columns_index_map[i] = -1; | |
378 | } | |
2fa1df7b AZ |
379 | } |
380 | ||
ec1eadce | 381 | const char * |
2fa1df7b AZ |
382 | ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon, |
383 | const struct ovsdb_table *table, | |
384 | const struct ovsdb_column *column, | |
385 | enum ovsdb_monitor_selection select, | |
386 | size_t *allocated_columns) | |
387 | { | |
388 | struct ovsdb_monitor_table *mt; | |
389 | struct ovsdb_monitor_column *c; | |
390 | ||
391 | mt = shash_find_data(&dbmon->tables, table->schema->name); | |
392 | ||
ec1eadce LS |
393 | /* Check for column duplication. Return duplicated column name. */ |
394 | if (mt->columns_index_map[column->index] != -1) { | |
395 | return column->name; | |
396 | } | |
397 | ||
2fa1df7b AZ |
398 | if (mt->n_columns >= *allocated_columns) { |
399 | mt->columns = x2nrealloc(mt->columns, allocated_columns, | |
400 | sizeof *mt->columns); | |
401 | } | |
402 | ||
403 | mt->select |= select; | |
ec1eadce | 404 | mt->columns_index_map[column->index] = mt->n_columns; |
2fa1df7b AZ |
405 | c = &mt->columns[mt->n_columns++]; |
406 | c->column = column; | |
407 | c->select = select; | |
2fa1df7b AZ |
408 | |
409 | return NULL; | |
410 | } | |
411 | ||
6e5a9216 | 412 | static struct ovsdb_monitor_changes * |
1158f320 AZ |
413 | ovsdb_monitor_table_add_changes(struct ovsdb_monitor_table *mt, |
414 | uint64_t next_txn) | |
415 | { | |
416 | struct ovsdb_monitor_changes *changes; | |
417 | ||
418 | changes = xzalloc(sizeof *changes); | |
419 | ||
420 | changes->transaction = next_txn; | |
421 | changes->mt = mt; | |
422 | changes->n_refs = 1; | |
423 | hmap_init(&changes->rows); | |
7e911055 | 424 | hmap_insert(&mt->changes, &changes->hmap_node, hash_uint64(next_txn)); |
6e5a9216 AZ |
425 | |
426 | return changes; | |
7e911055 AZ |
427 | }; |
428 | ||
429 | static struct ovsdb_monitor_changes * | |
430 | ovsdb_monitor_table_find_changes(struct ovsdb_monitor_table *mt, | |
431 | uint64_t transaction) | |
432 | { | |
433 | struct ovsdb_monitor_changes *changes; | |
434 | size_t hash = hash_uint64(transaction); | |
435 | ||
436 | HMAP_FOR_EACH_WITH_HASH(changes, hmap_node, hash, &mt->changes) { | |
437 | if (changes->transaction == transaction) { | |
438 | return changes; | |
439 | } | |
440 | } | |
441 | ||
442 | return NULL; | |
1158f320 AZ |
443 | } |
444 | ||
fcd48081 | 445 | /* Stop currently tracking changes to table 'mt' since 'transaction'. */ |
1158f320 AZ |
446 | static void |
447 | ovsdb_monitor_table_untrack_changes(struct ovsdb_monitor_table *mt, | |
448 | uint64_t transaction) | |
449 | { | |
7e911055 AZ |
450 | struct ovsdb_monitor_changes *changes = |
451 | ovsdb_monitor_table_find_changes(mt, transaction); | |
1158f320 | 452 | if (changes) { |
1158f320 | 453 | if (--changes->n_refs == 0) { |
7e911055 | 454 | hmap_remove(&mt->changes, &changes->hmap_node); |
1158f320 | 455 | ovsdb_monitor_changes_destroy(changes); |
1158f320 AZ |
456 | } |
457 | } | |
458 | } | |
459 | ||
460 | /* Start tracking changes to table 'mt' begins from 'transaction' inclusive. | |
461 | */ | |
462 | static void | |
463 | ovsdb_monitor_table_track_changes(struct ovsdb_monitor_table *mt, | |
464 | uint64_t transaction) | |
465 | { | |
7e911055 AZ |
466 | struct ovsdb_monitor_changes *changes; |
467 | ||
468 | changes = ovsdb_monitor_table_find_changes(mt, transaction); | |
469 | if (changes) { | |
470 | changes->n_refs++; | |
471 | } else { | |
472 | ovsdb_monitor_table_add_changes(mt, transaction); | |
473 | } | |
1158f320 AZ |
474 | } |
475 | ||
476 | static void | |
477 | ovsdb_monitor_changes_destroy(struct ovsdb_monitor_changes *changes) | |
478 | { | |
479 | struct ovsdb_monitor_row *row, *next; | |
480 | ||
481 | HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) { | |
482 | hmap_remove(&changes->rows, &row->hmap_node); | |
483 | ovsdb_monitor_row_destroy(changes->mt, row); | |
484 | } | |
485 | hmap_destroy(&changes->rows); | |
486 | free(changes); | |
487 | } | |
488 | ||
23cbedb7 AZ |
489 | static enum ovsdb_monitor_selection |
490 | ovsdb_monitor_row_update_type(bool initial, const bool old, const bool new) | |
491 | { | |
492 | return initial ? OJMS_INITIAL | |
493 | : !old ? OJMS_INSERT | |
494 | : !new ? OJMS_DELETE | |
495 | : OJMS_MODIFY; | |
496 | } | |
52553aea AZ |
497 | static bool |
498 | ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt, | |
499 | const struct ovsdb_monitor_row *row, | |
500 | enum ovsdb_monitor_selection type, | |
501 | unsigned long int *changed) | |
502 | { | |
503 | if (!(mt->select & type)) { | |
504 | return true; | |
505 | } | |
506 | ||
507 | if (type == OJMS_MODIFY) { | |
508 | size_t i, n_changes; | |
509 | ||
510 | n_changes = 0; | |
511 | memset(changed, 0, bitmap_n_bytes(mt->n_columns)); | |
512 | for (i = 0; i < mt->n_columns; i++) { | |
513 | const struct ovsdb_column *c = mt->columns[i].column; | |
514 | if (!ovsdb_datum_equals(&row->old[i], &row->new[i], &c->type)) { | |
515 | bitmap_set1(changed, i); | |
516 | n_changes++; | |
517 | } | |
518 | } | |
519 | if (!n_changes) { | |
520 | /* No actual changes: presumably a row changed and then | |
521 | * changed back later. */ | |
522 | return true; | |
523 | } | |
524 | } | |
525 | ||
526 | return false; | |
527 | } | |
23cbedb7 | 528 | |
2fa1df7b AZ |
529 | /* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within |
530 | * 'mt', or NULL if no row update should be sent. | |
531 | * | |
532 | * The caller should specify 'initial' as true if the returned JSON is going to | |
533 | * be used as part of the initial reply to a "monitor" request, false if it is | |
534 | * going to be used as part of an "update" notification. | |
535 | * | |
536 | * 'changed' must be a scratch buffer for internal use that is at least | |
537 | * bitmap_n_bytes(mt->n_columns) bytes long. */ | |
538 | static struct json * | |
539 | ovsdb_monitor_compose_row_update( | |
540 | const struct ovsdb_monitor_table *mt, | |
541 | const struct ovsdb_monitor_row *row, | |
542 | bool initial, unsigned long int *changed) | |
543 | { | |
544 | enum ovsdb_monitor_selection type; | |
545 | struct json *old_json, *new_json; | |
546 | struct json *row_json; | |
547 | size_t i; | |
548 | ||
23cbedb7 | 549 | type = ovsdb_monitor_row_update_type(initial, row->old, row->new); |
52553aea | 550 | if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) { |
2fa1df7b AZ |
551 | return NULL; |
552 | } | |
553 | ||
2fa1df7b AZ |
554 | row_json = json_object_create(); |
555 | old_json = new_json = NULL; | |
556 | if (type & (OJMS_DELETE | OJMS_MODIFY)) { | |
557 | old_json = json_object_create(); | |
558 | json_object_put(row_json, "old", old_json); | |
559 | } | |
560 | if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) { | |
561 | new_json = json_object_create(); | |
562 | json_object_put(row_json, "new", new_json); | |
563 | } | |
564 | for (i = 0; i < mt->n_columns; i++) { | |
565 | const struct ovsdb_monitor_column *c = &mt->columns[i]; | |
566 | ||
567 | if (!(type & c->select)) { | |
568 | /* We don't care about this type of change for this | |
569 | * particular column (but we will care about it for some | |
570 | * other column). */ | |
571 | continue; | |
572 | } | |
573 | ||
574 | if ((type == OJMS_MODIFY && bitmap_is_set(changed, i)) | |
575 | || type == OJMS_DELETE) { | |
576 | json_object_put(old_json, c->column->name, | |
577 | ovsdb_datum_to_json(&row->old[i], | |
578 | &c->column->type)); | |
579 | } | |
580 | if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) { | |
581 | json_object_put(new_json, c->column->name, | |
582 | ovsdb_datum_to_json(&row->new[i], | |
583 | &c->column->type)); | |
584 | } | |
585 | } | |
586 | ||
587 | return row_json; | |
588 | } | |
589 | ||
52553aea AZ |
590 | /* Returns JSON for a <row-update2> (as described in ovsdb-server(1) mapage) |
591 | * for 'row' within * 'mt', or NULL if no row update should be sent. | |
592 | * | |
593 | * The caller should specify 'initial' as true if the returned JSON is | |
594 | * going to be used as part of the initial reply to a "monitor2" request, | |
595 | * false if it is going to be used as part of an "update2" notification. | |
596 | * | |
597 | * 'changed' must be a scratch buffer for internal use that is at least | |
598 | * bitmap_n_bytes(mt->n_columns) bytes long. */ | |
599 | static struct json * | |
600 | ovsdb_monitor_compose_row_update2( | |
601 | const struct ovsdb_monitor_table *mt, | |
602 | const struct ovsdb_monitor_row *row, | |
603 | bool initial, unsigned long int *changed) | |
604 | { | |
605 | enum ovsdb_monitor_selection type; | |
606 | struct json *row_update2, *diff_json; | |
607 | size_t i; | |
608 | ||
609 | type = ovsdb_monitor_row_update_type(initial, row->old, row->new); | |
610 | if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) { | |
611 | return NULL; | |
612 | } | |
613 | ||
614 | row_update2 = json_object_create(); | |
615 | if (type == OJMS_DELETE) { | |
616 | json_object_put(row_update2, "delete", json_null_create()); | |
617 | } else { | |
618 | diff_json = json_object_create(); | |
619 | const char *op; | |
620 | ||
621 | for (i = 0; i < mt->n_columns; i++) { | |
622 | const struct ovsdb_monitor_column *c = &mt->columns[i]; | |
623 | ||
624 | if (!(type & c->select)) { | |
625 | /* We don't care about this type of change for this | |
626 | * particular column (but we will care about it for some | |
627 | * other column). */ | |
628 | continue; | |
629 | } | |
630 | ||
631 | if (type == OJMS_MODIFY) { | |
632 | struct ovsdb_datum diff; | |
633 | ||
634 | if (!bitmap_is_set(changed, i)) { | |
635 | continue; | |
636 | } | |
637 | ||
638 | ovsdb_datum_diff(&diff ,&row->old[i], &row->new[i], | |
639 | &c->column->type); | |
640 | json_object_put(diff_json, c->column->name, | |
641 | ovsdb_datum_to_json(&diff, &c->column->type)); | |
642 | ovsdb_datum_destroy(&diff, &c->column->type); | |
643 | } else { | |
644 | if (!ovsdb_datum_is_default(&row->new[i], &c->column->type)) { | |
645 | json_object_put(diff_json, c->column->name, | |
646 | ovsdb_datum_to_json(&row->new[i], | |
647 | &c->column->type)); | |
648 | } | |
649 | } | |
650 | } | |
651 | ||
652 | op = type == OJMS_INITIAL ? "initial" | |
653 | : type == OJMS_MODIFY ? "modify" : "insert"; | |
654 | json_object_put(row_update2, op, diff_json); | |
655 | } | |
656 | ||
657 | return row_update2; | |
658 | } | |
659 | ||
6cef8e87 AZ |
660 | static size_t |
661 | ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon) | |
662 | { | |
663 | struct shash_node *node; | |
664 | size_t max_columns = 0; | |
665 | ||
666 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
667 | struct ovsdb_monitor_table *mt = node->data; | |
668 | ||
669 | max_columns = MAX(max_columns, mt->n_columns); | |
670 | } | |
671 | ||
672 | return max_columns; | |
673 | } | |
674 | ||
2fa1df7b | 675 | /* Constructs and returns JSON for a <table-updates> object (as described in |
4c280978 AZ |
676 | * RFC 7047) for all the outstanding changes within 'monitor', starting from |
677 | * 'transaction'. */ | |
678 | static struct json* | |
679 | ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon, | |
52553aea AZ |
680 | bool initial, uint64_t transaction, |
681 | compose_row_update_cb_func row_update) | |
2fa1df7b AZ |
682 | { |
683 | struct shash_node *node; | |
2fa1df7b | 684 | struct json *json; |
6cef8e87 AZ |
685 | size_t max_columns = ovsdb_monitor_max_columns(dbmon); |
686 | unsigned long int *changed = xmalloc(bitmap_n_bytes(max_columns)); | |
2fa1df7b AZ |
687 | |
688 | json = NULL; | |
689 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
690 | struct ovsdb_monitor_table *mt = node->data; | |
691 | struct ovsdb_monitor_row *row, *next; | |
7e911055 | 692 | struct ovsdb_monitor_changes *changes; |
2fa1df7b AZ |
693 | struct json *table_json = NULL; |
694 | ||
4c280978 | 695 | changes = ovsdb_monitor_table_find_changes(mt, transaction); |
7e911055 | 696 | if (!changes) { |
1158f320 AZ |
697 | continue; |
698 | } | |
699 | ||
7e911055 | 700 | HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) { |
2fa1df7b AZ |
701 | struct json *row_json; |
702 | ||
52553aea | 703 | row_json = (*row_update)(mt, row, initial, changed); |
2fa1df7b AZ |
704 | if (row_json) { |
705 | char uuid[UUID_LEN + 1]; | |
706 | ||
707 | /* Create JSON object for transaction overall. */ | |
708 | if (!json) { | |
709 | json = json_object_create(); | |
710 | } | |
711 | ||
712 | /* Create JSON object for transaction on this table. */ | |
713 | if (!table_json) { | |
714 | table_json = json_object_create(); | |
715 | json_object_put(json, mt->table->schema->name, table_json); | |
716 | } | |
717 | ||
718 | /* Add JSON row to JSON table. */ | |
719 | snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(&row->uuid)); | |
720 | json_object_put(table_json, uuid, row_json); | |
721 | } | |
2fa1df7b | 722 | } |
4c280978 AZ |
723 | } |
724 | free(changed); | |
725 | ||
726 | return json; | |
727 | } | |
728 | ||
729 | /* Returns JSON for a <table-updates> object (as described in RFC 7047) | |
730 | * for all the outstanding changes within 'monitor' that starts from | |
731 | * '*unflushed' transaction id. | |
732 | * | |
733 | * The caller should specify 'initial' as true if the returned JSON is going to | |
734 | * be used as part of the initial reply to a "monitor" request, false if it is | |
735 | * going to be used as part of an "update" notification. */ | |
736 | struct json * | |
737 | ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon, | |
765b5a0e | 738 | bool initial, uint64_t *unflushed_, |
52553aea | 739 | enum ovsdb_monitor_version version) |
4c280978 AZ |
740 | { |
741 | struct ovsdb_monitor_json_cache_node *cache_node; | |
742 | struct shash_node *node; | |
743 | struct json *json; | |
765b5a0e AZ |
744 | const uint64_t unflushed = *unflushed_; |
745 | const uint64_t next_unflushed = dbmon->n_transactions + 1; | |
4c280978 AZ |
746 | |
747 | /* Return a clone of cached json if one exists. Otherwise, | |
748 | * generate a new one and add it to the cache. */ | |
765b5a0e | 749 | cache_node = ovsdb_monitor_json_cache_search(dbmon, version, unflushed); |
4c280978 AZ |
750 | if (cache_node) { |
751 | json = cache_node->json ? json_clone(cache_node->json) : NULL; | |
752 | } else { | |
52553aea | 753 | if (version == OVSDB_MONITOR_V1) { |
765b5a0e | 754 | json = ovsdb_monitor_compose_update(dbmon, initial, unflushed, |
52553aea AZ |
755 | ovsdb_monitor_compose_row_update); |
756 | } else { | |
757 | ovs_assert(version == OVSDB_MONITOR_V2); | |
765b5a0e | 758 | json = ovsdb_monitor_compose_update(dbmon, initial, unflushed, |
52553aea AZ |
759 | ovsdb_monitor_compose_row_update2); |
760 | } | |
765b5a0e | 761 | ovsdb_monitor_json_cache_insert(dbmon, version, unflushed, json); |
4c280978 AZ |
762 | } |
763 | ||
764 | /* Maintain transaction id of 'changes'. */ | |
765 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
766 | struct ovsdb_monitor_table *mt = node->data; | |
1158f320 | 767 | |
765b5a0e AZ |
768 | ovsdb_monitor_table_untrack_changes(mt, unflushed); |
769 | ovsdb_monitor_table_track_changes(mt, next_unflushed); | |
2fa1df7b | 770 | } |
765b5a0e | 771 | *unflushed_ = next_unflushed; |
4c280978 | 772 | |
2fa1df7b AZ |
773 | return json; |
774 | } | |
775 | ||
776 | bool | |
59c35e11 AZ |
777 | ovsdb_monitor_needs_flush(struct ovsdb_monitor *dbmon, |
778 | uint64_t next_transaction) | |
2fa1df7b | 779 | { |
59c35e11 AZ |
780 | ovs_assert(next_transaction <= dbmon->n_transactions + 1); |
781 | return (next_transaction <= dbmon->n_transactions); | |
2fa1df7b AZ |
782 | } |
783 | ||
784 | void | |
785 | ovsdb_monitor_table_add_select(struct ovsdb_monitor *dbmon, | |
786 | const struct ovsdb_table *table, | |
787 | enum ovsdb_monitor_selection select) | |
788 | { | |
789 | struct ovsdb_monitor_table * mt; | |
790 | ||
791 | mt = shash_find_data(&dbmon->tables, table->schema->name); | |
792 | mt->select |= select; | |
793 | } | |
794 | ||
58de87cc AZ |
795 | /* |
796 | * If a row's change type (insert, delete or modify) matches that of | |
797 | * the monitor, they should be sent to the monitor's clients as updates. | |
798 | * Of cause, the monitor should also internally update with this change. | |
799 | * | |
800 | * When a change type does not require client side update, the monitor | |
801 | * may still need to keep track of certain changes in order to generate | |
802 | * correct future updates. For example, the monitor internal state should | |
803 | * be updated whenever a new row is inserted, in order to generate the | |
804 | * correct initial state, regardless if a insert change type is being | |
805 | * monitored. | |
806 | * | |
807 | * On the other hand, if a transaction only contains changes to columns | |
808 | * that are not monitored, this transaction can be safely ignored by the | |
809 | * monitor. | |
810 | * | |
811 | * Thus, the order of the declaration is important: | |
812 | * 'OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE' always implies | |
813 | * 'OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE', but not vice versa. */ | |
814 | enum ovsdb_monitor_changes_efficacy { | |
815 | OVSDB_CHANGES_NO_EFFECT, /* Monitor does not care about this | |
816 | change. */ | |
817 | OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE, /* Monitor internal updates. */ | |
818 | OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE, /* Client needs to be updated. */ | |
819 | }; | |
820 | ||
2fa1df7b AZ |
821 | struct ovsdb_monitor_aux { |
822 | const struct ovsdb_monitor *monitor; | |
823 | struct ovsdb_monitor_table *mt; | |
a0cba5c2 | 824 | enum ovsdb_monitor_changes_efficacy efficacy; |
2fa1df7b AZ |
825 | }; |
826 | ||
827 | static void | |
828 | ovsdb_monitor_init_aux(struct ovsdb_monitor_aux *aux, | |
829 | const struct ovsdb_monitor *m) | |
830 | { | |
831 | aux->monitor = m; | |
832 | aux->mt = NULL; | |
a0cba5c2 | 833 | aux->efficacy = OVSDB_CHANGES_NO_EFFECT; |
2fa1df7b AZ |
834 | } |
835 | ||
7e911055 AZ |
836 | static void |
837 | ovsdb_monitor_changes_update(const struct ovsdb_row *old, | |
838 | const struct ovsdb_row *new, | |
839 | const struct ovsdb_monitor_table *mt, | |
840 | struct ovsdb_monitor_changes *changes) | |
2fa1df7b | 841 | { |
2fa1df7b AZ |
842 | const struct uuid *uuid = ovsdb_row_get_uuid(new ? new : old); |
843 | struct ovsdb_monitor_row *change; | |
2fa1df7b | 844 | |
7e911055 | 845 | change = ovsdb_monitor_changes_row_find(changes, uuid); |
2fa1df7b | 846 | if (!change) { |
1158f320 | 847 | change = xzalloc(sizeof *change); |
7e911055 | 848 | hmap_insert(&changes->rows, &change->hmap_node, uuid_hash(uuid)); |
2fa1df7b AZ |
849 | change->uuid = *uuid; |
850 | change->old = clone_monitor_row_data(mt, old); | |
851 | change->new = clone_monitor_row_data(mt, new); | |
852 | } else { | |
853 | if (new) { | |
854 | update_monitor_row_data(mt, new, change->new); | |
855 | } else { | |
856 | free_monitor_row_data(mt, change->new); | |
857 | change->new = NULL; | |
858 | ||
859 | if (!change->old) { | |
860 | /* This row was added then deleted. Forget about it. */ | |
7e911055 | 861 | hmap_remove(&changes->rows, &change->hmap_node); |
2fa1df7b AZ |
862 | free(change); |
863 | } | |
864 | } | |
865 | } | |
7e911055 AZ |
866 | } |
867 | ||
58de87cc AZ |
868 | static bool |
869 | ovsdb_monitor_columns_changed(const struct ovsdb_monitor_table *mt, | |
870 | const unsigned long int *changed) | |
871 | { | |
872 | size_t i; | |
873 | ||
874 | for (i = 0; i < mt->n_columns; i++) { | |
875 | size_t column_index = mt->columns[i].column->index; | |
876 | ||
877 | if (bitmap_is_set(changed, column_index)) { | |
878 | return true; | |
879 | } | |
880 | } | |
881 | ||
882 | return false; | |
883 | } | |
884 | ||
885 | /* Return the efficacy of a row's change to a monitor table. | |
886 | * | |
887 | * Please see the block comment above 'ovsdb_monitor_changes_efficacy' | |
888 | * definition form more information. */ | |
889 | static enum ovsdb_monitor_changes_efficacy | |
890 | ovsdb_monitor_changes_classify(enum ovsdb_monitor_selection type, | |
891 | const struct ovsdb_monitor_table *mt, | |
892 | const unsigned long int *changed) | |
893 | { | |
894 | if (type == OJMS_MODIFY && | |
895 | !ovsdb_monitor_columns_changed(mt, changed)) { | |
896 | return OVSDB_CHANGES_NO_EFFECT; | |
897 | } | |
898 | ||
899 | return (mt->select & type) | |
900 | ? OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE | |
901 | : OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE; | |
902 | } | |
903 | ||
7e911055 AZ |
904 | static bool |
905 | ovsdb_monitor_change_cb(const struct ovsdb_row *old, | |
906 | const struct ovsdb_row *new, | |
3a22387b | 907 | const unsigned long int *changed, |
7e911055 AZ |
908 | void *aux_) |
909 | { | |
910 | struct ovsdb_monitor_aux *aux = aux_; | |
911 | const struct ovsdb_monitor *m = aux->monitor; | |
912 | struct ovsdb_table *table = new ? new->table : old->table; | |
913 | struct ovsdb_monitor_table *mt; | |
914 | struct ovsdb_monitor_changes *changes; | |
915 | ||
916 | if (!aux->mt || table != aux->mt->table) { | |
917 | aux->mt = shash_find_data(&m->tables, table->schema->name); | |
918 | if (!aux->mt) { | |
919 | /* We don't care about rows in this table at all. Tell the caller | |
920 | * to skip it. */ | |
921 | return false; | |
922 | } | |
923 | } | |
924 | mt = aux->mt; | |
925 | ||
926 | HMAP_FOR_EACH(changes, hmap_node, &mt->changes) { | |
58de87cc AZ |
927 | enum ovsdb_monitor_changes_efficacy efficacy; |
928 | enum ovsdb_monitor_selection type; | |
929 | ||
930 | type = ovsdb_monitor_row_update_type(false, old, new); | |
931 | efficacy = ovsdb_monitor_changes_classify(type, mt, changed); | |
932 | if (efficacy > OVSDB_CHANGES_NO_EFFECT) { | |
933 | ovsdb_monitor_changes_update(old, new, mt, changes); | |
934 | } | |
a0cba5c2 AZ |
935 | |
936 | if (aux->efficacy < efficacy) { | |
937 | aux->efficacy = efficacy; | |
938 | } | |
7e911055 | 939 | } |
58de87cc | 940 | |
2fa1df7b AZ |
941 | return true; |
942 | } | |
943 | ||
61b63013 | 944 | void |
2fa1df7b AZ |
945 | ovsdb_monitor_get_initial(const struct ovsdb_monitor *dbmon) |
946 | { | |
947 | struct ovsdb_monitor_aux aux; | |
948 | struct shash_node *node; | |
2fa1df7b AZ |
949 | |
950 | ovsdb_monitor_init_aux(&aux, dbmon); | |
951 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
952 | struct ovsdb_monitor_table *mt = node->data; | |
953 | ||
954 | if (mt->select & OJMS_INITIAL) { | |
955 | struct ovsdb_row *row; | |
6e5a9216 | 956 | struct ovsdb_monitor_changes *changes; |
2fa1df7b | 957 | |
6e5a9216 AZ |
958 | changes = ovsdb_monitor_table_find_changes(mt, 0); |
959 | if (!changes) { | |
960 | changes = ovsdb_monitor_table_add_changes(mt, 0); | |
961 | HMAP_FOR_EACH (row, hmap_node, &mt->table->rows) { | |
962 | ovsdb_monitor_changes_update(NULL, row, mt, changes); | |
963 | } | |
964 | } else { | |
965 | changes->n_refs++; | |
2fa1df7b AZ |
966 | } |
967 | } | |
968 | } | |
2fa1df7b AZ |
969 | } |
970 | ||
971 | void | |
d9412837 | 972 | ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon, |
f76def25 AZ |
973 | struct ovsdb_jsonrpc_monitor *jsonrpc_monitor, |
974 | uint64_t unflushed) | |
d9412837 AZ |
975 | { |
976 | struct jsonrpc_monitor_node *jm; | |
977 | ||
417e7e66 | 978 | if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) { |
6e5a9216 AZ |
979 | ovsdb_monitor_destroy(dbmon); |
980 | return; | |
981 | } | |
982 | ||
d9412837 AZ |
983 | /* Find and remove the jsonrpc monitor from the list. */ |
984 | LIST_FOR_EACH(jm, node, &dbmon->jsonrpc_monitors) { | |
985 | if (jm->jsonrpc_monitor == jsonrpc_monitor) { | |
f76def25 AZ |
986 | /* Release the tracked changes. */ |
987 | struct shash_node *node; | |
988 | SHASH_FOR_EACH (node, &dbmon->tables) { | |
989 | struct ovsdb_monitor_table *mt = node->data; | |
990 | ovsdb_monitor_table_untrack_changes(mt, unflushed); | |
991 | } | |
417e7e66 | 992 | ovs_list_remove(&jm->node); |
d9412837 AZ |
993 | free(jm); |
994 | ||
995 | /* Destroy ovsdb monitor if this is the last user. */ | |
417e7e66 | 996 | if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) { |
d9412837 AZ |
997 | ovsdb_monitor_destroy(dbmon); |
998 | } | |
999 | ||
1000 | return; | |
1001 | }; | |
1002 | } | |
1003 | ||
1004 | /* Should never reach here. jsonrpc_monitor should be on the list. */ | |
1005 | OVS_NOT_REACHED(); | |
1006 | } | |
1007 | ||
6e5a9216 AZ |
1008 | static bool |
1009 | ovsdb_monitor_table_equal(const struct ovsdb_monitor_table *a, | |
1010 | const struct ovsdb_monitor_table *b) | |
1011 | { | |
1012 | size_t i; | |
1013 | ||
1014 | if ((a->table != b->table) || | |
1015 | (a->select != b->select) || | |
1016 | (a->n_columns != b->n_columns)) { | |
1017 | return false; | |
1018 | } | |
1019 | ||
1020 | for (i = 0; i < a->n_columns; i++) { | |
1021 | if ((a->columns[i].column != b->columns[i].column) || | |
1022 | (a->columns[i].select != b->columns[i].select)) { | |
1023 | return false; | |
1024 | } | |
1025 | } | |
1026 | ||
1027 | return true; | |
1028 | } | |
1029 | ||
1030 | static bool | |
1031 | ovsdb_monitor_equal(const struct ovsdb_monitor *a, | |
1032 | const struct ovsdb_monitor *b) | |
1033 | { | |
1034 | struct shash_node *node; | |
1035 | ||
1036 | if (shash_count(&a->tables) != shash_count(&b->tables)) { | |
1037 | return false; | |
1038 | } | |
1039 | ||
1040 | SHASH_FOR_EACH(node, &a->tables) { | |
1041 | const struct ovsdb_monitor_table *mta = node->data; | |
1042 | const struct ovsdb_monitor_table *mtb; | |
1043 | ||
1044 | mtb = shash_find_data(&b->tables, node->name); | |
1045 | if (!mtb) { | |
1046 | return false; | |
1047 | } | |
1048 | ||
1049 | if (!ovsdb_monitor_table_equal(mta, mtb)) { | |
1050 | return false; | |
1051 | } | |
1052 | } | |
1053 | ||
1054 | return true; | |
1055 | } | |
1056 | ||
1057 | static size_t | |
1058 | ovsdb_monitor_hash(const struct ovsdb_monitor *dbmon, size_t basis) | |
1059 | { | |
1060 | const struct shash_node **nodes; | |
1061 | size_t i, j, n; | |
1062 | ||
1063 | nodes = shash_sort(&dbmon->tables); | |
1064 | n = shash_count(&dbmon->tables); | |
1065 | ||
1066 | for (i = 0; i < n; i++) { | |
1067 | struct ovsdb_monitor_table *mt = nodes[i]->data; | |
1068 | ||
1069 | basis = hash_pointer(mt->table, basis); | |
1070 | basis = hash_3words(mt->select, mt->n_columns, basis); | |
1071 | ||
1072 | for (j = 0; j < mt->n_columns; j++) { | |
1073 | basis = hash_pointer(mt->columns[j].column, basis); | |
1074 | basis = hash_2words(mt->columns[j].select, basis); | |
1075 | } | |
1076 | } | |
1077 | free(nodes); | |
1078 | ||
1079 | return basis; | |
1080 | } | |
1081 | ||
1082 | struct ovsdb_monitor * | |
1083 | ovsdb_monitor_add(struct ovsdb_monitor *new_dbmon) | |
1084 | { | |
1085 | struct ovsdb_monitor *dbmon; | |
1086 | size_t hash; | |
1087 | ||
1088 | /* New_dbmon should be associated with only one jsonrpc | |
1089 | * connections. */ | |
417e7e66 | 1090 | ovs_assert(ovs_list_is_singleton(&new_dbmon->jsonrpc_monitors)); |
6e5a9216 | 1091 | |
ec1eadce LS |
1092 | ovsdb_monitor_columns_sort(new_dbmon); |
1093 | ||
6e5a9216 AZ |
1094 | hash = ovsdb_monitor_hash(new_dbmon, 0); |
1095 | HMAP_FOR_EACH_WITH_HASH(dbmon, hmap_node, hash, &ovsdb_monitors) { | |
1096 | if (ovsdb_monitor_equal(dbmon, new_dbmon)) { | |
1097 | return dbmon; | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | hmap_insert(&ovsdb_monitors, &new_dbmon->hmap_node, hash); | |
1102 | return new_dbmon; | |
1103 | } | |
1104 | ||
d9412837 | 1105 | static void |
2fa1df7b AZ |
1106 | ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon) |
1107 | { | |
1108 | struct shash_node *node; | |
1109 | ||
417e7e66 | 1110 | ovs_list_remove(&dbmon->replica.node); |
2fa1df7b | 1111 | |
6e5a9216 AZ |
1112 | if (!hmap_node_is_null(&dbmon->hmap_node)) { |
1113 | hmap_remove(&ovsdb_monitors, &dbmon->hmap_node); | |
1114 | } | |
1115 | ||
4c280978 AZ |
1116 | ovsdb_monitor_json_cache_flush(dbmon); |
1117 | hmap_destroy(&dbmon->json_cache); | |
1118 | ||
2fa1df7b AZ |
1119 | SHASH_FOR_EACH (node, &dbmon->tables) { |
1120 | struct ovsdb_monitor_table *mt = node->data; | |
7e911055 | 1121 | struct ovsdb_monitor_changes *changes, *next; |
2fa1df7b | 1122 | |
7e911055 AZ |
1123 | HMAP_FOR_EACH_SAFE (changes, next, hmap_node, &mt->changes) { |
1124 | hmap_remove(&mt->changes, &changes->hmap_node); | |
1125 | ovsdb_monitor_changes_destroy(changes); | |
1126 | } | |
a7ca2803 | 1127 | hmap_destroy(&mt->changes); |
2fa1df7b | 1128 | free(mt->columns); |
ec1eadce | 1129 | free(mt->columns_index_map); |
2fa1df7b AZ |
1130 | free(mt); |
1131 | } | |
1132 | shash_destroy(&dbmon->tables); | |
1133 | free(dbmon); | |
1134 | } | |
1135 | ||
1136 | static struct ovsdb_error * | |
1137 | ovsdb_monitor_commit(struct ovsdb_replica *replica, | |
1138 | const struct ovsdb_txn *txn, | |
1139 | bool durable OVS_UNUSED) | |
1140 | { | |
1141 | struct ovsdb_monitor *m = ovsdb_monitor_cast(replica); | |
1142 | struct ovsdb_monitor_aux aux; | |
1143 | ||
1144 | ovsdb_monitor_init_aux(&aux, m); | |
5e229177 AZ |
1145 | /* Update ovsdb_monitor's transaction number for |
1146 | * each transaction, before calling ovsdb_monitor_change_cb(). */ | |
1147 | m->n_transactions++; | |
2fa1df7b | 1148 | ovsdb_txn_for_each_change(txn, ovsdb_monitor_change_cb, &aux); |
a0cba5c2 | 1149 | |
5e229177 AZ |
1150 | switch(aux.efficacy) { |
1151 | case OVSDB_CHANGES_NO_EFFECT: | |
1152 | /* The transaction is ignored by the monitor. | |
1153 | * Roll back the 'n_transactions' as if the transaction | |
1154 | * has never happened. */ | |
1155 | m->n_transactions--; | |
1156 | break; | |
1157 | case OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE: | |
1158 | /* Nothing. */ | |
1159 | break; | |
1160 | case OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE: | |
a0cba5c2 | 1161 | ovsdb_monitor_json_cache_flush(m); |
5e229177 | 1162 | break; |
a0cba5c2 | 1163 | } |
2fa1df7b AZ |
1164 | |
1165 | return NULL; | |
1166 | } | |
1167 | ||
1168 | static void | |
1169 | ovsdb_monitor_destroy_callback(struct ovsdb_replica *replica) | |
1170 | { | |
1171 | struct ovsdb_monitor *dbmon = ovsdb_monitor_cast(replica); | |
d9412837 | 1172 | struct jsonrpc_monitor_node *jm, *next; |
2fa1df7b | 1173 | |
d9412837 AZ |
1174 | /* Delete all front end monitors. Removing the last front |
1175 | * end monitor will also destroy the corresponding 'ovsdb_monitor'. | |
1176 | * ovsdb monitor will also be destroied. */ | |
1177 | LIST_FOR_EACH_SAFE(jm, next, node, &dbmon->jsonrpc_monitors) { | |
1178 | ovsdb_jsonrpc_monitor_destroy(jm->jsonrpc_monitor); | |
1179 | } | |
2fa1df7b AZ |
1180 | } |
1181 | ||
e0c73ed1 AZ |
1182 | /* Add some memory usage statics for monitors into 'usage', for use with |
1183 | * memory_report(). */ | |
1184 | void | |
1185 | ovsdb_monitor_get_memory_usage(struct simap *usage) | |
1186 | { | |
8302b6d1 | 1187 | struct ovsdb_monitor *dbmon; |
e0c73ed1 | 1188 | simap_put(usage, "monitors", hmap_count(&ovsdb_monitors)); |
8302b6d1 AZ |
1189 | |
1190 | HMAP_FOR_EACH(dbmon, hmap_node, &ovsdb_monitors) { | |
1191 | simap_increase(usage, "json-caches", hmap_count(&dbmon->json_cache)); | |
1192 | } | |
e0c73ed1 AZ |
1193 | } |
1194 | ||
2fa1df7b AZ |
1195 | static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class = { |
1196 | ovsdb_monitor_commit, | |
1197 | ovsdb_monitor_destroy_callback, | |
1198 | }; |