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