]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ovsdb-idl.c
ovsdb-error: New function ovsdb_error_to_string_free().
[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_free(error);
1459 VLOG_WARN("error parsing database schema: %s", s);
1460 free(s);
1461 }
1462
1463 /* Frees 'schema', which is in the format returned by parse_schema(). */
1464 static void
1465 free_schema(struct shash *schema)
1466 {
1467 if (schema) {
1468 struct shash_node *node, *next;
1469
1470 SHASH_FOR_EACH_SAFE (node, next, schema) {
1471 struct sset *sset = node->data;
1472 sset_destroy(sset);
1473 free(sset);
1474 shash_delete(schema, node);
1475 }
1476 shash_destroy(schema);
1477 free(schema);
1478 }
1479 }
1480
1481 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1482 * 7047, to obtain the names of its rows and columns. If successful, returns
1483 * an shash whose keys are table names and whose values are ssets, where each
1484 * sset contains the names of its table's columns. On failure (due to a parse
1485 * error), returns NULL.
1486 *
1487 * It would also be possible to use the general-purpose OVSDB schema parser in
1488 * ovsdb-server, but that's overkill, possibly too strict for the current use
1489 * case, and would require restructuring ovsdb-server to separate the schema
1490 * code from the rest. */
1491 static struct shash *
1492 parse_schema(const struct json *schema_json)
1493 {
1494 struct ovsdb_parser parser;
1495 const struct json *tables_json;
1496 struct ovsdb_error *error;
1497 struct shash_node *node;
1498 struct shash *schema;
1499
1500 ovsdb_parser_init(&parser, schema_json, "database schema");
1501 tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
1502 error = ovsdb_parser_destroy(&parser);
1503 if (error) {
1504 log_error(error);
1505 return NULL;
1506 }
1507
1508 schema = xmalloc(sizeof *schema);
1509 shash_init(schema);
1510 SHASH_FOR_EACH (node, json_object(tables_json)) {
1511 const char *table_name = node->name;
1512 const struct json *json = node->data;
1513 const struct json *columns_json;
1514
1515 ovsdb_parser_init(&parser, json, "table schema for table %s",
1516 table_name);
1517 columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
1518 error = ovsdb_parser_destroy(&parser);
1519 if (error) {
1520 log_error(error);
1521 free_schema(schema);
1522 return NULL;
1523 }
1524
1525 struct sset *columns = xmalloc(sizeof *columns);
1526 sset_init(columns);
1527
1528 struct shash_node *node2;
1529 SHASH_FOR_EACH (node2, json_object(columns_json)) {
1530 const char *column_name = node2->name;
1531 sset_add(columns, column_name);
1532 }
1533 shash_add(schema, table_name, columns);
1534 }
1535 return schema;
1536 }
1537
1538 static void
1539 ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
1540 const char *method)
1541 {
1542 struct shash *schema;
1543 struct json *monitor_requests;
1544 struct jsonrpc_msg *msg;
1545 size_t i;
1546
1547 schema = parse_schema(idl->schema);
1548 monitor_requests = json_object_create();
1549 for (i = 0; i < idl->class_->n_tables; i++) {
1550 struct ovsdb_idl_table *table = &idl->tables[i];
1551 const struct ovsdb_idl_table_class *tc = table->class_;
1552 struct json *monitor_request, *columns, *where;
1553 const struct sset *table_schema;
1554 size_t j;
1555
1556 table_schema = (schema
1557 ? shash_find_data(schema, table->class_->name)
1558 : NULL);
1559
1560 columns = table->need_table ? json_array_create_empty() : NULL;
1561 for (j = 0; j < tc->n_columns; j++) {
1562 const struct ovsdb_idl_column *column = &tc->columns[j];
1563 if (table->modes[j] & OVSDB_IDL_MONITOR) {
1564 if (table_schema
1565 && !sset_contains(table_schema, column->name)) {
1566 VLOG_WARN("%s table in %s database lacks %s column "
1567 "(database needs upgrade?)",
1568 table->class_->name, idl->class_->database,
1569 column->name);
1570 continue;
1571 }
1572 if (!columns) {
1573 columns = json_array_create_empty();
1574 }
1575 json_array_add(columns, json_string_create(column->name));
1576 }
1577 }
1578
1579 if (columns) {
1580 if (schema && !table_schema) {
1581 VLOG_WARN("%s database lacks %s table "
1582 "(database needs upgrade?)",
1583 idl->class_->database, table->class_->name);
1584 json_destroy(columns);
1585 continue;
1586 }
1587
1588 monitor_request = json_object_create();
1589 json_object_put(monitor_request, "columns", columns);
1590 if (!strcmp(method, "monitor_cond")
1591 && !ovsdb_idl_condition_is_true(&table->condition)) {
1592 where = ovsdb_idl_condition_to_json(&table->condition);
1593 json_object_put(monitor_request, "where", where);
1594 table->cond_changed = false;
1595 }
1596 json_object_put(monitor_requests, tc->name, monitor_request);
1597 }
1598 }
1599 free_schema(schema);
1600
1601 json_destroy(idl->request_id);
1602
1603 msg = jsonrpc_create_request(
1604 method,
1605 json_array_create_3(json_string_create(idl->class_->database),
1606 json_string_create("monid"), monitor_requests),
1607 &idl->request_id);
1608 jsonrpc_session_send(idl->session, msg);
1609 idl->cond_changed = false;
1610 }
1611
1612 static void
1613 ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
1614 {
1615 ovsdb_idl_send_monitor_request__(idl, "monitor");
1616 }
1617
1618 static void
1619 log_parse_update_error(struct ovsdb_error *error)
1620 {
1621 if (!VLOG_DROP_WARN(&syntax_rl)) {
1622 char *s = ovsdb_error_to_string(error);
1623 VLOG_WARN_RL(&syntax_rl, "%s", s);
1624 free(s);
1625 }
1626 ovsdb_error_destroy(error);
1627 }
1628
1629 static void
1630 ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl *idl)
1631 {
1632 ovsdb_idl_send_monitor_request__(idl, "monitor_cond");
1633 }
1634
1635 static void
1636 ovsdb_idl_parse_update(struct ovsdb_idl *idl, const struct json *table_updates,
1637 enum ovsdb_update_version version)
1638 {
1639 struct ovsdb_error *error = ovsdb_idl_parse_update__(idl, table_updates,
1640 version);
1641 if (error) {
1642 log_parse_update_error(error);
1643 }
1644 }
1645
1646 static struct ovsdb_error *
1647 ovsdb_idl_parse_update__(struct ovsdb_idl *idl,
1648 const struct json *table_updates,
1649 enum ovsdb_update_version version)
1650 {
1651 const struct shash_node *tables_node;
1652 const char *table_updates_name = table_updates_names[version];
1653 const char *table_update_name = table_update_names[version];
1654 const char *row_update_name = row_update_names[version];
1655
1656 if (table_updates->type != JSON_OBJECT) {
1657 return ovsdb_syntax_error(table_updates, NULL,
1658 "<%s> is not an object",
1659 table_updates_name);
1660 }
1661
1662 SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
1663 const struct json *table_update = tables_node->data;
1664 const struct shash_node *table_node;
1665 struct ovsdb_idl_table *table;
1666
1667 table = shash_find_data(&idl->table_by_name, tables_node->name);
1668 if (!table) {
1669 return ovsdb_syntax_error(
1670 table_updates, NULL,
1671 "<%s> includes unknown table \"%s\"",
1672 table_updates_name,
1673 tables_node->name);
1674 }
1675
1676 if (table_update->type != JSON_OBJECT) {
1677 return ovsdb_syntax_error(table_update, NULL,
1678 "<%s> for table \"%s\" is "
1679 "not an object",
1680 table_update_name,
1681 table->class_->name);
1682 }
1683 SHASH_FOR_EACH (table_node, json_object(table_update)) {
1684 const struct json *row_update = table_node->data;
1685 const struct json *old_json, *new_json;
1686 struct uuid uuid;
1687
1688 if (!uuid_from_string(&uuid, table_node->name)) {
1689 return ovsdb_syntax_error(table_update, NULL,
1690 "<%s> for table \"%s\" "
1691 "contains bad UUID "
1692 "\"%s\" as member name",
1693 table_update_name,
1694 table->class_->name,
1695 table_node->name);
1696 }
1697 if (row_update->type != JSON_OBJECT) {
1698 return ovsdb_syntax_error(row_update, NULL,
1699 "<%s> for table \"%s\" "
1700 "contains <%s> for %s that "
1701 "is not an object",
1702 table_update_name,
1703 table->class_->name,
1704 row_update_name,
1705 table_node->name);
1706 }
1707
1708 switch(version) {
1709 case OVSDB_UPDATE:
1710 old_json = shash_find_data(json_object(row_update), "old");
1711 new_json = shash_find_data(json_object(row_update), "new");
1712 if (old_json && old_json->type != JSON_OBJECT) {
1713 return ovsdb_syntax_error(old_json, NULL,
1714 "\"old\" <row> is not object");
1715 } else if (new_json && new_json->type != JSON_OBJECT) {
1716 return ovsdb_syntax_error(new_json, NULL,
1717 "\"new\" <row> is not object");
1718 } else if ((old_json != NULL) + (new_json != NULL)
1719 != shash_count(json_object(row_update))) {
1720 return ovsdb_syntax_error(row_update, NULL,
1721 "<row-update> contains "
1722 "unexpected member");
1723 } else if (!old_json && !new_json) {
1724 return ovsdb_syntax_error(row_update, NULL,
1725 "<row-update> missing \"old\" "
1726 "and \"new\" members");
1727 }
1728
1729 if (ovsdb_idl_process_update(table, &uuid, old_json,
1730 new_json)) {
1731 idl->change_seqno++;
1732 }
1733 break;
1734
1735 case OVSDB_UPDATE2: {
1736 const char *ops[] = {"modify", "insert", "delete", "initial"};
1737 const char *operation;
1738 const struct json *row;
1739 int i;
1740
1741 for (i = 0; i < ARRAY_SIZE(ops); i++) {
1742 operation = ops[i];
1743 row = shash_find_data(json_object(row_update), operation);
1744
1745 if (row) {
1746 if (ovsdb_idl_process_update2(table, &uuid, operation,
1747 row)) {
1748 idl->change_seqno++;
1749 }
1750 break;
1751 }
1752 }
1753
1754 /* row_update2 should contain one of the objects */
1755 if (i == ARRAY_SIZE(ops)) {
1756 return ovsdb_syntax_error(row_update, NULL,
1757 "<row_update2> includes unknown "
1758 "object");
1759 }
1760 break;
1761 }
1762
1763 default:
1764 OVS_NOT_REACHED();
1765 }
1766 }
1767 }
1768
1769 return NULL;
1770 }
1771
1772 static struct ovsdb_idl_row *
1773 ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
1774 {
1775 struct ovsdb_idl_row *row;
1776
1777 HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) {
1778 if (uuid_equals(&row->uuid, uuid)) {
1779 return row;
1780 }
1781 }
1782 return NULL;
1783 }
1784
1785 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1786 * otherwise. */
1787 static bool
1788 ovsdb_idl_process_update(struct ovsdb_idl_table *table,
1789 const struct uuid *uuid, const struct json *old,
1790 const struct json *new)
1791 {
1792 struct ovsdb_idl_row *row;
1793
1794 row = ovsdb_idl_get_row(table, uuid);
1795 if (!new) {
1796 /* Delete row. */
1797 if (row && !ovsdb_idl_row_is_orphan(row)) {
1798 /* XXX perhaps we should check the 'old' values? */
1799 ovsdb_idl_delete_row(row);
1800 } else {
1801 VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
1802 "from table %s",
1803 UUID_ARGS(uuid), table->class_->name);
1804 return false;
1805 }
1806 } else if (!old) {
1807 /* Insert row. */
1808 if (!row) {
1809 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
1810 } else if (ovsdb_idl_row_is_orphan(row)) {
1811 ovsdb_idl_insert_row(row, new);
1812 } else {
1813 VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
1814 "table %s", UUID_ARGS(uuid), table->class_->name);
1815 return ovsdb_idl_modify_row(row, new);
1816 }
1817 } else {
1818 /* Modify row. */
1819 if (row) {
1820 /* XXX perhaps we should check the 'old' values? */
1821 if (!ovsdb_idl_row_is_orphan(row)) {
1822 return ovsdb_idl_modify_row(row, new);
1823 } else {
1824 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
1825 "referenced row "UUID_FMT" in table %s",
1826 UUID_ARGS(uuid), table->class_->name);
1827 ovsdb_idl_insert_row(row, new);
1828 }
1829 } else {
1830 VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
1831 "in table %s", UUID_ARGS(uuid), table->class_->name);
1832 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
1833 }
1834 }
1835
1836 return true;
1837 }
1838
1839 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1840 * otherwise. */
1841 static bool
1842 ovsdb_idl_process_update2(struct ovsdb_idl_table *table,
1843 const struct uuid *uuid,
1844 const char *operation,
1845 const struct json *json_row)
1846 {
1847 struct ovsdb_idl_row *row;
1848
1849 row = ovsdb_idl_get_row(table, uuid);
1850 if (!strcmp(operation, "delete")) {
1851 /* Delete row. */
1852 if (row && !ovsdb_idl_row_is_orphan(row)) {
1853 ovsdb_idl_delete_row(row);
1854 } else {
1855 VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
1856 "from table %s",
1857 UUID_ARGS(uuid), table->class_->name);
1858 return false;
1859 }
1860 } else if (!strcmp(operation, "insert") || !strcmp(operation, "initial")) {
1861 /* Insert row. */
1862 if (!row) {
1863 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), json_row);
1864 } else if (ovsdb_idl_row_is_orphan(row)) {
1865 ovsdb_idl_insert_row(row, json_row);
1866 } else {
1867 VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
1868 "table %s", UUID_ARGS(uuid), table->class_->name);
1869 ovsdb_idl_delete_row(row);
1870 ovsdb_idl_insert_row(row, json_row);
1871 }
1872 } else if (!strcmp(operation, "modify")) {
1873 /* Modify row. */
1874 if (row) {
1875 if (!ovsdb_idl_row_is_orphan(row)) {
1876 return ovsdb_idl_modify_row_by_diff(row, json_row);
1877 } else {
1878 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
1879 "referenced row "UUID_FMT" in table %s",
1880 UUID_ARGS(uuid), table->class_->name);
1881 return false;
1882 }
1883 } else {
1884 VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
1885 "in table %s", UUID_ARGS(uuid), table->class_->name);
1886 return false;
1887 }
1888 } else {
1889 VLOG_WARN_RL(&semantic_rl, "unknown operation %s to "
1890 "table %s", operation, table->class_->name);
1891 return false;
1892 }
1893
1894 return true;
1895 }
1896
1897 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1898 * otherwise.
1899 *
1900 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1901 * Caller needs to provide either valid 'row_json' or 'diff', but not
1902 * both. */
1903 static bool
1904 ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
1905 const struct json *diff_json,
1906 enum ovsdb_idl_change change)
1907 {
1908 struct ovsdb_idl_table *table = row->table;
1909 const struct ovsdb_idl_table_class *class = table->class_;
1910 struct shash_node *node;
1911 bool changed = false;
1912 bool apply_diff = diff_json != NULL;
1913 const struct json *json = apply_diff ? diff_json : row_json;
1914
1915 SHASH_FOR_EACH (node, json_object(json)) {
1916 const char *column_name = node->name;
1917 const struct ovsdb_idl_column *column;
1918 struct ovsdb_datum datum;
1919 struct ovsdb_error *error;
1920 unsigned int column_idx;
1921 struct ovsdb_datum *old;
1922
1923 column = shash_find_data(&table->columns, column_name);
1924 if (!column) {
1925 VLOG_WARN_RL(&syntax_rl, "unknown column %s updating row "UUID_FMT,
1926 column_name, UUID_ARGS(&row->uuid));
1927 continue;
1928 }
1929
1930 column_idx = column - table->class_->columns;
1931 old = &row->old_datum[column_idx];
1932
1933 error = NULL;
1934 if (apply_diff) {
1935 struct ovsdb_datum diff;
1936
1937 ovs_assert(!row_json);
1938 error = ovsdb_transient_datum_from_json(&diff, &column->type,
1939 node->data);
1940 if (!error) {
1941 error = ovsdb_datum_apply_diff(&datum, old, &diff,
1942 &column->type);
1943 ovsdb_datum_destroy(&diff, &column->type);
1944 }
1945 } else {
1946 ovs_assert(!diff_json);
1947 error = ovsdb_datum_from_json(&datum, &column->type, node->data,
1948 NULL);
1949 }
1950
1951 if (!error) {
1952 if (!ovsdb_datum_equals(old, &datum, &column->type)) {
1953 ovsdb_datum_swap(old, &datum);
1954 if (table->modes[column_idx] & OVSDB_IDL_ALERT) {
1955 changed = true;
1956 row->change_seqno[change]
1957 = row->table->change_seqno[change]
1958 = row->table->idl->change_seqno + 1;
1959 if (table->modes[column_idx] & OVSDB_IDL_TRACK) {
1960 if (!ovs_list_is_empty(&row->track_node)) {
1961 ovs_list_remove(&row->track_node);
1962 }
1963 ovs_list_push_back(&row->table->track_list,
1964 &row->track_node);
1965 if (!row->updated) {
1966 row->updated = bitmap_allocate(class->n_columns);
1967 }
1968 bitmap_set1(row->updated, column_idx);
1969 }
1970 }
1971 } else {
1972 /* Didn't really change but the OVSDB monitor protocol always
1973 * includes every value in a row. */
1974 }
1975
1976 ovsdb_datum_destroy(&datum, &column->type);
1977 } else {
1978 char *s = ovsdb_error_to_string_free(error);
1979 VLOG_WARN_RL(&syntax_rl, "error parsing column %s in row "UUID_FMT
1980 " in table %s: %s", column_name,
1981 UUID_ARGS(&row->uuid), table->class_->name, s);
1982 free(s);
1983 }
1984 }
1985 return changed;
1986 }
1987
1988 static bool
1989 ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json,
1990 enum ovsdb_idl_change change)
1991 {
1992 return ovsdb_idl_row_change__(row, row_json, NULL, change);
1993 }
1994
1995 static bool
1996 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *row,
1997 const struct json *diff_json,
1998 enum ovsdb_idl_change change)
1999 {
2000 return ovsdb_idl_row_change__(row, NULL, diff_json, change);
2001 }
2002
2003 /* When a row A refers to row B through a column with a "refTable" constraint,
2004 * but row B does not exist, row B is called an "orphan row". Orphan rows
2005 * should not persist, because the database enforces referential integrity, but
2006 * they can appear transiently as changes from the database are received (the
2007 * database doesn't try to topologically sort them and circular references mean
2008 * it isn't always possible anyhow).
2009 *
2010 * This function returns true if 'row' is an orphan row, otherwise false.
2011 */
2012 static bool
2013 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
2014 {
2015 return !row->old_datum && !row->new_datum;
2016 }
2017
2018 /* Returns true if 'row' is conceptually part of the database as modified by
2019 * the current transaction (if any), false otherwise.
2020 *
2021 * This function will return true if 'row' is not an orphan (see the comment on
2022 * ovsdb_idl_row_is_orphan()) and:
2023 *
2024 * - 'row' exists in the database and has not been deleted within the
2025 * current transaction (if any).
2026 *
2027 * - 'row' was inserted within the current transaction and has not been
2028 * deleted. (In the latter case you should not have passed 'row' in at
2029 * all, because ovsdb_idl_txn_delete() freed it.)
2030 *
2031 * This function will return false if 'row' is an orphan or if 'row' was
2032 * deleted within the current transaction.
2033 */
2034 static bool
2035 ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
2036 {
2037 return row->new_datum != NULL;
2038 }
2039
2040 static void
2041 ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
2042 {
2043 const struct ovsdb_idl_table_class *class = row->table->class_;
2044 size_t i;
2045
2046 for (i = 0; i < class->n_columns; i++) {
2047 const struct ovsdb_idl_column *c = &class->columns[i];
2048 (c->parse)(row, &row->old_datum[i]);
2049 }
2050 }
2051
2052 static void
2053 ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
2054 {
2055 const struct ovsdb_idl_table_class *class = row->table->class_;
2056 size_t i;
2057
2058 for (i = 0; i < class->n_columns; i++) {
2059 const struct ovsdb_idl_column *c = &class->columns[i];
2060 (c->unparse)(row);
2061 }
2062 }
2063 \f
2064 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2065 * table indexes over one or more columns in the IDL. These indexes provide
2066 * the ability to retrieve rows matching a particular search criteria and to
2067 * iterate over a subset of rows in a defined order.
2068 */
2069
2070 /* Creates a new index with the provided name, attached to the given idl and
2071 * table. Note that all indexes must be created and indexing columns added
2072 * before the first call to ovsdb_idl_run() is made.
2073 */
2074 struct ovsdb_idl_index *
2075 ovsdb_idl_create_index(struct ovsdb_idl *idl,
2076 const struct ovsdb_idl_table_class *tc,
2077 const char *index_name)
2078 {
2079 struct ovsdb_idl_index *index;
2080 size_t i;
2081
2082 for (i = 0; i < idl->class_->n_tables; i++) {
2083 struct ovsdb_idl_table *table = &idl->tables[i];
2084
2085 if (table->class_ == tc) {
2086 index = ovsdb_idl_create_index_(table, 1);
2087 if (!shash_add_once(&table->indexes, index_name, index)) {
2088 VLOG_ERR("Duplicate index name '%s' in table %s",
2089 index_name, table->class_->name);
2090 return NULL;
2091 }
2092 index->index_name = index_name;
2093 return index;
2094 }
2095 }
2096 OVS_NOT_REACHED();
2097 return NULL;
2098 }
2099
2100 /* Generic comparator that can compare each index, using the custom
2101 * configuration (an struct ovsdb_idl_index) passed to it.
2102 * Not intended for direct usage.
2103 */
2104 static int
2105 ovsdb_idl_index_generic_comparer(const void *a,
2106 const void *b, const void *conf)
2107 {
2108 const struct ovsdb_idl_column *column;
2109 const struct ovsdb_idl_index *index;
2110 size_t i;
2111
2112 index = CONST_CAST(struct ovsdb_idl_index *, conf);
2113
2114 if (a == b) {
2115 return 0;
2116 }
2117
2118 for (i = 0; i < index->n_columns; i++) {
2119 int val;
2120 if (index->columns[i].comparer) {
2121 val = index->columns[i].comparer(a, b);
2122 } else {
2123 column = index->columns[i].column;
2124 const struct ovsdb_idl_row *row_a, *row_b;
2125 row_a = CONST_CAST(struct ovsdb_idl_row *, a);
2126 row_b = CONST_CAST(struct ovsdb_idl_row *, b);
2127 const struct ovsdb_datum *datum_a, *datum_b;
2128 datum_a = ovsdb_idl_read(row_a, column);
2129 datum_b = ovsdb_idl_read(row_b, column);
2130 val = ovsdb_datum_compare_3way(datum_a, datum_b, &column->type);
2131 }
2132
2133 if (val) {
2134 return val * index->columns[i].sorting_order;
2135 }
2136 }
2137
2138 /* If ins_del is true then a row is being inserted into or deleted from
2139 * the index list. In this case, we augment the search key with
2140 * additional values (row UUID and memory address) to create a unique
2141 * search key in order to locate the correct entry efficiently and to
2142 * ensure that the correct entry is deleted in the case of a "delete"
2143 * operation.
2144 */
2145 if (index->ins_del) {
2146 const struct ovsdb_idl_row *row_a, *row_b;
2147
2148 row_a = (const struct ovsdb_idl_row *) a;
2149 row_b = (const struct ovsdb_idl_row *) b;
2150 int value = uuid_compare_3way(&row_a->uuid, &row_b->uuid);
2151
2152 return value ? value : (a < b) - (a > b);
2153 } else {
2154 return 0;
2155 }
2156 }
2157
2158 static struct ovsdb_idl_index *
2159 ovsdb_idl_create_index_(const struct ovsdb_idl_table *table,
2160 size_t allocated_cols)
2161 {
2162 struct ovsdb_idl_index *index;
2163
2164 index = xmalloc(sizeof (struct ovsdb_idl_index));
2165 index->n_columns = 0;
2166 index->alloc_columns = allocated_cols;
2167 index->skiplist = skiplist_create(ovsdb_idl_index_generic_comparer, index);
2168 index->columns = xmalloc(allocated_cols *
2169 sizeof (struct ovsdb_idl_index_column));
2170 index->ins_del = false;
2171 index->table = table;
2172 return index;
2173 }
2174
2175 static void
2176 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *table)
2177 {
2178 struct ovsdb_idl_index *index;
2179 struct shash_node *node;
2180
2181 SHASH_FOR_EACH (node, &(table->indexes)) {
2182 index = node->data;
2183 skiplist_destroy(index->skiplist, NULL);
2184 free(index->columns);
2185 }
2186 shash_destroy_free_data(&table->indexes);
2187 }
2188
2189 static void
2190 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *row)
2191 {
2192 struct ovsdb_idl_table *table = row->table;
2193 struct ovsdb_idl_index *index;
2194 struct shash_node *node;
2195
2196 SHASH_FOR_EACH (node, &(table->indexes)) {
2197 index = node->data;
2198 index->ins_del = true;
2199 skiplist_insert(index->skiplist, row);
2200 index->ins_del = false;
2201 }
2202 }
2203
2204 static void
2205 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *row)
2206 {
2207 struct ovsdb_idl_table *table = row->table;
2208 struct ovsdb_idl_index *index;
2209 struct shash_node *node;
2210
2211 SHASH_FOR_EACH (node, &(table->indexes)) {
2212 index = node->data;
2213 index->ins_del = true;
2214 skiplist_delete(index->skiplist, row);
2215 index->ins_del = false;
2216 }
2217 }
2218
2219 /* Adds a column to an existing index (note that columns can only be added to
2220 * an index before the first call to ovsdb_idl_run()). The 'order' parameter
2221 * specifies whether the sort order should be ascending (OVSDB_INDEX_ASC) or
2222 * descending (OVSDB_INDEX_DESC). The 'custom_comparer' parameter, if non-NULL,
2223 * contains a pointer to a custom comparison function. A default comparison
2224 * function is used if a custom comparison function is not provided (the
2225 * default comparison function can only be used for columns of type string,
2226 * uuid, integer, real, or boolean).
2227 */
2228 void
2229 ovsdb_idl_index_add_column(struct ovsdb_idl_index *index,
2230 const struct ovsdb_idl_column *column,
2231 int order, column_comparator *custom_comparer)
2232 {
2233 /* Check that the column or table is tracked */
2234 if (!index->table->need_table &&
2235 !((OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT) &
2236 *ovsdb_idl_get_mode(index->table->idl, column))) {
2237 VLOG_ERR("Can't add unmonitored column '%s' at index '%s' in "
2238 "table '%s'.",
2239 column->name, index->index_name, index->table->class_->name);
2240 }
2241 if (!ovsdb_type_is_scalar(&column->type) && !custom_comparer) {
2242 VLOG_WARN("Comparing non-scalar values.");
2243 }
2244
2245 /* Allocate more memory for column configuration */
2246 if (index->n_columns == index->alloc_columns) {
2247 index->alloc_columns++;
2248 index->columns = xrealloc(index->columns,
2249 index->alloc_columns *
2250 sizeof(struct ovsdb_idl_index_column));
2251 }
2252
2253 /* Append column to index */
2254 int i = index->n_columns;
2255
2256 index->columns[i].column = column;
2257 index->columns[i].comparer = custom_comparer ? custom_comparer : NULL;
2258 if (order == OVSDB_INDEX_ASC) {
2259 index->columns[i].sorting_order = OVSDB_INDEX_ASC;
2260 } else {
2261 index->columns[i].sorting_order = OVSDB_INDEX_DESC;
2262 }
2263 index->n_columns++;
2264 }
2265
2266 bool
2267 ovsdb_idl_initialize_cursor(struct ovsdb_idl *idl,
2268 const struct ovsdb_idl_table_class *tc,
2269 const char *index_name,
2270 struct ovsdb_idl_index_cursor *cursor)
2271 {
2272 size_t i;
2273
2274 for (i = 0; i < idl->class_->n_tables; i++) {
2275 struct ovsdb_idl_table *table = &idl->tables[i];
2276
2277 if (table->class_ == tc) {
2278 struct shash_node *node = shash_find(&table->indexes, index_name);
2279
2280 if (!node || !node->data) {
2281 VLOG_ERR("Cursor initialization failed, "
2282 "index %s at table %s does not exist.",
2283 index_name, tc->name);
2284 cursor->index = NULL;
2285 cursor->position = NULL;
2286 return false;
2287 }
2288 cursor->index = node->data;
2289 cursor->position = skiplist_first(cursor->index->skiplist);
2290 return true;
2291 }
2292 }
2293 VLOG_ERR("Cursor initialization failed, "
2294 "index %s at table %s does not exist.", index_name, tc->name);
2295 return false;
2296 }
2297
2298 /* ovsdb_idl_index_write_ writes a datum in an ovsdb_idl_row,
2299 * and updates the corresponding field in the table record.
2300 * Not intended for direct usage.
2301 */
2302 void
2303 ovsdb_idl_index_write_(struct ovsdb_idl_row *const_row,
2304 const struct ovsdb_idl_column *column,
2305 struct ovsdb_datum *datum,
2306 const struct ovsdb_idl_table_class *class)
2307 {
2308 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, const_row);
2309 size_t column_idx = column - class->columns;
2310
2311 if (bitmap_is_set(row->written, column_idx)) {
2312 free(row->new_datum[column_idx].values);
2313 free(row->new_datum[column_idx].keys);
2314 } else {
2315 bitmap_set1(row->written, column_idx);
2316 }
2317 row->new_datum[column_idx] = *datum;
2318 (column->unparse)(row);
2319 (column->parse)(row, &row->new_datum[column_idx]);
2320 }
2321
2322 /* Magic UUID for index rows */
2323 static const struct uuid index_row_uuid = {
2324 .parts = {0xdeadbeef,
2325 0xdeadbeef,
2326 0xdeadbeef,
2327 0xdeadbeef}};
2328
2329 /* Check if a row is an index row */
2330 static bool
2331 is_index_row(struct ovsdb_idl_row *row)
2332 {
2333 return uuid_equals(&row->uuid, &index_row_uuid);
2334 }
2335
2336 /* Initializes a row for use in an indexed query.
2337 * Not intended for direct usage.
2338 */
2339 struct ovsdb_idl_row *
2340 ovsdb_idl_index_init_row(struct ovsdb_idl * idl,
2341 const struct ovsdb_idl_table_class *class)
2342 {
2343 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
2344 class->row_init(row);
2345 row->uuid = index_row_uuid;
2346 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
2347 row->written = bitmap_allocate(class->n_columns);
2348 row->table = ovsdb_idl_table_from_class(idl, class);
2349 /* arcs are not used for index row, but it doesn't harm to initialize */
2350 ovs_list_init(&row->src_arcs);
2351 ovs_list_init(&row->dst_arcs);
2352 return row;
2353 }
2354
2355 /* Destroys 'row_' and frees all associated memory. This function is intended
2356 * to be used indirectly through one of the "index_destroy_row" functions
2357 * generated by ovsdb-idlc.
2358 */
2359 void
2360 ovsdb_idl_index_destroy_row__(const struct ovsdb_idl_row *row_)
2361 {
2362 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
2363 const struct ovsdb_idl_table_class *class = row->table->class_;
2364 const struct ovsdb_idl_column *c;
2365 size_t i;
2366
2367 ovs_assert(ovs_list_is_empty(&row_->src_arcs));
2368 ovs_assert(ovs_list_is_empty(&row_->dst_arcs));
2369 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
2370 c = &class->columns[i];
2371 (c->unparse) (row);
2372 free(row->new_datum[i].values);
2373 free(row->new_datum[i].keys);
2374 }
2375 free(row->new_datum);
2376 free(row->written);
2377 free(row);
2378 }
2379
2380 /* Moves the cursor to the first entry in the index. Returns a pointer to the
2381 * corresponding ovsdb_idl_row, or NULL if the index list is empy.
2382 */
2383 struct ovsdb_idl_row *
2384 ovsdb_idl_index_first(struct ovsdb_idl_index_cursor *cursor)
2385 {
2386 cursor->position = skiplist_first(cursor->index->skiplist);
2387 return ovsdb_idl_index_data(cursor);
2388 }
2389
2390 /* Moves the cursor to the next record in the index list.
2391 */
2392 struct ovsdb_idl_row *
2393 ovsdb_idl_index_next(struct ovsdb_idl_index_cursor *cursor)
2394 {
2395 if (!cursor->position) {
2396 return NULL;
2397 }
2398 cursor->position = skiplist_next(cursor->position);
2399 return ovsdb_idl_index_data(cursor);
2400 }
2401
2402 /* Returns the ovsdb_idl_row pointer corresponding to the record at the
2403 * current cursor location.
2404 */
2405 struct ovsdb_idl_row *
2406 ovsdb_idl_index_data(struct ovsdb_idl_index_cursor *cursor)
2407 {
2408 return skiplist_get_data(cursor->position);
2409 }
2410
2411 /* Moves the cursor to the first entry in the index matching the specified
2412 * value. If 'value' is NULL, the cursor is moved to the last entry in the
2413 * list. Returns a pointer to the corresponding ovsdb_idl_row or NULL.
2414 */
2415 struct ovsdb_idl_row *
2416 ovsdb_idl_index_find(struct ovsdb_idl_index_cursor *cursor,
2417 struct ovsdb_idl_row *value)
2418 {
2419 if (value) {
2420 cursor->position = skiplist_find(cursor->index->skiplist, value);
2421 } else {
2422 cursor->position = skiplist_first(cursor->index->skiplist);
2423 }
2424 return ovsdb_idl_index_data(cursor);
2425 }
2426
2427 /* Moves the cursor to the first entry in the index with a value greater than
2428 * or equal to the given value. If 'value' is NULL, the cursor is moved to the
2429 * first entry in the index. Returns a pointer to the corresponding
2430 * ovsdb_idl_row or NULL if such a row does not exist.
2431 */
2432 struct ovsdb_idl_row *
2433 ovsdb_idl_index_forward_to(struct ovsdb_idl_index_cursor *cursor,
2434 struct ovsdb_idl_row *value)
2435 {
2436 if (value) {
2437 cursor->position = skiplist_forward_to(cursor->index->skiplist, value);
2438 } else {
2439 cursor->position = skiplist_first(cursor->index->skiplist);
2440 }
2441 return ovsdb_idl_index_data(cursor);
2442 }
2443
2444 /* Returns the result of comparing two rows using the comparison function
2445 * for this index.
2446 * Returns:
2447 * < 0 if a < b
2448 * 0 if a == b
2449 * > 0 if a > b
2450 * When the pointer to either row is NULL, this function considers NULL to be
2451 * greater than any other value, and NULL == NULL.
2452 */
2453 int
2454 ovsdb_idl_index_compare(struct ovsdb_idl_index_cursor *cursor,
2455 struct ovsdb_idl_row *a, struct ovsdb_idl_row *b)
2456 {
2457 if (a && b) {
2458 return ovsdb_idl_index_generic_comparer(a, b, cursor->index);
2459 } else if (!a && !b) {
2460 return 0;
2461 } else if (a) {
2462 return -1;
2463 } else {
2464 return 1;
2465 }
2466 }
2467
2468 static void
2469 ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
2470 {
2471 ovs_assert(row->old_datum == row->new_datum);
2472 if (!ovsdb_idl_row_is_orphan(row)) {
2473 const struct ovsdb_idl_table_class *class = row->table->class_;
2474 size_t i;
2475
2476 for (i = 0; i < class->n_columns; i++) {
2477 ovsdb_datum_destroy(&row->old_datum[i], &class->columns[i].type);
2478 }
2479 free(row->old_datum);
2480 row->old_datum = row->new_datum = NULL;
2481 }
2482 }
2483
2484 static void
2485 ovsdb_idl_row_clear_new(struct ovsdb_idl_row *row)
2486 {
2487 if (row->old_datum != row->new_datum) {
2488 if (row->new_datum) {
2489 const struct ovsdb_idl_table_class *class = row->table->class_;
2490 size_t i;
2491
2492 if (row->written) {
2493 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
2494 ovsdb_datum_destroy(&row->new_datum[i],
2495 &class->columns[i].type);
2496 }
2497 }
2498 free(row->new_datum);
2499 free(row->written);
2500 row->written = NULL;
2501 }
2502 row->new_datum = row->old_datum;
2503 }
2504 }
2505
2506 static void
2507 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *row, bool destroy_dsts)
2508 {
2509 struct ovsdb_idl_arc *arc, *next;
2510
2511 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
2512 * that this causes to be unreferenced, if tracking is not enabled.
2513 * If tracking is enabled, orphaned nodes are removed from hmap but not
2514 * freed.
2515 */
2516 LIST_FOR_EACH_SAFE (arc, next, src_node, &row->src_arcs) {
2517 ovs_list_remove(&arc->dst_node);
2518 if (destroy_dsts
2519 && ovsdb_idl_row_is_orphan(arc->dst)
2520 && ovs_list_is_empty(&arc->dst->dst_arcs)) {
2521 ovsdb_idl_row_destroy(arc->dst);
2522 }
2523 free(arc);
2524 }
2525 ovs_list_init(&row->src_arcs);
2526 }
2527
2528 /* Force nodes that reference 'row' to reparse. */
2529 static void
2530 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row)
2531 {
2532 struct ovsdb_idl_arc *arc, *next;
2533
2534 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2535 * 'arc', so we need to use the "safe" variant of list traversal. However,
2536 * calling an ovsdb_idl_column's 'parse' function will add an arc
2537 * equivalent to 'arc' to row->arcs. That could be a problem for
2538 * traversal, but it adds it at the beginning of the list to prevent us
2539 * from stumbling upon it again.
2540 *
2541 * (If duplicate arcs were possible then we would need to make sure that
2542 * 'next' didn't also point into 'arc''s destination, but we forbid
2543 * duplicate arcs.) */
2544 LIST_FOR_EACH_SAFE (arc, next, dst_node, &row->dst_arcs) {
2545 struct ovsdb_idl_row *ref = arc->src;
2546
2547 ovsdb_idl_row_unparse(ref);
2548 ovsdb_idl_row_clear_arcs(ref, false);
2549 ovsdb_idl_row_parse(ref);
2550 }
2551 }
2552
2553 static struct ovsdb_idl_row *
2554 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
2555 {
2556 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
2557 class->row_init(row);
2558 ovs_list_init(&row->src_arcs);
2559 ovs_list_init(&row->dst_arcs);
2560 hmap_node_nullify(&row->txn_node);
2561 ovs_list_init(&row->track_node);
2562 return row;
2563 }
2564
2565 static struct ovsdb_idl_row *
2566 ovsdb_idl_row_create(struct ovsdb_idl_table *table, const struct uuid *uuid)
2567 {
2568 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(table->class_);
2569 hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
2570 row->uuid = *uuid;
2571 row->table = table;
2572 row->map_op_written = NULL;
2573 row->map_op_lists = NULL;
2574 row->set_op_written = NULL;
2575 row->set_op_lists = NULL;
2576 return row;
2577 }
2578
2579 static void
2580 ovsdb_idl_row_destroy(struct ovsdb_idl_row *row)
2581 {
2582 if (row) {
2583 ovsdb_idl_row_clear_old(row);
2584 hmap_remove(&row->table->rows, &row->hmap_node);
2585 ovsdb_idl_destroy_all_map_op_lists(row);
2586 ovsdb_idl_destroy_all_set_op_lists(row);
2587 if (ovsdb_idl_track_is_set(row->table)) {
2588 row->change_seqno[OVSDB_IDL_CHANGE_DELETE]
2589 = row->table->change_seqno[OVSDB_IDL_CHANGE_DELETE]
2590 = row->table->idl->change_seqno + 1;
2591 }
2592 if (!ovs_list_is_empty(&row->track_node)) {
2593 ovs_list_remove(&row->track_node);
2594 }
2595 ovs_list_push_back(&row->table->track_list, &row->track_node);
2596 }
2597 }
2598
2599 static void
2600 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *row)
2601 {
2602 if (row->map_op_written) {
2603 /* Clear Map Operation Lists */
2604 size_t idx, n_columns;
2605 const struct ovsdb_idl_column *columns;
2606 const struct ovsdb_type *type;
2607 n_columns = row->table->class_->n_columns;
2608 columns = row->table->class_->columns;
2609 BITMAP_FOR_EACH_1 (idx, n_columns, row->map_op_written) {
2610 type = &columns[idx].type;
2611 map_op_list_destroy(row->map_op_lists[idx], type);
2612 }
2613 free(row->map_op_lists);
2614 bitmap_free(row->map_op_written);
2615 row->map_op_lists = NULL;
2616 row->map_op_written = NULL;
2617 }
2618 }
2619
2620 static void
2621 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *row)
2622 {
2623 if (row->set_op_written) {
2624 /* Clear Set Operation Lists */
2625 size_t idx, n_columns;
2626 const struct ovsdb_idl_column *columns;
2627 const struct ovsdb_type *type;
2628 n_columns = row->table->class_->n_columns;
2629 columns = row->table->class_->columns;
2630 BITMAP_FOR_EACH_1 (idx, n_columns, row->set_op_written) {
2631 type = &columns[idx].type;
2632 set_op_list_destroy(row->set_op_lists[idx], type);
2633 }
2634 free(row->set_op_lists);
2635 bitmap_free(row->set_op_written);
2636 row->set_op_lists = NULL;
2637 row->set_op_written = NULL;
2638 }
2639 }
2640
2641 static void
2642 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *idl)
2643 {
2644 size_t i;
2645
2646 for (i = 0; i < idl->class_->n_tables; i++) {
2647 struct ovsdb_idl_table *table = &idl->tables[i];
2648
2649 if (!ovs_list_is_empty(&table->track_list)) {
2650 struct ovsdb_idl_row *row, *next;
2651
2652 LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
2653 if (!ovsdb_idl_track_is_set(row->table)) {
2654 ovs_list_remove(&row->track_node);
2655 free(row);
2656 }
2657 }
2658 }
2659 }
2660 }
2661
2662 static void
2663 ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
2664 {
2665 const struct ovsdb_idl_table_class *class = row->table->class_;
2666 size_t i, datum_size;
2667
2668 ovs_assert(!row->old_datum && !row->new_datum);
2669 datum_size = class->n_columns * sizeof *row->old_datum;
2670 row->old_datum = row->new_datum = xmalloc(datum_size);
2671 for (i = 0; i < class->n_columns; i++) {
2672 ovsdb_datum_init_default(&row->old_datum[i], &class->columns[i].type);
2673 }
2674 ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_INSERT);
2675 ovsdb_idl_row_parse(row);
2676
2677 ovsdb_idl_row_reparse_backrefs(row);
2678 ovsdb_idl_add_to_indexes(row);
2679 }
2680
2681 static void
2682 ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
2683 {
2684 ovsdb_idl_remove_from_indexes(row);
2685 ovsdb_idl_row_unparse(row);
2686 ovsdb_idl_row_clear_arcs(row, true);
2687 ovsdb_idl_row_clear_old(row);
2688 if (ovs_list_is_empty(&row->dst_arcs)) {
2689 ovsdb_idl_row_destroy(row);
2690 } else {
2691 ovsdb_idl_row_reparse_backrefs(row);
2692 }
2693 }
2694
2695 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2696 * otherwise. */
2697 static bool
2698 ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
2699 {
2700 bool changed;
2701
2702 ovsdb_idl_remove_from_indexes(row);
2703 ovsdb_idl_row_unparse(row);
2704 ovsdb_idl_row_clear_arcs(row, true);
2705 changed = ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_MODIFY);
2706 ovsdb_idl_row_parse(row);
2707 ovsdb_idl_add_to_indexes(row);
2708
2709 return changed;
2710 }
2711
2712 static bool
2713 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *row,
2714 const struct json *diff_json)
2715 {
2716 bool changed;
2717
2718 ovsdb_idl_row_unparse(row);
2719 ovsdb_idl_row_clear_arcs(row, true);
2720 changed = ovsdb_idl_row_apply_diff(row, diff_json,
2721 OVSDB_IDL_CHANGE_MODIFY);
2722 ovsdb_idl_row_parse(row);
2723
2724 return changed;
2725 }
2726
2727 static bool
2728 may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
2729 {
2730 const struct ovsdb_idl_arc *arc;
2731
2732 /* No self-arcs. */
2733 if (src == dst) {
2734 return false;
2735 }
2736
2737 /* No duplicate arcs.
2738 *
2739 * We only need to test whether the first arc in dst->dst_arcs originates
2740 * at 'src', since we add all of the arcs from a given source in a clump
2741 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
2742 * added at the front of the dst_arcs list. */
2743 if (ovs_list_is_empty(&dst->dst_arcs)) {
2744 return true;
2745 }
2746 arc = CONTAINER_OF(dst->dst_arcs.next, struct ovsdb_idl_arc, dst_node);
2747 return arc->src != src;
2748 }
2749
2750 static struct ovsdb_idl_table *
2751 ovsdb_idl_table_from_class(const struct ovsdb_idl *idl,
2752 const struct ovsdb_idl_table_class *table_class)
2753 {
2754 return &idl->tables[table_class - idl->class_->tables];
2755 }
2756
2757 /* Called by ovsdb-idlc generated code. */
2758 struct ovsdb_idl_row *
2759 ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
2760 const struct ovsdb_idl_table_class *dst_table_class,
2761 const struct uuid *dst_uuid)
2762 {
2763 struct ovsdb_idl *idl = src->table->idl;
2764 struct ovsdb_idl_table *dst_table;
2765 struct ovsdb_idl_arc *arc;
2766 struct ovsdb_idl_row *dst;
2767
2768 dst_table = ovsdb_idl_table_from_class(idl, dst_table_class);
2769 dst = ovsdb_idl_get_row(dst_table, dst_uuid);
2770 if (idl->txn || is_index_row(src)) {
2771 /* There are two cases we should not update any arcs:
2772 *
2773 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
2774 * any arcs, because the transaction will be backed out at commit or
2775 * abort time and we don't want our graph screwed up.
2776 *
2777 * 2. The row is used as an index for querying purpose only.
2778 *
2779 * In these cases, just return the destination row, if there is one and
2780 * it has not been deleted. */
2781 if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new_datum)) {
2782 return dst;
2783 }
2784 return NULL;
2785 } else {
2786 /* We're being called from some other context. Update the graph. */
2787 if (!dst) {
2788 dst = ovsdb_idl_row_create(dst_table, dst_uuid);
2789 }
2790
2791 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
2792 if (may_add_arc(src, dst)) {
2793 /* The arc *must* be added at the front of the dst_arcs list. See
2794 * ovsdb_idl_row_reparse_backrefs() for details. */
2795 arc = xmalloc(sizeof *arc);
2796 ovs_list_push_front(&src->src_arcs, &arc->src_node);
2797 ovs_list_push_front(&dst->dst_arcs, &arc->dst_node);
2798 arc->src = src;
2799 arc->dst = dst;
2800 }
2801
2802 return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
2803 }
2804 }
2805
2806 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
2807 * pointer to the row if there is one, otherwise a null pointer. */
2808 const struct ovsdb_idl_row *
2809 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
2810 const struct ovsdb_idl_table_class *tc,
2811 const struct uuid *uuid)
2812 {
2813 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
2814 }
2815
2816 static struct ovsdb_idl_row *
2817 next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
2818 {
2819 for (; node; node = hmap_next(&table->rows, node)) {
2820 struct ovsdb_idl_row *row;
2821
2822 row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
2823 if (ovsdb_idl_row_exists(row)) {
2824 return row;
2825 }
2826 }
2827 return NULL;
2828 }
2829
2830 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
2831 * table is empty.
2832 *
2833 * Database tables are internally maintained as hash tables, so adding or
2834 * removing rows while traversing the same table can cause some rows to be
2835 * visited twice or not at apply. */
2836 const struct ovsdb_idl_row *
2837 ovsdb_idl_first_row(const struct ovsdb_idl *idl,
2838 const struct ovsdb_idl_table_class *table_class)
2839 {
2840 struct ovsdb_idl_table *table
2841 = ovsdb_idl_table_from_class(idl, table_class);
2842 return next_real_row(table, hmap_first(&table->rows));
2843 }
2844
2845 /* Returns a row following 'row' within its table, or a null pointer if 'row'
2846 * is the last row in its table. */
2847 const struct ovsdb_idl_row *
2848 ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
2849 {
2850 struct ovsdb_idl_table *table = row->table;
2851
2852 return next_real_row(table, hmap_next(&table->rows, &row->hmap_node));
2853 }
2854
2855 /* Reads and returns the value of 'column' within 'row'. If an ongoing
2856 * transaction has changed 'column''s value, the modified value is returned.
2857 *
2858 * The caller must not modify or free the returned value.
2859 *
2860 * Various kinds of changes can invalidate the returned value: writing to the
2861 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
2862 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
2863 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
2864 * returned value is needed for a long time, it is best to make a copy of it
2865 * with ovsdb_datum_clone(). */
2866 const struct ovsdb_datum *
2867 ovsdb_idl_read(const struct ovsdb_idl_row *row,
2868 const struct ovsdb_idl_column *column)
2869 {
2870 const struct ovsdb_idl_table_class *class;
2871 size_t column_idx;
2872
2873 ovs_assert(!ovsdb_idl_row_is_synthetic(row));
2874
2875 class = row->table->class_;
2876 column_idx = column - class->columns;
2877
2878 ovs_assert(row->new_datum != NULL);
2879 ovs_assert(column_idx < class->n_columns);
2880
2881 if (row->written && bitmap_is_set(row->written, column_idx)) {
2882 return &row->new_datum[column_idx];
2883 } else if (row->old_datum) {
2884 return &row->old_datum[column_idx];
2885 } else {
2886 return ovsdb_datum_default(&column->type);
2887 }
2888 }
2889
2890 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
2891 * type 'key_type' and value type 'value_type'. (Scalar and set types will
2892 * have a value type of OVSDB_TYPE_VOID.)
2893 *
2894 * This is useful in code that "knows" that a particular column has a given
2895 * type, so that it will abort if someone changes the column's type without
2896 * updating the code that uses it. */
2897 const struct ovsdb_datum *
2898 ovsdb_idl_get(const struct ovsdb_idl_row *row,
2899 const struct ovsdb_idl_column *column,
2900 enum ovsdb_atomic_type key_type OVS_UNUSED,
2901 enum ovsdb_atomic_type value_type OVS_UNUSED)
2902 {
2903 ovs_assert(column->type.key.type == key_type);
2904 ovs_assert(column->type.value.type == value_type);
2905
2906 return ovsdb_idl_read(row, column);
2907 }
2908
2909 /* Returns true if the field represented by 'column' in 'row' may be modified,
2910 * false if it is immutable.
2911 *
2912 * Normally, whether a field is mutable is controlled by its column's schema.
2913 * However, an immutable column can be set to any initial value at the time of
2914 * insertion, so if 'row' is a new row (one that is being added as part of the
2915 * current transaction, supposing that a transaction is in progress) then even
2916 * its "immutable" fields are actually mutable. */
2917 bool
2918 ovsdb_idl_is_mutable(const struct ovsdb_idl_row *row,
2919 const struct ovsdb_idl_column *column)
2920 {
2921 return column->is_mutable || (row->new_datum && !row->old_datum);
2922 }
2923
2924 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
2925 * to all-zero-bits by some other entity. If 'row' was set up some other way
2926 * then the return value is indeterminate. */
2927 bool
2928 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *row)
2929 {
2930 return row->table == NULL;
2931 }
2932 \f
2933 /* Transactions. */
2934
2935 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
2936 enum ovsdb_idl_txn_status);
2937
2938 /* Returns a string representation of 'status'. The caller must not modify or
2939 * free the returned string.
2940 *
2941 * The return value is probably useful only for debug log messages and unit
2942 * tests. */
2943 const char *
2944 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
2945 {
2946 switch (status) {
2947 case TXN_UNCOMMITTED:
2948 return "uncommitted";
2949 case TXN_UNCHANGED:
2950 return "unchanged";
2951 case TXN_INCOMPLETE:
2952 return "incomplete";
2953 case TXN_ABORTED:
2954 return "aborted";
2955 case TXN_SUCCESS:
2956 return "success";
2957 case TXN_TRY_AGAIN:
2958 return "try again";
2959 case TXN_NOT_LOCKED:
2960 return "not locked";
2961 case TXN_ERROR:
2962 return "error";
2963 }
2964 return "<unknown>";
2965 }
2966
2967 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
2968 * active transaction at a time. See the large comment in ovsdb-idl.h for
2969 * general information on transactions. */
2970 struct ovsdb_idl_txn *
2971 ovsdb_idl_txn_create(struct ovsdb_idl *idl)
2972 {
2973 struct ovsdb_idl_txn *txn;
2974
2975 ovs_assert(!idl->txn);
2976 idl->txn = txn = xmalloc(sizeof *txn);
2977 txn->request_id = NULL;
2978 txn->idl = idl;
2979 hmap_init(&txn->txn_rows);
2980 txn->status = TXN_UNCOMMITTED;
2981 txn->error = NULL;
2982 txn->dry_run = false;
2983 ds_init(&txn->comment);
2984
2985 txn->inc_table = NULL;
2986 txn->inc_column = NULL;
2987
2988 hmap_init(&txn->inserted_rows);
2989
2990 return txn;
2991 }
2992
2993 /* Appends 's', which is treated as a printf()-type format string, to the
2994 * comments that will be passed to the OVSDB server when 'txn' is committed.
2995 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
2996 * show-log" can print in a relatively human-readable form.) */
2997 void
2998 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
2999 {
3000 va_list args;
3001
3002 if (txn->comment.length) {
3003 ds_put_char(&txn->comment, '\n');
3004 }
3005
3006 va_start(args, s);
3007 ds_put_format_valist(&txn->comment, s, args);
3008 va_end(args);
3009 }
3010
3011 /* Marks 'txn' as a transaction that will not actually modify the database. In
3012 * almost every way, the transaction is treated like other transactions. It
3013 * must be committed or aborted like other transactions, it will be sent to the
3014 * database server like other transactions, and so on. The only difference is
3015 * that the operations sent to the database server will include, as the last
3016 * step, an "abort" operation, so that any changes made by the transaction will
3017 * not actually take effect. */
3018 void
3019 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
3020 {
3021 txn->dry_run = true;
3022 }
3023
3024 /* Causes 'txn', when committed, to increment the value of 'column' within
3025 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3026 * successfully, the client may retrieve the final (incremented) value of
3027 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3028 *
3029 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3030 * change the database, then 'force' is important. If 'force' is false in this
3031 * case, the IDL suppresses the increment and skips a round trip to the
3032 * database server. If 'force' is true, the IDL will still increment the
3033 * column.
3034 *
3035 * The client could accomplish something similar with ovsdb_idl_read(),
3036 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3037 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3038 * will never (by itself) fail because of a verify error.
3039 *
3040 * The intended use is for incrementing the "next_cfg" column in the
3041 * Open_vSwitch table. */
3042 void
3043 ovsdb_idl_txn_increment(struct ovsdb_idl_txn *txn,
3044 const struct ovsdb_idl_row *row,
3045 const struct ovsdb_idl_column *column,
3046 bool force)
3047 {
3048 ovs_assert(!txn->inc_table);
3049 ovs_assert(column->type.key.type == OVSDB_TYPE_INTEGER);
3050 ovs_assert(column->type.value.type == OVSDB_TYPE_VOID);
3051
3052 txn->inc_table = row->table->class_->name;
3053 txn->inc_column = column->name;
3054 txn->inc_row = row->uuid;
3055 txn->inc_force = force;
3056 }
3057
3058 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3059 * has been called for 'txn' but the commit is still incomplete (that is, the
3060 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3061 * end up committing at the database server, but the client will not be able to
3062 * get any further status information back. */
3063 void
3064 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
3065 {
3066 struct ovsdb_idl_txn_insert *insert, *next;
3067
3068 json_destroy(txn->request_id);
3069 if (txn->status == TXN_INCOMPLETE) {
3070 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
3071 }
3072 ovsdb_idl_txn_abort(txn);
3073 ds_destroy(&txn->comment);
3074 free(txn->error);
3075 HMAP_FOR_EACH_SAFE (insert, next, hmap_node, &txn->inserted_rows) {
3076 free(insert);
3077 }
3078 hmap_destroy(&txn->inserted_rows);
3079 free(txn);
3080 }
3081
3082 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3083 void
3084 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
3085 {
3086 if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
3087 poll_immediate_wake();
3088 }
3089 }
3090
3091 static struct json *
3092 where_uuid_equals(const struct uuid *uuid)
3093 {
3094 return
3095 json_array_create_1(
3096 json_array_create_3(
3097 json_string_create("_uuid"),
3098 json_string_create("=="),
3099 json_array_create_2(
3100 json_string_create("uuid"),
3101 json_string_create_nocopy(
3102 xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
3103 }
3104
3105 static char *
3106 uuid_name_from_uuid(const struct uuid *uuid)
3107 {
3108 char *name;
3109 char *p;
3110
3111 name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
3112 for (p = name; *p != '\0'; p++) {
3113 if (*p == '-') {
3114 *p = '_';
3115 }
3116 }
3117
3118 return name;
3119 }
3120
3121 static const struct ovsdb_idl_row *
3122 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
3123 {
3124 const struct ovsdb_idl_row *row;
3125
3126 HMAP_FOR_EACH_WITH_HASH (row, txn_node, uuid_hash(uuid), &txn->txn_rows) {
3127 if (uuid_equals(&row->uuid, uuid)) {
3128 return row;
3129 }
3130 }
3131 return NULL;
3132 }
3133
3134 /* XXX there must be a cleaner way to do this */
3135 static struct json *
3136 substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
3137 {
3138 if (json->type == JSON_ARRAY) {
3139 struct uuid uuid;
3140 size_t i;
3141
3142 if (json->u.array.n == 2
3143 && json->u.array.elems[0]->type == JSON_STRING
3144 && json->u.array.elems[1]->type == JSON_STRING
3145 && !strcmp(json->u.array.elems[0]->u.string, "uuid")
3146 && uuid_from_string(&uuid, json->u.array.elems[1]->u.string)) {
3147 const struct ovsdb_idl_row *row;
3148
3149 row = ovsdb_idl_txn_get_row(txn, &uuid);
3150 if (row && !row->old_datum && row->new_datum) {
3151 json_destroy(json);
3152
3153 return json_array_create_2(
3154 json_string_create("named-uuid"),
3155 json_string_create_nocopy(uuid_name_from_uuid(&uuid)));
3156 }
3157 }
3158
3159 for (i = 0; i < json->u.array.n; i++) {
3160 json->u.array.elems[i] = substitute_uuids(json->u.array.elems[i],
3161 txn);
3162 }
3163 } else if (json->type == JSON_OBJECT) {
3164 struct shash_node *node;
3165
3166 SHASH_FOR_EACH (node, json_object(json)) {
3167 node->data = substitute_uuids(node->data, txn);
3168 }
3169 }
3170 return json;
3171 }
3172
3173 static void
3174 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
3175 {
3176 struct ovsdb_idl_row *row, *next;
3177
3178 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3179 * ovsdb_idl_column's 'parse' function, which will call
3180 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3181 * transaction and fail to update the graph. */
3182 txn->idl->txn = NULL;
3183
3184 HMAP_FOR_EACH_SAFE (row, next, txn_node, &txn->txn_rows) {
3185 ovsdb_idl_destroy_all_map_op_lists(row);
3186 ovsdb_idl_destroy_all_set_op_lists(row);
3187 if (row->old_datum) {
3188 if (row->written) {
3189 ovsdb_idl_row_unparse(row);
3190 ovsdb_idl_row_clear_arcs(row, false);
3191 ovsdb_idl_row_parse(row);
3192 }
3193 } else {
3194 ovsdb_idl_row_unparse(row);
3195 }
3196 ovsdb_idl_row_clear_new(row);
3197
3198 free(row->prereqs);
3199 row->prereqs = NULL;
3200
3201 free(row->written);
3202 row->written = NULL;
3203
3204 hmap_remove(&txn->txn_rows, &row->txn_node);
3205 hmap_node_nullify(&row->txn_node);
3206 if (!row->old_datum) {
3207 hmap_remove(&row->table->rows, &row->hmap_node);
3208 free(row);
3209 }
3210 }
3211 hmap_destroy(&txn->txn_rows);
3212 hmap_init(&txn->txn_rows);
3213 }
3214
3215 static bool
3216 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *row,
3217 struct json *mutations)
3218 {
3219 const struct ovsdb_idl_table_class *class = row->table->class_;
3220 size_t idx;
3221 bool any_mutations = false;
3222
3223 if (row->map_op_written) {
3224 BITMAP_FOR_EACH_1(idx, class->n_columns, row->map_op_written) {
3225 struct map_op_list *map_op_list;
3226 const struct ovsdb_idl_column *column;
3227 const struct ovsdb_datum *old_datum;
3228 enum ovsdb_atomic_type key_type, value_type;
3229 struct json *mutation, *map, *col_name, *mutator;
3230 struct json *del_set, *ins_map;
3231 bool any_del, any_ins;
3232
3233 map_op_list = row->map_op_lists[idx];
3234 column = &class->columns[idx];
3235 key_type = column->type.key.type;
3236 value_type = column->type.value.type;
3237
3238 /* Get the value to be changed */
3239 if (row->new_datum && row->written
3240 && bitmap_is_set(row->written,idx)) {
3241 old_datum = &row->new_datum[idx];
3242 } else if (row->old_datum != NULL) {
3243 old_datum = &row->old_datum[idx];
3244 } else {
3245 old_datum = ovsdb_datum_default(&column->type);
3246 }
3247
3248 del_set = json_array_create_empty();
3249 ins_map = json_array_create_empty();
3250 any_del = false;
3251 any_ins = false;
3252
3253 for (struct map_op *map_op = map_op_list_first(map_op_list); map_op;
3254 map_op = map_op_list_next(map_op_list, map_op)) {
3255
3256 if (map_op_type(map_op) == MAP_OP_UPDATE) {
3257 /* Find out if value really changed. */
3258 struct ovsdb_datum *new_datum;
3259 unsigned int pos;
3260 new_datum = map_op_datum(map_op);
3261 pos = ovsdb_datum_find_key(old_datum,
3262 &new_datum->keys[0],
3263 key_type);
3264 if (ovsdb_atom_equals(&new_datum->values[0],
3265 &old_datum->values[pos],
3266 value_type)) {
3267 /* No change in value. Move on to next update. */
3268 continue;
3269 }
3270 } else if (map_op_type(map_op) == MAP_OP_DELETE){
3271 /* Verify that there is a key to delete. */
3272 unsigned int pos;
3273 pos = ovsdb_datum_find_key(old_datum,
3274 &map_op_datum(map_op)->keys[0],
3275 key_type);
3276 if (pos == UINT_MAX) {
3277 /* No key to delete. Move on to next update. */
3278 VLOG_WARN("Trying to delete a key that doesn't "
3279 "exist in the map.");
3280 continue;
3281 }
3282 }
3283
3284 if (map_op_type(map_op) == MAP_OP_INSERT) {
3285 map = json_array_create_2(
3286 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3287 key_type),
3288 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
3289 value_type));
3290 json_array_add(ins_map, map);
3291 any_ins = true;
3292 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
3293 map = ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3294 key_type);
3295 json_array_add(del_set, map);
3296 any_del = true;
3297 }
3298
3299 /* Generate an additional insert mutate for updates. */
3300 if (map_op_type(map_op) == MAP_OP_UPDATE) {
3301 map = json_array_create_2(
3302 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
3303 key_type),
3304 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
3305 value_type));
3306 json_array_add(ins_map, map);
3307 any_ins = true;
3308 }
3309 }
3310
3311 if (any_del) {
3312 col_name = json_string_create(column->name);
3313 mutator = json_string_create("delete");
3314 map = json_array_create_2(json_string_create("set"), del_set);
3315 mutation = json_array_create_3(col_name, mutator, map);
3316 json_array_add(mutations, mutation);
3317 any_mutations = true;
3318 } else {
3319 json_destroy(del_set);
3320 }
3321 if (any_ins) {
3322 col_name = json_string_create(column->name);
3323 mutator = json_string_create("insert");
3324 map = json_array_create_2(json_string_create("map"), ins_map);
3325 mutation = json_array_create_3(col_name, mutator, map);
3326 json_array_add(mutations, mutation);
3327 any_mutations = true;
3328 } else {
3329 json_destroy(ins_map);
3330 }
3331 }
3332 }
3333 if (row->set_op_written) {
3334 BITMAP_FOR_EACH_1(idx, class->n_columns, row->set_op_written) {
3335 struct set_op_list *set_op_list;
3336 const struct ovsdb_idl_column *column;
3337 const struct ovsdb_datum *old_datum;
3338 enum ovsdb_atomic_type key_type;
3339 struct json *mutation, *set, *col_name, *mutator;
3340 struct json *del_set, *ins_set;
3341 bool any_del, any_ins;
3342
3343 set_op_list = row->set_op_lists[idx];
3344 column = &class->columns[idx];
3345 key_type = column->type.key.type;
3346
3347 /* Get the value to be changed */
3348 if (row->new_datum && row->written
3349 && bitmap_is_set(row->written,idx)) {
3350 old_datum = &row->new_datum[idx];
3351 } else if (row->old_datum != NULL) {
3352 old_datum = &row->old_datum[idx];
3353 } else {
3354 old_datum = ovsdb_datum_default(&column->type);
3355 }
3356
3357 del_set = json_array_create_empty();
3358 ins_set = json_array_create_empty();
3359 any_del = false;
3360 any_ins = false;
3361
3362 for (struct set_op *set_op = set_op_list_first(set_op_list); set_op;
3363 set_op = set_op_list_next(set_op_list, set_op)) {
3364 if (set_op_type(set_op) == SET_OP_INSERT) {
3365 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
3366 key_type);
3367 json_array_add(ins_set, set);
3368 any_ins = true;
3369 } else { /* SETP_OP_DELETE */
3370 /* Verify that there is a key to delete. */
3371 unsigned int pos;
3372 pos = ovsdb_datum_find_key(old_datum,
3373 &set_op_datum(set_op)->keys[0],
3374 key_type);
3375 if (pos == UINT_MAX) {
3376 /* No key to delete. Move on to next update. */
3377 VLOG_WARN("Trying to delete a key that doesn't "
3378 "exist in the set.");
3379 continue;
3380 }
3381 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
3382 key_type);
3383 json_array_add(del_set, set);
3384 any_del = true;
3385 }
3386 }
3387 if (any_del) {
3388 col_name = json_string_create(column->name);
3389 mutator = json_string_create("delete");
3390 set = json_array_create_2(json_string_create("set"), del_set);
3391 mutation = json_array_create_3(col_name, mutator, set);
3392 json_array_add(mutations, mutation);
3393 any_mutations = true;
3394 } else {
3395 json_destroy(del_set);
3396 }
3397 if (any_ins) {
3398 col_name = json_string_create(column->name);
3399 mutator = json_string_create("insert");
3400 set = json_array_create_2(json_string_create("set"), ins_set);
3401 mutation = json_array_create_3(col_name, mutator, set);
3402 json_array_add(mutations, mutation);
3403 any_mutations = true;
3404 } else {
3405 json_destroy(ins_set);
3406 }
3407 }
3408 }
3409 return any_mutations;
3410 }
3411
3412 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
3413 * of the following TXN_* constants:
3414 *
3415 * TXN_INCOMPLETE:
3416 *
3417 * The transaction is in progress, but not yet complete. The caller
3418 * should call again later, after calling ovsdb_idl_run() to let the IDL
3419 * do OVSDB protocol processing.
3420 *
3421 * TXN_UNCHANGED:
3422 *
3423 * The transaction is complete. (It didn't actually change the database,
3424 * so the IDL didn't send any request to the database server.)
3425 *
3426 * TXN_ABORTED:
3427 *
3428 * The caller previously called ovsdb_idl_txn_abort().
3429 *
3430 * TXN_SUCCESS:
3431 *
3432 * The transaction was successful. The update made by the transaction
3433 * (and possibly other changes made by other database clients) should
3434 * already be visible in the IDL.
3435 *
3436 * TXN_TRY_AGAIN:
3437 *
3438 * The transaction failed for some transient reason, e.g. because a
3439 * "verify" operation reported an inconsistency or due to a network
3440 * problem. The caller should wait for a change to the database, then
3441 * compose a new transaction, and commit the new transaction.
3442 *
3443 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
3444 * the database. It is important to use its return value *before* the
3445 * initial call to ovsdb_idl_txn_commit() as the baseline for this
3446 * purpose, because the change that one should wait for can happen after
3447 * the initial call but before the call that returns TXN_TRY_AGAIN, and
3448 * using some other baseline value in that situation could cause an
3449 * indefinite wait if the database rarely changes.
3450 *
3451 * TXN_NOT_LOCKED:
3452 *
3453 * The transaction failed because the IDL has been configured to require
3454 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
3455 * has already lost it.
3456 *
3457 * Committing a transaction rolls back all of the changes that it made to the
3458 * IDL's copy of the database. If the transaction commits successfully, then
3459 * the database server will send an update and, thus, the IDL will be updated
3460 * with the committed changes. */
3461 enum ovsdb_idl_txn_status
3462 ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
3463 {
3464 struct ovsdb_idl_row *row;
3465 struct json *operations;
3466 bool any_updates;
3467
3468 if (txn != txn->idl->txn) {
3469 goto coverage_out;
3470 }
3471
3472 /* If we need a lock but don't have it, give up quickly. */
3473 if (txn->idl->lock_name && !ovsdb_idl_has_lock(txn->idl)) {
3474 txn->status = TXN_NOT_LOCKED;
3475 goto disassemble_out;
3476 }
3477
3478 operations = json_array_create_1(
3479 json_string_create(txn->idl->class_->database));
3480
3481 /* Assert that we have the required lock (avoiding a race). */
3482 if (txn->idl->lock_name) {
3483 struct json *op = json_object_create();
3484 json_array_add(operations, op);
3485 json_object_put_string(op, "op", "assert");
3486 json_object_put_string(op, "lock", txn->idl->lock_name);
3487 }
3488
3489 /* Add prerequisites and declarations of new rows. */
3490 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
3491 /* XXX check that deleted rows exist even if no prereqs? */
3492 if (row->prereqs) {
3493 const struct ovsdb_idl_table_class *class = row->table->class_;
3494 size_t n_columns = class->n_columns;
3495 struct json *op, *columns, *row_json;
3496 size_t idx;
3497
3498 op = json_object_create();
3499 json_array_add(operations, op);
3500 json_object_put_string(op, "op", "wait");
3501 json_object_put_string(op, "table", class->name);
3502 json_object_put(op, "timeout", json_integer_create(0));
3503 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3504 json_object_put_string(op, "until", "==");
3505 columns = json_array_create_empty();
3506 json_object_put(op, "columns", columns);
3507 row_json = json_object_create();
3508 json_object_put(op, "rows", json_array_create_1(row_json));
3509
3510 BITMAP_FOR_EACH_1 (idx, n_columns, row->prereqs) {
3511 const struct ovsdb_idl_column *column = &class->columns[idx];
3512 json_array_add(columns, json_string_create(column->name));
3513 json_object_put(row_json, column->name,
3514 ovsdb_datum_to_json(&row->old_datum[idx],
3515 &column->type));
3516 }
3517 }
3518 }
3519
3520 /* Add updates. */
3521 any_updates = false;
3522 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
3523 const struct ovsdb_idl_table_class *class = row->table->class_;
3524
3525 if (!row->new_datum) {
3526 if (class->is_root) {
3527 struct json *op = json_object_create();
3528 json_object_put_string(op, "op", "delete");
3529 json_object_put_string(op, "table", class->name);
3530 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3531 json_array_add(operations, op);
3532 any_updates = true;
3533 } else {
3534 /* Let ovsdb-server decide whether to really delete it. */
3535 }
3536 } else if (row->old_datum != row->new_datum) {
3537 struct json *row_json;
3538 size_t idx;
3539
3540 if (!row->old_datum && class->is_singleton) {
3541 /* We're inserting a row into a table that allows only a
3542 * single row. (This is a fairly common OVSDB pattern for
3543 * storing global data.) Verify that the table is empty
3544 * before inserting the row, so that we get a clear
3545 * verification-related failure if there was an insertion
3546 * race with another client. */
3547 struct json *op = json_object_create();
3548 json_array_add(operations, op);
3549 json_object_put_string(op, "op", "wait");
3550 json_object_put_string(op, "table", class->name);
3551 json_object_put(op, "where", json_array_create_empty());
3552 json_object_put(op, "timeout", json_integer_create(0));
3553 json_object_put_string(op, "until", "==");
3554 json_object_put(op, "rows", json_array_create_empty());
3555 }
3556
3557 struct json *op = json_object_create();
3558 json_object_put_string(op, "op",
3559 row->old_datum ? "update" : "insert");
3560 json_object_put_string(op, "table", class->name);
3561 if (row->old_datum) {
3562 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3563 } else {
3564 struct ovsdb_idl_txn_insert *insert;
3565
3566 any_updates = true;
3567
3568 json_object_put(op, "uuid-name",
3569 json_string_create_nocopy(
3570 uuid_name_from_uuid(&row->uuid)));
3571
3572 insert = xmalloc(sizeof *insert);
3573 insert->dummy = row->uuid;
3574 insert->op_index = operations->u.array.n - 1;
3575 uuid_zero(&insert->real);
3576 hmap_insert(&txn->inserted_rows, &insert->hmap_node,
3577 uuid_hash(&insert->dummy));
3578 }
3579 row_json = json_object_create();
3580 json_object_put(op, "row", row_json);
3581
3582 if (row->written) {
3583 BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
3584 const struct ovsdb_idl_column *column =
3585 &class->columns[idx];
3586
3587 if (row->old_datum
3588 || !ovsdb_datum_is_default(&row->new_datum[idx],
3589 &column->type)) {
3590 struct json *value;
3591
3592 value = ovsdb_datum_to_json(&row->new_datum[idx],
3593 &column->type);
3594 json_object_put(row_json, column->name,
3595 substitute_uuids(value, txn));
3596
3597 /* If anything really changed, consider it an update.
3598 * We can't suppress not-really-changed values earlier
3599 * or transactions would become nonatomic (see the big
3600 * comment inside ovsdb_idl_txn_write()). */
3601 if (!any_updates && row->old_datum &&
3602 !ovsdb_datum_equals(&row->old_datum[idx],
3603 &row->new_datum[idx],
3604 &column->type)) {
3605 any_updates = true;
3606 }
3607 }
3608 }
3609 }
3610
3611 if (!row->old_datum || !shash_is_empty(json_object(row_json))) {
3612 json_array_add(operations, op);
3613 } else {
3614 json_destroy(op);
3615 }
3616 }
3617
3618 /* Add mutate operation, for partial map or partial set updates. */
3619 if (row->map_op_written || row->set_op_written) {
3620 struct json *op, *mutations;
3621 bool any_mutations;
3622
3623 op = json_object_create();
3624 json_object_put_string(op, "op", "mutate");
3625 json_object_put_string(op, "table", class->name);
3626 json_object_put(op, "where", where_uuid_equals(&row->uuid));
3627 mutations = json_array_create_empty();
3628 any_mutations = ovsdb_idl_txn_extract_mutations(row, mutations);
3629 json_object_put(op, "mutations", mutations);
3630
3631 if (any_mutations) {
3632 op = substitute_uuids(op, txn);
3633 json_array_add(operations, op);
3634 any_updates = true;
3635 } else {
3636 json_destroy(op);
3637 }
3638 }
3639 }
3640
3641 /* Add increment. */
3642 if (txn->inc_table && (any_updates || txn->inc_force)) {
3643 any_updates = true;
3644 txn->inc_index = operations->u.array.n - 1;
3645
3646 struct json *op = json_object_create();
3647 json_object_put_string(op, "op", "mutate");
3648 json_object_put_string(op, "table", txn->inc_table);
3649 json_object_put(op, "where",
3650 substitute_uuids(where_uuid_equals(&txn->inc_row),
3651 txn));
3652 json_object_put(op, "mutations",
3653 json_array_create_1(
3654 json_array_create_3(
3655 json_string_create(txn->inc_column),
3656 json_string_create("+="),
3657 json_integer_create(1))));
3658 json_array_add(operations, op);
3659
3660 op = json_object_create();
3661 json_object_put_string(op, "op", "select");
3662 json_object_put_string(op, "table", txn->inc_table);
3663 json_object_put(op, "where",
3664 substitute_uuids(where_uuid_equals(&txn->inc_row),
3665 txn));
3666 json_object_put(op, "columns",
3667 json_array_create_1(json_string_create(
3668 txn->inc_column)));
3669 json_array_add(operations, op);
3670 }
3671
3672 if (txn->comment.length) {
3673 struct json *op = json_object_create();
3674 json_object_put_string(op, "op", "comment");
3675 json_object_put_string(op, "comment", ds_cstr(&txn->comment));
3676 json_array_add(operations, op);
3677 }
3678
3679 if (txn->dry_run) {
3680 struct json *op = json_object_create();
3681 json_object_put_string(op, "op", "abort");
3682 json_array_add(operations, op);
3683 }
3684
3685 if (!any_updates) {
3686 txn->status = TXN_UNCHANGED;
3687 json_destroy(operations);
3688 } else if (!jsonrpc_session_send(
3689 txn->idl->session,
3690 jsonrpc_create_request(
3691 "transact", operations, &txn->request_id))) {
3692 hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
3693 json_hash(txn->request_id, 0));
3694 txn->status = TXN_INCOMPLETE;
3695 } else {
3696 txn->status = TXN_TRY_AGAIN;
3697 }
3698
3699 disassemble_out:
3700 ovsdb_idl_txn_disassemble(txn);
3701 coverage_out:
3702 switch (txn->status) {
3703 case TXN_UNCOMMITTED: COVERAGE_INC(txn_uncommitted); break;
3704 case TXN_UNCHANGED: COVERAGE_INC(txn_unchanged); break;
3705 case TXN_INCOMPLETE: COVERAGE_INC(txn_incomplete); break;
3706 case TXN_ABORTED: COVERAGE_INC(txn_aborted); break;
3707 case TXN_SUCCESS: COVERAGE_INC(txn_success); break;
3708 case TXN_TRY_AGAIN: COVERAGE_INC(txn_try_again); break;
3709 case TXN_NOT_LOCKED: COVERAGE_INC(txn_not_locked); break;
3710 case TXN_ERROR: COVERAGE_INC(txn_error); break;
3711 }
3712
3713 return txn->status;
3714 }
3715
3716 /* Attempts to commit 'txn', blocking until the commit either succeeds or
3717 * fails. Returns the final commit status, which may be any TXN_* value other
3718 * than TXN_INCOMPLETE.
3719 *
3720 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
3721 * return value of ovsdb_idl_get_seqno() to change. */
3722 enum ovsdb_idl_txn_status
3723 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
3724 {
3725 enum ovsdb_idl_txn_status status;
3726
3727 fatal_signal_run();
3728 while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
3729 ovsdb_idl_run(txn->idl);
3730 ovsdb_idl_wait(txn->idl);
3731 ovsdb_idl_txn_wait(txn);
3732 poll_block();
3733 }
3734 return status;
3735 }
3736
3737 /* Returns the final (incremented) value of the column in 'txn' that was set to
3738 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
3739 * successfully. */
3740 int64_t
3741 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
3742 {
3743 ovs_assert(txn->status == TXN_SUCCESS);
3744 return txn->inc_new_value;
3745 }
3746
3747 /* Aborts 'txn' without sending it to the database server. This is effective
3748 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
3749 * Otherwise, it has no effect.
3750 *
3751 * Aborting a transaction doesn't free its memory. Use
3752 * ovsdb_idl_txn_destroy() to do that. */
3753 void
3754 ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
3755 {
3756 ovsdb_idl_txn_disassemble(txn);
3757 if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
3758 txn->status = TXN_ABORTED;
3759 }
3760 }
3761
3762 /* Returns a string that reports the error status for 'txn'. The caller must
3763 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
3764 * for 'txn' may free the returned string.
3765 *
3766 * The return value is ordinarily one of the strings that
3767 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
3768 * due to an error reported by the database server, the return value is that
3769 * error. */
3770 const char *
3771 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
3772 {
3773 if (txn->status != TXN_ERROR) {
3774 return ovsdb_idl_txn_status_to_string(txn->status);
3775 } else if (txn->error) {
3776 return txn->error;
3777 } else {
3778 return "no error details available";
3779 }
3780 }
3781
3782 static void
3783 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
3784 const struct json *json)
3785 {
3786 if (txn->error == NULL) {
3787 txn->error = json_to_string(json, JSSF_SORT);
3788 }
3789 }
3790
3791 /* For transaction 'txn' that completed successfully, finds and returns the
3792 * permanent UUID that the database assigned to a newly inserted row, given the
3793 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
3794 *
3795 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
3796 * if it was assigned by that function and then deleted by
3797 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
3798 * and then deleted within a single transaction are never sent to the database
3799 * server, so it never assigns them a permanent UUID.) */
3800 const struct uuid *
3801 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *txn,
3802 const struct uuid *uuid)
3803 {
3804 const struct ovsdb_idl_txn_insert *insert;
3805
3806 ovs_assert(txn->status == TXN_SUCCESS || txn->status == TXN_UNCHANGED);
3807 HMAP_FOR_EACH_IN_BUCKET (insert, hmap_node,
3808 uuid_hash(uuid), &txn->inserted_rows) {
3809 if (uuid_equals(uuid, &insert->dummy)) {
3810 return &insert->real;
3811 }
3812 }
3813 return NULL;
3814 }
3815
3816 static void
3817 ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
3818 enum ovsdb_idl_txn_status status)
3819 {
3820 txn->status = status;
3821 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
3822 }
3823
3824 static void
3825 ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
3826 const struct ovsdb_idl_column *column,
3827 struct ovsdb_datum *datum, bool owns_datum)
3828 {
3829 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
3830 const struct ovsdb_idl_table_class *class;
3831 size_t column_idx;
3832 bool write_only;
3833
3834 if (ovsdb_idl_row_is_synthetic(row)) {
3835 goto discard_datum;
3836 }
3837
3838 class = row->table->class_;
3839 column_idx = column - class->columns;
3840 write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
3841
3842 ovs_assert(row->new_datum != NULL);
3843 ovs_assert(column_idx < class->n_columns);
3844 ovs_assert(row->old_datum == NULL ||
3845 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
3846
3847 if (row->table->idl->verify_write_only && !write_only) {
3848 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
3849 " explicitly configured not to.", class->name, column->name);
3850 goto discard_datum;
3851 }
3852
3853 /* If this is a write-only column and the datum being written is the same
3854 * as the one already there, just skip the update entirely. This is worth
3855 * optimizing because we have a lot of columns that get periodically
3856 * refreshed into the database but don't actually change that often.
3857 *
3858 * We don't do this for read/write columns because that would break
3859 * atomicity of transactions--some other client might have written a
3860 * different value in that column since we read it. (But if a whole
3861 * transaction only does writes of existing values, without making any real
3862 * changes, we will drop the whole transaction later in
3863 * ovsdb_idl_txn_commit().) */
3864 if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
3865 datum, &column->type)) {
3866 goto discard_datum;
3867 }
3868
3869 if (hmap_node_is_null(&row->txn_node)) {
3870 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
3871 uuid_hash(&row->uuid));
3872 }
3873 if (row->old_datum == row->new_datum) {
3874 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
3875 }
3876 if (!row->written) {
3877 row->written = bitmap_allocate(class->n_columns);
3878 }
3879 if (bitmap_is_set(row->written, column_idx)) {
3880 ovsdb_datum_destroy(&row->new_datum[column_idx], &column->type);
3881 } else {
3882 bitmap_set1(row->written, column_idx);
3883 }
3884 if (owns_datum) {
3885 row->new_datum[column_idx] = *datum;
3886 } else {
3887 ovsdb_datum_clone(&row->new_datum[column_idx], datum, &column->type);
3888 }
3889 (column->unparse)(row);
3890 (column->parse)(row, &row->new_datum[column_idx]);
3891 return;
3892
3893 discard_datum:
3894 if (owns_datum) {
3895 ovsdb_datum_destroy(datum, &column->type);
3896 }
3897 }
3898
3899 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
3900 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
3901 * ovs-vswitchd).
3902 *
3903 * 'datum' must have the correct type for its column, but it needs not be
3904 * sorted or unique because this function will take care of that. The IDL does
3905 * not check that it meets schema constraints, but ovsdb-server will do so at
3906 * commit time so it had better be correct.
3907 *
3908 * A transaction must be in progress. Replication of 'column' must not have
3909 * been disabled (by calling ovsdb_idl_omit()).
3910 *
3911 * Usually this function is used indirectly through one of the "set" functions
3912 * generated by ovsdb-idlc.
3913 *
3914 * Takes ownership of what 'datum' points to (and in some cases destroys that
3915 * data before returning) but makes a copy of 'datum' itself. (Commonly
3916 * 'datum' is on the caller's stack.) */
3917 void
3918 ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
3919 const struct ovsdb_idl_column *column,
3920 struct ovsdb_datum *datum)
3921 {
3922 ovsdb_datum_sort_unique(datum,
3923 column->type.key.type, column->type.value.type);
3924 ovsdb_idl_txn_write__(row, column, datum, true);
3925 }
3926
3927 /* Similar to ovsdb_idl_txn_write(), except:
3928 *
3929 * - The caller retains ownership of 'datum' and what it points to.
3930 *
3931 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
3932 * ovsdb_datum_sort_unique().) */
3933 void
3934 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
3935 const struct ovsdb_idl_column *column,
3936 const struct ovsdb_datum *datum)
3937 {
3938 ovsdb_idl_txn_write__(row, column,
3939 CONST_CAST(struct ovsdb_datum *, datum), false);
3940 }
3941
3942 /* Causes the original contents of 'column' in 'row_' to be verified as a
3943 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
3944 * changed (or if 'row_' was deleted) between the time that the IDL originally
3945 * read its contents and the time that the transaction commits, then the
3946 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
3947 *
3948 * The intention is that, to ensure that no transaction commits based on dirty
3949 * reads, an application should call ovsdb_idl_txn_verify() on each data item
3950 * read as part of a read-modify-write operation.
3951 *
3952 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
3953 * value of 'column' is already known:
3954 *
3955 * - If 'row_' is a row created by the current transaction (returned by
3956 * ovsdb_idl_txn_insert()).
3957 *
3958 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
3959 * within the current transaction.
3960 *
3961 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
3962 * ovsdb_idl_txn_write() for a given read-modify-write.
3963 *
3964 * A transaction must be in progress.
3965 *
3966 * Usually this function is used indirectly through one of the "verify"
3967 * functions generated by ovsdb-idlc. */
3968 void
3969 ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
3970 const struct ovsdb_idl_column *column)
3971 {
3972 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
3973 const struct ovsdb_idl_table_class *class;
3974 size_t column_idx;
3975
3976 if (ovsdb_idl_row_is_synthetic(row)) {
3977 return;
3978 }
3979
3980 class = row->table->class_;
3981 column_idx = column - class->columns;
3982
3983 ovs_assert(row->new_datum != NULL);
3984 ovs_assert(row->old_datum == NULL ||
3985 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
3986 if (!row->old_datum
3987 || (row->written && bitmap_is_set(row->written, column_idx))) {
3988 return;
3989 }
3990
3991 if (hmap_node_is_null(&row->txn_node)) {
3992 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
3993 uuid_hash(&row->uuid));
3994 }
3995 if (!row->prereqs) {
3996 row->prereqs = bitmap_allocate(class->n_columns);
3997 }
3998 bitmap_set1(row->prereqs, column_idx);
3999 }
4000
4001 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4002 * accessed afterward.
4003 *
4004 * A transaction must be in progress.
4005 *
4006 * Usually this function is used indirectly through one of the "delete"
4007 * functions generated by ovsdb-idlc. */
4008 void
4009 ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
4010 {
4011 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4012
4013 if (ovsdb_idl_row_is_synthetic(row)) {
4014 return;
4015 }
4016
4017 ovs_assert(row->new_datum != NULL);
4018 if (!row->old_datum) {
4019 ovsdb_idl_row_unparse(row);
4020 ovsdb_idl_row_clear_new(row);
4021 ovs_assert(!row->prereqs);
4022 hmap_remove(&row->table->rows, &row->hmap_node);
4023 hmap_remove(&row->table->idl->txn->txn_rows, &row->txn_node);
4024 free(row);
4025 return;
4026 }
4027 if (hmap_node_is_null(&row->txn_node)) {
4028 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4029 uuid_hash(&row->uuid));
4030 }
4031 ovsdb_idl_row_clear_new(row);
4032 row->new_datum = NULL;
4033 }
4034
4035 /* Inserts and returns a new row in the table with the specified 'class' in the
4036 * database with open transaction 'txn'.
4037 *
4038 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4039 * randomly generated; otherwise 'uuid' should specify a randomly generated
4040 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4041 * 'txn' is committed, but the IDL will replace any uses of the provisional
4042 * UUID in the data to be to be committed by the UUID assigned by
4043 * ovsdb-server.
4044 *
4045 * Usually this function is used indirectly through one of the "insert"
4046 * functions generated by ovsdb-idlc. */
4047 const struct ovsdb_idl_row *
4048 ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
4049 const struct ovsdb_idl_table_class *class,
4050 const struct uuid *uuid)
4051 {
4052 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);
4053
4054 if (uuid) {
4055 ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
4056 row->uuid = *uuid;
4057 } else {
4058 uuid_generate(&row->uuid);
4059 }
4060
4061 row->table = ovsdb_idl_table_from_class(txn->idl, class);
4062 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
4063 hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
4064 hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
4065 return row;
4066 }
4067
4068 static void
4069 ovsdb_idl_txn_abort_all(struct ovsdb_idl *idl)
4070 {
4071 struct ovsdb_idl_txn *txn;
4072
4073 HMAP_FOR_EACH (txn, hmap_node, &idl->outstanding_txns) {
4074 ovsdb_idl_txn_complete(txn, TXN_TRY_AGAIN);
4075 }
4076 }
4077
4078 static struct ovsdb_idl_txn *
4079 ovsdb_idl_txn_find(struct ovsdb_idl *idl, const struct json *id)
4080 {
4081 struct ovsdb_idl_txn *txn;
4082
4083 HMAP_FOR_EACH_WITH_HASH (txn, hmap_node,
4084 json_hash(id, 0), &idl->outstanding_txns) {
4085 if (json_equal(id, txn->request_id)) {
4086 return txn;
4087 }
4088 }
4089 return NULL;
4090 }
4091
4092 static bool
4093 check_json_type(const struct json *json, enum json_type type, const char *name)
4094 {
4095 if (!json) {
4096 VLOG_WARN_RL(&syntax_rl, "%s is missing", name);
4097 return false;
4098 } else if (json->type != type) {
4099 VLOG_WARN_RL(&syntax_rl, "%s is %s instead of %s",
4100 name, json_type_to_string(json->type),
4101 json_type_to_string(type));
4102 return false;
4103 } else {
4104 return true;
4105 }
4106 }
4107
4108 static bool
4109 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
4110 const struct json_array *results)
4111 {
4112 struct json *count, *rows, *row, *column;
4113 struct shash *mutate, *select;
4114
4115 if (txn->inc_index + 2 > results->n) {
4116 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4117 "for increment (has %"PRIuSIZE", needs %u)",
4118 results->n, txn->inc_index + 2);
4119 return false;
4120 }
4121
4122 /* We know that this is a JSON object because the loop in
4123 * ovsdb_idl_txn_process_reply() checked. */
4124 mutate = json_object(results->elems[txn->inc_index]);
4125 count = shash_find_data(mutate, "count");
4126 if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) {
4127 return false;
4128 }
4129 if (count->u.integer != 1) {
4130 VLOG_WARN_RL(&syntax_rl,
4131 "\"mutate\" reply \"count\" is %lld instead of 1",
4132 count->u.integer);
4133 return false;
4134 }
4135
4136 select = json_object(results->elems[txn->inc_index + 1]);
4137 rows = shash_find_data(select, "rows");
4138 if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) {
4139 return false;
4140 }
4141 if (rows->u.array.n != 1) {
4142 VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
4143 "instead of 1",
4144 rows->u.array.n);
4145 return false;
4146 }
4147 row = rows->u.array.elems[0];
4148 if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) {
4149 return false;
4150 }
4151 column = shash_find_data(json_object(row), txn->inc_column);
4152 if (!check_json_type(column, JSON_INTEGER,
4153 "\"select\" reply inc column")) {
4154 return false;
4155 }
4156 txn->inc_new_value = column->u.integer;
4157 return true;
4158 }
4159
4160 static bool
4161 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
4162 const struct json_array *results)
4163 {
4164 static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT;
4165 struct ovsdb_error *error;
4166 struct json *json_uuid;
4167 union ovsdb_atom uuid;
4168 struct shash *reply;
4169
4170 if (insert->op_index >= results->n) {
4171 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4172 "for insert (has %"PRIuSIZE", needs %u)",
4173 results->n, insert->op_index);
4174 return false;
4175 }
4176
4177 /* We know that this is a JSON object because the loop in
4178 * ovsdb_idl_txn_process_reply() checked. */
4179 reply = json_object(results->elems[insert->op_index]);
4180 json_uuid = shash_find_data(reply, "uuid");
4181 if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) {
4182 return false;
4183 }
4184
4185 error = ovsdb_atom_from_json(&uuid, &uuid_type, json_uuid, NULL);
4186 if (error) {
4187 char *s = ovsdb_error_to_string_free(error);
4188 VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
4189 "UUID: %s", s);
4190 free(s);
4191 return false;
4192 }
4193
4194 insert->real = uuid.uuid;
4195
4196 return true;
4197 }
4198
4199 static bool
4200 ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
4201 const struct jsonrpc_msg *msg)
4202 {
4203 struct ovsdb_idl_txn *txn;
4204 enum ovsdb_idl_txn_status status;
4205
4206 txn = ovsdb_idl_txn_find(idl, msg->id);
4207 if (!txn) {
4208 return false;
4209 }
4210
4211 if (msg->type == JSONRPC_ERROR) {
4212 status = TXN_ERROR;
4213 } else if (msg->result->type != JSON_ARRAY) {
4214 VLOG_WARN_RL(&syntax_rl, "reply to \"transact\" is not JSON array");
4215 status = TXN_ERROR;
4216 } else {
4217 struct json_array *ops = &msg->result->u.array;
4218 int hard_errors = 0;
4219 int soft_errors = 0;
4220 int lock_errors = 0;
4221 size_t i;
4222
4223 for (i = 0; i < ops->n; i++) {
4224 struct json *op = ops->elems[i];
4225
4226 if (op->type == JSON_NULL) {
4227 /* This isn't an error in itself but indicates that some prior
4228 * operation failed, so make sure that we know about it. */
4229 soft_errors++;
4230 } else if (op->type == JSON_OBJECT) {
4231 struct json *error;
4232
4233 error = shash_find_data(json_object(op), "error");
4234 if (error) {
4235 if (error->type == JSON_STRING) {
4236 if (!strcmp(error->u.string, "timed out")) {
4237 soft_errors++;
4238 } else if (!strcmp(error->u.string, "not owner")) {
4239 lock_errors++;
4240 } else if (!strcmp(error->u.string, "not allowed")) {
4241 hard_errors++;
4242 ovsdb_idl_txn_set_error_json(txn, op);
4243 } else if (strcmp(error->u.string, "aborted")) {
4244 hard_errors++;
4245 ovsdb_idl_txn_set_error_json(txn, op);
4246 VLOG_WARN_RL(&other_rl,
4247 "transaction error: %s", txn->error);
4248 }
4249 } else {
4250 hard_errors++;
4251 ovsdb_idl_txn_set_error_json(txn, op);
4252 VLOG_WARN_RL(&syntax_rl,
4253 "\"error\" in reply is not JSON string");
4254 }
4255 }
4256 } else {
4257 hard_errors++;
4258 ovsdb_idl_txn_set_error_json(txn, op);
4259 VLOG_WARN_RL(&syntax_rl,
4260 "operation reply is not JSON null or object");
4261 }
4262 }
4263
4264 if (!soft_errors && !hard_errors && !lock_errors) {
4265 struct ovsdb_idl_txn_insert *insert;
4266
4267 if (txn->inc_table && !ovsdb_idl_txn_process_inc_reply(txn, ops)) {
4268 hard_errors++;
4269 }
4270
4271 HMAP_FOR_EACH (insert, hmap_node, &txn->inserted_rows) {
4272 if (!ovsdb_idl_txn_process_insert_reply(insert, ops)) {
4273 hard_errors++;
4274 }
4275 }
4276 }
4277
4278 status = (hard_errors ? TXN_ERROR
4279 : lock_errors ? TXN_NOT_LOCKED
4280 : soft_errors ? TXN_TRY_AGAIN
4281 : TXN_SUCCESS);
4282 }
4283
4284 ovsdb_idl_txn_complete(txn, status);
4285 return true;
4286 }
4287
4288 /* Returns the transaction currently active for 'row''s IDL. A transaction
4289 * must currently be active. */
4290 struct ovsdb_idl_txn *
4291 ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
4292 {
4293 struct ovsdb_idl_txn *txn = row->table->idl->txn;
4294 ovs_assert(txn != NULL);
4295 return txn;
4296 }
4297
4298 /* Returns the IDL on which 'txn' acts. */
4299 struct ovsdb_idl *
4300 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
4301 {
4302 return txn->idl;
4303 }
4304
4305 /* Blocks until 'idl' successfully connects to the remote database and
4306 * retrieves its contents. */
4307 void
4308 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *idl)
4309 {
4310 while (1) {
4311 ovsdb_idl_run(idl);
4312 if (ovsdb_idl_has_ever_connected(idl)) {
4313 return;
4314 }
4315 ovsdb_idl_wait(idl);
4316 poll_block();
4317 }
4318 }
4319 \f
4320 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
4321 * the database server and to avoid modifying the database when the lock cannot
4322 * be acquired (that is, when another client has the same lock).
4323 *
4324 * If 'lock_name' is NULL, drops the locking requirement and releases the
4325 * lock. */
4326 void
4327 ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
4328 {
4329 ovs_assert(!idl->txn);
4330 ovs_assert(hmap_is_empty(&idl->outstanding_txns));
4331
4332 if (idl->lock_name && (!lock_name || strcmp(lock_name, idl->lock_name))) {
4333 /* Release previous lock. */
4334 ovsdb_idl_send_unlock_request(idl);
4335 free(idl->lock_name);
4336 idl->lock_name = NULL;
4337 idl->is_lock_contended = false;
4338 }
4339
4340 if (lock_name && !idl->lock_name) {
4341 /* Acquire new lock. */
4342 idl->lock_name = xstrdup(lock_name);
4343 ovsdb_idl_send_lock_request(idl);
4344 }
4345 }
4346
4347 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
4348 *
4349 * Locking and unlocking happens asynchronously from the database client's
4350 * point of view, so the information is only useful for optimization (e.g. if
4351 * the client doesn't have the lock then there's no point in trying to write to
4352 * the database). */
4353 bool
4354 ovsdb_idl_has_lock(const struct ovsdb_idl *idl)
4355 {
4356 return idl->has_lock;
4357 }
4358
4359 /* Returns true if 'idl' is configured to obtain a lock but the database server
4360 * has indicated that some other client already owns the requested lock. */
4361 bool
4362 ovsdb_idl_is_lock_contended(const struct ovsdb_idl *idl)
4363 {
4364 return idl->is_lock_contended;
4365 }
4366
4367 static void
4368 ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock)
4369 {
4370 if (new_has_lock && !idl->has_lock) {
4371 if (idl->state == IDL_S_MONITORING ||
4372 idl->state == IDL_S_MONITORING_COND) {
4373 idl->change_seqno++;
4374 } else {
4375 /* We're setting up a session, so don't signal that the database
4376 * changed. Finalizing the session will increment change_seqno
4377 * anyhow. */
4378 }
4379 idl->is_lock_contended = false;
4380 }
4381 idl->has_lock = new_has_lock;
4382 }
4383
4384 static void
4385 ovsdb_idl_send_lock_request__(struct ovsdb_idl *idl, const char *method,
4386 struct json **idp)
4387 {
4388 ovsdb_idl_update_has_lock(idl, false);
4389
4390 json_destroy(idl->lock_request_id);
4391 idl->lock_request_id = NULL;
4392
4393 if (jsonrpc_session_is_connected(idl->session)) {
4394 struct json *params;
4395
4396 params = json_array_create_1(json_string_create(idl->lock_name));
4397 jsonrpc_session_send(idl->session,
4398 jsonrpc_create_request(method, params, idp));
4399 }
4400 }
4401
4402 static void
4403 ovsdb_idl_send_lock_request(struct ovsdb_idl *idl)
4404 {
4405 ovsdb_idl_send_lock_request__(idl, "lock", &idl->lock_request_id);
4406 }
4407
4408 static void
4409 ovsdb_idl_send_unlock_request(struct ovsdb_idl *idl)
4410 {
4411 ovsdb_idl_send_lock_request__(idl, "unlock", NULL);
4412 }
4413
4414 static void
4415 ovsdb_idl_parse_lock_reply(struct ovsdb_idl *idl, const struct json *result)
4416 {
4417 bool got_lock;
4418
4419 json_destroy(idl->lock_request_id);
4420 idl->lock_request_id = NULL;
4421
4422 if (result->type == JSON_OBJECT) {
4423 const struct json *locked;
4424
4425 locked = shash_find_data(json_object(result), "locked");
4426 got_lock = locked && locked->type == JSON_TRUE;
4427 } else {
4428 got_lock = false;
4429 }
4430
4431 ovsdb_idl_update_has_lock(idl, got_lock);
4432 if (!got_lock) {
4433 idl->is_lock_contended = true;
4434 }
4435 }
4436
4437 static void
4438 ovsdb_idl_parse_lock_notify(struct ovsdb_idl *idl,
4439 const struct json *params,
4440 bool new_has_lock)
4441 {
4442 if (idl->lock_name
4443 && params->type == JSON_ARRAY
4444 && json_array(params)->n > 0
4445 && json_array(params)->elems[0]->type == JSON_STRING) {
4446 const char *lock_name = json_string(json_array(params)->elems[0]);
4447
4448 if (!strcmp(idl->lock_name, lock_name)) {
4449 ovsdb_idl_update_has_lock(idl, new_has_lock);
4450 if (!new_has_lock) {
4451 idl->is_lock_contended = true;
4452 }
4453 }
4454 }
4455 }
4456
4457 /* Inserts a new Map Operation into current transaction. */
4458 static void
4459 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *row,
4460 const struct ovsdb_idl_column *column,
4461 struct ovsdb_datum *datum,
4462 enum map_op_type op_type)
4463 {
4464 const struct ovsdb_idl_table_class *class;
4465 size_t column_idx;
4466 struct map_op *map_op;
4467
4468 class = row->table->class_;
4469 column_idx = column - class->columns;
4470
4471 /* Check if a map operation list exists for this column. */
4472 if (!row->map_op_written) {
4473 row->map_op_written = bitmap_allocate(class->n_columns);
4474 row->map_op_lists = xzalloc(class->n_columns *
4475 sizeof *row->map_op_lists);
4476 }
4477 if (!row->map_op_lists[column_idx]) {
4478 row->map_op_lists[column_idx] = map_op_list_create();
4479 }
4480
4481 /* Add a map operation to the corresponding list. */
4482 map_op = map_op_create(datum, op_type);
4483 bitmap_set1(row->map_op_written, column_idx);
4484 map_op_list_add(row->map_op_lists[column_idx], map_op, &column->type);
4485
4486 /* Add this row to transaction's list of rows. */
4487 if (hmap_node_is_null(&row->txn_node)) {
4488 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4489 uuid_hash(&row->uuid));
4490 }
4491 }
4492
4493 /* Inserts a new Set Operation into current transaction. */
4494 static void
4495 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *row,
4496 const struct ovsdb_idl_column *column,
4497 struct ovsdb_datum *datum,
4498 enum set_op_type op_type)
4499 {
4500 const struct ovsdb_idl_table_class *class;
4501 size_t column_idx;
4502 struct set_op *set_op;
4503
4504 class = row->table->class_;
4505 column_idx = column - class->columns;
4506
4507 /* Check if a set operation list exists for this column. */
4508 if (!row->set_op_written) {
4509 row->set_op_written = bitmap_allocate(class->n_columns);
4510 row->set_op_lists = xzalloc(class->n_columns *
4511 sizeof *row->set_op_lists);
4512 }
4513 if (!row->set_op_lists[column_idx]) {
4514 row->set_op_lists[column_idx] = set_op_list_create();
4515 }
4516
4517 /* Add a set operation to the corresponding list. */
4518 set_op = set_op_create(datum, op_type);
4519 bitmap_set1(row->set_op_written, column_idx);
4520 set_op_list_add(row->set_op_lists[column_idx], set_op, &column->type);
4521
4522 /* Add this row to the transactions's list of rows. */
4523 if (hmap_node_is_null(&row->txn_node)) {
4524 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
4525 uuid_hash(&row->uuid));
4526 }
4527 }
4528
4529 static bool
4530 is_valid_partial_update(const struct ovsdb_idl_row *row,
4531 const struct ovsdb_idl_column *column,
4532 struct ovsdb_datum *datum)
4533 {
4534 /* Verify that this column is being monitored. */
4535 unsigned int column_idx = column - row->table->class_->columns;
4536 if (!(row->table->modes[column_idx] & OVSDB_IDL_MONITOR)) {
4537 VLOG_WARN("cannot partially update non-monitored column");
4538 return false;
4539 }
4540
4541 /* Verify that the update affects a single element. */
4542 if (datum->n != 1) {
4543 VLOG_WARN("invalid datum for partial update");
4544 return false;
4545 }
4546
4547 return true;
4548 }
4549
4550 /* Inserts the value described in 'datum' into the map in 'column' in
4551 * 'row_'. If the value doesn't already exist in 'column' then it's value
4552 * is added. The value in 'datum' must be of the same type as the values
4553 * in 'column'. This function takes ownership of 'datum'.
4554 *
4555 * Usually this function is used indirectly through one of the "update"
4556 * functions generated by vswitch-idl. */
4557 void
4558 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *row_,
4559 const struct ovsdb_idl_column *column,
4560 struct ovsdb_datum *datum)
4561 {
4562 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4563 enum set_op_type op_type;
4564
4565 if (!is_valid_partial_update(row, column, datum)) {
4566 ovsdb_datum_destroy(datum, &column->type);
4567 free(datum);
4568 return;
4569 }
4570
4571 op_type = SET_OP_INSERT;
4572
4573 ovsdb_idl_txn_add_set_op(row, column, datum, op_type);
4574 }
4575
4576 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
4577 * The value in 'datum' must be of the same type as the keys in 'column'.
4578 * This function takes ownership of 'datum'.
4579 *
4580 * Usually this function is used indirectly through one of the "update"
4581 * functions generated by vswitch-idl. */
4582 void
4583 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *row_,
4584 const struct ovsdb_idl_column *column,
4585 struct ovsdb_datum *datum)
4586 {
4587 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4588
4589 if (!is_valid_partial_update(row, column, datum)) {
4590 struct ovsdb_type type_ = column->type;
4591 type_.value.type = OVSDB_TYPE_VOID;
4592 ovsdb_datum_destroy(datum, &type_);
4593 free(datum);
4594 return;
4595 }
4596 ovsdb_idl_txn_add_set_op(row, column, datum, SET_OP_DELETE);
4597 }
4598
4599 /* Inserts the key-value specified in 'datum' into the map in 'column' in
4600 * 'row_'. If the key already exist in 'column', then it's value is updated
4601 * with the value in 'datum'. The key-value in 'datum' must be of the same type
4602 * as the keys-values in 'column'. This function takes ownership of 'datum'.
4603 *
4604 * Usually this function is used indirectly through one of the "update"
4605 * functions generated by vswitch-idl. */
4606 void
4607 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *row_,
4608 const struct ovsdb_idl_column *column,
4609 struct ovsdb_datum *datum)
4610 {
4611 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4612 enum ovsdb_atomic_type key_type;
4613 enum map_op_type op_type;
4614 unsigned int pos;
4615 const struct ovsdb_datum *old_datum;
4616
4617 if (!is_valid_partial_update(row, column, datum)) {
4618 ovsdb_datum_destroy(datum, &column->type);
4619 free(datum);
4620 return;
4621 }
4622
4623 /* Find out if this is an insert or an update. */
4624 key_type = column->type.key.type;
4625 old_datum = ovsdb_idl_read(row, column);
4626 pos = ovsdb_datum_find_key(old_datum, &datum->keys[0], key_type);
4627 op_type = pos == UINT_MAX ? MAP_OP_INSERT : MAP_OP_UPDATE;
4628
4629 ovsdb_idl_txn_add_map_op(row, column, datum, op_type);
4630 }
4631
4632 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
4633 * The key in 'datum' must be of the same type as the keys in 'column'.
4634 * The value in 'datum' must be NULL. This function takes ownership of
4635 * 'datum'.
4636 *
4637 * Usually this function is used indirectly through one of the "update"
4638 * functions generated by vswitch-idl. */
4639 void
4640 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *row_,
4641 const struct ovsdb_idl_column *column,
4642 struct ovsdb_datum *datum)
4643 {
4644 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4645
4646 if (!is_valid_partial_update(row, column, datum)) {
4647 struct ovsdb_type type_ = column->type;
4648 type_.value.type = OVSDB_TYPE_VOID;
4649 ovsdb_datum_destroy(datum, &type_);
4650 free(datum);
4651 return;
4652 }
4653 ovsdb_idl_txn_add_map_op(row, column, datum, MAP_OP_DELETE);
4654 }
4655
4656 void
4657 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *loop)
4658 {
4659 if (loop) {
4660 ovsdb_idl_destroy(loop->idl);
4661 }
4662 }
4663
4664 struct ovsdb_idl_txn *
4665 ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
4666 {
4667 ovsdb_idl_run(loop->idl);
4668 loop->open_txn = (loop->committing_txn
4669 || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
4670 ? NULL
4671 : ovsdb_idl_txn_create(loop->idl));
4672 return loop->open_txn;
4673 }
4674
4675 /* Attempts to commit the current transaction, if one is open, and sets up the
4676 * poll loop to wake up when some more work might be needed.
4677 *
4678 * If a transaction was open, in this or a previous iteration of the main loop,
4679 * and had not before finished committing (successfully or unsuccessfully), the
4680 * return value is one of:
4681 *
4682 * 1: The transaction committed successfully (or it did not change anything in
4683 * the database).
4684 * 0: The transaction failed.
4685 * -1: The commit is still in progress.
4686 *
4687 * Thus, the return value is -1 if the transaction is in progress and otherwise
4688 * true for success, false for failure.
4689 *
4690 * (In the corner case where the IDL sends a transaction to the database and
4691 * the database commits it, and the connection between the IDL and the database
4692 * drops before the IDL receives the message confirming the commit, this
4693 * function can return 0 even though the transaction succeeded.)
4694 */
4695 int
4696 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
4697 {
4698 if (loop->open_txn) {
4699 loop->committing_txn = loop->open_txn;
4700 loop->open_txn = NULL;
4701
4702 loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
4703 }
4704
4705 struct ovsdb_idl_txn *txn = loop->committing_txn;
4706 int retval;
4707 if (txn) {
4708 enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
4709 if (status != TXN_INCOMPLETE) {
4710 switch (status) {
4711 case TXN_TRY_AGAIN:
4712 /* We want to re-evaluate the database when it's changed from
4713 * the contents that it had when we started the commit. (That
4714 * might have already happened.) */
4715 loop->skip_seqno = loop->precommit_seqno;
4716 if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
4717 poll_immediate_wake();
4718 }
4719 retval = 0;
4720 break;
4721
4722 case TXN_SUCCESS:
4723 /* Possibly some work on the database was deferred because no
4724 * further transaction could proceed. Wake up again. */
4725 retval = 1;
4726 loop->cur_cfg = loop->next_cfg;
4727 poll_immediate_wake();
4728 break;
4729
4730 case TXN_UNCHANGED:
4731 retval = 1;
4732 loop->cur_cfg = loop->next_cfg;
4733 break;
4734
4735 case TXN_ABORTED:
4736 case TXN_NOT_LOCKED:
4737 case TXN_ERROR:
4738 retval = 0;
4739 break;
4740
4741 case TXN_UNCOMMITTED:
4742 case TXN_INCOMPLETE:
4743 default:
4744 OVS_NOT_REACHED();
4745 }
4746 ovsdb_idl_txn_destroy(txn);
4747 loop->committing_txn = NULL;
4748 } else {
4749 retval = -1;
4750 }
4751 } else {
4752 /* Not a meaningful return value: no transaction was in progress. */
4753 retval = 1;
4754 }
4755
4756 ovsdb_idl_wait(loop->idl);
4757
4758 return retval;
4759 }