]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ovsdb-idl.c
ovsdb-idl: Tolerate initialization races for singleton tables.
[mirror_ovs.git] / lib / ovsdb-idl.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
2 * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
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 "ovsdb-idl.h"
20
21 #include <errno.h>
22 #include <inttypes.h>
23 #include <limits.h>
24 #include <stdlib.h>
25
26 #include "bitmap.h"
27 #include "coverage.h"
28 #include "hash.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "openvswitch/json.h"
32 #include "jsonrpc.h"
33 #include "ovsdb/ovsdb.h"
34 #include "ovsdb/table.h"
35 #include "ovsdb-data.h"
36 #include "ovsdb-error.h"
37 #include "ovsdb-idl-provider.h"
38 #include "ovsdb-parser.h"
39 #include "openvswitch/poll-loop.h"
40 #include "openvswitch/shash.h"
41 #include "skiplist.h"
42 #include "sset.h"
43 #include "util.h"
44 #include "uuid.h"
45 #include "openvswitch/vlog.h"
46
47 VLOG_DEFINE_THIS_MODULE(ovsdb_idl);
48
49 COVERAGE_DEFINE(txn_uncommitted);
50 COVERAGE_DEFINE(txn_unchanged);
51 COVERAGE_DEFINE(txn_incomplete);
52 COVERAGE_DEFINE(txn_aborted);
53 COVERAGE_DEFINE(txn_success);
54 COVERAGE_DEFINE(txn_try_again);
55 COVERAGE_DEFINE(txn_not_locked);
56 COVERAGE_DEFINE(txn_error);
57
58 /* An arc from one idl_row to another. When row A contains a UUID that
59 * references row B, this is represented by an arc from A (the source) to B
60 * (the destination).
61 *
62 * Arcs from a row to itself are omitted, that is, src and dst are always
63 * different.
64 *
65 * Arcs are never duplicated, that is, even if there are multiple references
66 * from A to B, there is only a single arc from A to B.
67 *
68 * Arcs are directed: an arc from A to B is the converse of an an arc from B to
69 * A. Both an arc and its converse may both be present, if each row refers
70 * to the other circularly.
71 *
72 * The source and destination row may be in the same table or in different
73 * tables.
74 */
75 struct ovsdb_idl_arc {
76 struct ovs_list src_node; /* In src->src_arcs list. */
77 struct ovs_list dst_node; /* In dst->dst_arcs list. */
78 struct ovsdb_idl_row *src; /* Source row. */
79 struct ovsdb_idl_row *dst; /* Destination row. */
80 };
81
82 /* Connection state machine.
83 *
84 * When a JSON-RPC session connects, the IDL sends a "get_schema" request and
85 * transitions to IDL_S_SCHEMA_REQUESTED. If the session drops and reconnects,
86 * the IDL starts over again in the same way. */
87 enum ovsdb_idl_state {
88 /* Waits for "get_schema" reply, then sends a "monitor_cond" request whose
89 * details are informed by the schema and transitions to
90 * IDL_S_MONITOR_COND_REQUESTED. */
91 IDL_S_SCHEMA_REQUESTED,
92
93 /* Waits for "monitor_cond" reply:
94 *
95 * - If the reply indicates success, replaces the IDL contents by the
96 * data carried in the reply and transitions to IDL_S_MONITORING_COND.
97 *
98 * - If the reply indicates failure because the database is too old to
99 * support monitor_cond, sends a "monitor" request and transitions to
100 * IDl_S_MONITOR_REQUESTED. */
101 IDL_S_MONITOR_COND_REQUESTED,
102
103 /* Waits for "monitor" reply, then replaces the IDL contents by the data
104 * carried in the reply and transitions to IDL_S_MONITORING. */
105 IDL_S_MONITOR_REQUESTED,
106
107 /* Terminal states that process "update2" (IDL_S_MONITORING_COND) or
108 * "update" (IDL_S_MONITORING) notifications. */
109 IDL_S_MONITORING_COND,
110 IDL_S_MONITORING,
111
112 /* Terminal error state that indicates that nothing useful can be done.
113 * The most likely reason is that the database server doesn't have the
114 * desired database. We maintain the session with the database server
115 * anyway. If it starts serving the database that we want, then it will
116 * kill the session and we will automatically reconnect and try again. */
117 IDL_S_NO_SCHEMA
118 };
119
120 struct ovsdb_idl {
121 /* Data. */
122 const struct ovsdb_idl_class *class_;
123 struct shash table_by_name; /* Contains "struct ovsdb_idl_table *"s.*/
124 struct ovsdb_idl_table *tables; /* Array of ->class_->n_tables elements. */
125 unsigned int change_seqno;
126
127 /* Session state.
128 *
129 *'state_seqno' is a snapshot of the session's sequence number as returned
130 * jsonrpc_session_get_seqno(session), so if it differs from the value that
131 * function currently returns then the session has reconnected and the
132 * state machine must restart. */
133 struct jsonrpc_session *session; /* Connection to the server. */
134 enum ovsdb_idl_state state; /* Current session state. */
135 unsigned int state_seqno; /* See above. */
136 struct json *request_id; /* JSON ID for request awaiting reply. */
137 struct json *schema; /* Temporary copy of database schema. */
138
139 /* Database locking. */
140 char *lock_name; /* Name of lock we need, NULL if none. */
141 bool has_lock; /* Has db server told us we have the lock? */
142 bool is_lock_contended; /* Has db server told us we can't get lock? */
143 struct json *lock_request_id; /* JSON-RPC ID of in-flight lock request. */
144
145 /* Transaction support. */
146 struct ovsdb_idl_txn *txn;
147 struct hmap outstanding_txns;
148 bool verify_write_only;
149
150 /* Conditional monitoring. */
151 bool cond_changed;
152 unsigned int cond_seqno; /* Keep track of condition clauses changes
153 over a single conditional monitoring session.
154 Reverts to zero when idl session
155 reconnects. */
156 };
157
158 struct ovsdb_idl_txn {
159 struct hmap_node hmap_node;
160 struct json *request_id;
161 struct ovsdb_idl *idl;
162 struct hmap txn_rows;
163 enum ovsdb_idl_txn_status status;
164 char *error;
165 bool dry_run;
166 struct ds comment;
167
168 /* Increments. */
169 const char *inc_table;
170 const char *inc_column;
171 struct uuid inc_row;
172 bool inc_force;
173 unsigned int inc_index;
174 int64_t inc_new_value;
175
176 /* Inserted rows. */
177 struct hmap inserted_rows; /* Contains "struct ovsdb_idl_txn_insert"s. */
178 };
179
180 struct ovsdb_idl_txn_insert {
181 struct hmap_node hmap_node; /* In struct ovsdb_idl_txn's inserted_rows. */
182 struct uuid dummy; /* Dummy UUID used locally. */
183 int op_index; /* Index into transaction's operation array. */
184 struct uuid real; /* Real UUID used by database server. */
185 };
186
187 enum ovsdb_update_version {
188 OVSDB_UPDATE, /* RFC 7047 "update" method. */
189 OVSDB_UPDATE2 /* "update2" Extension to RFC 7047.
190 See ovsdb-server(1) for more information. */
191 };
192
193 /* Name arrays indexed by 'enum ovsdb_update_version'. */
194 static const char *table_updates_names[] = {"table_updates", "table_updates2"};
195 static const char *table_update_names[] = {"table_update", "table_update2"};
196 static const char *row_update_names[] = {"row_update", "row_update2"};
197
198 static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
199 static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5);
200 static struct vlog_rate_limit other_rl = VLOG_RATE_LIMIT_INIT(1, 5);
201
202 static void ovsdb_idl_clear(struct ovsdb_idl *);
203 static void ovsdb_idl_send_schema_request(struct ovsdb_idl *);
204 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *);
205 static void ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl *);
206 static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct json *,
207 enum ovsdb_update_version);
208 static struct ovsdb_error *ovsdb_idl_parse_update__(struct ovsdb_idl *,
209 const struct json *,
210 enum ovsdb_update_version);
211 static bool ovsdb_idl_process_update(struct ovsdb_idl_table *,
212 const struct uuid *,
213 const struct json *old,
214 const struct json *new);
215 static bool ovsdb_idl_process_update2(struct ovsdb_idl_table *,
216 const struct uuid *,
217 const char *operation,
218 const struct json *row);
219 static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct json *);
220 static void ovsdb_idl_delete_row(struct ovsdb_idl_row *);
221 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct json *);
222 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *,
223 const struct json *);
224
225 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *);
226 static struct ovsdb_idl_row *ovsdb_idl_row_create__(
227 const struct ovsdb_idl_table_class *);
228 static struct ovsdb_idl_row *ovsdb_idl_row_create(struct ovsdb_idl_table *,
229 const struct uuid *);
230 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row *);
231 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *);
232 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *);
233 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *);
234
235 static void ovsdb_idl_row_parse(struct ovsdb_idl_row *);
236 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row *);
237 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row *);
238 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row *);
239 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *, bool destroy_dsts);
240
241 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl *);
242 static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl *,
243 const struct jsonrpc_msg *msg);
244 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *,
245 struct json *);
246 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *,
247 const struct ovsdb_idl_column *,
248 struct ovsdb_datum *,
249 enum map_op_type);
250 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *,
251 const struct ovsdb_idl_column *,
252 struct ovsdb_datum *,
253 enum set_op_type);
254
255 static void ovsdb_idl_send_lock_request(struct ovsdb_idl *);
256 static void ovsdb_idl_send_unlock_request(struct ovsdb_idl *);
257 static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl *,
258 const struct json *);
259 static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
260 const struct json *params,
261 bool new_has_lock);
262 static struct ovsdb_idl_table *
263 ovsdb_idl_table_from_class(const struct ovsdb_idl *,
264 const struct ovsdb_idl_table_class *);
265 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table);
266 static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
267
268 static struct ovsdb_idl_index *ovsdb_idl_create_index_(const struct
269 ovsdb_idl_table *table,
270 size_t allocated_cols);
271 static void
272 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *table);
273 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
274 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
275
276 /* Creates and returns a connection to database 'remote', which should be in a
277 * form acceptable to jsonrpc_session_open(). The connection will maintain an
278 * in-memory replica of the remote database whose schema is described by
279 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
280 * by ovsdb-idlc.)
281 *
282 * Passes 'retry' to jsonrpc_session_open(). See that function for
283 * documentation.
284 *
285 * If 'monitor_everything_by_default' is true, then everything in the remote
286 * database will be replicated by default. ovsdb_idl_omit() and
287 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
288 * monitoring.
289 *
290 * If 'monitor_everything_by_default' is false, then no columns or tables will
291 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
292 * must be used to choose some columns or tables to replicate.
293 */
294 struct ovsdb_idl *
295 ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
296 bool monitor_everything_by_default, bool retry)
297 {
298 struct ovsdb_idl *idl;
299 uint8_t default_mode;
300 size_t i;
301
302 default_mode = (monitor_everything_by_default
303 ? OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT
304 : 0);
305
306 idl = xzalloc(sizeof *idl);
307 idl->class_ = class;
308 idl->session = jsonrpc_session_open(remote, retry);
309 shash_init(&idl->table_by_name);
310 idl->tables = xmalloc(class->n_tables * sizeof *idl->tables);
311 for (i = 0; i < class->n_tables; i++) {
312 const struct ovsdb_idl_table_class *tc = &class->tables[i];
313 struct ovsdb_idl_table *table = &idl->tables[i];
314 size_t j;
315
316 shash_add_assert(&idl->table_by_name, tc->name, table);
317 table->class_ = tc;
318 table->modes = xmalloc(tc->n_columns);
319 memset(table->modes, default_mode, tc->n_columns);
320 table->need_table = false;
321 shash_init(&table->columns);
322 shash_init(&table->indexes);
323 for (j = 0; j < tc->n_columns; j++) {
324 const struct ovsdb_idl_column *column = &tc->columns[j];
325
326 shash_add_assert(&table->columns, column->name, column);
327 }
328 hmap_init(&table->rows);
329 ovs_list_init(&table->track_list);
330 table->change_seqno[OVSDB_IDL_CHANGE_INSERT]
331 = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
332 = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
333 table->idl = idl;
334 ovsdb_idl_condition_init(&table->condition);
335 ovsdb_idl_condition_add_clause_true(&table->condition);
336 table->cond_changed = false;
337 }
338
339 idl->cond_changed = false;
340 idl->cond_seqno = 0;
341 idl->state_seqno = UINT_MAX;
342 idl->request_id = NULL;
343 idl->schema = NULL;
344
345 hmap_init(&idl->outstanding_txns);
346
347 return idl;
348 }
349
350 /* Changes the remote and creates a new session. */
351 void
352 ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
353 bool retry)
354 {
355 if (idl) {
356 ovs_assert(!idl->txn);
357 jsonrpc_session_close(idl->session);
358 idl->session = jsonrpc_session_open(remote, retry);
359 idl->state_seqno = UINT_MAX;
360 }
361 }
362
363 /* Destroys 'idl' and all of the data structures that it manages. */
364 void
365 ovsdb_idl_destroy(struct ovsdb_idl *idl)
366 {
367 if (idl) {
368 size_t i;
369
370 ovs_assert(!idl->txn);
371 ovsdb_idl_clear(idl);
372 jsonrpc_session_close(idl->session);
373
374 for (i = 0; i < idl->class_->n_tables; i++) {
375 struct ovsdb_idl_table *table = &idl->tables[i];
376 ovsdb_idl_condition_destroy(&table->condition);
377 ovsdb_idl_destroy_indexes(table);
378 shash_destroy(&table->columns);
379 hmap_destroy(&table->rows);
380 free(table->modes);
381 }
382 shash_destroy(&idl->table_by_name);
383 free(idl->tables);
384 json_destroy(idl->request_id);
385 free(idl->lock_name);
386 json_destroy(idl->lock_request_id);
387 json_destroy(idl->schema);
388 hmap_destroy(&idl->outstanding_txns);
389 free(idl);
390 }
391 }
392
393 static void
394 ovsdb_idl_clear(struct ovsdb_idl *idl)
395 {
396 bool changed = false;
397 size_t i;
398
399 for (i = 0; i < idl->class_->n_tables; i++) {
400 struct ovsdb_idl_table *table = &idl->tables[i];
401 struct ovsdb_idl_row *row, *next_row;
402
403 table->cond_changed = false;
404 if (hmap_is_empty(&table->rows)) {
405 continue;
406 }
407
408 changed = true;
409 HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &table->rows) {
410 struct ovsdb_idl_arc *arc, *next_arc;
411
412 if (!ovsdb_idl_row_is_orphan(row)) {
413 ovsdb_idl_remove_from_indexes(row);
414 ovsdb_idl_row_unparse(row);
415 }
416 LIST_FOR_EACH_SAFE (arc, next_arc, src_node, &row->src_arcs) {
417 free(arc);
418 }
419 /* No need to do anything with dst_arcs: some node has those arcs
420 * as forward arcs and will destroy them itself. */
421
422 if (!ovs_list_is_empty(&row->track_node)) {
423 ovs_list_remove(&row->track_node);
424 }
425
426 ovsdb_idl_row_destroy(row);
427 }
428 }
429
430 idl->cond_changed = false;
431 idl->cond_seqno = 0;
432 ovsdb_idl_track_clear(idl);
433
434 if (changed) {
435 idl->change_seqno++;
436 }
437 }
438
439 /* Processes a batch of messages from the database server on 'idl'. This may
440 * cause the IDL's contents to change. The client may check for that with
441 * ovsdb_idl_get_seqno(). */
442 void
443 ovsdb_idl_run(struct ovsdb_idl *idl)
444 {
445 int i;
446
447 ovs_assert(!idl->txn);
448
449 ovsdb_idl_send_cond_change(idl);
450
451 jsonrpc_session_run(idl->session);
452 for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
453 struct jsonrpc_msg *msg;
454 unsigned int seqno;
455
456 seqno = jsonrpc_session_get_seqno(idl->session);
457 if (idl->state_seqno != seqno) {
458 idl->state_seqno = seqno;
459 json_destroy(idl->request_id);
460 idl->request_id = NULL;
461 ovsdb_idl_txn_abort_all(idl);
462
463 ovsdb_idl_send_schema_request(idl);
464 idl->state = IDL_S_SCHEMA_REQUESTED;
465 if (idl->lock_name) {
466 ovsdb_idl_send_lock_request(idl);
467 }
468 }
469
470 msg = jsonrpc_session_recv(idl->session);
471 if (!msg) {
472 break;
473 }
474
475 if (msg->type == JSONRPC_NOTIFY
476 && !strcmp(msg->method, "update2")
477 && msg->params->type == JSON_ARRAY
478 && msg->params->u.array.n == 2
479 && msg->params->u.array.elems[0]->type == JSON_STRING) {
480 /* Database contents changed. */
481 ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1],
482 OVSDB_UPDATE2);
483 } else if (msg->type == JSONRPC_REPLY
484 && idl->request_id
485 && json_equal(idl->request_id, msg->id)) {
486 json_destroy(idl->request_id);
487 idl->request_id = NULL;
488
489 switch (idl->state) {
490 case IDL_S_SCHEMA_REQUESTED:
491 /* Reply to our "get_schema" request. */
492 idl->schema = json_clone(msg->result);
493 ovsdb_idl_send_monitor_cond_request(idl);
494 idl->state = IDL_S_MONITOR_COND_REQUESTED;
495 break;
496
497 case IDL_S_MONITOR_REQUESTED:
498 case IDL_S_MONITOR_COND_REQUESTED:
499 /* Reply to our "monitor" or "monitor_cond" request. */
500 idl->change_seqno++;
501 ovsdb_idl_clear(idl);
502 if (idl->state == IDL_S_MONITOR_REQUESTED) {
503 idl->state = IDL_S_MONITORING;
504 ovsdb_idl_parse_update(idl, msg->result, OVSDB_UPDATE);
505 } else { /* IDL_S_MONITOR_COND_REQUESTED. */
506 idl->state = IDL_S_MONITORING_COND;
507 ovsdb_idl_parse_update(idl, msg->result, OVSDB_UPDATE2);
508 }
509
510 /* Schema is not useful after monitor request is accepted
511 * by the server. */
512 json_destroy(idl->schema);
513 idl->schema = NULL;
514 break;
515
516 case IDL_S_MONITORING_COND:
517 /* Conditional monitor clauses were updated. Send out
518 * the next condition changes, in any, immediately. */
519 ovsdb_idl_send_cond_change(idl);
520 idl->cond_seqno++;
521 break;
522
523 case IDL_S_MONITORING:
524 case IDL_S_NO_SCHEMA:
525 default:
526 OVS_NOT_REACHED();
527 }
528 } else if (msg->type == JSONRPC_NOTIFY
529 && !strcmp(msg->method, "update")
530 && msg->params->type == JSON_ARRAY
531 && msg->params->u.array.n == 2
532 && msg->params->u.array.elems[0]->type == JSON_STRING) {
533 /* Database contents changed. */
534 ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1],
535 OVSDB_UPDATE);
536 } else if (msg->type == JSONRPC_REPLY
537 && idl->lock_request_id
538 && json_equal(idl->lock_request_id, msg->id)) {
539 /* Reply to our "lock" request. */
540 ovsdb_idl_parse_lock_reply(idl, msg->result);
541 } else if (msg->type == JSONRPC_NOTIFY
542 && !strcmp(msg->method, "locked")) {
543 /* We got our lock. */
544 ovsdb_idl_parse_lock_notify(idl, msg->params, true);
545 } else if (msg->type == JSONRPC_NOTIFY
546 && !strcmp(msg->method, "stolen")) {
547 /* Someone else stole our lock. */
548 ovsdb_idl_parse_lock_notify(idl, msg->params, false);
549 } else if (msg->type == JSONRPC_ERROR
550 && idl->state == IDL_S_MONITOR_COND_REQUESTED
551 && idl->request_id
552 && json_equal(idl->request_id, msg->id)) {
553 if (msg->error && msg->error->type == JSON_STRING
554 && !strcmp(json_string(msg->error), "unknown method")) {
555 /* Fall back to using "monitor" method. */
556 json_destroy(idl->request_id);
557 idl->request_id = NULL;
558 ovsdb_idl_send_monitor_request(idl);
559 idl->state = IDL_S_MONITOR_REQUESTED;
560 }
561 } else if (msg->type == JSONRPC_ERROR
562 && idl->state == IDL_S_MONITORING_COND
563 && idl->request_id
564 && json_equal(idl->request_id, msg->id)) {
565 json_destroy(idl->request_id);
566 idl->request_id = NULL;
567 VLOG_ERR("%s: conditional monitor update failed",
568 jsonrpc_session_get_name(idl->session));
569 idl->state = IDL_S_NO_SCHEMA;
570 } else if (msg->type == JSONRPC_ERROR
571 && idl->state == IDL_S_SCHEMA_REQUESTED
572 && idl->request_id
573 && json_equal(idl->request_id, msg->id)) {
574 json_destroy(idl->request_id);
575 idl->request_id = NULL;
576 VLOG_ERR("%s: requested schema not found",
577 jsonrpc_session_get_name(idl->session));
578 idl->state = IDL_S_NO_SCHEMA;
579 } else if ((msg->type == JSONRPC_ERROR
580 || msg->type == JSONRPC_REPLY)
581 && ovsdb_idl_txn_process_reply(idl, msg)) {
582 /* ovsdb_idl_txn_process_reply() did everything needful. */
583 } else {
584 /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
585 * a transaction before we receive the reply, so keep the log level
586 * low. */
587 VLOG_DBG("%s: received unexpected %s message",
588 jsonrpc_session_get_name(idl->session),
589 jsonrpc_msg_type_to_string(msg->type));
590 }
591 jsonrpc_msg_destroy(msg);
592 }
593 ovsdb_idl_row_destroy_postprocess(idl);
594 }
595
596 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
597 * do or when activity occurs on a transaction on 'idl'. */
598 void
599 ovsdb_idl_wait(struct ovsdb_idl *idl)
600 {
601 jsonrpc_session_wait(idl->session);
602 jsonrpc_session_recv_wait(idl->session);
603 }
604
605 /* Returns a "sequence number" that represents the state of 'idl'. When
606 * ovsdb_idl_run() changes the database, the sequence number changes. The
607 * initial fetch of the entire contents of the remote database is considered to
608 * be one kind of change. Successfully acquiring a lock, if one has been
609 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
610 *
611 * As long as the sequence number does not change, the client may continue to
612 * use any data structures it obtains from 'idl'. But when it changes, the
613 * client must not access any of these data structures again, because they
614 * could have freed or reused for other purposes.
615 *
616 * The sequence number can occasionally change even if the database does not.
617 * This happens if the connection to the database drops and reconnects, which
618 * causes the database contents to be reloaded even if they didn't change. (It
619 * could also happen if the database server sends out a "change" that reflects
620 * what the IDL already thought was in the database. The database server is
621 * not supposed to do that, but bugs could in theory cause it to do so.) */
622 unsigned int
623 ovsdb_idl_get_seqno(const struct ovsdb_idl *idl)
624 {
625 return idl->change_seqno;
626 }
627
628 /* Returns a "sequence number" that represents the number of conditional
629 * monitoring updates successfully received by the OVSDB server of an IDL
630 * connection.
631 *
632 * ovsdb_idl_set_condition() sets a new condition that is different from
633 * the current condtion, the next expected "sequence number" is returned.
634 *
635 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
636 * the return value of ovsdb_idl_set_condition(), The client is
637 * assured that:
638 * - The ovsdb_idl_set_condition() changes has been acknowledged by
639 * the OVSDB sever.
640 *
641 * - 'idl' now contains the content matches the new conditions. */
642 unsigned int
643 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl *idl)
644 {
645 return idl->cond_seqno;
646 }
647
648 /* Returns true if 'idl' successfully connected to the remote database and
649 * retrieved its contents (even if the connection subsequently dropped and is
650 * in the process of reconnecting). If so, then 'idl' contains an atomic
651 * snapshot of the database's contents (but it might be arbitrarily old if the
652 * connection dropped).
653 *
654 * Returns false if 'idl' has never connected or retrieved the database's
655 * contents. If so, 'idl' is empty. */
656 bool
657 ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
658 {
659 return ovsdb_idl_get_seqno(idl) != 0;
660 }
661
662 /* Reconfigures 'idl' so that it would reconnect to the database, if
663 * connection was dropped. */
664 void
665 ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
666 {
667 jsonrpc_session_enable_reconnect(idl->session);
668 }
669
670 /* Forces 'idl' to drop its connection to the database and reconnect. In the
671 * meantime, the contents of 'idl' will not change. */
672 void
673 ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
674 {
675 jsonrpc_session_force_reconnect(idl->session);
676 }
677
678 /* Some IDL users should only write to write-only columns. Furthermore,
679 * writing to a column which is not write-only can cause serious performance
680 * degradations for these users. This function causes 'idl' to reject writes
681 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
682 void
683 ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
684 {
685 idl->verify_write_only = true;
686 }
687
688 /* Returns true if 'idl' is currently connected or trying to connect
689 * and a negative response to a schema request has not been received */
690 bool
691 ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
692 {
693 return jsonrpc_session_is_alive(idl->session) &&
694 idl->state != IDL_S_NO_SCHEMA;
695 }
696
697 /* Returns the last error reported on a connection by 'idl'. The return value
698 * is 0 only if no connection made by 'idl' has ever encountered an error and
699 * a negative response to a schema request has never been received. See
700 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
701 * interpretation. */
702 int
703 ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
704 {
705 int err;
706
707 err = jsonrpc_session_get_last_error(idl->session);
708
709 if (err) {
710 return err;
711 } else if (idl->state == IDL_S_NO_SCHEMA) {
712 return ENOENT;
713 } else {
714 return 0;
715 }
716 }
717
718 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
719 * milliseconds.
720 */
721 void
722 ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
723 {
724 jsonrpc_session_set_probe_interval(idl->session, probe_interval);
725 }
726
727 static size_t
728 find_uuid_in_array(const struct uuid *target,
729 const struct uuid *array, size_t n)
730 {
731 for (size_t i = 0; i < n; i++) {
732 if (uuid_equals(&array[i], target)) {
733 return i;
734 }
735 }
736 return SIZE_MAX;
737 }
738
739 static size_t
740 array_contains_uuid(const struct uuid *target,
741 const struct uuid *array, size_t n)
742 {
743 return find_uuid_in_array(target, array, n) != SIZE_MAX;
744 }
745
746 static bool
747 remove_uuid_from_array(const struct uuid *target,
748 struct uuid *array, size_t *n)
749 {
750 size_t i = find_uuid_in_array(target, array, *n);
751 if (i != SIZE_MAX) {
752 array[i] = array[--*n];
753 return true;
754 } else {
755 return false;
756 }
757 }
758
759 static void
760 add_row_references(const struct ovsdb_base_type *type,
761 const union ovsdb_atom *atoms, size_t n_atoms,
762 const struct uuid *exclude_uuid,
763 struct uuid **dstsp, size_t *n_dstsp,
764 size_t *allocated_dstsp)
765 {
766 if (type->type != OVSDB_TYPE_UUID || !type->u.uuid.refTableName) {
767 return;
768 }
769
770 for (size_t i = 0; i < n_atoms; i++) {
771 const struct uuid *uuid = &atoms[i].uuid;
772 if (!uuid_equals(uuid, exclude_uuid)
773 && !array_contains_uuid(uuid, *dstsp, *n_dstsp)) {
774 if (*n_dstsp >= *allocated_dstsp) {
775 *dstsp = x2nrealloc(*dstsp, allocated_dstsp,
776 sizeof **dstsp);
777
778 }
779 (*dstsp)[*n_dstsp] = *uuid;
780 ++*n_dstsp;
781 }
782 }
783 }
784
785 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
786 * reference from one row to a different row should be reflected as a "struct
787 * ovsdb_idl_arc" between those rows.
788 *
789 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
790 * thus it is only for use in test programs. */
791 void
792 ovsdb_idl_check_consistency(const struct ovsdb_idl *idl)
793 {
794 /* Consistency is broken while a transaction is in progress. */
795 if (!idl->txn) {
796 return;
797 }
798
799 bool ok = true;
800
801 struct uuid *dsts = NULL;
802 size_t allocated_dsts = 0;
803
804 for (size_t i = 0; i < idl->class_->n_tables; i++) {
805 const struct ovsdb_idl_table *table = &idl->tables[i];
806 const struct ovsdb_idl_table_class *class = table->class_;
807
808 const struct ovsdb_idl_row *row;
809 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
810 size_t n_dsts = 0;
811 if (row->new_datum) {
812 size_t n_columns = shash_count(&row->table->columns);
813 for (size_t j = 0; j < n_columns; j++) {
814 const struct ovsdb_type *type = &class->columns[j].type;
815 const struct ovsdb_datum *datum = &row->new_datum[j];
816 add_row_references(&type->key,
817 datum->keys, datum->n, &row->uuid,
818 &dsts, &n_dsts, &allocated_dsts);
819 add_row_references(&type->value,
820 datum->values, datum->n, &row->uuid,
821 &dsts, &n_dsts, &allocated_dsts);
822 }
823 }
824 const struct ovsdb_idl_arc *arc;
825 LIST_FOR_EACH (arc, src_node, &row->src_arcs) {
826 if (!remove_uuid_from_array(&arc->dst->uuid,
827 dsts, &n_dsts)) {
828 VLOG_ERR("unexpected arc from %s row "UUID_FMT" to %s "
829 "row "UUID_FMT,
830 table->class_->name,
831 UUID_ARGS(&row->uuid),
832 arc->dst->table->class_->name,
833 UUID_ARGS(&arc->dst->uuid));
834 ok = false;
835 }
836 }
837 for (size_t j = 0; j < n_dsts; j++) {
838 VLOG_ERR("%s row "UUID_FMT" missing arc to row "UUID_FMT,
839 table->class_->name, UUID_ARGS(&row->uuid),
840 UUID_ARGS(&dsts[j]));
841 ok = false;
842 }
843 }
844 }
845 free(dsts);
846 ovs_assert(ok);
847 }
848 \f
849 const struct ovsdb_idl_class *
850 ovsdb_idl_get_class(const struct ovsdb_idl *idl)
851 {
852 return idl->class_;
853 }
854
855 /* Given 'column' in some table in 'class', returns the table's class. */
856 const struct ovsdb_idl_table_class *
857 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class *class,
858 const struct ovsdb_idl_column *column)
859 {
860 for (size_t i = 0; i < class->n_tables; i++) {
861 const struct ovsdb_idl_table_class *tc = &class->tables[i];
862 if (column >= tc->columns && column < &tc->columns[tc->n_columns]) {
863 return tc;
864 }
865 }
866
867 OVS_NOT_REACHED();
868 }
869
870 /* Given 'column' in some table in 'idl', returns the table. */
871 static struct ovsdb_idl_table *
872 ovsdb_idl_table_from_column(struct ovsdb_idl *idl,
873 const struct ovsdb_idl_column *column)
874 {
875 const struct ovsdb_idl_table_class *tc =
876 ovsdb_idl_table_class_from_column(idl->class_, column);
877 return &idl->tables[tc - idl->class_->tables];
878 }
879
880 static unsigned char *
881 ovsdb_idl_get_mode(struct ovsdb_idl *idl,
882 const struct ovsdb_idl_column *column)
883 {
884 ovs_assert(!idl->change_seqno);
885
886 const struct ovsdb_idl_table *table = ovsdb_idl_table_from_column(idl,
887 column);
888 return &table->modes[column - table->class_->columns];
889 }
890
891 static void
892 add_ref_table(struct ovsdb_idl *idl, const struct ovsdb_base_type *base)
893 {
894 if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName) {
895 struct ovsdb_idl_table *table;
896
897 table = shash_find_data(&idl->table_by_name,
898 base->u.uuid.refTableName);
899 if (table) {
900 table->need_table = true;
901 } else {
902 VLOG_WARN("%s IDL class missing referenced table %s",
903 idl->class_->database, base->u.uuid.refTableName);
904 }
905 }
906 }
907
908 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
909 * ensures that any tables referenced by 'column' will be replicated, even if
910 * no columns in that table are selected for replication (see
911 * ovsdb_idl_add_table() for more information).
912 *
913 * This function is only useful if 'monitor_everything_by_default' was false in
914 * the call to ovsdb_idl_create(). This function should be called between
915 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
916 */
917 void
918 ovsdb_idl_add_column(struct ovsdb_idl *idl,
919 const struct ovsdb_idl_column *column)
920 {
921 *ovsdb_idl_get_mode(idl, column) = OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT;
922 add_ref_table(idl, &column->type.key);
923 add_ref_table(idl, &column->type.value);
924 }
925
926 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
927 * no columns are selected for replication. Just the necessary data for table
928 * references will be replicated (the UUID of the rows, for instance), any
929 * columns not selected for replication will remain unreplicated.
930 * This can be useful because it allows 'idl' to keep track of what rows in the
931 * table actually exist, which in turn allows columns that reference the table
932 * to have accurate contents. (The IDL presents the database with references to
933 * rows that do not exist removed.)
934 *
935 * This function is only useful if 'monitor_everything_by_default' was false in
936 * the call to ovsdb_idl_create(). This function should be called between
937 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
938 */
939 void
940 ovsdb_idl_add_table(struct ovsdb_idl *idl,
941 const struct ovsdb_idl_table_class *tc)
942 {
943 size_t i;
944
945 for (i = 0; i < idl->class_->n_tables; i++) {
946 struct ovsdb_idl_table *table = &idl->tables[i];
947
948 if (table->class_ == tc) {
949 table->need_table = true;
950 return;
951 }
952 }
953
954 OVS_NOT_REACHED();
955 }
956 \f
957 /* A single clause within an ovsdb_idl_condition. */
958 struct ovsdb_idl_clause {
959 struct hmap_node hmap_node; /* In struct ovsdb_idl_condition. */
960 enum ovsdb_function function; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
961 const struct ovsdb_idl_column *column; /* Must be nonnull. */
962 struct ovsdb_datum arg; /* Has ovsdb_type ->column->type. */
963 };
964
965 static uint32_t
966 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause *clause)
967 {
968 uint32_t hash = hash_pointer(clause->column, clause->function);
969 return ovsdb_datum_hash(&clause->arg, &clause->column->type, hash);
970 }
971
972 static int
973 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause *a,
974 const struct ovsdb_idl_clause *b)
975 {
976 return (a->function == b->function
977 && a->column == b->column
978 && ovsdb_datum_equals(&a->arg, &b->arg, &a->column->type));
979 }
980
981 static struct json *
982 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
983 {
984 const char *function = ovsdb_function_to_string(clause->function);
985 return json_array_create_3(json_string_create(clause->column->name),
986 json_string_create(function),
987 ovsdb_datum_to_json(&clause->arg,
988 &clause->column->type));
989 }
990
991 static void
992 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause *clause)
993 {
994 if (clause) {
995 ovsdb_datum_destroy(&clause->arg, &clause->column->type);
996 free(clause);
997 }
998 }
999 \f
1000 /* ovsdb_idl_condition. */
1001
1002 void
1003 ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd)
1004 {
1005 hmap_init(&cnd->clauses);
1006 cnd->is_true = false;
1007 }
1008
1009 void
1010 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cond)
1011 {
1012 if (cond) {
1013 ovsdb_idl_condition_clear(cond);
1014 hmap_destroy(&cond->clauses);
1015 }
1016 }
1017
1018 void
1019 ovsdb_idl_condition_clear(struct ovsdb_idl_condition *cond)
1020 {
1021 struct ovsdb_idl_clause *clause, *next;
1022 HMAP_FOR_EACH_SAFE (clause, next, hmap_node, &cond->clauses) {
1023 hmap_remove(&cond->clauses, &clause->hmap_node);
1024 ovsdb_idl_clause_destroy(clause);
1025 }
1026 cond->is_true = false;
1027 }
1028
1029 bool
1030 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition *condition)
1031 {
1032 return condition->is_true;
1033 }
1034
1035 static struct ovsdb_idl_clause *
1036 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition *condition,
1037 const struct ovsdb_idl_clause *target,
1038 uint32_t hash)
1039 {
1040 struct ovsdb_idl_clause *clause;
1041 HMAP_FOR_EACH_WITH_HASH (clause, hmap_node, hash, &condition->clauses) {
1042 if (ovsdb_idl_clause_equals(clause, target)) {
1043 return clause;
1044 }
1045 }
1046 return NULL;
1047 }
1048
1049 static void
1050 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition *condition,
1051 const struct ovsdb_idl_clause *src,
1052 uint32_t hash)
1053 {
1054 struct ovsdb_idl_clause *clause = xmalloc(sizeof *clause);
1055 clause->function = src->function;
1056 clause->column = src->column;
1057 ovsdb_datum_clone(&clause->arg, &src->arg, &src->column->type);
1058 hmap_insert(&condition->clauses, &clause->hmap_node, hash);
1059 }
1060
1061 /* Adds a clause to the condition for replicating the table with class 'tc' in
1062 * 'idl'.
1063 *
1064 * The IDL replicates only rows in a table that satisfy at least one clause in
1065 * the table's condition. The default condition for a table has a single
1066 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1067 * the table. When the IDL client replaces the default condition by one of its
1068 * own, the condition can have any number of clauses. If it has no conditions,
1069 * then no rows are replicated.
1070 *
1071 * Two distinct of clauses can usefully be added:
1072 *
1073 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1074 * replicated, regardless of whether other clauses exist. 'column' and
1075 * 'arg' are ignored.
1076 *
1077 * - Binary 'functions' add a clause of the form "<column> <function>
1078 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1079 * have a type that is compatible with 'column'.
1080 */
1081 void
1082 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *condition,
1083 enum ovsdb_function function,
1084 const struct ovsdb_idl_column *column,
1085 const struct ovsdb_datum *arg)
1086 {
1087 if (condition->is_true) {
1088 /* Adding a clause to an always-true condition has no effect. */
1089 } else if (function == OVSDB_F_TRUE) {
1090 ovsdb_idl_condition_add_clause_true(condition);
1091 } else if (function == OVSDB_F_FALSE) {
1092 /* Adding a "false" clause never has any effect. */
1093 } else {
1094 struct ovsdb_idl_clause clause = {
1095 .function = function,
1096 .column = column,
1097 .arg = *arg,
1098 };
1099 uint32_t hash = ovsdb_idl_clause_hash(&clause);
1100 if (!ovsdb_idl_condition_find_clause(condition, &clause, hash)) {
1101 ovsdb_idl_condition_add_clause__(condition, &clause, hash);
1102 }
1103 }
1104 }
1105
1106 void
1107 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition *condition)
1108 {
1109 if (!condition->is_true) {
1110 ovsdb_idl_condition_clear(condition);
1111 condition->is_true = true;
1112 }
1113 }
1114
1115 static bool
1116 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a,
1117 const struct ovsdb_idl_condition *b)
1118 {
1119 if (hmap_count(&a->clauses) != hmap_count(&b->clauses)) {
1120 return false;
1121 }
1122 if (a->is_true != b->is_true) {
1123 return false;
1124 }
1125
1126 const struct ovsdb_idl_clause *clause;
1127 HMAP_FOR_EACH (clause, hmap_node, &a->clauses) {
1128 if (!ovsdb_idl_condition_find_clause(b, clause,
1129 clause->hmap_node.hash)) {
1130 return false;
1131 }
1132 }
1133 return true;
1134 }
1135
1136 static void
1137 ovsdb_idl_condition_clone(struct ovsdb_idl_condition *dst,
1138 const struct ovsdb_idl_condition *src)
1139 {
1140 ovsdb_idl_condition_init(dst);
1141
1142 dst->is_true = src->is_true;
1143
1144 const struct ovsdb_idl_clause *clause;
1145 HMAP_FOR_EACH (clause, hmap_node, &src->clauses) {
1146 ovsdb_idl_condition_add_clause__(dst, clause, clause->hmap_node.hash);
1147 }
1148 }
1149
1150 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1151 * arranges to send the new condition to the database server.
1152 *
1153 * Return the next conditional update sequence number. When this
1154 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1155 * contains rows that match the 'condition'. */
1156 unsigned int
1157 ovsdb_idl_set_condition(struct ovsdb_idl *idl,
1158 const struct ovsdb_idl_table_class *tc,
1159 const struct ovsdb_idl_condition *condition)
1160 {
1161 struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
1162 unsigned int seqno = idl->cond_seqno;
1163 if (!ovsdb_idl_condition_equals(condition, &table->condition)) {
1164 ovsdb_idl_condition_destroy(&table->condition);
1165 ovsdb_idl_condition_clone(&table->condition, condition);
1166 idl->cond_changed = table->cond_changed = true;
1167 poll_immediate_wake();
1168 return seqno + 1;
1169 }
1170
1171 return seqno;
1172 }
1173
1174 static struct json *
1175 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
1176 {
1177 if (cnd->is_true) {
1178 return json_array_create_empty();
1179 }
1180
1181 size_t n = hmap_count(&cnd->clauses);
1182 if (!n) {
1183 return json_array_create_1(json_boolean_create(false));
1184 }
1185
1186 struct json **clauses = xmalloc(n * sizeof *clauses);
1187 const struct ovsdb_idl_clause *clause;
1188 size_t i = 0;
1189 HMAP_FOR_EACH (clause, hmap_node, &cnd->clauses) {
1190 clauses[i++] = ovsdb_idl_clause_to_json(clause);
1191 }
1192 ovs_assert(i == n);
1193 return json_array_create(clauses, n);
1194 }
1195 \f
1196 static struct json *
1197 ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table *table)
1198 {
1199 const struct ovsdb_idl_condition *cond = &table->condition;
1200 struct json *monitor_cond_change_request = json_object_create();
1201 struct json *cond_json = ovsdb_idl_condition_to_json(cond);
1202
1203 json_object_put(monitor_cond_change_request, "where", cond_json);
1204
1205 return monitor_cond_change_request;
1206 }
1207
1208 static void
1209 ovsdb_idl_send_cond_change(struct ovsdb_idl *idl)
1210 {
1211 int i;
1212 struct json *params;
1213 struct jsonrpc_msg *request;
1214
1215 /* When 'idl-request_id' is not NULL, there is an outstanding
1216 * conditional monitoring update request that we have not heard
1217 * from the server yet. Don't generate another request in this case. */
1218 if (!idl->cond_changed || !jsonrpc_session_is_connected(idl->session) ||
1219 idl->state != IDL_S_MONITORING_COND || idl->request_id) {
1220 return;
1221 }
1222
1223 struct json *monitor_cond_change_requests = NULL;
1224
1225 for (i = 0; i < idl->class_->n_tables; i++) {
1226 struct ovsdb_idl_table *table = &idl->tables[i];
1227
1228 if (table->cond_changed) {
1229 struct json *req = ovsdb_idl_create_cond_change_req(table);
1230 if (req) {
1231 if (!monitor_cond_change_requests) {
1232 monitor_cond_change_requests = json_object_create();
1233 }
1234 json_object_put(monitor_cond_change_requests,
1235 table->class_->name,
1236 json_array_create_1(req));
1237 }
1238 table->cond_changed = false;
1239 }
1240 }
1241
1242 /* Send request if not empty. */
1243 if (monitor_cond_change_requests) {
1244 params = json_array_create_3(json_string_create("monid"),
1245 json_string_create("monid"),
1246 monitor_cond_change_requests);
1247
1248 request = jsonrpc_create_request("monitor_cond_change", params,
1249 &idl->request_id);
1250 jsonrpc_session_send(idl->session, request);
1251 }
1252 idl->cond_changed = false;
1253 }
1254
1255 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
1256 *
1257 * This function should be called between ovsdb_idl_create() and the first call
1258 * to ovsdb_idl_run().
1259 */
1260 void
1261 ovsdb_idl_omit_alert(struct ovsdb_idl *idl,
1262 const struct ovsdb_idl_column *column)
1263 {
1264 *ovsdb_idl_get_mode(idl, column) &= ~OVSDB_IDL_ALERT;
1265 }
1266
1267 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1268 * OVSDB_IDL_MONITOR for details.
1269 *
1270 * This function should be called between ovsdb_idl_create() and the first call
1271 * to ovsdb_idl_run().
1272 */
1273 void
1274 ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column)
1275 {
1276 *ovsdb_idl_get_mode(idl, column) = 0;
1277 }
1278
1279 /* Returns the most recent IDL change sequence number that caused a
1280 * insert, modify or delete update to the table with class 'table_class'.
1281 */
1282 unsigned int
1283 ovsdb_idl_table_get_seqno(const struct ovsdb_idl *idl,
1284 const struct ovsdb_idl_table_class *table_class)
1285 {
1286 struct ovsdb_idl_table *table
1287 = ovsdb_idl_table_from_class(idl, table_class);
1288 unsigned int max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_INSERT];
1289
1290 if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]) {
1291 max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY];
1292 }
1293 if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_DELETE]) {
1294 max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_DELETE];
1295 }
1296 return max_seqno;
1297 }
1298
1299 /* For each row that contains tracked columns, IDL stores the most
1300 * recent IDL change sequence numbers associateed with insert, modify
1301 * and delete updates to the table.
1302 */
1303 unsigned int
1304 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row *row,
1305 enum ovsdb_idl_change change)
1306 {
1307 return row->change_seqno[change];
1308 }
1309
1310 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1311 * all rows whose 'column' is modified are traced. Similarly, insert
1312 * or delete of rows having 'column' are tracked. Clients are able
1313 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1314 * functions.
1315 *
1316 * This function should be called between ovsdb_idl_create() and
1317 * the first call to ovsdb_idl_run(). The column to be tracked
1318 * should have OVSDB_IDL_ALERT turned on.
1319 */
1320 void
1321 ovsdb_idl_track_add_column(struct ovsdb_idl *idl,
1322 const struct ovsdb_idl_column *column)
1323 {
1324 if (!(*ovsdb_idl_get_mode(idl, column) & OVSDB_IDL_ALERT)) {
1325 ovsdb_idl_add_column(idl, column);
1326 }
1327 *ovsdb_idl_get_mode(idl, column) |= OVSDB_IDL_TRACK;
1328 }
1329
1330 void
1331 ovsdb_idl_track_add_all(struct ovsdb_idl *idl)
1332 {
1333 size_t i, j;
1334
1335 for (i = 0; i < idl->class_->n_tables; i++) {
1336 const struct ovsdb_idl_table_class *tc = &idl->class_->tables[i];
1337
1338 for (j = 0; j < tc->n_columns; j++) {
1339 const struct ovsdb_idl_column *column = &tc->columns[j];
1340 ovsdb_idl_track_add_column(idl, column);
1341 }
1342 }
1343 }
1344
1345 /* Returns true if 'table' has any tracked column. */
1346 static bool
1347 ovsdb_idl_track_is_set(struct ovsdb_idl_table *table)
1348 {
1349 size_t i;
1350
1351 for (i = 0; i < table->class_->n_columns; i++) {
1352 if (table->modes[i] & OVSDB_IDL_TRACK) {
1353 return true;
1354 }
1355 }
1356 return false;
1357 }
1358
1359 /* Returns the first tracked row in table with class 'table_class'
1360 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1361 const struct ovsdb_idl_row *
1362 ovsdb_idl_track_get_first(const struct ovsdb_idl *idl,
1363 const struct ovsdb_idl_table_class *table_class)
1364 {
1365 struct ovsdb_idl_table *table
1366 = ovsdb_idl_table_from_class(idl, table_class);
1367
1368 if (!ovs_list_is_empty(&table->track_list)) {
1369 return CONTAINER_OF(ovs_list_front(&table->track_list), struct ovsdb_idl_row, track_node);
1370 }
1371 return NULL;
1372 }
1373
1374 /* Returns the next tracked row in table after the specified 'row'
1375 * (in no particular order). Returns NULL if there are no tracked rows */
1376 const struct ovsdb_idl_row *
1377 ovsdb_idl_track_get_next(const struct ovsdb_idl_row *row)
1378 {
1379 if (row->track_node.next != &row->table->track_list) {
1380 return CONTAINER_OF(row->track_node.next, struct ovsdb_idl_row, track_node);
1381 }
1382
1383 return NULL;
1384 }
1385
1386 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1387 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1388 *
1389 * Function returns false if 'column' is not tracked (see
1390 * ovsdb_idl_track_add_column()).
1391 */
1392 bool
1393 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
1394 const struct ovsdb_idl_column *column)
1395 {
1396 const struct ovsdb_idl_table_class *class;
1397 size_t column_idx;
1398
1399 class = row->table->class_;
1400 column_idx = column - class->columns;
1401
1402 if (row->updated && bitmap_is_set(row->updated, column_idx)) {
1403 return true;
1404 } else {
1405 return false;
1406 }
1407 }
1408
1409 /* Flushes the tracked rows. Client calls this function after calling
1410 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1411 * functions. This is usually done at the end of the client's processing
1412 * loop when it is ready to do ovsdb_idl_run() again.
1413 */
1414 void
1415 ovsdb_idl_track_clear(const struct ovsdb_idl *idl)
1416 {
1417 size_t i;
1418
1419 for (i = 0; i < idl->class_->n_tables; i++) {
1420 struct ovsdb_idl_table *table = &idl->tables[i];
1421
1422 if (!ovs_list_is_empty(&table->track_list)) {
1423 struct ovsdb_idl_row *row, *next;
1424
1425 LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
1426 if (row->updated) {
1427 free(row->updated);
1428 row->updated = NULL;
1429 }
1430 ovs_list_remove(&row->track_node);
1431 ovs_list_init(&row->track_node);
1432 if (ovsdb_idl_row_is_orphan(row)) {
1433 ovsdb_idl_row_clear_old(row);
1434 free(row);
1435 }
1436 }
1437 }
1438 }
1439 }
1440
1441 \f
1442 static void
1443 ovsdb_idl_send_schema_request(struct ovsdb_idl *idl)
1444 {
1445 struct jsonrpc_msg *msg;
1446
1447 json_destroy(idl->request_id);
1448 msg = jsonrpc_create_request(
1449 "get_schema",
1450 json_array_create_1(json_string_create(idl->class_->database)),
1451 &idl->request_id);
1452 jsonrpc_session_send(idl->session, msg);
1453 }
1454
1455 static void
1456 log_error(struct ovsdb_error *error)
1457 {
1458 char *s = ovsdb_error_to_string(error);
1459 VLOG_WARN("error parsing database schema: %s", s);
1460 free(s);
1461 ovsdb_error_destroy(error);
1462 }
1463
1464 /* Frees 'schema', which is in the format returned by parse_schema(). */
1465 static void
1466 free_schema(struct shash *schema)
1467 {
1468 if (schema) {
1469 struct shash_node *node, *next;
1470
1471 SHASH_FOR_EACH_SAFE (node, next, schema) {
1472 struct sset *sset = node->data;
1473 sset_destroy(sset);
1474 free(sset);
1475 shash_delete(schema, node);
1476 }
1477 shash_destroy(schema);
1478 free(schema);
1479 }
1480 }
1481
1482 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1483 * 7047, to obtain the names of its rows and columns. If successful, returns
1484 * an shash whose keys are table names and whose values are ssets, where each
1485 * sset contains the names of its table's columns. On failure (due to a parse
1486 * error), returns NULL.
1487 *
1488 * It would also be possible to use the general-purpose OVSDB schema parser in
1489 * ovsdb-server, but that's overkill, possibly too strict for the current use
1490 * case, and would require restructuring ovsdb-server to separate the schema
1491 * code from the rest. */
1492 static struct shash *
1493 parse_schema(const struct json *schema_json)
1494 {
1495 struct ovsdb_parser parser;
1496 const struct json *tables_json;
1497 struct ovsdb_error *error;
1498 struct shash_node *node;
1499 struct shash *schema;
1500
1501 ovsdb_parser_init(&parser, schema_json, "database schema");
1502 tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
1503 error = ovsdb_parser_destroy(&parser);
1504 if (error) {
1505 log_error(error);
1506 return NULL;
1507 }
1508
1509 schema = xmalloc(sizeof *schema);
1510 shash_init(schema);
1511 SHASH_FOR_EACH (node, json_object(tables_json)) {
1512 const char *table_name = node->name;
1513 const struct json *json = node->data;
1514 const struct json *columns_json;
1515
1516 ovsdb_parser_init(&parser, json, "table schema for table %s",
1517 table_name);
1518 columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
1519 error = ovsdb_parser_destroy(&parser);
1520 if (error) {
1521 log_error(error);
1522 free_schema(schema);
1523 return NULL;
1524 }
1525
1526 struct sset *columns = xmalloc(sizeof *columns);
1527 sset_init(columns);
1528
1529 struct shash_node *node2;
1530 SHASH_FOR_EACH (node2, json_object(columns_json)) {
1531 const char *column_name = node2->name;
1532 sset_add(columns, column_name);
1533 }
1534 shash_add(schema, table_name, columns);
1535 }
1536 return schema;
1537 }
1538
1539 static void
1540 ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
1541 const char *method)
1542 {
1543 struct shash *schema;
1544 struct json *monitor_requests;
1545 struct jsonrpc_msg *msg;
1546 size_t i;
1547
1548 schema = parse_schema(idl->schema);
1549 monitor_requests = json_object_create();
1550 for (i = 0; i < idl->class_->n_tables; i++) {
1551 struct ovsdb_idl_table *table = &idl->tables[i];
1552 const struct ovsdb_idl_table_class *tc = table->class_;
1553 struct json *monitor_request, *columns, *where;
1554 const struct sset *table_schema;
1555 size_t j;
1556
1557 table_schema = (schema
1558 ? shash_find_data(schema, table->class_->name)
1559 : NULL);
1560
1561 columns = table->need_table ? json_array_create_empty() : NULL;
1562 for (j = 0; j < tc->n_columns; j++) {
1563 const struct ovsdb_idl_column *column = &tc->columns[j];
1564 if (table->modes[j] & OVSDB_IDL_MONITOR) {
1565 if (table_schema
1566 && !sset_contains(table_schema, column->name)) {
1567 VLOG_WARN("%s table in %s database lacks %s column "
1568 "(database needs upgrade?)",
1569 table->class_->name, idl->class_->database,
1570 column->name);
1571 continue;
1572 }
1573 if (!columns) {
1574 columns = json_array_create_empty();
1575 }
1576 json_array_add(columns, json_string_create(column->name));
1577 }
1578 }
1579
1580 if (columns) {
1581 if (schema && !table_schema) {
1582 VLOG_WARN("%s database lacks %s table "
1583 "(database needs upgrade?)",
1584 idl->class_->database, table->class_->name);
1585 json_destroy(columns);
1586 continue;
1587 }
1588
1589 monitor_request = json_object_create();
1590 json_object_put(monitor_request, "columns", columns);
1591 if (!strcmp(method, "monitor_cond")
1592 && !ovsdb_idl_condition_is_true(&table->condition)) {
1593 where = ovsdb_idl_condition_to_json(&table->condition);
1594 json_object_put(monitor_request, "where", where);
1595 table->cond_changed = false;
1596 }
1597 json_object_put(monitor_requests, tc->name, monitor_request);
1598 }
1599 }
1600 free_schema(schema);
1601
1602 json_destroy(idl->request_id);
1603
1604 msg = jsonrpc_create_request(
1605 method,
1606 json_array_create_3(json_string_create(idl->class_->database),
1607 json_string_create("monid"), monitor_requests),
1608 &idl->request_id);
1609 jsonrpc_session_send(idl->session, msg);
1610 idl->cond_changed = false;
1611 }
1612
1613 static void
1614 ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
1615 {
1616 ovsdb_idl_send_monitor_request__(idl, "monitor");
1617 }
1618
1619 static void
1620 log_parse_update_error(struct ovsdb_error *error)
1621 {
1622 if (!VLOG_DROP_WARN(&syntax_rl)) {
1623 char *s = ovsdb_error_to_string(error);
1624 VLOG_WARN_RL(&syntax_rl, "%s", s);
1625 free(s);
1626 }
1627 ovsdb_error_destroy(error);
1628 }
1629
1630 static void
1631 ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl *idl)
1632 {
1633 ovsdb_idl_send_monitor_request__(idl, "monitor_cond");
1634 }
1635
1636 static void
1637 ovsdb_idl_parse_update(struct ovsdb_idl *idl, const struct json *table_updates,
1638 enum ovsdb_update_version version)
1639 {
1640 struct ovsdb_error *error = ovsdb_idl_parse_update__(idl, table_updates,
1641 version);
1642 if (error) {
1643 log_parse_update_error(error);
1644 }
1645 }
1646
1647 static struct ovsdb_error *
1648 ovsdb_idl_parse_update__(struct ovsdb_idl *idl,
1649 const struct json *table_updates,
1650 enum ovsdb_update_version version)
1651 {
1652 const struct shash_node *tables_node;
1653 const char *table_updates_name = table_updates_names[version];
1654 const char *table_update_name = table_update_names[version];
1655 const char *row_update_name = row_update_names[version];
1656
1657 if (table_updates->type != JSON_OBJECT) {
1658 return ovsdb_syntax_error(table_updates, NULL,
1659 "<%s> is not an object",
1660 table_updates_name);
1661 }
1662
1663 SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
1664 const struct json *table_update = tables_node->data;
1665 const struct shash_node *table_node;
1666 struct ovsdb_idl_table *table;
1667
1668 table = shash_find_data(&idl->table_by_name, tables_node->name);
1669 if (!table) {
1670 return ovsdb_syntax_error(
1671 table_updates, NULL,
1672 "<%s> includes unknown table \"%s\"",
1673 table_updates_name,
1674 tables_node->name);
1675 }
1676
1677 if (table_update->type != JSON_OBJECT) {
1678 return ovsdb_syntax_error(table_update, NULL,
1679 "<%s> for table \"%s\" is "
1680 "not an object",
1681 table_update_name,
1682 table->class_->name);
1683 }
1684 SHASH_FOR_EACH (table_node, json_object(table_update)) {
1685 const struct json *row_update = table_node->data;
1686 const struct json *old_json, *new_json;
1687 struct uuid uuid;
1688
1689 if (!uuid_from_string(&uuid, table_node->name)) {
1690 return ovsdb_syntax_error(table_update, NULL,
1691 "<%s> for table \"%s\" "
1692 "contains bad UUID "
1693 "\"%s\" as member name",
1694 table_update_name,
1695 table->class_->name,
1696 table_node->name);
1697 }
1698 if (row_update->type != JSON_OBJECT) {
1699 return ovsdb_syntax_error(row_update, NULL,
1700 "<%s> for table \"%s\" "
1701 "contains <%s> for %s that "
1702 "is not an object",
1703 table_update_name,
1704 table->class_->name,
1705 row_update_name,
1706 table_node->name);
1707 }
1708
1709 switch(version) {
1710 case OVSDB_UPDATE:
1711 old_json = shash_find_data(json_object(row_update), "old");
1712 new_json = shash_find_data(json_object(row_update), "new");
1713 if (old_json && old_json->type != JSON_OBJECT) {
1714 return ovsdb_syntax_error(old_json, NULL,
1715 "\"old\" <row> is not object");
1716 } else if (new_json && new_json->type != JSON_OBJECT) {
1717 return ovsdb_syntax_error(new_json, NULL,
1718 "\"new\" <row> is not object");
1719 } else if ((old_json != NULL) + (new_json != NULL)
1720 != shash_count(json_object(row_update))) {
1721 return ovsdb_syntax_error(row_update, NULL,
1722 "<row-update> contains "
1723 "unexpected member");
1724 } else if (!old_json && !new_json) {
1725 return ovsdb_syntax_error(row_update, NULL,
1726 "<row-update> missing \"old\" "
1727 "and \"new\" members");
1728 }
1729
1730 if (ovsdb_idl_process_update(table, &uuid, old_json,
1731 new_json)) {
1732 idl->change_seqno++;
1733 }
1734 break;
1735
1736 case OVSDB_UPDATE2: {
1737 const char *ops[] = {"modify", "insert", "delete", "initial"};
1738 const char *operation;
1739 const struct json *row;
1740 int i;
1741
1742 for (i = 0; i < ARRAY_SIZE(ops); i++) {
1743 operation = ops[i];
1744 row = shash_find_data(json_object(row_update), operation);
1745
1746 if (row) {
1747 if (ovsdb_idl_process_update2(table, &uuid, operation,
1748 row)) {
1749 idl->change_seqno++;
1750 }
1751 break;
1752 }
1753 }
1754
1755 /* row_update2 should contain one of the objects */
1756 if (i == ARRAY_SIZE(ops)) {
1757 return ovsdb_syntax_error(row_update, NULL,
1758 "<row_update2> includes unknown "
1759 "object");
1760 }
1761 break;
1762 }
1763
1764 default:
1765 OVS_NOT_REACHED();
1766 }
1767 }
1768 }
1769
1770 return NULL;
1771 }
1772
1773 static struct ovsdb_idl_row *
1774 ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
1775 {
1776 struct ovsdb_idl_row *row;
1777
1778 HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) {
1779 if (uuid_equals(&row->uuid, uuid)) {
1780 return row;
1781 }
1782 }
1783 return NULL;
1784 }
1785
1786 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1787 * otherwise. */
1788 static bool
1789 ovsdb_idl_process_update(struct ovsdb_idl_table *table,
1790 const struct uuid *uuid, const struct json *old,
1791 const struct json *new)
1792 {
1793 struct ovsdb_idl_row *row;
1794
1795 row = ovsdb_idl_get_row(table, uuid);
1796 if (!new) {
1797 /* Delete row. */
1798 if (row && !ovsdb_idl_row_is_orphan(row)) {
1799 /* XXX perhaps we should check the 'old' values? */
1800 ovsdb_idl_delete_row(row);
1801 } else {
1802 VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
1803 "from table %s",
1804 UUID_ARGS(uuid), table->class_->name);
1805 return false;
1806 }
1807 } else if (!old) {
1808 /* Insert row. */
1809 if (!row) {
1810 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
1811 } else if (ovsdb_idl_row_is_orphan(row)) {
1812 ovsdb_idl_insert_row(row, new);
1813 } else {
1814 VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
1815 "table %s", UUID_ARGS(uuid), table->class_->name);
1816 return ovsdb_idl_modify_row(row, new);
1817 }
1818 } else {
1819 /* Modify row. */
1820 if (row) {
1821 /* XXX perhaps we should check the 'old' values? */
1822 if (!ovsdb_idl_row_is_orphan(row)) {
1823 return ovsdb_idl_modify_row(row, new);
1824 } else {
1825 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
1826 "referenced row "UUID_FMT" in table %s",
1827 UUID_ARGS(uuid), table->class_->name);
1828 ovsdb_idl_insert_row(row, new);
1829 }
1830 } else {
1831 VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
1832 "in table %s", UUID_ARGS(uuid), table->class_->name);
1833 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
1834 }
1835 }
1836
1837 return true;
1838 }
1839
1840 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1841 * otherwise. */
1842 static bool
1843 ovsdb_idl_process_update2(struct ovsdb_idl_table *table,
1844 const struct uuid *uuid,
1845 const char *operation,
1846 const struct json *json_row)
1847 {
1848 struct ovsdb_idl_row *row;
1849
1850 row = ovsdb_idl_get_row(table, uuid);
1851 if (!strcmp(operation, "delete")) {
1852 /* Delete row. */
1853 if (row && !ovsdb_idl_row_is_orphan(row)) {
1854 ovsdb_idl_delete_row(row);
1855 } else {
1856 VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
1857 "from table %s",
1858 UUID_ARGS(uuid), table->class_->name);
1859 return false;
1860 }
1861 } else if (!strcmp(operation, "insert") || !strcmp(operation, "initial")) {
1862 /* Insert row. */
1863 if (!row) {
1864 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), json_row);
1865 } else if (ovsdb_idl_row_is_orphan(row)) {
1866 ovsdb_idl_insert_row(row, json_row);
1867 } else {
1868 VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
1869 "table %s", UUID_ARGS(uuid), table->class_->name);
1870 ovsdb_idl_delete_row(row);
1871 ovsdb_idl_insert_row(row, json_row);
1872 }
1873 } else if (!strcmp(operation, "modify")) {
1874 /* Modify row. */
1875 if (row) {
1876 if (!ovsdb_idl_row_is_orphan(row)) {
1877 return ovsdb_idl_modify_row_by_diff(row, json_row);
1878 } else {
1879 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
1880 "referenced row "UUID_FMT" in table %s",
1881 UUID_ARGS(uuid), table->class_->name);
1882 return false;
1883 }
1884 } else {
1885 VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
1886 "in table %s", UUID_ARGS(uuid), table->class_->name);
1887 return false;
1888 }
1889 } else {
1890 VLOG_WARN_RL(&semantic_rl, "unknown operation %s to "
1891 "table %s", operation, table->class_->name);
1892 return false;
1893 }
1894
1895 return true;
1896 }
1897
1898 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1899 * otherwise.
1900 *
1901 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1902 * Caller needs to provide either valid 'row_json' or 'diff', but not
1903 * both. */
1904 static bool
1905 ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
1906 const struct json *diff_json,
1907 enum ovsdb_idl_change change)
1908 {
1909 struct ovsdb_idl_table *table = row->table;
1910 const struct ovsdb_idl_table_class *class = table->class_;
1911 struct shash_node *node;
1912 bool changed = false;
1913 bool apply_diff = diff_json != NULL;
1914 const struct json *json = apply_diff ? diff_json : row_json;
1915
1916 SHASH_FOR_EACH (node, json_object(json)) {
1917 const char *column_name = node->name;
1918 const struct ovsdb_idl_column *column;
1919 struct ovsdb_datum datum;
1920 struct ovsdb_error *error;
1921 unsigned int column_idx;
1922 struct ovsdb_datum *old;
1923
1924 column = shash_find_data(&table->columns, column_name);
1925 if (!column) {
1926 VLOG_WARN_RL(&syntax_rl, "unknown column %s updating row "UUID_FMT,
1927 column_name, UUID_ARGS(&row->uuid));
1928 continue;
1929 }
1930
1931 column_idx = column - table->class_->columns;
1932 old = &row->old_datum[column_idx];
1933
1934 error = NULL;
1935 if (apply_diff) {
1936 struct ovsdb_datum diff;
1937
1938 ovs_assert(!row_json);
1939 error = ovsdb_transient_datum_from_json(&diff, &column->type,
1940 node->data);
1941 if (!error) {
1942 error = ovsdb_datum_apply_diff(&datum, old, &diff,
1943 &column->type);
1944 ovsdb_datum_destroy(&diff, &column->type);
1945 }
1946 } else {
1947 ovs_assert(!diff_json);
1948 error = ovsdb_datum_from_json(&datum, &column->type, node->data,
1949 NULL);
1950 }
1951
1952 if (!error) {
1953 if (!ovsdb_datum_equals(old, &datum, &column->type)) {
1954 ovsdb_datum_swap(old, &datum);
1955 if (table->modes[column_idx] & OVSDB_IDL_ALERT) {
1956 changed = true;
1957 row->change_seqno[change]
1958 = row->table->change_seqno[change]
1959 = row->table->idl->change_seqno + 1;
1960 if (table->modes[column_idx] & OVSDB_IDL_TRACK) {
1961 if (!ovs_list_is_empty(&row->track_node)) {
1962 ovs_list_remove(&row->track_node);
1963 }
1964 ovs_list_push_back(&row->table->track_list,
1965 &row->track_node);
1966 if (!row->updated) {
1967 row->updated = bitmap_allocate(class->n_columns);
1968 }
1969 bitmap_set1(row->updated, column_idx);
1970 }
1971 }
1972 } else {
1973 /* Didn't really change but the OVSDB monitor protocol always
1974 * includes every value in a row. */
1975 }
1976
1977 ovsdb_datum_destroy(&datum, &column->type);
1978 } else {
1979 char *s = ovsdb_error_to_string(error);
1980 VLOG_WARN_RL(&syntax_rl, "error parsing column %s in row "UUID_FMT
1981 " in table %s: %s", column_name,
1982 UUID_ARGS(&row->uuid), table->class_->name, s);
1983 free(s);
1984 ovsdb_error_destroy(error);
1985 }
1986 }
1987 return changed;
1988 }
1989
1990 static bool
1991 ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json,
1992 enum ovsdb_idl_change change)
1993 {
1994 return ovsdb_idl_row_change__(row, row_json, NULL, change);
1995 }
1996
1997 static bool
1998 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *row,
1999 const struct json *diff_json,
2000 enum ovsdb_idl_change change)
2001 {
2002 return ovsdb_idl_row_change__(row, NULL, diff_json, change);
2003 }
2004
2005 /* When a row A refers to row B through a column with a "refTable" constraint,
2006 * but row B does not exist, row B is called an "orphan row". Orphan rows
2007 * should not persist, because the database enforces referential integrity, but
2008 * they can appear transiently as changes from the database are received (the
2009 * database doesn't try to topologically sort them and circular references mean
2010 * it isn't always possible anyhow).
2011 *
2012 * This function returns true if 'row' is an orphan row, otherwise false.
2013 */
2014 static bool
2015 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
2016 {
2017 return !row->old_datum && !row->new_datum;
2018 }
2019
2020 /* Returns true if 'row' is conceptually part of the database as modified by
2021 * the current transaction (if any), false otherwise.
2022 *
2023 * This function will return true if 'row' is not an orphan (see the comment on
2024 * ovsdb_idl_row_is_orphan()) and:
2025 *
2026 * - 'row' exists in the database and has not been deleted within the
2027 * current transaction (if any).
2028 *
2029 * - 'row' was inserted within the current transaction and has not been
2030 * deleted. (In the latter case you should not have passed 'row' in at
2031 * all, because ovsdb_idl_txn_delete() freed it.)
2032 *
2033 * This function will return false if 'row' is an orphan or if 'row' was
2034 * deleted within the current transaction.
2035 */
2036 static bool
2037 ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
2038 {
2039 return row->new_datum != NULL;
2040 }
2041
2042 static void
2043 ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
2044 {
2045 const struct ovsdb_idl_table_class *class = row->table->class_;
2046 size_t i;
2047
2048 for (i = 0; i < class->n_columns; i++) {
2049 const struct ovsdb_idl_column *c = &class->columns[i];
2050 (c->parse)(row, &row->old_datum[i]);
2051 }
2052 }
2053
2054 static void
2055 ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
2056 {
2057 const struct ovsdb_idl_table_class *class = row->table->class_;
2058 size_t i;
2059
2060 for (i = 0; i < class->n_columns; i++) {
2061 const struct ovsdb_idl_column *c = &class->columns[i];
2062 (c->unparse)(row);
2063 }
2064 }
2065 \f
2066 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2067 * table indexes over one or more columns in the IDL. These indexes provide
2068 * the ability to retrieve rows matching a particular search criteria and to
2069 * iterate over a subset of rows in a defined order.
2070 */
2071
2072 /* Creates a new index with the provided name, attached to the given idl and
2073 * table. Note that all indexes must be created and indexing columns added
2074 * before the first call to ovsdb_idl_run() is made.
2075 */
2076 struct ovsdb_idl_index *
2077 ovsdb_idl_create_index(struct ovsdb_idl *idl,
2078 const struct ovsdb_idl_table_class *tc,
2079 const char *index_name)
2080 {
2081 struct ovsdb_idl_index *index;
2082 size_t i;
2083
2084 for (i = 0; i < idl->class_->n_tables; i++) {
2085 struct ovsdb_idl_table *table = &idl->tables[i];
2086
2087 if (table->class_ == tc) {
2088 index = ovsdb_idl_create_index_(table, 1);
2089 if (!shash_add_once(&table->indexes, index_name, index)) {
2090 VLOG_ERR("Duplicate index name '%s' in table %s",
2091 index_name, table->class_->name);
2092 return NULL;
2093 }
2094 index->index_name = index_name;
2095 return index;
2096 }
2097 }
2098 OVS_NOT_REACHED();
2099 return NULL;
2100 }
2101
2102 /* Generic comparator that can compare each index, using the custom
2103 * configuration (an struct ovsdb_idl_index) passed to it.
2104 * Not intended for direct usage.
2105 */
2106 static int
2107 ovsdb_idl_index_generic_comparer(const void *a,
2108 const void *b, const void *conf)
2109 {
2110 const struct ovsdb_idl_column *column;
2111 const struct ovsdb_idl_index *index;
2112 size_t i;
2113
2114 index = CONST_CAST(struct ovsdb_idl_index *, conf);
2115
2116 if (a == b) {
2117 return 0;
2118 }
2119
2120 for (i = 0; i < index->n_columns; i++) {
2121 int val;
2122 if (index->columns[i].comparer) {
2123 val = index->columns[i].comparer(a, b);
2124 } else {
2125 column = index->columns[i].column;
2126 const struct ovsdb_idl_row *row_a, *row_b;
2127 row_a = CONST_CAST(struct ovsdb_idl_row *, a);
2128 row_b = CONST_CAST(struct ovsdb_idl_row *, b);
2129 const struct ovsdb_datum *datum_a, *datum_b;
2130 datum_a = ovsdb_idl_read(row_a, column);
2131 datum_b = ovsdb_idl_read(row_b, column);
2132 val = ovsdb_datum_compare_3way(datum_a, datum_b, &column->type);
2133 }
2134
2135 if (val) {
2136 return val * index->columns[i].sorting_order;
2137 }
2138 }
2139
2140 /* If ins_del is true then a row is being inserted into or deleted from
2141 * the index list. In this case, we augment the search key with
2142 * additional values (row UUID and memory address) to create a unique
2143 * search key in order to locate the correct entry efficiently and to
2144 * ensure that the correct entry is deleted in the case of a "delete"
2145 * operation.
2146 */
2147 if (index->ins_del) {
2148 const struct ovsdb_idl_row *row_a, *row_b;
2149
2150 row_a = (const struct ovsdb_idl_row *) a;
2151 row_b = (const struct ovsdb_idl_row *) b;
2152 int value = uuid_compare_3way(&row_a->uuid, &row_b->uuid);
2153
2154 return value ? value : (a < b) - (a > b);
2155 } else {
2156 return 0;
2157 }
2158 }
2159
2160 static struct ovsdb_idl_index *
2161 ovsdb_idl_create_index_(const struct ovsdb_idl_table *table,
2162 size_t allocated_cols)
2163 {
2164 struct ovsdb_idl_index *index;
2165
2166 index = xmalloc(sizeof (struct ovsdb_idl_index));
2167 index->n_columns = 0;
2168 index->alloc_columns = allocated_cols;
2169 index->skiplist = skiplist_create(ovsdb_idl_index_generic_comparer, index);
2170 index->columns = xmalloc(allocated_cols *
2171 sizeof (struct ovsdb_idl_index_column));
2172 index->ins_del = false;
2173 index->table = table;
2174 return index;
2175 }
2176
2177 static void
2178 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *table)
2179 {
2180 struct ovsdb_idl_index *index;
2181 struct shash_node *node;
2182
2183 SHASH_FOR_EACH (node, &(table->indexes)) {
2184 index = node->data;
2185 skiplist_destroy(index->skiplist, NULL);
2186 free(index->columns);
2187 }
2188 shash_destroy_free_data(&table->indexes);
2189 }
2190
2191 static void
2192 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *row)
2193 {
2194 struct ovsdb_idl_table *table = row->table;
2195 struct ovsdb_idl_index *index;
2196 struct shash_node *node;
2197
2198 SHASH_FOR_EACH (node, &(table->indexes)) {
2199 index = node->data;
2200 index->ins_del = true;
2201 skiplist_insert(index->skiplist, row);
2202 index->ins_del = false;
2203 }
2204 }
2205
2206 static void
2207 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *row)
2208 {
2209 struct ovsdb_idl_table *table = row->table;
2210 struct ovsdb_idl_index *index;
2211 struct shash_node *node;
2212
2213 SHASH_FOR_EACH (node, &(table->indexes)) {
2214 index = node->data;
2215 index->ins_del = true;
2216 skiplist_delete(index->skiplist, row);
2217 index->ins_del = false;
2218 }
2219 }
2220
2221 /* Adds a column to an existing index (note that columns can only be added to
2222 * an index before the first call to ovsdb_idl_run()). The 'order' parameter
2223 * specifies whether the sort order should be ascending (OVSDB_INDEX_ASC) or
2224 * descending (OVSDB_INDEX_DESC). The 'custom_comparer' parameter, if non-NULL,
2225 * contains a pointer to a custom comparison function. A default comparison
2226 * function is used if a custom comparison function is not provided (the
2227 * default comparison function can only be used for columns of type string,
2228 * uuid, integer, real, or boolean).
2229 */
2230 void
2231 ovsdb_idl_index_add_column(struct ovsdb_idl_index *index,
2232 const struct ovsdb_idl_column *column,
2233 int order, column_comparator *custom_comparer)
2234 {
2235 /* Check that the column or table is tracked */
2236 if (!index->table->need_table &&
2237 !((OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT) &
2238 *ovsdb_idl_get_mode(index->table->idl, column))) {
2239 VLOG_ERR("Can't add unmonitored column '%s' at index '%s' in "
2240 "table '%s'.",
2241 column->name, index->index_name, index->table->class_->name);
2242 }
2243 if (!ovsdb_type_is_scalar(&column->type) && !custom_comparer) {
2244 VLOG_WARN("Comparing non-scalar values.");
2245 }
2246
2247 /* Allocate more memory for column configuration */
2248 if (index->n_columns == index->alloc_columns) {
2249 index->alloc_columns++;
2250 index->columns = xrealloc(index->columns,
2251 index->alloc_columns *
2252 sizeof(struct ovsdb_idl_index_column));
2253 }
2254
2255 /* Append column to index */
2256 int i = index->n_columns;
2257
2258 index->columns[i].column = column;
2259 index->columns[i].comparer = custom_comparer ? custom_comparer : NULL;
2260 if (order == OVSDB_INDEX_ASC) {
2261 index->columns[i].sorting_order = OVSDB_INDEX_ASC;
2262 } else {
2263 index->columns[i].sorting_order = OVSDB_INDEX_DESC;
2264 }
2265 index->n_columns++;
2266 }
2267
2268 bool
2269 ovsdb_idl_initialize_cursor(struct ovsdb_idl *idl,
2270 const struct ovsdb_idl_table_class *tc,
2271 const char *index_name,
2272 struct ovsdb_idl_index_cursor *cursor)
2273 {
2274 size_t i;
2275
2276 for (i = 0; i < idl->class_->n_tables; i++) {
2277 struct ovsdb_idl_table *table = &idl->tables[i];
2278
2279 if (table->class_ == tc) {
2280 struct shash_node *node = shash_find(&table->indexes, index_name);
2281
2282 if (!node || !node->data) {
2283 VLOG_ERR("Cursor initialization failed, "
2284 "index %s at table %s does not exist.",
2285 index_name, tc->name);
2286 cursor->index = NULL;
2287 cursor->position = NULL;
2288 return false;
2289 }
2290 cursor->index = node->data;
2291 cursor->position = skiplist_first(cursor->index->skiplist);
2292 return true;
2293 }
2294 }
2295 VLOG_ERR("Cursor initialization failed, "
2296 "index %s at table %s does not exist.", index_name, tc->name);
2297 return false;
2298 }
2299
2300 /* ovsdb_idl_index_write_ writes a datum in an ovsdb_idl_row,
2301 * and updates the corresponding field in the table record.
2302 * Not intended for direct usage.
2303 */
2304 void
2305 ovsdb_idl_index_write_(struct ovsdb_idl_row *const_row,
2306 const struct ovsdb_idl_column *column,
2307 struct ovsdb_datum *datum,
2308 const struct ovsdb_idl_table_class *class)
2309 {
2310 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, const_row);
2311 size_t column_idx = column - class->columns;
2312
2313 if (bitmap_is_set(row->written, column_idx)) {
2314 free(row->new_datum[column_idx].values);
2315 free(row->new_datum[column_idx].keys);
2316 } else {
2317 bitmap_set1(row->written, column_idx);
2318 }
2319 row->new_datum[column_idx] = *datum;
2320 (column->unparse)(row);
2321 (column->parse)(row, &row->new_datum[column_idx]);
2322 }
2323
2324 /* Magic UUID for index rows */
2325 static const struct uuid index_row_uuid = {
2326 .parts = {0xdeadbeef,
2327 0xdeadbeef,
2328 0xdeadbeef,
2329 0xdeadbeef}};
2330
2331 /* Check if a row is an index row */
2332 static bool
2333 is_index_row(struct ovsdb_idl_row *row)
2334 {
2335 return uuid_equals(&row->uuid, &index_row_uuid);
2336 }
2337
2338 /* Initializes a row for use in an indexed query.
2339 * Not intended for direct usage.
2340 */
2341 struct ovsdb_idl_row *
2342 ovsdb_idl_index_init_row(struct ovsdb_idl * idl,
2343 const struct ovsdb_idl_table_class *class)
2344 {
2345 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
2346 class->row_init(row);
2347 row->uuid = index_row_uuid;
2348 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
2349 row->written = bitmap_allocate(class->n_columns);
2350 row->table = ovsdb_idl_table_from_class(idl, class);
2351 /* arcs are not used for index row, but it doesn't harm to initialize */
2352 ovs_list_init(&row->src_arcs);
2353 ovs_list_init(&row->dst_arcs);
2354 return row;
2355 }
2356
2357 /* Destroys 'row_' and frees all associated memory. This function is intended
2358 * to be used indirectly through one of the "index_destroy_row" functions
2359 * generated by ovsdb-idlc.
2360 */
2361 void
2362 ovsdb_idl_index_destroy_row__(const struct ovsdb_idl_row *row_)
2363 {
2364 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
2365 const struct ovsdb_idl_table_class *class = row->table->class_;
2366 const struct ovsdb_idl_column *c;
2367 size_t i;
2368
2369 ovs_assert(ovs_list_is_empty(&row_->src_arcs));
2370 ovs_assert(ovs_list_is_empty(&row_->dst_arcs));
2371 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
2372 c = &class->columns[i];
2373 (c->unparse) (row);
2374 free(row->new_datum[i].values);
2375 free(row->new_datum[i].keys);
2376 }
2377 free(row->new_datum);
2378 free(row->written);
2379 free(row);
2380 }
2381
2382 /* Moves the cursor to the first entry in the index. Returns a pointer to the
2383 * corresponding ovsdb_idl_row, or NULL if the index list is empy.
2384 */
2385 struct ovsdb_idl_row *
2386 ovsdb_idl_index_first(struct ovsdb_idl_index_cursor *cursor)
2387 {
2388 cursor->position = skiplist_first(cursor->index->skiplist);
2389 return ovsdb_idl_index_data(cursor);
2390 }
2391
2392 /* Moves the cursor to the next record in the index list.
2393 */
2394 struct ovsdb_idl_row *
2395 ovsdb_idl_index_next(struct ovsdb_idl_index_cursor *cursor)
2396 {
2397 if (!cursor->position) {
2398 return NULL;
2399 }
2400 cursor->position = skiplist_next(cursor->position);
2401 return ovsdb_idl_index_data(cursor);
2402 }
2403
2404 /* Returns the ovsdb_idl_row pointer corresponding to the record at the
2405 * current cursor location.
2406 */
2407 struct ovsdb_idl_row *
2408 ovsdb_idl_index_data(struct ovsdb_idl_index_cursor *cursor)
2409 {
2410 return skiplist_get_data(cursor->position);
2411 }
2412
2413 /* Moves the cursor to the first entry in the index matching the specified
2414 * value. If 'value' is NULL, the cursor is moved to the last entry in the
2415 * list. Returns a pointer to the corresponding ovsdb_idl_row or NULL.
2416 */
2417 struct ovsdb_idl_row *
2418 ovsdb_idl_index_find(struct ovsdb_idl_index_cursor *cursor,
2419 struct ovsdb_idl_row *value)
2420 {
2421 if (value) {
2422 cursor->position = skiplist_find(cursor->index->skiplist, value);
2423 } else {
2424 cursor->position = skiplist_first(cursor->index->skiplist);
2425 }
2426 return ovsdb_idl_index_data(cursor);
2427 }
2428
2429 /* Moves the cursor to the first entry in the index with a value greater than
2430 * or equal to the given value. If 'value' is NULL, the cursor is moved to the
2431 * first entry in the index. Returns a pointer to the corresponding
2432 * ovsdb_idl_row or NULL if such a row does not exist.
2433 */
2434 struct ovsdb_idl_row *
2435 ovsdb_idl_index_forward_to(struct ovsdb_idl_index_cursor *cursor,
2436 struct ovsdb_idl_row *value)
2437 {
2438 if (value) {
2439 cursor->position = skiplist_forward_to(cursor->index->skiplist, value);
2440 } else {
2441 cursor->position = skiplist_first(cursor->index->skiplist);
2442 }
2443 return ovsdb_idl_index_data(cursor);
2444 }
2445
2446 /* Returns the result of comparing two rows using the comparison function
2447 * for this index.
2448 * Returns:
2449 * < 0 if a < b
2450 * 0 if a == b
2451 * > 0 if a > b
2452 * When the pointer to either row is NULL, this function considers NULL to be
2453 * greater than any other value, and NULL == NULL.
2454 */
2455 int
2456 ovsdb_idl_index_compare(struct ovsdb_idl_index_cursor *cursor,
2457 struct ovsdb_idl_row *a, struct ovsdb_idl_row *b)
2458 {
2459 if (a && b) {
2460 return ovsdb_idl_index_generic_comparer(a, b, cursor->index);
2461 } else if (!a && !b) {
2462 return 0;
2463 } else if (a) {
2464 return -1;
2465 } else {
2466 return 1;
2467 }
2468 }
2469
2470 static void
2471 ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
2472 {
2473 ovs_assert(row->old_datum == row->new_datum);
2474 if (!ovsdb_idl_row_is_orphan(row)) {
2475 const struct ovsdb_idl_table_class *class = row->table->class_;
2476 size_t i;
2477
2478 for (i = 0; i < class->n_columns; i++) {
2479 ovsdb_datum_destroy(&row->old_datum[i], &class->columns[i].type);
2480 }
2481 free(row->old_datum);
2482 row->old_datum = row->new_datum = NULL;
2483 }
2484 }
2485
2486 static void
2487 ovsdb_idl_row_clear_new(struct ovsdb_idl_row *row)
2488 {
2489 if (row->old_datum != row->new_datum) {
2490 if (row->new_datum) {
2491 const struct ovsdb_idl_table_class *class = row->table->class_;
2492 size_t i;
2493
2494 if (row->written) {
2495 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
2496 ovsdb_datum_destroy(&row->new_datum[i],
2497 &class->columns[i].type);
2498 }
2499 }
2500 free(row->new_datum);
2501 free(row->written);
2502 row->written = NULL;
2503 }
2504 row->new_datum = row->old_datum;
2505 }
2506 }
2507
2508 static void
2509 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *row, bool destroy_dsts)
2510 {
2511 struct ovsdb_idl_arc *arc, *next;
2512
2513 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
2514 * that this causes to be unreferenced, if tracking is not enabled.
2515 * If tracking is enabled, orphaned nodes are removed from hmap but not
2516 * freed.
2517 */
2518 LIST_FOR_EACH_SAFE (arc, next, src_node, &row->src_arcs) {
2519 ovs_list_remove(&arc->dst_node);
2520 if (destroy_dsts
2521 && ovsdb_idl_row_is_orphan(arc->dst)
2522 && ovs_list_is_empty(&arc->dst->dst_arcs)) {
2523 ovsdb_idl_row_destroy(arc->dst);
2524 }
2525 free(arc);
2526 }
2527 ovs_list_init(&row->src_arcs);
2528 }
2529
2530 /* Force nodes that reference 'row' to reparse. */
2531 static void
2532 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row)
2533 {
2534 struct ovsdb_idl_arc *arc, *next;
2535
2536 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2537 * 'arc', so we need to use the "safe" variant of list traversal. However,
2538 * calling an ovsdb_idl_column's 'parse' function will add an arc
2539 * equivalent to 'arc' to row->arcs. That could be a problem for
2540 * traversal, but it adds it at the beginning of the list to prevent us
2541 * from stumbling upon it again.
2542 *
2543 * (If duplicate arcs were possible then we would need to make sure that
2544 * 'next' didn't also point into 'arc''s destination, but we forbid
2545 * duplicate arcs.) */
2546 LIST_FOR_EACH_SAFE (arc, next, dst_node, &row->dst_arcs) {
2547 struct ovsdb_idl_row *ref = arc->src;
2548
2549 ovsdb_idl_row_unparse(ref);
2550 ovsdb_idl_row_clear_arcs(ref, false);
2551 ovsdb_idl_row_parse(ref);
2552 }
2553 }
2554
2555 static struct ovsdb_idl_row *
2556 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
2557 {
2558 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
2559 class->row_init(row);
2560 ovs_list_init(&row->src_arcs);
2561 ovs_list_init(&row->dst_arcs);
2562 hmap_node_nullify(&row->txn_node);
2563 ovs_list_init(&row->track_node);
2564 return row;
2565 }
2566
2567 static struct ovsdb_idl_row *
2568 ovsdb_idl_row_create(struct ovsdb_idl_table *table, const struct uuid *uuid)
2569 {
2570 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(table->class_);
2571 hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
2572 row->uuid = *uuid;
2573 row->table = table;
2574 row->map_op_written = NULL;
2575 row->map_op_lists = NULL;
2576 row->set_op_written = NULL;
2577 row->set_op_lists = NULL;
2578 return row;
2579 }
2580
2581 static void
2582 ovsdb_idl_row_destroy(struct ovsdb_idl_row *row)
2583 {
2584 if (row) {
2585 ovsdb_idl_row_clear_old(row);
2586 hmap_remove(&row->table->rows, &row->hmap_node);
2587 ovsdb_idl_destroy_all_map_op_lists(row);
2588 ovsdb_idl_destroy_all_set_op_lists(row);
2589 if (ovsdb_idl_track_is_set(row->table)) {
2590 row->change_seqno[OVSDB_IDL_CHANGE_DELETE]
2591 = row->table->change_seqno[OVSDB_IDL_CHANGE_DELETE]
2592 = row->table->idl->change_seqno + 1;
2593 }
2594 if (!ovs_list_is_empty(&row->track_node)) {
2595 ovs_list_remove(&row->track_node);
2596 }
2597 ovs_list_push_back(&row->table->track_list, &row->track_node);
2598 }
2599 }
2600
2601 static void
2602 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *row)
2603 {
2604 if (row->map_op_written) {
2605 /* Clear Map Operation Lists */
2606 size_t idx, n_columns;
2607 const struct ovsdb_idl_column *columns;
2608 const struct ovsdb_type *type;
2609 n_columns = row->table->class_->n_columns;
2610 columns = row->table->class_->columns;
2611 BITMAP_FOR_EACH_1 (idx, n_columns, row->map_op_written) {
2612 type = &columns[idx].type;
2613 map_op_list_destroy(row->map_op_lists[idx], type);
2614 }
2615 free(row->map_op_lists);
2616 bitmap_free(row->map_op_written);
2617 row->map_op_lists = NULL;
2618 row->map_op_written = NULL;
2619 }
2620 }
2621
2622 static void
2623 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *row)
2624 {
2625 if (row->set_op_written) {
2626 /* Clear Set Operation Lists */
2627 size_t idx, n_columns;
2628 const struct ovsdb_idl_column *columns;
2629 const struct ovsdb_type *type;
2630 n_columns = row->table->class_->n_columns;
2631 columns = row->table->class_->columns;
2632 BITMAP_FOR_EACH_1 (idx, n_columns, row->set_op_written) {
2633 type = &columns[idx].type;
2634 set_op_list_destroy(row->set_op_lists[idx], type);
2635 }
2636 free(row->set_op_lists);
2637 bitmap_free(row->set_op_written);
2638 row->set_op_lists = NULL;
2639 row->set_op_written = NULL;
2640 }
2641 }
2642
2643 static void
2644 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *idl)
2645 {
2646 size_t i;
2647
2648 for (i = 0; i < idl->class_->n_tables; i++) {
2649 struct ovsdb_idl_table *table = &idl->tables[i];
2650
2651 if (!ovs_list_is_empty(&table->track_list)) {
2652 struct ovsdb_idl_row *row, *next;
2653
2654 LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
2655 if (!ovsdb_idl_track_is_set(row->table)) {
2656 ovs_list_remove(&row->track_node);
2657 free(row);
2658 }
2659 }
2660 }
2661 }
2662 }
2663
2664 static void
2665 ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
2666 {
2667 const struct ovsdb_idl_table_class *class = row->table->class_;
2668 size_t i, datum_size;
2669
2670 ovs_assert(!row->old_datum && !row->new_datum);
2671 datum_size = class->n_columns * sizeof *row->old_datum;
2672 row->old_datum = row->new_datum = xmalloc(datum_size);
2673 for (i = 0; i < class->n_columns; i++) {
2674 ovsdb_datum_init_default(&row->old_datum[i], &class->columns[i].type);
2675 }
2676 ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_INSERT);
2677 ovsdb_idl_row_parse(row);
2678
2679 ovsdb_idl_row_reparse_backrefs(row);
2680 ovsdb_idl_add_to_indexes(row);
2681 }
2682
2683 static void
2684 ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
2685 {
2686 ovsdb_idl_remove_from_indexes(row);
2687 ovsdb_idl_row_unparse(row);
2688 ovsdb_idl_row_clear_arcs(row, true);
2689 ovsdb_idl_row_clear_old(row);
2690 if (ovs_list_is_empty(&row->dst_arcs)) {
2691 ovsdb_idl_row_destroy(row);
2692 } else {
2693 ovsdb_idl_row_reparse_backrefs(row);
2694 }
2695 }
2696
2697 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2698 * otherwise. */
2699 static bool
2700 ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
2701 {
2702 bool changed;
2703
2704 ovsdb_idl_remove_from_indexes(row);
2705 ovsdb_idl_row_unparse(row);
2706 ovsdb_idl_row_clear_arcs(row, true);
2707 changed = ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_MODIFY);
2708 ovsdb_idl_row_parse(row);
2709 ovsdb_idl_add_to_indexes(row);
2710
2711 return changed;
2712 }
2713
2714 static bool
2715 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *row,
2716 const struct json *diff_json)
2717 {
2718 bool changed;
2719
2720 ovsdb_idl_row_unparse(row);
2721 ovsdb_idl_row_clear_arcs(row, true);
2722 changed = ovsdb_idl_row_apply_diff(row, diff_json,
2723 OVSDB_IDL_CHANGE_MODIFY);
2724 ovsdb_idl_row_parse(row);
2725
2726 return changed;
2727 }
2728
2729 static bool
2730 may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
2731 {
2732 const struct ovsdb_idl_arc *arc;
2733
2734 /* No self-arcs. */
2735 if (src == dst) {
2736 return false;
2737 }
2738
2739 /* No duplicate arcs.
2740 *
2741 * We only need to test whether the first arc in dst->dst_arcs originates
2742 * at 'src', since we add all of the arcs from a given source in a clump
2743 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
2744 * added at the front of the dst_arcs list. */
2745 if (ovs_list_is_empty(&dst->dst_arcs)) {
2746 return true;
2747 }
2748 arc = CONTAINER_OF(dst->dst_arcs.next, struct ovsdb_idl_arc, dst_node);
2749 return arc->src != src;
2750 }
2751
2752 static struct ovsdb_idl_table *
2753 ovsdb_idl_table_from_class(const struct ovsdb_idl *idl,
2754 const struct ovsdb_idl_table_class *table_class)
2755 {
2756 return &idl->tables[table_class - idl->class_->tables];
2757 }
2758
2759 /* Called by ovsdb-idlc generated code. */
2760 struct ovsdb_idl_row *
2761 ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
2762 const struct ovsdb_idl_table_class *dst_table_class,
2763 const struct uuid *dst_uuid)
2764 {
2765 struct ovsdb_idl *idl = src->table->idl;
2766 struct ovsdb_idl_table *dst_table;
2767 struct ovsdb_idl_arc *arc;
2768 struct ovsdb_idl_row *dst;
2769
2770 dst_table = ovsdb_idl_table_from_class(idl, dst_table_class);
2771 dst = ovsdb_idl_get_row(dst_table, dst_uuid);
2772 if (idl->txn || is_index_row(src)) {
2773 /* There are two cases we should not update any arcs:
2774 *
2775 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
2776 * any arcs, because the transaction will be backed out at commit or
2777 * abort time and we don't want our graph screwed up.
2778 *
2779 * 2. The row is used as an index for querying purpose only.
2780 *
2781 * In these cases, just return the destination row, if there is one and
2782 * it has not been deleted. */
2783 if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new_datum)) {
2784 return dst;
2785 }
2786 return NULL;
2787 } else {
2788 /* We're being called from some other context. Update the graph. */
2789 if (!dst) {
2790 dst = ovsdb_idl_row_create(dst_table, dst_uuid);
2791 }
2792
2793 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
2794 if (may_add_arc(src, dst)) {
2795 /* The arc *must* be added at the front of the dst_arcs list. See
2796 * ovsdb_idl_row_reparse_backrefs() for details. */
2797 arc = xmalloc(sizeof *arc);
2798 ovs_list_push_front(&src->src_arcs, &arc->src_node);
2799 ovs_list_push_front(&dst->dst_arcs, &arc->dst_node);
2800 arc->src = src;
2801 arc->dst = dst;
2802 }
2803
2804 return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
2805 }
2806 }
2807
2808 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
2809 * pointer to the row if there is one, otherwise a null pointer. */
2810 const struct ovsdb_idl_row *
2811 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
2812 const struct ovsdb_idl_table_class *tc,
2813 const struct uuid *uuid)
2814 {
2815 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
2816 }
2817
2818 static struct ovsdb_idl_row *
2819 next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
2820 {
2821 for (; node; node = hmap_next(&table->rows, node)) {
2822 struct ovsdb_idl_row *row;
2823
2824 row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
2825 if (ovsdb_idl_row_exists(row)) {
2826 return row;
2827 }
2828 }
2829 return NULL;
2830 }
2831
2832 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
2833 * table is empty.
2834 *
2835 * Database tables are internally maintained as hash tables, so adding or
2836 * removing rows while traversing the same table can cause some rows to be
2837 * visited twice or not at apply. */
2838 const struct ovsdb_idl_row *
2839 ovsdb_idl_first_row(const struct ovsdb_idl *idl,
2840 const struct ovsdb_idl_table_class *table_class)
2841 {
2842 struct ovsdb_idl_table *table
2843 = ovsdb_idl_table_from_class(idl, table_class);
2844 return next_real_row(table, hmap_first(&table->rows));
2845 }
2846
2847 /* Returns a row following 'row' within its table, or a null pointer if 'row'
2848 * is the last row in its table. */
2849 const struct ovsdb_idl_row *
2850 ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
2851 {
2852 struct ovsdb_idl_table *table = row->table;
2853
2854 return next_real_row(table, hmap_next(&table->rows, &row->hmap_node));
2855 }
2856
2857 /* Reads and returns the value of 'column' within 'row'. If an ongoing
2858 * transaction has changed 'column''s value, the modified value is returned.
2859 *
2860 * The caller must not modify or free the returned value.
2861 *
2862 * Various kinds of changes can invalidate the returned value: writing to the
2863 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
2864 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
2865 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
2866 * returned value is needed for a long time, it is best to make a copy of it
2867 * with ovsdb_datum_clone(). */
2868 const struct ovsdb_datum *
2869 ovsdb_idl_read(const struct ovsdb_idl_row *row,
2870 const struct ovsdb_idl_column *column)
2871 {
2872 const struct ovsdb_idl_table_class *class;
2873 size_t column_idx;
2874
2875 ovs_assert(!ovsdb_idl_row_is_synthetic(row));
2876
2877 class = row->table->class_;
2878 column_idx = column - class->columns;
2879
2880 ovs_assert(row->new_datum != NULL);
2881 ovs_assert(column_idx < class->n_columns);
2882
2883 if (row->written && bitmap_is_set(row->written, column_idx)) {
2884 return &row->new_datum[column_idx];
2885 } else if (row->old_datum) {
2886 return &row->old_datum[column_idx];
2887 } else {
2888 return ovsdb_datum_default(&column->type);
2889 }
2890 }
2891
2892 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
2893 * type 'key_type' and value type 'value_type'. (Scalar and set types will
2894 * have a value type of OVSDB_TYPE_VOID.)
2895 *
2896 * This is useful in code that "knows" that a particular column has a given
2897 * type, so that it will abort if someone changes the column's type without
2898 * updating the code that uses it. */
2899 const struct ovsdb_datum *
2900 ovsdb_idl_get(const struct ovsdb_idl_row *row,
2901 const struct ovsdb_idl_column *column,
2902 enum ovsdb_atomic_type key_type OVS_UNUSED,
2903 enum ovsdb_atomic_type value_type OVS_UNUSED)
2904 {
2905 ovs_assert(column->type.key.type == key_type);
2906 ovs_assert(column->type.value.type == value_type);
2907
2908 return ovsdb_idl_read(row, column);
2909 }
2910
2911 /* Returns true if the field represented by 'column' in 'row' may be modified,
2912 * false if it is immutable.
2913 *
2914 * Normally, whether a field is mutable is controlled by its column's schema.
2915 * However, an immutable column can be set to any initial value at the time of
2916 * insertion, so if 'row' is a new row (one that is being added as part of the
2917 * current transaction, supposing that a transaction is in progress) then even
2918 * its "immutable" fields are actually mutable. */
2919 bool
2920 ovsdb_idl_is_mutable(const struct ovsdb_idl_row *row,
2921 const struct ovsdb_idl_column *column)
2922 {
2923 return column->is_mutable || (row->new_datum && !row->old_datum);
2924 }
2925
2926 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
2927 * to all-zero-bits by some other entity. If 'row' was set up some other way
2928 * then the return value is indeterminate. */
2929 bool
2930 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *row)
2931 {
2932 return row->table == NULL;
2933 }
2934 \f
2935 /* Transactions. */
2936
2937 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
2938 enum ovsdb_idl_txn_status);
2939
2940 /* Returns a string representation of 'status'. The caller must not modify or
2941 * free the returned string.
2942 *
2943 * The return value is probably useful only for debug log messages and unit
2944 * tests. */
2945 const char *
2946 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
2947 {
2948 switch (status) {
2949 case TXN_UNCOMMITTED:
2950 return "uncommitted";
2951 case TXN_UNCHANGED:
2952 return "unchanged";
2953 case TXN_INCOMPLETE:
2954 return "incomplete";
2955 case TXN_ABORTED:
2956 return "aborted";
2957 case TXN_SUCCESS:
2958 return "success";
2959 case TXN_TRY_AGAIN:
2960 return "try again";
2961 case TXN_NOT_LOCKED:
2962 return "not locked";
2963 case TXN_ERROR:
2964 return "error";
2965 }
2966 return "<unknown>";
2967 }
2968
2969 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
2970 * active transaction at a time. See the large comment in ovsdb-idl.h for
2971 * general information on transactions. */
2972 struct ovsdb_idl_txn *
2973 ovsdb_idl_txn_create(struct ovsdb_idl *idl)
2974 {
2975 struct ovsdb_idl_txn *txn;
2976
2977 ovs_assert(!idl->txn);
2978 idl->txn = txn = xmalloc(sizeof *txn);
2979 txn->request_id = NULL;
2980 txn->idl = idl;
2981 hmap_init(&txn->txn_rows);
2982 txn->status = TXN_UNCOMMITTED;
2983 txn->error = NULL;
2984 txn->dry_run = false;
2985 ds_init(&txn->comment);
2986
2987 txn->inc_table = NULL;
2988 txn->inc_column = NULL;
2989
2990 hmap_init(&txn->inserted_rows);
2991
2992 return txn;
2993 }
2994
2995 /* Appends 's', which is treated as a printf()-type format string, to the
2996 * comments that will be passed to the OVSDB server when 'txn' is committed.
2997 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
2998 * show-log" can print in a relatively human-readable form.) */
2999 void
3000 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
3001 {
3002 va_list args;
3003
3004 if (txn->comment.length) {
3005 ds_put_char(&txn->comment, '\n');
3006 }
3007
3008 va_start(args, s);
3009 ds_put_format_valist(&txn->comment, s, args);
3010 va_end(args);
3011 }
3012
3013 /* Marks 'txn' as a transaction that will not actually modify the database. In
3014 * almost every way, the transaction is treated like other transactions. It
3015 * must be committed or aborted like other transactions, it will be sent to the
3016 * database server like other transactions, and so on. The only difference is
3017 * that the operations sent to the database server will include, as the last
3018 * step, an "abort" operation, so that any changes made by the transaction will
3019 * not actually take effect. */
3020 void
3021 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
3022 {
3023 txn->dry_run = true;
3024 }
3025
3026 /* Causes 'txn', when committed, to increment the value of 'column' within
3027 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3028 * successfully, the client may retrieve the final (incremented) value of
3029 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3030 *
3031 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3032 * change the database, then 'force' is important. If 'force' is false in this
3033 * case, the IDL suppresses the increment and skips a round trip to the
3034 * database server. If 'force' is true, the IDL will still increment the
3035 * column.
3036 *
3037 * The client could accomplish something similar with ovsdb_idl_read(),
3038 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3039 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3040 * will never (by itself) fail because of a verify error.
3041 *
3042 * The intended use is for incrementing the "next_cfg" column in the
3043 * Open_vSwitch table. */
3044 void
3045 ovsdb_idl_txn_increment(struct ovsdb_idl_txn *txn,
3046 const struct ovsdb_idl_row *row,
3047 const struct ovsdb_idl_column *column,
3048 bool force)
3049 {
3050 ovs_assert(!txn->inc_table);
3051 ovs_assert(column->type.key.type == OVSDB_TYPE_INTEGER);
3052 ovs_assert(column->type.value.type == OVSDB_TYPE_VOID);
3053
3054 txn->inc_table = row->table->class_->name;
3055 txn->inc_column = column->name;
3056 txn->inc_row = row->uuid;
3057 txn->inc_force = force;
3058 }
3059
3060 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3061 * has been called for 'txn' but the commit is still incomplete (that is, the
3062 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3063 * end up committing at the database server, but the client will not be able to
3064 * get any further status information back. */
3065 void
3066 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
3067 {
3068 struct ovsdb_idl_txn_insert *insert, *next;
3069
3070 json_destroy(txn->request_id);
3071 if (txn->status == TXN_INCOMPLETE) {
3072 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
3073 }
3074 ovsdb_idl_txn_abort(txn);
3075 ds_destroy(&txn->comment);
3076 free(txn->error);
3077 HMAP_FOR_EACH_SAFE (insert, next, hmap_node, &txn->inserted_rows) {
3078 free(insert);
3079 }
3080 hmap_destroy(&txn->inserted_rows);
3081 free(txn);
3082 }
3083
3084 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3085 void
3086 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
3087 {
3088 if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
3089 poll_immediate_wake();
3090 }
3091 }
3092
3093 static struct json *
3094 where_uuid_equals(const struct uuid *uuid)
3095 {
3096 return
3097 json_array_create_1(
3098 json_array_create_3(
3099 json_string_create("_uuid"),
3100 json_string_create("=="),
3101 json_array_create_2(
3102 json_string_create("uuid"),
3103 json_string_create_nocopy(
3104 xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
3105 }
3106
3107 static char *
3108 uuid_name_from_uuid(const struct uuid *uuid)
3109 {
3110 char *name;
3111 char *p;
3112
3113 name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
3114 for (p = name; *p != '\0'; p++) {
3115 if (*p == '-') {
3116 *p = '_';
3117 }
3118 }
3119
3120 return name;
3121 }
3122
3123 static const struct ovsdb_idl_row *
3124 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
3125 {
3126 const struct ovsdb_idl_row *row;
3127
3128 HMAP_FOR_EACH_WITH_HASH (row, txn_node, uuid_hash(uuid), &txn->txn_rows) {
3129 if (uuid_equals(&row->uuid, uuid)) {
3130 return row;
3131 }
3132 }
3133 return NULL;
3134 }
3135
3136 /* XXX there must be a cleaner way to do this */
3137 static struct json *
3138 substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
3139 {
3140 if (json->type == JSON_ARRAY) {
3141 struct uuid uuid;
3142 size_t i;
3143
3144 if (json->u.array.n == 2
3145 && json->u.array.elems[0]->type == JSON_STRING
3146 && json->u.array.elems[1]->type == JSON_STRING
3147 && !strcmp(json->u.array.elems[0]->u.string, "uuid")
3148 && uuid_from_string(&uuid, json->u.array.elems[1]->u.string)) {
3149 const struct ovsdb_idl_row *row;
3150
3151 row = ovsdb_idl_txn_get_row(txn, &uuid);
3152 if (row && !row->old_datum && row->new_datum) {
3153 json_destroy(json);
3154
3155 return json_array_create_2(
3156 json_string_create("named-uuid"),
3157 json_string_create_nocopy(uuid_name_from_uuid(&uuid)));
3158 }
3159 }
3160
3161 for (i = 0; i < json->u.array.n; i++) {
3162 json->u.array.elems[i] = substitute_uuids(json->u.array.elems[i],
3163 txn);
3164 }
3165 } else if (json->type == JSON_OBJECT) {
3166 struct shash_node *node;
3167
3168 SHASH_FOR_EACH (node, json_object(json)) {
3169 node->data = substitute_uuids(node->data, txn);
3170 }
3171 }
3172 return json;
3173 }
3174
3175 static void
3176 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
3177 {
3178 struct ovsdb_idl_row *row, *next;
3179
3180 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3181 * ovsdb_idl_column's 'parse' function, which will call
3182 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3183 * transaction and fail to update the graph. */
3184 txn->idl->txn = NULL;
3185
3186 HMAP_FOR_EACH_SAFE (row, next, txn_node, &txn->txn_rows) {
3187 ovsdb_idl_destroy_all_map_op_lists(row);
3188 ovsdb_idl_destroy_all_set_op_lists(row);
3189 if (row->old_datum) {
3190 if (row->written) {
3191 ovsdb_idl_row_unparse(row);
3192 ovsdb_idl_row_clear_arcs(row, false);
3193 ovsdb_idl_row_parse(row);
3194 }
3195 } else {
3196 ovsdb_idl_row_unparse(row);
3197 }
3198 ovsdb_idl_row_clear_new(row);
3199
3200 free(row->prereqs);
3201 row->prereqs = NULL;
3202
3203 free(row->written);
3204 row->written = NULL;
3205
3206 hmap_remove(&txn->txn_rows, &row->txn_node);
3207 hmap_node_nullify(&row->txn_node);
3208 if (!row->old_datum) {
3209 hmap_remove(&row->table->rows, &row->hmap_node);
3210 free(row);
3211 }
3212 }
3213 hmap_destroy(&txn->txn_rows);
3214 hmap_init(&txn->txn_rows);
3215 }
3216
3217 static bool
3218 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *row,
3219 struct json *mutations)
3220 {
3221 const struct ovsdb_idl_table_class *class = row->table->class_;
3222 size_t idx;
3223 bool any_mutations = false;
3224
3225 if (row->map_op_written) {
3226 BITMAP_FOR_EACH_1(idx, class->n_columns, row->map_op_written) {
3227 struct map_op_list *map_op_list;
3228 const struct ovsdb_idl_column *column;
3229 const struct ovsdb_datum *old_datum;
3230 enum ovsdb_atomic_type key_type, value_type;
3231 struct json *mutation, *map, *col_name, *mutator;
3232 struct json *del_set, *ins_map;
3233 bool any_del, any_ins;
3234
3235 map_op_list = row->map_op_lists[idx];
3236 column = &class->columns[idx];
3237 key_type = column->type.key.type;
3238 value_type = column->type.value.type;
3239
3240 /* Get the value to be changed */
3241 if (row->new_datum && row->written
3242 && bitmap_is_set(row->written,idx)) {
3243 old_datum = &row->new_datum[idx];
3244 } else if (row->old_datum != NULL) {
3245 old_datum = &row->old_datum[idx];
3246 } else {
3247 old_datum = ovsdb_datum_default(&column->type);
3248 }
3249
3250 del_set = json_array_create_empty();
3251 ins_map = json_array_create_empty();
3252 any_del = false;
3253 any_ins = false;
3254
3255 for (struct map_op *map_op = map_op_list_first(map_op_list); map_op;
3256 map_op = map_op_list_next(map_op_list, map_op)) {
3257
3258 if (map_op_type(map_op) == MAP_OP_UPDATE) {
3259 /* Find out if value really changed. */
3260 struct ovsdb_datum *new_datum;
3261 unsigned int pos;
3262 new_datum = map_op_datum(map_op);
3263 pos = ovsdb_datum_find_key(old_datum,
3264 &new_datum->keys[0],
3265 key_type);
3266 if (ovsdb_atom_equals(&new_datum->values[0],
3267 &old_datum->values[pos],
3268 value_type)) {
3269 /* No change in value. Move on to next update. */
3270 continue;
3271 }
3272 } else if (map_op_type(map_op) == MAP_OP_DELETE){
3273 /* Verify that there is a key to delete. */
3274 unsigned int pos;
3275 pos = ovsdb_datum_find_key(old_datum,
3276 &map_op_datum(map_op)->keys[0],
3277 key_type);
3278 if (pos == UINT_MAX) {
3279 /* No key to delete. Move on to next update. */
3280 VLOG_WARN("Trying to delete a key that doesn't "
3281 "exist in the map.");
3282 continue;
3283 }
3284 }
3285
3286 if (map_op_type(map_op) == MAP_OP_INSERT) {
3287 map = json_array_create_2(
3288 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3289 key_type),
3290 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
3291 value_type));
3292 json_array_add(ins_map, map);
3293 any_ins = true;
3294 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
3295 map = ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3296 key_type);
3297 json_array_add(del_set, map);
3298 any_del = true;
3299 }
3300
3301 /* Generate an additional insert mutate for updates. */
3302 if (map_op_type(map_op) == MAP_OP_UPDATE) {
3303 map = json_array_create_2(
3304 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3305 key_type),
3306 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
3307 value_type));
3308 json_array_add(ins_map, map);
3309 any_ins = true;
3310 }
3311 }
3312
3313 if (any_del) {
3314 col_name = json_string_create(column->name);
3315 mutator = json_string_create("delete");
3316 map = json_array_create_2(json_string_create("set"), del_set);
3317 mutation = json_array_create_3(col_name, mutator, map);
3318 json_array_add(mutations, mutation);
3319 any_mutations = true;
3320 } else {
3321 json_destroy(del_set);
3322 }
3323 if (any_ins) {
3324 col_name = json_string_create(column->name);
3325 mutator = json_string_create("insert");
3326 map = json_array_create_2(json_string_create("map"), ins_map);
3327 mutation = json_array_create_3(col_name, mutator, map);
3328 json_array_add(mutations, mutation);
3329 any_mutations = true;
3330 } else {
3331 json_destroy(ins_map);
3332 }
3333 }
3334 }
3335 if (row->set_op_written) {
3336 BITMAP_FOR_EACH_1(idx, class->n_columns, row->set_op_written) {
3337 struct set_op_list *set_op_list;
3338 const struct ovsdb_idl_column *column;
3339 const struct ovsdb_datum *old_datum;
3340 enum ovsdb_atomic_type key_type;
3341 struct json *mutation, *set, *col_name, *mutator;
3342 struct json *del_set, *ins_set;
3343 bool any_del, any_ins;
3344
3345 set_op_list = row->set_op_lists[idx];
3346 column = &class->columns[idx];
3347 key_type = column->type.key.type;
3348
3349 /* Get the value to be changed */
3350 if (row->new_datum && row->written
3351 && bitmap_is_set(row->written,idx)) {
3352 old_datum = &row->new_datum[idx];
3353 } else if (row->old_datum != NULL) {
3354 old_datum = &row->old_datum[idx];
3355 } else {
3356 old_datum = ovsdb_datum_default(&column->type);
3357 }
3358
3359 del_set = json_array_create_empty();
3360 ins_set = json_array_create_empty();
3361 any_del = false;
3362 any_ins = false;
3363
3364 for (struct set_op *set_op = set_op_list_first(set_op_list); set_op;
3365 set_op = set_op_list_next(set_op_list, set_op)) {
3366 if (set_op_type(set_op) == SET_OP_INSERT) {
3367 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
3368 key_type);
3369 json_array_add(ins_set, set);
3370 any_ins = true;
3371 } else { /* SETP_OP_DELETE */
3372 /* Verify that there is a key to delete. */
3373 unsigned int pos;
3374 pos = ovsdb_datum_find_key(old_datum,
3375 &set_op_datum(set_op)->keys[0],
3376 key_type);
3377 if (pos == UINT_MAX) {
3378 /* No key to delete. Move on to next update. */
3379 VLOG_WARN("Trying to delete a key that doesn't "
3380 "exist in the set.");
3381 continue;
3382 }
3383 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
3384 key_type);
3385 json_array_add(del_set, set);
3386 any_del = true;
3387 }
3388 }
3389 if (any_del) {
3390 col_name = json_string_create(column->name);
3391 mutator = json_string_create("delete");
3392 set = json_array_create_2(json_string_create("set"), del_set);
3393 mutation = json_array_create_3(col_name, mutator, set);
3394 json_array_add(mutations, mutation);
3395 any_mutations = true;
3396 } else {
3397 json_destroy(del_set);
3398 }
3399 if (any_ins) {
3400 col_name = json_string_create(column->name);
3401 mutator = json_string_create("insert");
3402 set = json_array_create_2(json_string_create("set"), ins_set);
3403 mutation = json_array_create_3(col_name, mutator, set);
3404 json_array_add(mutations, mutation);
3405 any_mutations = true;
3406 } else {
3407 json_destroy(ins_set);
3408 }
3409 }
3410 }
3411 return any_mutations;
3412 }
3413
3414 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
3415 * of the following TXN_* constants:
3416 *
3417 * TXN_INCOMPLETE:
3418 *
3419 * The transaction is in progress, but not yet complete. The caller
3420 * should call again later, after calling ovsdb_idl_run() to let the IDL
3421 * do OVSDB protocol processing.
3422 *
3423 * TXN_UNCHANGED:
3424 *
3425 * The transaction is complete. (It didn't actually change the database,
3426 * so the IDL didn't send any request to the database server.)
3427 *
3428 * TXN_ABORTED:
3429 *
3430 * The caller previously called ovsdb_idl_txn_abort().
3431 *
3432 * TXN_SUCCESS:
3433 *
3434 * The transaction was successful. The update made by the transaction
3435 * (and possibly other changes made by other database clients) should
3436 * already be visible in the IDL.
3437 *
3438 * TXN_TRY_AGAIN:
3439 *
3440 * The transaction failed for some transient reason, e.g. because a
3441 * "verify" operation reported an inconsistency or due to a network
3442 * problem. The caller should wait for a change to the database, then
3443 * compose a new transaction, and commit the new transaction.
3444 *
3445 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
3446 * the database. It is important to use its return value *before* the
3447 * initial call to ovsdb_idl_txn_commit() as the baseline for this
3448 * purpose, because the change that one should wait for can happen after
3449 * the initial call but before the call that returns TXN_TRY_AGAIN, and
3450 * using some other baseline value in that situation could cause an
3451 * indefinite wait if the database rarely changes.
3452 *
3453 * TXN_NOT_LOCKED:
3454 *
3455 * The transaction failed because the IDL has been configured to require
3456 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
3457 * has already lost it.
3458 *
3459 * Committing a transaction rolls back all of the changes that it made to the
3460 * IDL's copy of the database. If the transaction commits successfully, then
3461 * the database server will send an update and, thus, the IDL will be updated
3462 * with the committed changes. */
3463 enum ovsdb_idl_txn_status
3464 ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
3465 {
3466 struct ovsdb_idl_row *row;
3467 struct json *operations;
3468 bool any_updates;
3469
3470 if (txn != txn->idl->txn) {
3471 goto coverage_out;
3472 }
3473
3474 /* If we need a lock but don't have it, give up quickly. */
3475 if (txn->idl->lock_name && !ovsdb_idl_has_lock(txn->idl)) {
3476 txn->status = TXN_NOT_LOCKED;
3477 goto disassemble_out;
3478 }
3479
3480 operations = json_array_create_1(
3481 json_string_create(txn->idl->class_->database));
3482
3483 /* Assert that we have the required lock (avoiding a race). */
3484 if (txn->idl->lock_name) {
3485 struct json *op = json_object_create();
3486 json_array_add(operations, op);
3487 json_object_put_string(op, "op", "assert");
3488 json_object_put_string(op, "lock", txn->idl->lock_name);
3489 }
3490
3491 /* Add prerequisites and declarations of new rows. */
3492 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
3493 /* XXX check that deleted rows exist even if no prereqs? */
3494 if (row->prereqs) {
3495 const struct ovsdb_idl_table_class *class = row->table->class_;
3496 size_t n_columns = class->n_columns;
3497 struct json *op, *columns, *row_json;
3498 size_t idx;
3499
3500 op = json_object_create();
3501 json_array_add(operations, op);
3502 json_object_put_string(op, "op", "wait");
3503 json_object_put_string(op, "table", class->name);
3504 json_object_put(op, "timeout", json_integer_create(0));
3505 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3506 json_object_put_string(op, "until", "==");
3507 columns = json_array_create_empty();
3508 json_object_put(op, "columns", columns);
3509 row_json = json_object_create();
3510 json_object_put(op, "rows", json_array_create_1(row_json));
3511
3512 BITMAP_FOR_EACH_1 (idx, n_columns, row->prereqs) {
3513 const struct ovsdb_idl_column *column = &class->columns[idx];
3514 json_array_add(columns, json_string_create(column->name));
3515 json_object_put(row_json, column->name,
3516 ovsdb_datum_to_json(&row->old_datum[idx],
3517 &column->type));
3518 }
3519 }
3520 }
3521
3522 /* Add updates. */
3523 any_updates = false;
3524 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
3525 const struct ovsdb_idl_table_class *class = row->table->class_;
3526
3527 if (!row->new_datum) {
3528 if (class->is_root) {
3529 struct json *op = json_object_create();
3530 json_object_put_string(op, "op", "delete");
3531 json_object_put_string(op, "table", class->name);
3532 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3533 json_array_add(operations, op);
3534 any_updates = true;
3535 } else {
3536 /* Let ovsdb-server decide whether to really delete it. */
3537 }
3538 } else if (row->old_datum != row->new_datum) {
3539 struct json *row_json;
3540 size_t idx;
3541
3542 if (!row->old_datum && class->is_singleton) {
3543 /* We're inserting a row into a table that allows only a
3544 * single row. (This is a fairly common OVSDB pattern for
3545 * storing global data.) Verify that the table is empty
3546 * before inserting the row, so that we get a clear
3547 * verification-related failure if there was an insertion
3548 * race with another client. */
3549 struct json *op = json_object_create();
3550 json_array_add(operations, op);
3551 json_object_put_string(op, "op", "wait");
3552 json_object_put_string(op, "table", class->name);
3553 json_object_put(op, "where", json_array_create_empty());
3554 json_object_put(op, "timeout", json_integer_create(0));
3555 json_object_put_string(op, "until", "==");
3556 json_object_put(op, "rows", json_array_create_empty());
3557 }
3558
3559 struct json *op = json_object_create();
3560 json_object_put_string(op, "op",
3561 row->old_datum ? "update" : "insert");
3562 json_object_put_string(op, "table", class->name);
3563 if (row->old_datum) {
3564 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3565 } else {
3566 struct ovsdb_idl_txn_insert *insert;
3567
3568 any_updates = true;
3569
3570 json_object_put(op, "uuid-name",
3571 json_string_create_nocopy(
3572 uuid_name_from_uuid(&row->uuid)));
3573
3574 insert = xmalloc(sizeof *insert);
3575 insert->dummy = row->uuid;
3576 insert->op_index = operations->u.array.n - 1;
3577 uuid_zero(&insert->real);
3578 hmap_insert(&txn->inserted_rows, &insert->hmap_node,
3579 uuid_hash(&insert->dummy));
3580 }
3581 row_json = json_object_create();
3582 json_object_put(op, "row", row_json);
3583
3584 if (row->written) {
3585 BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
3586 const struct ovsdb_idl_column *column =
3587 &class->columns[idx];
3588
3589 if (row->old_datum
3590 || !ovsdb_datum_is_default(&row->new_datum[idx],
3591 &column->type)) {
3592 struct json *value;
3593
3594 value = ovsdb_datum_to_json(&row->new_datum[idx],
3595 &column->type);
3596 json_object_put(row_json, column->name,
3597 substitute_uuids(value, txn));
3598
3599 /* If anything really changed, consider it an update.
3600 * We can't suppress not-really-changed values earlier
3601 * or transactions would become nonatomic (see the big
3602 * comment inside ovsdb_idl_txn_write()). */
3603 if (!any_updates && row->old_datum &&
3604 !ovsdb_datum_equals(&row->old_datum[idx],
3605 &row->new_datum[idx],
3606 &column->type)) {
3607 any_updates = true;
3608 }
3609 }
3610 }
3611 }
3612
3613 if (!row->old_datum || !shash_is_empty(json_object(row_json))) {
3614 json_array_add(operations, op);
3615 } else {
3616 json_destroy(op);
3617 }
3618 }
3619
3620 /* Add mutate operation, for partial map or partial set updates. */
3621 if (row->map_op_written || row->set_op_written) {
3622 struct json *op, *mutations;
3623 bool any_mutations;
3624
3625 op = json_object_create();
3626 json_object_put_string(op, "op", "mutate");
3627 json_object_put_string(op, "table", class->name);
3628 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3629 mutations = json_array_create_empty();
3630 any_mutations = ovsdb_idl_txn_extract_mutations(row, mutations);
3631 json_object_put(op, "mutations", mutations);
3632
3633 if (any_mutations) {
3634 op = substitute_uuids(op, txn);
3635 json_array_add(operations, op);
3636 any_updates = true;
3637 } else {
3638 json_destroy(op);
3639 }
3640 }
3641 }
3642
3643 /* Add increment. */
3644 if (txn->inc_table && (any_updates || txn->inc_force)) {
3645 any_updates = true;
3646 txn->inc_index = operations->u.array.n - 1;
3647
3648 struct json *op = json_object_create();
3649 json_object_put_string(op, "op", "mutate");
3650 json_object_put_string(op, "table", txn->inc_table);
3651 json_object_put(op, "where",
3652 substitute_uuids(where_uuid_equals(&txn->inc_row),
3653 txn));
3654 json_object_put(op, "mutations",
3655 json_array_create_1(
3656 json_array_create_3(
3657 json_string_create(txn->inc_column),
3658 json_string_create("+="),
3659 json_integer_create(1))));
3660 json_array_add(operations, op);
3661
3662 op = json_object_create();
3663 json_object_put_string(op, "op", "select");
3664 json_object_put_string(op, "table", txn->inc_table);
3665 json_object_put(op, "where",
3666 substitute_uuids(where_uuid_equals(&txn->inc_row),
3667 txn));
3668 json_object_put(op, "columns",
3669 json_array_create_1(json_string_create(
3670 txn->inc_column)));
3671 json_array_add(operations, op);
3672 }
3673
3674 if (txn->comment.length) {
3675 struct json *op = json_object_create();
3676 json_object_put_string(op, "op", "comment");
3677 json_object_put_string(op, "comment", ds_cstr(&txn->comment));
3678 json_array_add(operations, op);
3679 }
3680
3681 if (txn->dry_run) {
3682 struct json *op = json_object_create();
3683 json_object_put_string(op, "op", "abort");
3684 json_array_add(operations, op);
3685 }
3686
3687 if (!any_updates) {
3688 txn->status = TXN_UNCHANGED;
3689 json_destroy(operations);
3690 } else if (!jsonrpc_session_send(
3691 txn->idl->session,
3692 jsonrpc_create_request(
3693 "transact", operations, &txn->request_id))) {
3694 hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
3695 json_hash(txn->request_id, 0));
3696 txn->status = TXN_INCOMPLETE;
3697 } else {
3698 txn->status = TXN_TRY_AGAIN;
3699 }
3700
3701 disassemble_out:
3702 ovsdb_idl_txn_disassemble(txn);
3703 coverage_out:
3704 switch (txn->status) {
3705 case TXN_UNCOMMITTED: COVERAGE_INC(txn_uncommitted); break;
3706 case TXN_UNCHANGED: COVERAGE_INC(txn_unchanged); break;
3707 case TXN_INCOMPLETE: COVERAGE_INC(txn_incomplete); break;
3708 case TXN_ABORTED: COVERAGE_INC(txn_aborted); break;
3709 case TXN_SUCCESS: COVERAGE_INC(txn_success); break;
3710 case TXN_TRY_AGAIN: COVERAGE_INC(txn_try_again); break;
3711 case TXN_NOT_LOCKED: COVERAGE_INC(txn_not_locked); break;
3712 case TXN_ERROR: COVERAGE_INC(txn_error); break;
3713 }
3714
3715 return txn->status;
3716 }
3717
3718 /* Attempts to commit 'txn', blocking until the commit either succeeds or
3719 * fails. Returns the final commit status, which may be any TXN_* value other
3720 * than TXN_INCOMPLETE.
3721 *
3722 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
3723 * return value of ovsdb_idl_get_seqno() to change. */
3724 enum ovsdb_idl_txn_status
3725 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
3726 {
3727 enum ovsdb_idl_txn_status status;
3728
3729 fatal_signal_run();
3730 while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
3731 ovsdb_idl_run(txn->idl);
3732 ovsdb_idl_wait(txn->idl);
3733 ovsdb_idl_txn_wait(txn);
3734 poll_block();
3735 }
3736 return status;
3737 }
3738
3739 /* Returns the final (incremented) value of the column in 'txn' that was set to
3740 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
3741 * successfully. */
3742 int64_t
3743 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
3744 {
3745 ovs_assert(txn->status == TXN_SUCCESS);
3746 return txn->inc_new_value;
3747 }
3748
3749 /* Aborts 'txn' without sending it to the database server. This is effective
3750 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
3751 * Otherwise, it has no effect.
3752 *
3753 * Aborting a transaction doesn't free its memory. Use
3754 * ovsdb_idl_txn_destroy() to do that. */
3755 void
3756 ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
3757 {
3758 ovsdb_idl_txn_disassemble(txn);
3759 if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
3760 txn->status = TXN_ABORTED;
3761 }
3762 }
3763
3764 /* Returns a string that reports the error status for 'txn'. The caller must
3765 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
3766 * for 'txn' may free the returned string.
3767 *
3768 * The return value is ordinarily one of the strings that
3769 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
3770 * due to an error reported by the database server, the return value is that
3771 * error. */
3772 const char *
3773 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
3774 {
3775 if (txn->status != TXN_ERROR) {
3776 return ovsdb_idl_txn_status_to_string(txn->status);
3777 } else if (txn->error) {
3778 return txn->error;
3779 } else {
3780 return "no error details available";
3781 }
3782 }
3783
3784 static void
3785 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
3786 const struct json *json)
3787 {
3788 if (txn->error == NULL) {
3789 txn->error = json_to_string(json, JSSF_SORT);
3790 }
3791 }
3792
3793 /* For transaction 'txn' that completed successfully, finds and returns the
3794 * permanent UUID that the database assigned to a newly inserted row, given the
3795 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
3796 *
3797 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
3798 * if it was assigned by that function and then deleted by
3799 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
3800 * and then deleted within a single transaction are never sent to the database
3801 * server, so it never assigns them a permanent UUID.) */
3802 const struct uuid *
3803 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *txn,
3804 const struct uuid *uuid)
3805 {
3806 const struct ovsdb_idl_txn_insert *insert;
3807
3808 ovs_assert(txn->status == TXN_SUCCESS || txn->status == TXN_UNCHANGED);
3809 HMAP_FOR_EACH_IN_BUCKET (insert, hmap_node,
3810 uuid_hash(uuid), &txn->inserted_rows) {
3811 if (uuid_equals(uuid, &insert->dummy)) {
3812 return &insert->real;
3813 }
3814 }
3815 return NULL;
3816 }
3817
3818 static void
3819 ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
3820 enum ovsdb_idl_txn_status status)
3821 {
3822 txn->status = status;
3823 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
3824 }
3825
3826 static void
3827 ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
3828 const struct ovsdb_idl_column *column,
3829 struct ovsdb_datum *datum, bool owns_datum)
3830 {
3831 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
3832 const struct ovsdb_idl_table_class *class;
3833 size_t column_idx;
3834 bool write_only;
3835
3836 if (ovsdb_idl_row_is_synthetic(row)) {
3837 goto discard_datum;
3838 }
3839
3840 class = row->table->class_;
3841 column_idx = column - class->columns;
3842 write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
3843
3844 ovs_assert(row->new_datum != NULL);
3845 ovs_assert(column_idx < class->n_columns);
3846 ovs_assert(row->old_datum == NULL ||
3847 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
3848
3849 if (row->table->idl->verify_write_only && !write_only) {
3850 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
3851 " explicitly configured not to.", class->name, column->name);
3852 goto discard_datum;
3853 }
3854
3855 /* If this is a write-only column and the datum being written is the same
3856 * as the one already there, just skip the update entirely. This is worth
3857 * optimizing because we have a lot of columns that get periodically
3858 * refreshed into the database but don't actually change that often.
3859 *
3860 * We don't do this for read/write columns because that would break
3861 * atomicity of transactions--some other client might have written a
3862 * different value in that column since we read it. (But if a whole
3863 * transaction only does writes of existing values, without making any real
3864 * changes, we will drop the whole transaction later in
3865 * ovsdb_idl_txn_commit().) */
3866 if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
3867 datum, &column->type)) {
3868 goto discard_datum;
3869 }
3870
3871 if (hmap_node_is_null(&row->txn_node)) {
3872 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
3873 uuid_hash(&row->uuid));
3874 }
3875 if (row->old_datum == row->new_datum) {
3876 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
3877 }
3878 if (!row->written) {
3879 row->written = bitmap_allocate(class->n_columns);
3880 }
3881 if (bitmap_is_set(row->written, column_idx)) {
3882 ovsdb_datum_destroy(&row->new_datum[column_idx], &column->type);
3883 } else {
3884 bitmap_set1(row->written, column_idx);
3885 }
3886 if (owns_datum) {
3887 row->new_datum[column_idx] = *datum;
3888 } else {
3889 ovsdb_datum_clone(&row->new_datum[column_idx], datum, &column->type);
3890 }
3891 (column->unparse)(row);
3892 (column->parse)(row, &row->new_datum[column_idx]);
3893 return;
3894
3895 discard_datum:
3896 if (owns_datum) {
3897 ovsdb_datum_destroy(datum, &column->type);
3898 }
3899 }
3900
3901 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
3902 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
3903 * ovs-vswitchd).
3904 *
3905 * 'datum' must have the correct type for its column, but it needs not be
3906 * sorted or unique because this function will take care of that. The IDL does
3907 * not check that it meets schema constraints, but ovsdb-server will do so at
3908 * commit time so it had better be correct.
3909 *
3910 * A transaction must be in progress. Replication of 'column' must not have
3911 * been disabled (by calling ovsdb_idl_omit()).
3912 *
3913 * Usually this function is used indirectly through one of the "set" functions
3914 * generated by ovsdb-idlc.
3915 *
3916 * Takes ownership of what 'datum' points to (and in some cases destroys that
3917 * data before returning) but makes a copy of 'datum' itself. (Commonly
3918 * 'datum' is on the caller's stack.) */
3919 void
3920 ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
3921 const struct ovsdb_idl_column *column,
3922 struct ovsdb_datum *datum)
3923 {
3924 ovsdb_datum_sort_unique(datum,
3925 column->type.key.type, column->type.value.type);
3926 ovsdb_idl_txn_write__(row, column, datum, true);
3927 }
3928
3929 /* Similar to ovsdb_idl_txn_write(), except:
3930 *
3931 * - The caller retains ownership of 'datum' and what it points to.
3932 *
3933 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
3934 * ovsdb_datum_sort_unique().) */
3935 void
3936 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
3937 const struct ovsdb_idl_column *column,
3938 const struct ovsdb_datum *datum)
3939 {
3940 ovsdb_idl_txn_write__(row, column,
3941 CONST_CAST(struct ovsdb_datum *, datum), false);
3942 }
3943
3944 /* Causes the original contents of 'column' in 'row_' to be verified as a
3945 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
3946 * changed (or if 'row_' was deleted) between the time that the IDL originally
3947 * read its contents and the time that the transaction commits, then the
3948 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
3949 *
3950 * The intention is that, to ensure that no transaction commits based on dirty
3951 * reads, an application should call ovsdb_idl_txn_verify() on each data item
3952 * read as part of a read-modify-write operation.
3953 *
3954 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
3955 * value of 'column' is already known:
3956 *
3957 * - If 'row_' is a row created by the current transaction (returned by
3958 * ovsdb_idl_txn_insert()).
3959 *
3960 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
3961 * within the current transaction.
3962 *
3963 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
3964 * ovsdb_idl_txn_write() for a given read-modify-write.
3965 *
3966 * A transaction must be in progress.
3967 *
3968 * Usually this function is used indirectly through one of the "verify"
3969 * functions generated by ovsdb-idlc. */
3970 void
3971 ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
3972 const struct ovsdb_idl_column *column)
3973 {
3974 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
3975 const struct ovsdb_idl_table_class *class;
3976 size_t column_idx;
3977
3978 if (ovsdb_idl_row_is_synthetic(row)) {
3979 return;
3980 }
3981
3982 class = row->table->class_;
3983 column_idx = column - class->columns;
3984
3985 ovs_assert(row->new_datum != NULL);
3986 ovs_assert(row->old_datum == NULL ||
3987 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
3988 if (!row->old_datum
3989 || (row->written && bitmap_is_set(row->written, column_idx))) {
3990 return;
3991 }
3992
3993 if (hmap_node_is_null(&row->txn_node)) {
3994 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
3995 uuid_hash(&row->uuid));
3996 }
3997 if (!row->prereqs) {
3998 row->prereqs = bitmap_allocate(class->n_columns);
3999 }
4000 bitmap_set1(row->prereqs, column_idx);
4001 }
4002
4003 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4004 * accessed afterward.
4005 *
4006 * A transaction must be in progress.
4007 *
4008 * Usually this function is used indirectly through one of the "delete"
4009 * functions generated by ovsdb-idlc. */
4010 void
4011 ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
4012 {
4013 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4014
4015 if (ovsdb_idl_row_is_synthetic(row)) {
4016 return;
4017 }
4018
4019 ovs_assert(row->new_datum != NULL);
4020 if (!row->old_datum) {
4021 ovsdb_idl_row_unparse(row);
4022 ovsdb_idl_row_clear_new(row);
4023 ovs_assert(!row->prereqs);
4024 hmap_remove(&row->table->rows, &row->hmap_node);
4025 hmap_remove(&row->table->idl->txn->txn_rows, &row->txn_node);
4026 free(row);
4027 return;
4028 }
4029 if (hmap_node_is_null(&row->txn_node)) {
4030 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4031 uuid_hash(&row->uuid));
4032 }
4033 ovsdb_idl_row_clear_new(row);
4034 row->new_datum = NULL;
4035 }
4036
4037 /* Inserts and returns a new row in the table with the specified 'class' in the
4038 * database with open transaction 'txn'.
4039 *
4040 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4041 * randomly generated; otherwise 'uuid' should specify a randomly generated
4042 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4043 * 'txn' is committed, but the IDL will replace any uses of the provisional
4044 * UUID in the data to be to be committed by the UUID assigned by
4045 * ovsdb-server.
4046 *
4047 * Usually this function is used indirectly through one of the "insert"
4048 * functions generated by ovsdb-idlc. */
4049 const struct ovsdb_idl_row *
4050 ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
4051 const struct ovsdb_idl_table_class *class,
4052 const struct uuid *uuid)
4053 {
4054 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);
4055
4056 if (uuid) {
4057 ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
4058 row->uuid = *uuid;
4059 } else {
4060 uuid_generate(&row->uuid);
4061 }
4062
4063 row->table = ovsdb_idl_table_from_class(txn->idl, class);
4064 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
4065 hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
4066 hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
4067 return row;
4068 }
4069
4070 static void
4071 ovsdb_idl_txn_abort_all(struct ovsdb_idl *idl)
4072 {
4073 struct ovsdb_idl_txn *txn;
4074
4075 HMAP_FOR_EACH (txn, hmap_node, &idl->outstanding_txns) {
4076 ovsdb_idl_txn_complete(txn, TXN_TRY_AGAIN);
4077 }
4078 }
4079
4080 static struct ovsdb_idl_txn *
4081 ovsdb_idl_txn_find(struct ovsdb_idl *idl, const struct json *id)
4082 {
4083 struct ovsdb_idl_txn *txn;
4084
4085 HMAP_FOR_EACH_WITH_HASH (txn, hmap_node,
4086 json_hash(id, 0), &idl->outstanding_txns) {
4087 if (json_equal(id, txn->request_id)) {
4088 return txn;
4089 }
4090 }
4091 return NULL;
4092 }
4093
4094 static bool
4095 check_json_type(const struct json *json, enum json_type type, const char *name)
4096 {
4097 if (!json) {
4098 VLOG_WARN_RL(&syntax_rl, "%s is missing", name);
4099 return false;
4100 } else if (json->type != type) {
4101 VLOG_WARN_RL(&syntax_rl, "%s is %s instead of %s",
4102 name, json_type_to_string(json->type),
4103 json_type_to_string(type));
4104 return false;
4105 } else {
4106 return true;
4107 }
4108 }
4109
4110 static bool
4111 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
4112 const struct json_array *results)
4113 {
4114 struct json *count, *rows, *row, *column;
4115 struct shash *mutate, *select;
4116
4117 if (txn->inc_index + 2 > results->n) {
4118 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4119 "for increment (has %"PRIuSIZE", needs %u)",
4120 results->n, txn->inc_index + 2);
4121 return false;
4122 }
4123
4124 /* We know that this is a JSON object because the loop in
4125 * ovsdb_idl_txn_process_reply() checked. */
4126 mutate = json_object(results->elems[txn->inc_index]);
4127 count = shash_find_data(mutate, "count");
4128 if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) {
4129 return false;
4130 }
4131 if (count->u.integer != 1) {
4132 VLOG_WARN_RL(&syntax_rl,
4133 "\"mutate\" reply \"count\" is %lld instead of 1",
4134 count->u.integer);
4135 return false;
4136 }
4137
4138 select = json_object(results->elems[txn->inc_index + 1]);
4139 rows = shash_find_data(select, "rows");
4140 if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) {
4141 return false;
4142 }
4143 if (rows->u.array.n != 1) {
4144 VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
4145 "instead of 1",
4146 rows->u.array.n);
4147 return false;
4148 }
4149 row = rows->u.array.elems[0];
4150 if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) {
4151 return false;
4152 }
4153 column = shash_find_data(json_object(row), txn->inc_column);
4154 if (!check_json_type(column, JSON_INTEGER,
4155 "\"select\" reply inc column")) {
4156 return false;
4157 }
4158 txn->inc_new_value = column->u.integer;
4159 return true;
4160 }
4161
4162 static bool
4163 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
4164 const struct json_array *results)
4165 {
4166 static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT;
4167 struct ovsdb_error *error;
4168 struct json *json_uuid;
4169 union ovsdb_atom uuid;
4170 struct shash *reply;
4171
4172 if (insert->op_index >= results->n) {
4173 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4174 "for insert (has %"PRIuSIZE", needs %u)",
4175 results->n, insert->op_index);
4176 return false;
4177 }
4178
4179 /* We know that this is a JSON object because the loop in
4180 * ovsdb_idl_txn_process_reply() checked. */
4181 reply = json_object(results->elems[insert->op_index]);
4182 json_uuid = shash_find_data(reply, "uuid");
4183 if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) {
4184 return false;
4185 }
4186
4187 error = ovsdb_atom_from_json(&uuid, &uuid_type, json_uuid, NULL);
4188 if (error) {
4189 char *s = ovsdb_error_to_string(error);
4190 VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
4191 "UUID: %s", s);
4192 free(s);
4193 ovsdb_error_destroy(error);
4194 return false;
4195 }
4196
4197 insert->real = uuid.uuid;
4198
4199 return true;
4200 }
4201
4202 static bool
4203 ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
4204 const struct jsonrpc_msg *msg)
4205 {
4206 struct ovsdb_idl_txn *txn;
4207 enum ovsdb_idl_txn_status status;
4208
4209 txn = ovsdb_idl_txn_find(idl, msg->id);
4210 if (!txn) {
4211 return false;
4212 }
4213
4214 if (msg->type == JSONRPC_ERROR) {
4215 status = TXN_ERROR;
4216 } else if (msg->result->type != JSON_ARRAY) {
4217 VLOG_WARN_RL(&syntax_rl, "reply to \"transact\" is not JSON array");
4218 status = TXN_ERROR;
4219 } else {
4220 struct json_array *ops = &msg->result->u.array;
4221 int hard_errors = 0;
4222 int soft_errors = 0;
4223 int lock_errors = 0;
4224 size_t i;
4225
4226 for (i = 0; i < ops->n; i++) {
4227 struct json *op = ops->elems[i];
4228
4229 if (op->type == JSON_NULL) {
4230 /* This isn't an error in itself but indicates that some prior
4231 * operation failed, so make sure that we know about it. */
4232 soft_errors++;
4233 } else if (op->type == JSON_OBJECT) {
4234 struct json *error;
4235
4236 error = shash_find_data(json_object(op), "error");
4237 if (error) {
4238 if (error->type == JSON_STRING) {
4239 if (!strcmp(error->u.string, "timed out")) {
4240 soft_errors++;
4241 } else if (!strcmp(error->u.string, "not owner")) {
4242 lock_errors++;
4243 } else if (!strcmp(error->u.string, "not allowed")) {
4244 hard_errors++;
4245 ovsdb_idl_txn_set_error_json(txn, op);
4246 } else if (strcmp(error->u.string, "aborted")) {
4247 hard_errors++;
4248 ovsdb_idl_txn_set_error_json(txn, op);
4249 VLOG_WARN_RL(&other_rl,
4250 "transaction error: %s", txn->error);
4251 }
4252 } else {
4253 hard_errors++;
4254 ovsdb_idl_txn_set_error_json(txn, op);
4255 VLOG_WARN_RL(&syntax_rl,
4256 "\"error\" in reply is not JSON string");
4257 }
4258 }
4259 } else {
4260 hard_errors++;
4261 ovsdb_idl_txn_set_error_json(txn, op);
4262 VLOG_WARN_RL(&syntax_rl,
4263 "operation reply is not JSON null or object");
4264 }
4265 }
4266
4267 if (!soft_errors && !hard_errors && !lock_errors) {
4268 struct ovsdb_idl_txn_insert *insert;
4269
4270 if (txn->inc_table && !ovsdb_idl_txn_process_inc_reply(txn, ops)) {
4271 hard_errors++;
4272 }
4273
4274 HMAP_FOR_EACH (insert, hmap_node, &txn->inserted_rows) {
4275 if (!ovsdb_idl_txn_process_insert_reply(insert, ops)) {
4276 hard_errors++;
4277 }
4278 }
4279 }
4280
4281 status = (hard_errors ? TXN_ERROR
4282 : lock_errors ? TXN_NOT_LOCKED
4283 : soft_errors ? TXN_TRY_AGAIN
4284 : TXN_SUCCESS);
4285 }
4286
4287 ovsdb_idl_txn_complete(txn, status);
4288 return true;
4289 }
4290
4291 /* Returns the transaction currently active for 'row''s IDL. A transaction
4292 * must currently be active. */
4293 struct ovsdb_idl_txn *
4294 ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
4295 {
4296 struct ovsdb_idl_txn *txn = row->table->idl->txn;
4297 ovs_assert(txn != NULL);
4298 return txn;
4299 }
4300
4301 /* Returns the IDL on which 'txn' acts. */
4302 struct ovsdb_idl *
4303 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
4304 {
4305 return txn->idl;
4306 }
4307
4308 /* Blocks until 'idl' successfully connects to the remote database and
4309 * retrieves its contents. */
4310 void
4311 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *idl)
4312 {
4313 while (1) {
4314 ovsdb_idl_run(idl);
4315 if (ovsdb_idl_has_ever_connected(idl)) {
4316 return;
4317 }
4318 ovsdb_idl_wait(idl);
4319 poll_block();
4320 }
4321 }
4322 \f
4323 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
4324 * the database server and to avoid modifying the database when the lock cannot
4325 * be acquired (that is, when another client has the same lock).
4326 *
4327 * If 'lock_name' is NULL, drops the locking requirement and releases the
4328 * lock. */
4329 void
4330 ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
4331 {
4332 ovs_assert(!idl->txn);
4333 ovs_assert(hmap_is_empty(&idl->outstanding_txns));
4334
4335 if (idl->lock_name && (!lock_name || strcmp(lock_name, idl->lock_name))) {
4336 /* Release previous lock. */
4337 ovsdb_idl_send_unlock_request(idl);
4338 free(idl->lock_name);
4339 idl->lock_name = NULL;
4340 idl->is_lock_contended = false;
4341 }
4342
4343 if (lock_name && !idl->lock_name) {
4344 /* Acquire new lock. */
4345 idl->lock_name = xstrdup(lock_name);
4346 ovsdb_idl_send_lock_request(idl);
4347 }
4348 }
4349
4350 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
4351 *
4352 * Locking and unlocking happens asynchronously from the database client's
4353 * point of view, so the information is only useful for optimization (e.g. if
4354 * the client doesn't have the lock then there's no point in trying to write to
4355 * the database). */
4356 bool
4357 ovsdb_idl_has_lock(const struct ovsdb_idl *idl)
4358 {
4359 return idl->has_lock;
4360 }
4361
4362 /* Returns true if 'idl' is configured to obtain a lock but the database server
4363 * has indicated that some other client already owns the requested lock. */
4364 bool
4365 ovsdb_idl_is_lock_contended(const struct ovsdb_idl *idl)
4366 {
4367 return idl->is_lock_contended;
4368 }
4369
4370 static void
4371 ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock)
4372 {
4373 if (new_has_lock && !idl->has_lock) {
4374 if (idl->state == IDL_S_MONITORING ||
4375 idl->state == IDL_S_MONITORING_COND) {
4376 idl->change_seqno++;
4377 } else {
4378 /* We're setting up a session, so don't signal that the database
4379 * changed. Finalizing the session will increment change_seqno
4380 * anyhow. */
4381 }
4382 idl->is_lock_contended = false;
4383 }
4384 idl->has_lock = new_has_lock;
4385 }
4386
4387 static void
4388 ovsdb_idl_send_lock_request__(struct ovsdb_idl *idl, const char *method,
4389 struct json **idp)
4390 {
4391 ovsdb_idl_update_has_lock(idl, false);
4392
4393 json_destroy(idl->lock_request_id);
4394 idl->lock_request_id = NULL;
4395
4396 if (jsonrpc_session_is_connected(idl->session)) {
4397 struct json *params;
4398
4399 params = json_array_create_1(json_string_create(idl->lock_name));
4400 jsonrpc_session_send(idl->session,
4401 jsonrpc_create_request(method, params, idp));
4402 }
4403 }
4404
4405 static void
4406 ovsdb_idl_send_lock_request(struct ovsdb_idl *idl)
4407 {
4408 ovsdb_idl_send_lock_request__(idl, "lock", &idl->lock_request_id);
4409 }
4410
4411 static void
4412 ovsdb_idl_send_unlock_request(struct ovsdb_idl *idl)
4413 {
4414 ovsdb_idl_send_lock_request__(idl, "unlock", NULL);
4415 }
4416
4417 static void
4418 ovsdb_idl_parse_lock_reply(struct ovsdb_idl *idl, const struct json *result)
4419 {
4420 bool got_lock;
4421
4422 json_destroy(idl->lock_request_id);
4423 idl->lock_request_id = NULL;
4424
4425 if (result->type == JSON_OBJECT) {
4426 const struct json *locked;
4427
4428 locked = shash_find_data(json_object(result), "locked");
4429 got_lock = locked && locked->type == JSON_TRUE;
4430 } else {
4431 got_lock = false;
4432 }
4433
4434 ovsdb_idl_update_has_lock(idl, got_lock);
4435 if (!got_lock) {
4436 idl->is_lock_contended = true;
4437 }
4438 }
4439
4440 static void
4441 ovsdb_idl_parse_lock_notify(struct ovsdb_idl *idl,
4442 const struct json *params,
4443 bool new_has_lock)
4444 {
4445 if (idl->lock_name
4446 && params->type == JSON_ARRAY
4447 && json_array(params)->n > 0
4448 && json_array(params)->elems[0]->type == JSON_STRING) {
4449 const char *lock_name = json_string(json_array(params)->elems[0]);
4450
4451 if (!strcmp(idl->lock_name, lock_name)) {
4452 ovsdb_idl_update_has_lock(idl, new_has_lock);
4453 if (!new_has_lock) {
4454 idl->is_lock_contended = true;
4455 }
4456 }
4457 }
4458 }
4459
4460 /* Inserts a new Map Operation into current transaction. */
4461 static void
4462 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *row,
4463 const struct ovsdb_idl_column *column,
4464 struct ovsdb_datum *datum,
4465 enum map_op_type op_type)
4466 {
4467 const struct ovsdb_idl_table_class *class;
4468 size_t column_idx;
4469 struct map_op *map_op;
4470
4471 class = row->table->class_;
4472 column_idx = column - class->columns;
4473
4474 /* Check if a map operation list exists for this column. */
4475 if (!row->map_op_written) {
4476 row->map_op_written = bitmap_allocate(class->n_columns);
4477 row->map_op_lists = xzalloc(class->n_columns *
4478 sizeof *row->map_op_lists);
4479 }
4480 if (!row->map_op_lists[column_idx]) {
4481 row->map_op_lists[column_idx] = map_op_list_create();
4482 }
4483
4484 /* Add a map operation to the corresponding list. */
4485 map_op = map_op_create(datum, op_type);
4486 bitmap_set1(row->map_op_written, column_idx);
4487 map_op_list_add(row->map_op_lists[column_idx], map_op, &column->type);
4488
4489 /* Add this row to transaction's list of rows. */
4490 if (hmap_node_is_null(&row->txn_node)) {
4491 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4492 uuid_hash(&row->uuid));
4493 }
4494 }
4495
4496 /* Inserts a new Set Operation into current transaction. */
4497 static void
4498 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *row,
4499 const struct ovsdb_idl_column *column,
4500 struct ovsdb_datum *datum,
4501 enum set_op_type op_type)
4502 {
4503 const struct ovsdb_idl_table_class *class;
4504 size_t column_idx;
4505 struct set_op *set_op;
4506
4507 class = row->table->class_;
4508 column_idx = column - class->columns;
4509
4510 /* Check if a set operation list exists for this column. */
4511 if (!row->set_op_written) {
4512 row->set_op_written = bitmap_allocate(class->n_columns);
4513 row->set_op_lists = xzalloc(class->n_columns *
4514 sizeof *row->set_op_lists);
4515 }
4516 if (!row->set_op_lists[column_idx]) {
4517 row->set_op_lists[column_idx] = set_op_list_create();
4518 }
4519
4520 /* Add a set operation to the corresponding list. */
4521 set_op = set_op_create(datum, op_type);
4522 bitmap_set1(row->set_op_written, column_idx);
4523 set_op_list_add(row->set_op_lists[column_idx], set_op, &column->type);
4524
4525 /* Add this row to the transactions's list of rows. */
4526 if (hmap_node_is_null(&row->txn_node)) {
4527 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4528 uuid_hash(&row->uuid));
4529 }
4530 }
4531
4532 static bool
4533 is_valid_partial_update(const struct ovsdb_idl_row *row,
4534 const struct ovsdb_idl_column *column,
4535 struct ovsdb_datum *datum)
4536 {
4537 /* Verify that this column is being monitored. */
4538 unsigned int column_idx = column - row->table->class_->columns;
4539 if (!(row->table->modes[column_idx] & OVSDB_IDL_MONITOR)) {
4540 VLOG_WARN("cannot partially update non-monitored column");
4541 return false;
4542 }
4543
4544 /* Verify that the update affects a single element. */
4545 if (datum->n != 1) {
4546 VLOG_WARN("invalid datum for partial update");
4547 return false;
4548 }
4549
4550 return true;
4551 }
4552
4553 /* Inserts the value described in 'datum' into the map in 'column' in
4554 * 'row_'. If the value doesn't already exist in 'column' then it's value
4555 * is added. The value in 'datum' must be of the same type as the values
4556 * in 'column'. This function takes ownership of 'datum'.
4557 *
4558 * Usually this function is used indirectly through one of the "update"
4559 * functions generated by vswitch-idl. */
4560 void
4561 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *row_,
4562 const struct ovsdb_idl_column *column,
4563 struct ovsdb_datum *datum)
4564 {
4565 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4566 enum set_op_type op_type;
4567
4568 if (!is_valid_partial_update(row, column, datum)) {
4569 ovsdb_datum_destroy(datum, &column->type);
4570 free(datum);
4571 return;
4572 }
4573
4574 op_type = SET_OP_INSERT;
4575
4576 ovsdb_idl_txn_add_set_op(row, column, datum, op_type);
4577 }
4578
4579 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
4580 * The value in 'datum' must be of the same type as the keys in 'column'.
4581 * This function takes ownership of 'datum'.
4582 *
4583 * Usually this function is used indirectly through one of the "update"
4584 * functions generated by vswitch-idl. */
4585 void
4586 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *row_,
4587 const struct ovsdb_idl_column *column,
4588 struct ovsdb_datum *datum)
4589 {
4590 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4591
4592 if (!is_valid_partial_update(row, column, datum)) {
4593 struct ovsdb_type type_ = column->type;
4594 type_.value.type = OVSDB_TYPE_VOID;
4595 ovsdb_datum_destroy(datum, &type_);
4596 free(datum);
4597 return;
4598 }
4599 ovsdb_idl_txn_add_set_op(row, column, datum, SET_OP_DELETE);
4600 }
4601
4602 /* Inserts the key-value specified in 'datum' into the map in 'column' in
4603 * 'row_'. If the key already exist in 'column', then it's value is updated
4604 * with the value in 'datum'. The key-value in 'datum' must be of the same type
4605 * as the keys-values in 'column'. This function takes ownership of 'datum'.
4606 *
4607 * Usually this function is used indirectly through one of the "update"
4608 * functions generated by vswitch-idl. */
4609 void
4610 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *row_,
4611 const struct ovsdb_idl_column *column,
4612 struct ovsdb_datum *datum)
4613 {
4614 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4615 enum ovsdb_atomic_type key_type;
4616 enum map_op_type op_type;
4617 unsigned int pos;
4618 const struct ovsdb_datum *old_datum;
4619
4620 if (!is_valid_partial_update(row, column, datum)) {
4621 ovsdb_datum_destroy(datum, &column->type);
4622 free(datum);
4623 return;
4624 }
4625
4626 /* Find out if this is an insert or an update. */
4627 key_type = column->type.key.type;
4628 old_datum = ovsdb_idl_read(row, column);
4629 pos = ovsdb_datum_find_key(old_datum, &datum->keys[0], key_type);
4630 op_type = pos == UINT_MAX ? MAP_OP_INSERT : MAP_OP_UPDATE;
4631
4632 ovsdb_idl_txn_add_map_op(row, column, datum, op_type);
4633 }
4634
4635 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
4636 * The key in 'datum' must be of the same type as the keys in 'column'.
4637 * The value in 'datum' must be NULL. This function takes ownership of
4638 * 'datum'.
4639 *
4640 * Usually this function is used indirectly through one of the "update"
4641 * functions generated by vswitch-idl. */
4642 void
4643 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *row_,
4644 const struct ovsdb_idl_column *column,
4645 struct ovsdb_datum *datum)
4646 {
4647 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4648
4649 if (!is_valid_partial_update(row, column, datum)) {
4650 struct ovsdb_type type_ = column->type;
4651 type_.value.type = OVSDB_TYPE_VOID;
4652 ovsdb_datum_destroy(datum, &type_);
4653 free(datum);
4654 return;
4655 }
4656 ovsdb_idl_txn_add_map_op(row, column, datum, MAP_OP_DELETE);
4657 }
4658
4659 void
4660 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *loop)
4661 {
4662 if (loop) {
4663 ovsdb_idl_destroy(loop->idl);
4664 }
4665 }
4666
4667 struct ovsdb_idl_txn *
4668 ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
4669 {
4670 ovsdb_idl_run(loop->idl);
4671 loop->open_txn = (loop->committing_txn
4672 || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
4673 ? NULL
4674 : ovsdb_idl_txn_create(loop->idl));
4675 return loop->open_txn;
4676 }
4677
4678 /* Attempts to commit the current transaction, if one is open, and sets up the
4679 * poll loop to wake up when some more work might be needed.
4680 *
4681 * If a transaction was open, in this or a previous iteration of the main loop,
4682 * and had not before finished committing (successfully or unsuccessfully), the
4683 * return value is one of:
4684 *
4685 * 1: The transaction committed successfully (or it did not change anything in
4686 * the database).
4687 * 0: The transaction failed.
4688 * -1: The commit is still in progress.
4689 *
4690 * Thus, the return value is -1 if the transaction is in progress and otherwise
4691 * true for success, false for failure.
4692 *
4693 * (In the corner case where the IDL sends a transaction to the database and
4694 * the database commits it, and the connection between the IDL and the database
4695 * drops before the IDL receives the message confirming the commit, this
4696 * function can return 0 even though the transaction succeeded.)
4697 */
4698 int
4699 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
4700 {
4701 if (loop->open_txn) {
4702 loop->committing_txn = loop->open_txn;
4703 loop->open_txn = NULL;
4704
4705 loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
4706 }
4707
4708 struct ovsdb_idl_txn *txn = loop->committing_txn;
4709 int retval;
4710 if (txn) {
4711 enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
4712 if (status != TXN_INCOMPLETE) {
4713 switch (status) {
4714 case TXN_TRY_AGAIN:
4715 /* We want to re-evaluate the database when it's changed from
4716 * the contents that it had when we started the commit. (That
4717 * might have already happened.) */
4718 loop->skip_seqno = loop->precommit_seqno;
4719 if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
4720 poll_immediate_wake();
4721 }
4722 retval = 0;
4723 break;
4724
4725 case TXN_SUCCESS:
4726 /* Possibly some work on the database was deferred because no
4727 * further transaction could proceed. Wake up again. */
4728 retval = 1;
4729 loop->cur_cfg = loop->next_cfg;
4730 poll_immediate_wake();
4731 break;
4732
4733 case TXN_UNCHANGED:
4734 retval = 1;
4735 loop->cur_cfg = loop->next_cfg;
4736 break;
4737
4738 case TXN_ABORTED:
4739 case TXN_NOT_LOCKED:
4740 case TXN_ERROR:
4741 retval = 0;
4742 break;
4743
4744 case TXN_UNCOMMITTED:
4745 case TXN_INCOMPLETE:
4746 default:
4747 OVS_NOT_REACHED();
4748 }
4749 ovsdb_idl_txn_destroy(txn);
4750 loop->committing_txn = NULL;
4751 } else {
4752 retval = -1;
4753 }
4754 } else {
4755 /* Not a meaningful return value: no transaction was in progress. */
4756 retval = 1;
4757 }
4758
4759 ovsdb_idl_wait(loop->idl);
4760
4761 return retval;
4762 }