]> git.proxmox.com Git - ovs.git/blame - lib/ovsdb-idl.c
lockfile: Support \-delimited file names in lockfile_name().
[ovs.git] / lib / ovsdb-idl.c
CommitLineData
8d668224 1/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
c3bb4bd7
BP
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
475281c0 20#include <errno.h>
b54e22e9 21#include <inttypes.h>
c3bb4bd7
BP
22#include <limits.h>
23#include <stdlib.h>
24
475281c0 25#include "bitmap.h"
60032110 26#include "coverage.h"
d171b584 27#include "dynamic-string.h"
b302749b 28#include "fatal-signal.h"
c3bb4bd7
BP
29#include "json.h"
30#include "jsonrpc.h"
31#include "ovsdb-data.h"
32#include "ovsdb-error.h"
33#include "ovsdb-idl-provider.h"
586bb84a 34#include "poll-loop.h"
c3bb4bd7
BP
35#include "shash.h"
36#include "util.h"
e6211adc 37#include "openvswitch/vlog.h"
c3bb4bd7 38
d98e6007 39VLOG_DEFINE_THIS_MODULE(ovsdb_idl);
5136ce49 40
60032110
RW
41COVERAGE_DEFINE(txn_uncommitted);
42COVERAGE_DEFINE(txn_unchanged);
43COVERAGE_DEFINE(txn_incomplete);
44COVERAGE_DEFINE(txn_aborted);
45COVERAGE_DEFINE(txn_success);
46COVERAGE_DEFINE(txn_try_again);
47COVERAGE_DEFINE(txn_not_locked);
48COVERAGE_DEFINE(txn_error);
49
c3bb4bd7
BP
50/* An arc from one idl_row to another. When row A contains a UUID that
51 * references row B, this is represented by an arc from A (the source) to B
52 * (the destination).
53 *
54 * Arcs from a row to itself are omitted, that is, src and dst are always
55 * different.
56 *
57 * Arcs are never duplicated, that is, even if there are multiple references
58 * from A to B, there is only a single arc from A to B.
59 *
60 * Arcs are directed: an arc from A to B is the converse of an an arc from B to
61 * A. Both an arc and its converse may both be present, if each row refers
62 * to the other circularly.
63 *
64 * The source and destination row may be in the same table or in different
65 * tables.
66 */
67struct ovsdb_idl_arc {
ca6ba700
TG
68 struct ovs_list src_node; /* In src->src_arcs list. */
69 struct ovs_list dst_node; /* In dst->dst_arcs list. */
c3bb4bd7
BP
70 struct ovsdb_idl_row *src; /* Source row. */
71 struct ovsdb_idl_row *dst; /* Destination row. */
72};
73
74struct ovsdb_idl {
115f1e4d 75 const struct ovsdb_idl_class *class;
c3bb4bd7 76 struct jsonrpc_session *session;
115f1e4d 77 struct shash table_by_name;
ef73f86c 78 struct ovsdb_idl_table *tables; /* Contains "struct ovsdb_idl_table *"s.*/
c3bb4bd7
BP
79 struct json *monitor_request_id;
80 unsigned int last_monitor_request_seqno;
81 unsigned int change_seqno;
8cdec725 82 bool verify_write_only;
475281c0 83
06b6d651
BP
84 /* Database locking. */
85 char *lock_name; /* Name of lock we need, NULL if none. */
86 bool has_lock; /* Has db server told us we have the lock? */
87 bool is_lock_contended; /* Has db server told us we can't get lock? */
88 struct json *lock_request_id; /* JSON-RPC ID of in-flight lock request. */
89
475281c0
BP
90 /* Transaction support. */
91 struct ovsdb_idl_txn *txn;
92 struct hmap outstanding_txns;
93};
94
95struct ovsdb_idl_txn {
96 struct hmap_node hmap_node;
97 struct json *request_id;
98 struct ovsdb_idl *idl;
99 struct hmap txn_rows;
100 enum ovsdb_idl_txn_status status;
91e310a5 101 char *error;
577aebdf 102 bool dry_run;
d171b584 103 struct ds comment;
b54e22e9
BP
104
105 /* Increments. */
94fbe1aa
BP
106 const char *inc_table;
107 const char *inc_column;
108 struct uuid inc_row;
b54e22e9
BP
109 unsigned int inc_index;
110 int64_t inc_new_value;
69490970
BP
111
112 /* Inserted rows. */
d95d1510 113 struct hmap inserted_rows; /* Contains "struct ovsdb_idl_txn_insert"s. */
69490970
BP
114};
115
116struct ovsdb_idl_txn_insert {
117 struct hmap_node hmap_node; /* In struct ovsdb_idl_txn's inserted_rows. */
118 struct uuid dummy; /* Dummy UUID used locally. */
119 int op_index; /* Index into transaction's operation array. */
120 struct uuid real; /* Real UUID used by database server. */
c3bb4bd7
BP
121};
122
123static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
124static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5);
125
126static void ovsdb_idl_clear(struct ovsdb_idl *);
127static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *);
128static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct json *);
129static struct ovsdb_error *ovsdb_idl_parse_update__(struct ovsdb_idl *,
130 const struct json *);
c547535a 131static bool ovsdb_idl_process_update(struct ovsdb_idl_table *,
c3bb4bd7
BP
132 const struct uuid *,
133 const struct json *old,
134 const struct json *new);
135static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct json *);
136static void ovsdb_idl_delete_row(struct ovsdb_idl_row *);
c547535a 137static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct json *);
c3bb4bd7
BP
138
139static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *);
475281c0
BP
140static struct ovsdb_idl_row *ovsdb_idl_row_create__(
141 const struct ovsdb_idl_table_class *);
c3bb4bd7
BP
142static struct ovsdb_idl_row *ovsdb_idl_row_create(struct ovsdb_idl_table *,
143 const struct uuid *);
144static void ovsdb_idl_row_destroy(struct ovsdb_idl_row *);
145
979821c0
BP
146static void ovsdb_idl_row_parse(struct ovsdb_idl_row *);
147static void ovsdb_idl_row_unparse(struct ovsdb_idl_row *);
475281c0
BP
148static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row *);
149static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row *);
150
151static void ovsdb_idl_txn_abort_all(struct ovsdb_idl *);
152static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl *,
153 const struct jsonrpc_msg *msg);
c3bb4bd7 154
06b6d651
BP
155static void ovsdb_idl_send_lock_request(struct ovsdb_idl *);
156static void ovsdb_idl_send_unlock_request(struct ovsdb_idl *);
157static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl *,
158 const struct json *);
159static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
160 const struct json *params,
161 bool new_has_lock);
162
2ce42c88
BP
163/* Creates and returns a connection to database 'remote', which should be in a
164 * form acceptable to jsonrpc_session_open(). The connection will maintain an
165 * in-memory replica of the remote database whose schema is described by
166 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
ef73f86c
BP
167 * by ovsdb-idlc.)
168 *
fba6bd1d
BP
169 * Passes 'retry' to jsonrpc_session_open(). See that function for
170 * documentation.
171 *
ef73f86c
BP
172 * If 'monitor_everything_by_default' is true, then everything in the remote
173 * database will be replicated by default. ovsdb_idl_omit() and
174 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
175 * monitoring.
176 *
177 * If 'monitor_everything_by_default' is false, then no columns or tables will
178 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
179 * must be used to choose some columns or tables to replicate.
180 */
c3bb4bd7 181struct ovsdb_idl *
ef73f86c 182ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
fba6bd1d 183 bool monitor_everything_by_default, bool retry)
c3bb4bd7
BP
184{
185 struct ovsdb_idl *idl;
ef73f86c 186 uint8_t default_mode;
c3bb4bd7
BP
187 size_t i;
188
ef73f86c
BP
189 default_mode = (monitor_everything_by_default
190 ? OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT
191 : 0);
192
c3bb4bd7 193 idl = xzalloc(sizeof *idl);
115f1e4d 194 idl->class = class;
fba6bd1d 195 idl->session = jsonrpc_session_open(remote, retry);
115f1e4d
BP
196 shash_init(&idl->table_by_name);
197 idl->tables = xmalloc(class->n_tables * sizeof *idl->tables);
c3bb4bd7
BP
198 for (i = 0; i < class->n_tables; i++) {
199 const struct ovsdb_idl_table_class *tc = &class->tables[i];
115f1e4d 200 struct ovsdb_idl_table *table = &idl->tables[i];
c3bb4bd7
BP
201 size_t j;
202
efdd9088 203 shash_add_assert(&idl->table_by_name, tc->name, table);
c3bb4bd7 204 table->class = tc;
c547535a 205 table->modes = xmalloc(tc->n_columns);
ef73f86c
BP
206 memset(table->modes, default_mode, tc->n_columns);
207 table->need_table = false;
c3bb4bd7
BP
208 shash_init(&table->columns);
209 for (j = 0; j < tc->n_columns; j++) {
210 const struct ovsdb_idl_column *column = &tc->columns[j];
211
efdd9088 212 shash_add_assert(&table->columns, column->name, column);
c3bb4bd7
BP
213 }
214 hmap_init(&table->rows);
215 table->idl = idl;
216 }
217 idl->last_monitor_request_seqno = UINT_MAX;
475281c0 218 hmap_init(&idl->outstanding_txns);
c3bb4bd7
BP
219
220 return idl;
221}
222
2ce42c88 223/* Destroys 'idl' and all of the data structures that it manages. */
c3bb4bd7
BP
224void
225ovsdb_idl_destroy(struct ovsdb_idl *idl)
226{
227 if (idl) {
115f1e4d 228 size_t i;
c3bb4bd7 229
cb22974d 230 ovs_assert(!idl->txn);
c3bb4bd7
BP
231 ovsdb_idl_clear(idl);
232 jsonrpc_session_close(idl->session);
233
115f1e4d
BP
234 for (i = 0; i < idl->class->n_tables; i++) {
235 struct ovsdb_idl_table *table = &idl->tables[i];
c3bb4bd7
BP
236 shash_destroy(&table->columns);
237 hmap_destroy(&table->rows);
c547535a 238 free(table->modes);
c3bb4bd7 239 }
115f1e4d
BP
240 shash_destroy(&idl->table_by_name);
241 free(idl->tables);
c3bb4bd7 242 json_destroy(idl->monitor_request_id);
06b6d651
BP
243 free(idl->lock_name);
244 json_destroy(idl->lock_request_id);
da157f1e 245 hmap_destroy(&idl->outstanding_txns);
c3bb4bd7
BP
246 free(idl);
247 }
248}
249
250static void
251ovsdb_idl_clear(struct ovsdb_idl *idl)
252{
c3bb4bd7 253 bool changed = false;
115f1e4d 254 size_t i;
c3bb4bd7 255
115f1e4d
BP
256 for (i = 0; i < idl->class->n_tables; i++) {
257 struct ovsdb_idl_table *table = &idl->tables[i];
c3bb4bd7
BP
258 struct ovsdb_idl_row *row, *next_row;
259
260 if (hmap_is_empty(&table->rows)) {
261 continue;
262 }
263
264 changed = true;
4e8e4213 265 HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &table->rows) {
c3bb4bd7
BP
266 struct ovsdb_idl_arc *arc, *next_arc;
267
268 if (!ovsdb_idl_row_is_orphan(row)) {
979821c0 269 ovsdb_idl_row_unparse(row);
c3bb4bd7 270 }
4e8e4213 271 LIST_FOR_EACH_SAFE (arc, next_arc, src_node, &row->src_arcs) {
c3bb4bd7
BP
272 free(arc);
273 }
274 /* No need to do anything with dst_arcs: some node has those arcs
275 * as forward arcs and will destroy them itself. */
276
0196cc15 277 ovsdb_idl_row_destroy(row);
c3bb4bd7
BP
278 }
279 }
280
281 if (changed) {
282 idl->change_seqno++;
283 }
284}
285
854a94d9
BP
286/* Processes a batch of messages from the database server on 'idl'. This may
287 * cause the IDL's contents to change. The client may check for that with
288 * ovsdb_idl_get_seqno(). */
289void
c3bb4bd7
BP
290ovsdb_idl_run(struct ovsdb_idl *idl)
291{
292 int i;
293
cb22974d 294 ovs_assert(!idl->txn);
c3bb4bd7
BP
295 jsonrpc_session_run(idl->session);
296 for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
828cd4c7 297 struct jsonrpc_msg *msg;
c3bb4bd7
BP
298 unsigned int seqno;
299
300 seqno = jsonrpc_session_get_seqno(idl->session);
301 if (idl->last_monitor_request_seqno != seqno) {
302 idl->last_monitor_request_seqno = seqno;
475281c0 303 ovsdb_idl_txn_abort_all(idl);
c3bb4bd7 304 ovsdb_idl_send_monitor_request(idl);
06b6d651
BP
305 if (idl->lock_name) {
306 ovsdb_idl_send_lock_request(idl);
307 }
c3bb4bd7
BP
308 break;
309 }
310
311 msg = jsonrpc_session_recv(idl->session);
312 if (!msg) {
313 break;
314 }
315
4931f33a 316 if (msg->type == JSONRPC_NOTIFY
d95d1510
BP
317 && !strcmp(msg->method, "update")
318 && msg->params->type == JSON_ARRAY
319 && msg->params->u.array.n == 2
320 && msg->params->u.array.elems[0]->type == JSON_NULL) {
06b6d651 321 /* Database contents changed. */
c3bb4bd7
BP
322 ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1]);
323 } else if (msg->type == JSONRPC_REPLY
324 && idl->monitor_request_id
325 && json_equal(idl->monitor_request_id, msg->id)) {
06b6d651 326 /* Reply to our "monitor" request. */
c547535a 327 idl->change_seqno++;
c3bb4bd7
BP
328 json_destroy(idl->monitor_request_id);
329 idl->monitor_request_id = NULL;
330 ovsdb_idl_clear(idl);
331 ovsdb_idl_parse_update(idl, msg->result);
06b6d651
BP
332 } else if (msg->type == JSONRPC_REPLY
333 && idl->lock_request_id
334 && json_equal(idl->lock_request_id, msg->id)) {
335 /* Reply to our "lock" request. */
336 ovsdb_idl_parse_lock_reply(idl, msg->result);
337 } else if (msg->type == JSONRPC_NOTIFY
338 && !strcmp(msg->method, "locked")) {
339 /* We got our lock. */
340 ovsdb_idl_parse_lock_notify(idl, msg->params, true);
341 } else if (msg->type == JSONRPC_NOTIFY
342 && !strcmp(msg->method, "stolen")) {
343 /* Someone else stole our lock. */
344 ovsdb_idl_parse_lock_notify(idl, msg->params, false);
475281c0
BP
345 } else if ((msg->type == JSONRPC_ERROR
346 || msg->type == JSONRPC_REPLY)
347 && ovsdb_idl_txn_process_reply(idl, msg)) {
348 /* ovsdb_idl_txn_process_reply() did everything needful. */
c3bb4bd7 349 } else {
c5a80c70
BP
350 /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
351 * a transaction before we receive the reply, so keep the log level
352 * low. */
353 VLOG_DBG("%s: received unexpected %s message",
354 jsonrpc_session_get_name(idl->session),
355 jsonrpc_msg_type_to_string(msg->type));
c3bb4bd7 356 }
c3bb4bd7
BP
357 jsonrpc_msg_destroy(msg);
358 }
359}
360
2ce42c88
BP
361/* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
362 * do or when activity occurs on a transaction on 'idl'. */
c3bb4bd7
BP
363void
364ovsdb_idl_wait(struct ovsdb_idl *idl)
365{
366 jsonrpc_session_wait(idl->session);
367 jsonrpc_session_recv_wait(idl->session);
368}
369
2f926787
BP
370/* Returns a "sequence number" that represents the state of 'idl'. When
371 * ovsdb_idl_run() changes the database, the sequence number changes. The
372 * initial fetch of the entire contents of the remote database is considered to
373 * be one kind of change. Successfully acquiring a lock, if one has been
374 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
375 *
376 * As long as the sequence number does not change, the client may continue to
377 * use any data structures it obtains from 'idl'. But when it changes, the
378 * client must not access any of these data structures again, because they
379 * could have freed or reused for other purposes.
380 *
381 * The sequence number can occasionally change even if the database does not.
382 * This happens if the connection to the database drops and reconnects, which
383 * causes the database contents to be reloaded even if they didn't change. (It
384 * could also happen if the database server sends out a "change" that reflects
385 * what the IDL already thought was in the database. The database server is
386 * not supposed to do that, but bugs could in theory cause it to do so.) */
c3bb4bd7
BP
387unsigned int
388ovsdb_idl_get_seqno(const struct ovsdb_idl *idl)
389{
390 return idl->change_seqno;
391}
392
2ce42c88
BP
393/* Returns true if 'idl' successfully connected to the remote database and
394 * retrieved its contents (even if the connection subsequently dropped and is
395 * in the process of reconnecting). If so, then 'idl' contains an atomic
396 * snapshot of the database's contents (but it might be arbitrarily old if the
397 * connection dropped).
398 *
399 * Returns false if 'idl' has never connected or retrieved the database's
400 * contents. If so, 'idl' is empty. */
f3d64521
JP
401bool
402ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
403{
404 return ovsdb_idl_get_seqno(idl) != 0;
405}
406
705d7a39
AA
407/* Reconfigures 'idl' so that it would reconnect to the database, if
408 * connection was dropped. */
409void
410ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
411{
412 jsonrpc_session_enable_reconnect(idl->session);
413}
414
2ce42c88
BP
415/* Forces 'idl' to drop its connection to the database and reconnect. In the
416 * meantime, the contents of 'idl' will not change. */
c3bb4bd7
BP
417void
418ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
419{
420 jsonrpc_session_force_reconnect(idl->session);
421}
8cdec725
EJ
422
423/* Some IDL users should only write to write-only columns. Furthermore,
424 * writing to a column which is not write-only can cause serious performance
425 * degradations for these users. This function causes 'idl' to reject writes
426 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
427void
428ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
429{
430 idl->verify_write_only = true;
431}
fba6bd1d 432
8d668224 433/* Returns true if 'idl' is currently connected or trying to connect. */
fba6bd1d
BP
434bool
435ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
436{
437 return jsonrpc_session_is_alive(idl->session);
438}
439
8d668224
BP
440/* Returns the last error reported on a connection by 'idl'. The return value
441 * is 0 only if no connection made by 'idl' has ever encountered an error. See
442 * jsonrpc_get_status() for return value interpretation. */
fba6bd1d
BP
443int
444ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
445{
446 return jsonrpc_session_get_last_error(idl->session);
447}
ef73f86c
BP
448\f
449static unsigned char *
450ovsdb_idl_get_mode(struct ovsdb_idl *idl,
451 const struct ovsdb_idl_column *column)
c547535a
BP
452{
453 size_t i;
454
cb22974d 455 ovs_assert(!idl->change_seqno);
ef73f86c 456
c547535a
BP
457 for (i = 0; i < idl->class->n_tables; i++) {
458 const struct ovsdb_idl_table *table = &idl->tables[i];
459 const struct ovsdb_idl_table_class *tc = table->class;
460
461 if (column >= tc->columns && column < &tc->columns[tc->n_columns]) {
ef73f86c 462 return &table->modes[column - tc->columns];
c547535a
BP
463 }
464 }
465
428b2edd 466 OVS_NOT_REACHED();
c547535a
BP
467}
468
ef73f86c
BP
469static void
470add_ref_table(struct ovsdb_idl *idl, const struct ovsdb_base_type *base)
471{
472 if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName) {
473 struct ovsdb_idl_table *table;
474
475 table = shash_find_data(&idl->table_by_name,
476 base->u.uuid.refTableName);
477 if (table) {
478 table->need_table = true;
479 } else {
480 VLOG_WARN("%s IDL class missing referenced table %s",
481 idl->class->database, base->u.uuid.refTableName);
482 }
483 }
484}
485
486/* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
487 * ensures that any tables referenced by 'column' will be replicated, even if
488 * no columns in that table are selected for replication (see
489 * ovsdb_idl_add_table() for more information).
c547535a 490 *
ef73f86c
BP
491 * This function is only useful if 'monitor_everything_by_default' was false in
492 * the call to ovsdb_idl_create(). This function should be called between
493 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
494 */
495void
496ovsdb_idl_add_column(struct ovsdb_idl *idl,
497 const struct ovsdb_idl_column *column)
498{
499 *ovsdb_idl_get_mode(idl, column) = OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT;
500 add_ref_table(idl, &column->type.key);
501 add_ref_table(idl, &column->type.value);
502}
503
504/* Ensures that the table with class 'tc' will be replicated on 'idl' even if
505 * no columns are selected for replication. This can be useful because it
506 * allows 'idl' to keep track of what rows in the table actually exist, which
507 * in turn allows columns that reference the table to have accurate contents.
508 * (The IDL presents the database with references to rows that do not exist
509 * removed.)
c547535a 510 *
ef73f86c
BP
511 * This function is only useful if 'monitor_everything_by_default' was false in
512 * the call to ovsdb_idl_create(). This function should be called between
513 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
514 */
515void
516ovsdb_idl_add_table(struct ovsdb_idl *idl,
517 const struct ovsdb_idl_table_class *tc)
518{
519 size_t i;
520
521 for (i = 0; i < idl->class->n_tables; i++) {
522 struct ovsdb_idl_table *table = &idl->tables[i];
523
524 if (table->class == tc) {
525 table->need_table = true;
526 return;
527 }
528 }
529
428b2edd 530 OVS_NOT_REACHED();
ef73f86c
BP
531}
532
533/* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
c547535a 534 *
ef73f86c
BP
535 * This function should be called between ovsdb_idl_create() and the first call
536 * to ovsdb_idl_run().
537 */
c547535a 538void
ef73f86c
BP
539ovsdb_idl_omit_alert(struct ovsdb_idl *idl,
540 const struct ovsdb_idl_column *column)
c547535a 541{
ef73f86c 542 *ovsdb_idl_get_mode(idl, column) &= ~OVSDB_IDL_ALERT;
c547535a
BP
543}
544
ef73f86c
BP
545/* Sets the mode for 'column' in 'idl' to 0. See the big comment above
546 * OVSDB_IDL_MONITOR for details.
c547535a 547 *
ef73f86c
BP
548 * This function should be called between ovsdb_idl_create() and the first call
549 * to ovsdb_idl_run().
550 */
c547535a
BP
551void
552ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column)
553{
ef73f86c 554 *ovsdb_idl_get_mode(idl, column) = 0;
c547535a 555}
c3bb4bd7
BP
556\f
557static void
558ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
559{
560 struct json *monitor_requests;
c3bb4bd7 561 struct jsonrpc_msg *msg;
115f1e4d 562 size_t i;
c3bb4bd7
BP
563
564 monitor_requests = json_object_create();
115f1e4d
BP
565 for (i = 0; i < idl->class->n_tables; i++) {
566 const struct ovsdb_idl_table *table = &idl->tables[i];
c3bb4bd7
BP
567 const struct ovsdb_idl_table_class *tc = table->class;
568 struct json *monitor_request, *columns;
2a022368 569 size_t j;
c3bb4bd7 570
ef73f86c 571 columns = table->need_table ? json_array_create_empty() : NULL;
2a022368
BP
572 for (j = 0; j < tc->n_columns; j++) {
573 const struct ovsdb_idl_column *column = &tc->columns[j];
ef73f86c
BP
574 if (table->modes[j] & OVSDB_IDL_MONITOR) {
575 if (!columns) {
576 columns = json_array_create_empty();
577 }
c547535a
BP
578 json_array_add(columns, json_string_create(column->name));
579 }
c3bb4bd7 580 }
ef73f86c
BP
581
582 if (columns) {
583 monitor_request = json_object_create();
584 json_object_put(monitor_request, "columns", columns);
585 json_object_put(monitor_requests, tc->name, monitor_request);
586 }
c3bb4bd7
BP
587 }
588
589 json_destroy(idl->monitor_request_id);
590 msg = jsonrpc_create_request(
9cb53f26
BP
591 "monitor",
592 json_array_create_3(json_string_create(idl->class->database),
593 json_null_create(), monitor_requests),
c3bb4bd7
BP
594 &idl->monitor_request_id);
595 jsonrpc_session_send(idl->session, msg);
596}
597
598static void
599ovsdb_idl_parse_update(struct ovsdb_idl *idl, const struct json *table_updates)
600{
c547535a 601 struct ovsdb_error *error = ovsdb_idl_parse_update__(idl, table_updates);
c3bb4bd7
BP
602 if (error) {
603 if (!VLOG_DROP_WARN(&syntax_rl)) {
604 char *s = ovsdb_error_to_string(error);
605 VLOG_WARN_RL(&syntax_rl, "%s", s);
606 free(s);
607 }
608 ovsdb_error_destroy(error);
609 }
610}
611
612static struct ovsdb_error *
613ovsdb_idl_parse_update__(struct ovsdb_idl *idl,
614 const struct json *table_updates)
615{
616 const struct shash_node *tables_node;
617
618 if (table_updates->type != JSON_OBJECT) {
619 return ovsdb_syntax_error(table_updates, NULL,
620 "<table-updates> is not an object");
621 }
622 SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
623 const struct json *table_update = tables_node->data;
624 const struct shash_node *table_node;
625 struct ovsdb_idl_table *table;
626
115f1e4d 627 table = shash_find_data(&idl->table_by_name, tables_node->name);
c3bb4bd7
BP
628 if (!table) {
629 return ovsdb_syntax_error(
630 table_updates, NULL,
631 "<table-updates> includes unknown table \"%s\"",
632 tables_node->name);
633 }
634
635 if (table_update->type != JSON_OBJECT) {
636 return ovsdb_syntax_error(table_update, NULL,
637 "<table-update> for table \"%s\" is "
638 "not an object", table->class->name);
639 }
640 SHASH_FOR_EACH (table_node, json_object(table_update)) {
641 const struct json *row_update = table_node->data;
642 const struct json *old_json, *new_json;
643 struct uuid uuid;
644
645 if (!uuid_from_string(&uuid, table_node->name)) {
646 return ovsdb_syntax_error(table_update, NULL,
647 "<table-update> for table \"%s\" "
648 "contains bad UUID "
649 "\"%s\" as member name",
650 table->class->name,
651 table_node->name);
652 }
653 if (row_update->type != JSON_OBJECT) {
654 return ovsdb_syntax_error(row_update, NULL,
655 "<table-update> for table \"%s\" "
656 "contains <row-update> for %s that "
657 "is not an object",
658 table->class->name,
659 table_node->name);
660 }
661
662 old_json = shash_find_data(json_object(row_update), "old");
663 new_json = shash_find_data(json_object(row_update), "new");
664 if (old_json && old_json->type != JSON_OBJECT) {
665 return ovsdb_syntax_error(old_json, NULL,
666 "\"old\" <row> is not object");
667 } else if (new_json && new_json->type != JSON_OBJECT) {
668 return ovsdb_syntax_error(new_json, NULL,
669 "\"new\" <row> is not object");
670 } else if ((old_json != NULL) + (new_json != NULL)
671 != shash_count(json_object(row_update))) {
672 return ovsdb_syntax_error(row_update, NULL,
673 "<row-update> contains unexpected "
674 "member");
675 } else if (!old_json && !new_json) {
676 return ovsdb_syntax_error(row_update, NULL,
677 "<row-update> missing \"old\" "
678 "and \"new\" members");
679 }
680
c547535a
BP
681 if (ovsdb_idl_process_update(table, &uuid, old_json, new_json)) {
682 idl->change_seqno++;
683 }
c3bb4bd7
BP
684 }
685 }
686
687 return NULL;
688}
689
690static struct ovsdb_idl_row *
691ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
692{
693 struct ovsdb_idl_row *row;
694
4e8e4213 695 HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) {
c3bb4bd7
BP
696 if (uuid_equals(&row->uuid, uuid)) {
697 return row;
698 }
699 }
700 return NULL;
701}
702
c547535a
BP
703/* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
704 * otherwise. */
705static bool
c3bb4bd7
BP
706ovsdb_idl_process_update(struct ovsdb_idl_table *table,
707 const struct uuid *uuid, const struct json *old,
708 const struct json *new)
709{
710 struct ovsdb_idl_row *row;
711
712 row = ovsdb_idl_get_row(table, uuid);
713 if (!new) {
714 /* Delete row. */
715 if (row && !ovsdb_idl_row_is_orphan(row)) {
716 /* XXX perhaps we should check the 'old' values? */
717 ovsdb_idl_delete_row(row);
718 } else {
719 VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
720 "from table %s",
721 UUID_ARGS(uuid), table->class->name);
c547535a 722 return false;
c3bb4bd7
BP
723 }
724 } else if (!old) {
725 /* Insert row. */
726 if (!row) {
727 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
728 } else if (ovsdb_idl_row_is_orphan(row)) {
729 ovsdb_idl_insert_row(row, new);
730 } else {
731 VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
732 "table %s", UUID_ARGS(uuid), table->class->name);
c547535a 733 return ovsdb_idl_modify_row(row, new);
c3bb4bd7
BP
734 }
735 } else {
736 /* Modify row. */
737 if (row) {
738 /* XXX perhaps we should check the 'old' values? */
739 if (!ovsdb_idl_row_is_orphan(row)) {
c547535a 740 return ovsdb_idl_modify_row(row, new);
c3bb4bd7
BP
741 } else {
742 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
743 "referenced row "UUID_FMT" in table %s",
744 UUID_ARGS(uuid), table->class->name);
745 ovsdb_idl_insert_row(row, new);
746 }
747 } else {
748 VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
749 "in table %s", UUID_ARGS(uuid), table->class->name);
750 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
751 }
752 }
c547535a
BP
753
754 return true;
c3bb4bd7
BP
755}
756
c547535a
BP
757/* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
758 * otherwise. */
759static bool
c3bb4bd7
BP
760ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json)
761{
762 struct ovsdb_idl_table *table = row->table;
763 struct shash_node *node;
c547535a 764 bool changed = false;
c3bb4bd7
BP
765
766 SHASH_FOR_EACH (node, json_object(row_json)) {
767 const char *column_name = node->name;
768 const struct ovsdb_idl_column *column;
769 struct ovsdb_datum datum;
770 struct ovsdb_error *error;
771
772 column = shash_find_data(&table->columns, column_name);
773 if (!column) {
774 VLOG_WARN_RL(&syntax_rl, "unknown column %s updating row "UUID_FMT,
775 column_name, UUID_ARGS(&row->uuid));
776 continue;
777 }
778
779 error = ovsdb_datum_from_json(&datum, &column->type, node->data, NULL);
780 if (!error) {
c547535a 781 unsigned int column_idx = column - table->class->columns;
e85bbd75
BP
782 struct ovsdb_datum *old = &row->old[column_idx];
783
784 if (!ovsdb_datum_equals(old, &datum, &column->type)) {
785 ovsdb_datum_swap(old, &datum);
ef73f86c 786 if (table->modes[column_idx] & OVSDB_IDL_ALERT) {
e85bbd75
BP
787 changed = true;
788 }
789 } else {
790 /* Didn't really change but the OVSDB monitor protocol always
791 * includes every value in a row. */
c547535a 792 }
e85bbd75
BP
793
794 ovsdb_datum_destroy(&datum, &column->type);
c3bb4bd7
BP
795 } else {
796 char *s = ovsdb_error_to_string(error);
797 VLOG_WARN_RL(&syntax_rl, "error parsing column %s in row "UUID_FMT
798 " in table %s: %s", column_name,
799 UUID_ARGS(&row->uuid), table->class->name, s);
800 free(s);
801 ovsdb_error_destroy(error);
802 }
803 }
c547535a 804 return changed;
c3bb4bd7
BP
805}
806
90887925
BP
807/* When a row A refers to row B through a column with a "refTable" constraint,
808 * but row B does not exist, row B is called an "orphan row". Orphan rows
809 * should not persist, because the database enforces referential integrity, but
810 * they can appear transiently as changes from the database are received (the
811 * database doesn't try to topologically sort them and circular references mean
812 * it isn't always possible anyhow).
813 *
814 * This function returns true if 'row' is an orphan row, otherwise false.
815 */
c3bb4bd7
BP
816static bool
817ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
818{
90887925
BP
819 return !row->old && !row->new;
820}
821
f2ba3c0a
BP
822/* Returns true if 'row' is conceptually part of the database as modified by
823 * the current transaction (if any), false otherwise.
824 *
825 * This function will return true if 'row' is not an orphan (see the comment on
826 * ovsdb_idl_row_is_orphan()) and:
827 *
828 * - 'row' exists in the database and has not been deleted within the
829 * current transaction (if any).
830 *
831 * - 'row' was inserted within the current transaction and has not been
832 * deleted. (In the latter case you should not have passed 'row' in at
833 * all, because ovsdb_idl_txn_delete() freed it.)
834 *
835 * This function will return false if 'row' is an orphan or if 'row' was
836 * deleted within the current transaction.
837 */
838static bool
839ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
840{
841 return row->new != NULL;
c3bb4bd7
BP
842}
843
979821c0
BP
844static void
845ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
846{
847 const struct ovsdb_idl_table_class *class = row->table->class;
848 size_t i;
849
850 for (i = 0; i < class->n_columns; i++) {
851 const struct ovsdb_idl_column *c = &class->columns[i];
852 (c->parse)(row, &row->old[i]);
853 }
854}
855
856static void
857ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
858{
859 const struct ovsdb_idl_table_class *class = row->table->class;
860 size_t i;
861
862 for (i = 0; i < class->n_columns; i++) {
863 const struct ovsdb_idl_column *c = &class->columns[i];
864 (c->unparse)(row);
865 }
866}
867
c3bb4bd7 868static void
475281c0 869ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
c3bb4bd7 870{
cb22974d 871 ovs_assert(row->old == row->new);
c3bb4bd7
BP
872 if (!ovsdb_idl_row_is_orphan(row)) {
873 const struct ovsdb_idl_table_class *class = row->table->class;
874 size_t i;
875
876 for (i = 0; i < class->n_columns; i++) {
475281c0
BP
877 ovsdb_datum_destroy(&row->old[i], &class->columns[i].type);
878 }
879 free(row->old);
880 row->old = row->new = NULL;
881 }
882}
883
884static void
885ovsdb_idl_row_clear_new(struct ovsdb_idl_row *row)
886{
887 if (row->old != row->new) {
888 if (row->new) {
889 const struct ovsdb_idl_table_class *class = row->table->class;
890 size_t i;
891
35c2ce98
JG
892 if (row->written) {
893 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
894 ovsdb_datum_destroy(&row->new[i], &class->columns[i].type);
895 }
475281c0
BP
896 }
897 free(row->new);
898 free(row->written);
899 row->written = NULL;
c3bb4bd7 900 }
475281c0 901 row->new = row->old;
c3bb4bd7
BP
902 }
903}
904
905static void
906ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *row, bool destroy_dsts)
907{
908 struct ovsdb_idl_arc *arc, *next;
909
910 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
911 * that this causes to be unreferenced. */
4e8e4213 912 LIST_FOR_EACH_SAFE (arc, next, src_node, &row->src_arcs) {
c3bb4bd7
BP
913 list_remove(&arc->dst_node);
914 if (destroy_dsts
915 && ovsdb_idl_row_is_orphan(arc->dst)
916 && list_is_empty(&arc->dst->dst_arcs)) {
917 ovsdb_idl_row_destroy(arc->dst);
918 }
919 free(arc);
920 }
921 list_init(&row->src_arcs);
922}
923
924/* Force nodes that reference 'row' to reparse. */
925static void
0196cc15 926ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row)
c3bb4bd7
BP
927{
928 struct ovsdb_idl_arc *arc, *next;
929
930 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
931 * 'arc', so we need to use the "safe" variant of list traversal. However,
979821c0
BP
932 * calling an ovsdb_idl_column's 'parse' function will add an arc
933 * equivalent to 'arc' to row->arcs. That could be a problem for
934 * traversal, but it adds it at the beginning of the list to prevent us
935 * from stumbling upon it again.
c3bb4bd7
BP
936 *
937 * (If duplicate arcs were possible then we would need to make sure that
938 * 'next' didn't also point into 'arc''s destination, but we forbid
939 * duplicate arcs.) */
4e8e4213 940 LIST_FOR_EACH_SAFE (arc, next, dst_node, &row->dst_arcs) {
c3bb4bd7
BP
941 struct ovsdb_idl_row *ref = arc->src;
942
979821c0 943 ovsdb_idl_row_unparse(ref);
0196cc15 944 ovsdb_idl_row_clear_arcs(ref, false);
979821c0 945 ovsdb_idl_row_parse(ref);
c3bb4bd7
BP
946 }
947}
948
475281c0
BP
949static struct ovsdb_idl_row *
950ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
951{
72c6edc5 952 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
a699f614 953 class->row_init(row);
475281c0
BP
954 list_init(&row->src_arcs);
955 list_init(&row->dst_arcs);
956 hmap_node_nullify(&row->txn_node);
957 return row;
958}
959
c3bb4bd7
BP
960static struct ovsdb_idl_row *
961ovsdb_idl_row_create(struct ovsdb_idl_table *table, const struct uuid *uuid)
962{
475281c0 963 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(table->class);
c3bb4bd7
BP
964 hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
965 row->uuid = *uuid;
c3bb4bd7 966 row->table = table;
c3bb4bd7
BP
967 return row;
968}
969
970static void
971ovsdb_idl_row_destroy(struct ovsdb_idl_row *row)
972{
973 if (row) {
475281c0 974 ovsdb_idl_row_clear_old(row);
c3bb4bd7
BP
975 hmap_remove(&row->table->rows, &row->hmap_node);
976 free(row);
977 }
978}
979
980static void
981ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
982{
983 const struct ovsdb_idl_table_class *class = row->table->class;
984 size_t i;
985
cb22974d 986 ovs_assert(!row->old && !row->new);
475281c0 987 row->old = row->new = xmalloc(class->n_columns * sizeof *row->old);
c3bb4bd7 988 for (i = 0; i < class->n_columns; i++) {
475281c0 989 ovsdb_datum_init_default(&row->old[i], &class->columns[i].type);
c3bb4bd7
BP
990 }
991 ovsdb_idl_row_update(row, row_json);
979821c0 992 ovsdb_idl_row_parse(row);
c3bb4bd7 993
0196cc15 994 ovsdb_idl_row_reparse_backrefs(row);
c3bb4bd7
BP
995}
996
997static void
998ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
999{
979821c0 1000 ovsdb_idl_row_unparse(row);
c3bb4bd7 1001 ovsdb_idl_row_clear_arcs(row, true);
475281c0 1002 ovsdb_idl_row_clear_old(row);
c3bb4bd7
BP
1003 if (list_is_empty(&row->dst_arcs)) {
1004 ovsdb_idl_row_destroy(row);
1005 } else {
0196cc15 1006 ovsdb_idl_row_reparse_backrefs(row);
c3bb4bd7
BP
1007 }
1008}
1009
c547535a
BP
1010/* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1011 * otherwise. */
1012static bool
c3bb4bd7
BP
1013ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
1014{
c547535a
BP
1015 bool changed;
1016
979821c0 1017 ovsdb_idl_row_unparse(row);
c3bb4bd7 1018 ovsdb_idl_row_clear_arcs(row, true);
c547535a 1019 changed = ovsdb_idl_row_update(row, row_json);
979821c0 1020 ovsdb_idl_row_parse(row);
c547535a
BP
1021
1022 return changed;
c3bb4bd7
BP
1023}
1024
1025static bool
1026may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
1027{
1028 const struct ovsdb_idl_arc *arc;
1029
1030 /* No self-arcs. */
1031 if (src == dst) {
1032 return false;
1033 }
1034
1035 /* No duplicate arcs.
1036 *
1037 * We only need to test whether the first arc in dst->dst_arcs originates
1038 * at 'src', since we add all of the arcs from a given source in a clump
979821c0 1039 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
c3bb4bd7
BP
1040 * added at the front of the dst_arcs list. */
1041 if (list_is_empty(&dst->dst_arcs)) {
1042 return true;
1043 }
1044 arc = CONTAINER_OF(dst->dst_arcs.next, struct ovsdb_idl_arc, dst_node);
1045 return arc->src != src;
1046}
1047
115f1e4d 1048static struct ovsdb_idl_table *
475281c0
BP
1049ovsdb_idl_table_from_class(const struct ovsdb_idl *idl,
1050 const struct ovsdb_idl_table_class *table_class)
115f1e4d
BP
1051{
1052 return &idl->tables[table_class - idl->class->tables];
1053}
1054
2f926787 1055/* Called by ovsdb-idlc generated code. */
c3bb4bd7
BP
1056struct ovsdb_idl_row *
1057ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
1058 struct ovsdb_idl_table_class *dst_table_class,
1059 const struct uuid *dst_uuid)
1060{
1061 struct ovsdb_idl *idl = src->table->idl;
e9011ac8 1062 struct ovsdb_idl_table *dst_table;
c3bb4bd7
BP
1063 struct ovsdb_idl_arc *arc;
1064 struct ovsdb_idl_row *dst;
1065
475281c0 1066 dst_table = ovsdb_idl_table_from_class(idl, dst_table_class);
e9011ac8 1067 dst = ovsdb_idl_get_row(dst_table, dst_uuid);
979821c0
BP
1068 if (idl->txn) {
1069 /* We're being called from ovsdb_idl_txn_write(). We must not update
1070 * any arcs, because the transaction will be backed out at commit or
1071 * abort time and we don't want our graph screwed up.
1072 *
1073 * Just return the destination row, if there is one and it has not been
1074 * deleted. */
1075 if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new)) {
1076 return dst;
1077 }
1078 return NULL;
1079 } else {
1080 /* We're being called from some other context. Update the graph. */
1081 if (!dst) {
1082 dst = ovsdb_idl_row_create(dst_table, dst_uuid);
1083 }
c3bb4bd7 1084
979821c0
BP
1085 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
1086 if (may_add_arc(src, dst)) {
1087 /* The arc *must* be added at the front of the dst_arcs list. See
1088 * ovsdb_idl_row_reparse_backrefs() for details. */
1089 arc = xmalloc(sizeof *arc);
1090 list_push_front(&src->src_arcs, &arc->src_node);
1091 list_push_front(&dst->dst_arcs, &arc->dst_node);
1092 arc->src = src;
1093 arc->dst = dst;
1094 }
1095
1096 return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
c3bb4bd7 1097 }
979821c0 1098}
c3bb4bd7 1099
2f926787
BP
1100/* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
1101 * pointer to the row if there is one, otherwise a null pointer. */
979821c0
BP
1102const struct ovsdb_idl_row *
1103ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
1104 const struct ovsdb_idl_table_class *tc,
1105 const struct uuid *uuid)
1106{
1107 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
c3bb4bd7
BP
1108}
1109
1110static struct ovsdb_idl_row *
1111next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
1112{
1113 for (; node; node = hmap_next(&table->rows, node)) {
1114 struct ovsdb_idl_row *row;
1115
1116 row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
f2ba3c0a 1117 if (ovsdb_idl_row_exists(row)) {
c3bb4bd7
BP
1118 return row;
1119 }
1120 }
1121 return NULL;
1122}
1123
2f926787
BP
1124/* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
1125 * table is empty.
1126 *
1127 * Database tables are internally maintained as hash tables, so adding or
1128 * removing rows while traversing the same table can cause some rows to be
1129 * visited twice or not at apply. */
979821c0 1130const struct ovsdb_idl_row *
c3bb4bd7
BP
1131ovsdb_idl_first_row(const struct ovsdb_idl *idl,
1132 const struct ovsdb_idl_table_class *table_class)
1133{
475281c0
BP
1134 struct ovsdb_idl_table *table
1135 = ovsdb_idl_table_from_class(idl, table_class);
c3bb4bd7
BP
1136 return next_real_row(table, hmap_first(&table->rows));
1137}
1138
2f926787
BP
1139/* Returns a row following 'row' within its table, or a null pointer if 'row'
1140 * is the last row in its table. */
979821c0 1141const struct ovsdb_idl_row *
c3bb4bd7
BP
1142ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
1143{
1144 struct ovsdb_idl_table *table = row->table;
1145
1146 return next_real_row(table, hmap_next(&table->rows, &row->hmap_node));
1147}
8c3c2f30
BP
1148
1149/* Reads and returns the value of 'column' within 'row'. If an ongoing
1150 * transaction has changed 'column''s value, the modified value is returned.
1151 *
1152 * The caller must not modify or free the returned value.
1153 *
1154 * Various kinds of changes can invalidate the returned value: writing to the
1155 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
1156 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
1157 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
1158 * returned value is needed for a long time, it is best to make a copy of it
1159 * with ovsdb_datum_clone(). */
1160const struct ovsdb_datum *
1161ovsdb_idl_read(const struct ovsdb_idl_row *row,
1162 const struct ovsdb_idl_column *column)
1163{
942d31c8
BP
1164 const struct ovsdb_idl_table_class *class;
1165 size_t column_idx;
1166
cb22974d 1167 ovs_assert(!ovsdb_idl_row_is_synthetic(row));
942d31c8
BP
1168
1169 class = row->table->class;
1170 column_idx = column - class->columns;
8c3c2f30 1171
cb22974d
BP
1172 ovs_assert(row->new != NULL);
1173 ovs_assert(column_idx < class->n_columns);
8c3c2f30
BP
1174
1175 if (row->written && bitmap_is_set(row->written, column_idx)) {
1176 return &row->new[column_idx];
1177 } else if (row->old) {
1178 return &row->old[column_idx];
1179 } else {
1180 return ovsdb_datum_default(&column->type);
1181 }
1182}
1183
1184/* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
1185 * type 'key_type' and value type 'value_type'. (Scalar and set types will
1186 * have a value type of OVSDB_TYPE_VOID.)
1187 *
1188 * This is useful in code that "knows" that a particular column has a given
1189 * type, so that it will abort if someone changes the column's type without
1190 * updating the code that uses it. */
1191const struct ovsdb_datum *
1192ovsdb_idl_get(const struct ovsdb_idl_row *row,
1193 const struct ovsdb_idl_column *column,
1194 enum ovsdb_atomic_type key_type OVS_UNUSED,
1195 enum ovsdb_atomic_type value_type OVS_UNUSED)
1196{
cb22974d
BP
1197 ovs_assert(column->type.key.type == key_type);
1198 ovs_assert(column->type.value.type == value_type);
8c3c2f30
BP
1199
1200 return ovsdb_idl_read(row, column);
1201}
cfea354b 1202
ff495b63
BP
1203/* Returns true if the field represented by 'column' in 'row' may be modified,
1204 * false if it is immutable.
1205 *
1206 * Normally, whether a field is mutable is controlled by its column's schema.
1207 * However, an immutable column can be set to any initial value at the time of
1208 * insertion, so if 'row' is a new row (one that is being added as part of the
1209 * current transaction, supposing that a transaction is in progress) then even
1210 * its "immutable" fields are actually mutable. */
1211bool
1212ovsdb_idl_is_mutable(const struct ovsdb_idl_row *row,
1213 const struct ovsdb_idl_column *column)
1214{
1215 return column->mutable || (row->new && !row->old);
1216}
1217
cfea354b
BP
1218/* Returns false if 'row' was obtained from the IDL, true if it was initialized
1219 * to all-zero-bits by some other entity. If 'row' was set up some other way
1220 * then the return value is indeterminate. */
1221bool
1222ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *row)
1223{
1224 return row->table == NULL;
1225}
475281c0
BP
1226\f
1227/* Transactions. */
1228
1229static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
1230 enum ovsdb_idl_txn_status);
1231
2f926787
BP
1232/* Returns a string representation of 'status'. The caller must not modify or
1233 * free the returned string.
1234 *
1235 * The return value is probably useful only for debug log messages and unit
1236 * tests. */
475281c0
BP
1237const char *
1238ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
1239{
1240 switch (status) {
2096903b
BP
1241 case TXN_UNCOMMITTED:
1242 return "uncommitted";
b54e22e9
BP
1243 case TXN_UNCHANGED:
1244 return "unchanged";
475281c0
BP
1245 case TXN_INCOMPLETE:
1246 return "incomplete";
1247 case TXN_ABORTED:
1248 return "aborted";
1249 case TXN_SUCCESS:
1250 return "success";
854a94d9
BP
1251 case TXN_TRY_AGAIN:
1252 return "try again";
06b6d651
BP
1253 case TXN_NOT_LOCKED:
1254 return "not locked";
475281c0
BP
1255 case TXN_ERROR:
1256 return "error";
1257 }
1258 return "<unknown>";
1259}
1260
2f926787
BP
1261/* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
1262 * active transaction at a time. See the large comment in ovsdb-idl.h for
1263 * general information on transactions. */
475281c0
BP
1264struct ovsdb_idl_txn *
1265ovsdb_idl_txn_create(struct ovsdb_idl *idl)
1266{
1267 struct ovsdb_idl_txn *txn;
1268
cb22974d 1269 ovs_assert(!idl->txn);
475281c0 1270 idl->txn = txn = xmalloc(sizeof *txn);
0196cc15 1271 txn->request_id = NULL;
475281c0 1272 txn->idl = idl;
475281c0 1273 hmap_init(&txn->txn_rows);
2096903b 1274 txn->status = TXN_UNCOMMITTED;
91e310a5 1275 txn->error = NULL;
577aebdf 1276 txn->dry_run = false;
d171b584 1277 ds_init(&txn->comment);
0196cc15 1278
b54e22e9
BP
1279 txn->inc_table = NULL;
1280 txn->inc_column = NULL;
0196cc15 1281
69490970 1282 hmap_init(&txn->inserted_rows);
0196cc15 1283
475281c0
BP
1284 return txn;
1285}
1286
e1c0e2d1
BP
1287/* Appends 's', which is treated as a printf()-type format string, to the
1288 * comments that will be passed to the OVSDB server when 'txn' is committed.
1289 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
1290 * show-log" can print in a relatively human-readable form.) */
d171b584 1291void
e1c0e2d1 1292ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
d171b584 1293{
e1c0e2d1
BP
1294 va_list args;
1295
d171b584
BP
1296 if (txn->comment.length) {
1297 ds_put_char(&txn->comment, '\n');
1298 }
e1c0e2d1
BP
1299
1300 va_start(args, s);
1301 ds_put_format_valist(&txn->comment, s, args);
1302 va_end(args);
d171b584
BP
1303}
1304
2f926787
BP
1305/* Marks 'txn' as a transaction that will not actually modify the database. In
1306 * almost every way, the transaction is treated like other transactions. It
1307 * must be committed or aborted like other transactions, it will be sent to the
1308 * database server like other transactions, and so on. The only difference is
1309 * that the operations sent to the database server will include, as the last
1310 * step, an "abort" operation, so that any changes made by the transaction will
1311 * not actually take effect. */
577aebdf
BP
1312void
1313ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
1314{
1315 txn->dry_run = true;
1316}
1317
94fbe1aa
BP
1318/* Causes 'txn', when committed, to increment the value of 'column' within
1319 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
1320 * successfully, the client may retrieve the final (incremented) value of
1321 * 'column' with ovsdb_idl_txn_get_increment_new_value().
1322 *
1323 * The client could accomplish something similar with ovsdb_idl_read(),
1324 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
1325 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
1326 * will never (by itself) fail because of a verify error.
1327 *
1328 * The intended use is for incrementing the "next_cfg" column in the
1329 * Open_vSwitch table. */
b54e22e9 1330void
94fbe1aa
BP
1331ovsdb_idl_txn_increment(struct ovsdb_idl_txn *txn,
1332 const struct ovsdb_idl_row *row,
1333 const struct ovsdb_idl_column *column)
b54e22e9 1334{
cb22974d
BP
1335 ovs_assert(!txn->inc_table);
1336 ovs_assert(column->type.key.type == OVSDB_TYPE_INTEGER);
1337 ovs_assert(column->type.value.type == OVSDB_TYPE_VOID);
94fbe1aa
BP
1338
1339 txn->inc_table = row->table->class->name;
1340 txn->inc_column = column->name;
1341 txn->inc_row = row->uuid;
b54e22e9
BP
1342}
1343
2f926787
BP
1344/* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
1345 * has been called for 'txn' but the commit is still incomplete (that is, the
1346 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
1347 * end up committing at the database server, but the client will not be able to
1348 * get any further status information back. */
475281c0
BP
1349void
1350ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
1351{
69490970
BP
1352 struct ovsdb_idl_txn_insert *insert, *next;
1353
0196cc15 1354 json_destroy(txn->request_id);
fbd8fd40
BP
1355 if (txn->status == TXN_INCOMPLETE) {
1356 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
1357 }
475281c0 1358 ovsdb_idl_txn_abort(txn);
d171b584 1359 ds_destroy(&txn->comment);
91e310a5 1360 free(txn->error);
4e8e4213 1361 HMAP_FOR_EACH_SAFE (insert, next, hmap_node, &txn->inserted_rows) {
69490970
BP
1362 free(insert);
1363 }
0196cc15 1364 hmap_destroy(&txn->inserted_rows);
475281c0
BP
1365 free(txn);
1366}
1367
2f926787 1368/* Causes poll_block() to wake up if 'txn' has completed committing. */
586bb84a
BP
1369void
1370ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
1371{
2096903b 1372 if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
586bb84a
BP
1373 poll_immediate_wake();
1374 }
1375}
1376
475281c0
BP
1377static struct json *
1378where_uuid_equals(const struct uuid *uuid)
1379{
1380 return
1381 json_array_create_1(
1382 json_array_create_3(
1383 json_string_create("_uuid"),
1384 json_string_create("=="),
1385 json_array_create_2(
1386 json_string_create("uuid"),
1387 json_string_create_nocopy(
1388 xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
1389}
1390
1391static char *
1392uuid_name_from_uuid(const struct uuid *uuid)
1393{
1394 char *name;
1395 char *p;
1396
1397 name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
1398 for (p = name; *p != '\0'; p++) {
1399 if (*p == '-') {
1400 *p = '_';
1401 }
1402 }
1403
1404 return name;
1405}
1406
1407static const struct ovsdb_idl_row *
1408ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
1409{
1410 const struct ovsdb_idl_row *row;
1411
4e8e4213 1412 HMAP_FOR_EACH_WITH_HASH (row, txn_node, uuid_hash(uuid), &txn->txn_rows) {
475281c0
BP
1413 if (uuid_equals(&row->uuid, uuid)) {
1414 return row;
1415 }
1416 }
1417 return NULL;
1418}
1419
1420/* XXX there must be a cleaner way to do this */
1421static struct json *
1422substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
1423{
1424 if (json->type == JSON_ARRAY) {
1425 struct uuid uuid;
1426 size_t i;
1427
1428 if (json->u.array.n == 2
1429 && json->u.array.elems[0]->type == JSON_STRING
1430 && json->u.array.elems[1]->type == JSON_STRING
1431 && !strcmp(json->u.array.elems[0]->u.string, "uuid")
1432 && uuid_from_string(&uuid, json->u.array.elems[1]->u.string)) {
1433 const struct ovsdb_idl_row *row;
1434
1435 row = ovsdb_idl_txn_get_row(txn, &uuid);
1436 if (row && !row->old && row->new) {
1437 json_destroy(json);
1438
1439 return json_array_create_2(
1440 json_string_create("named-uuid"),
1441 json_string_create_nocopy(uuid_name_from_uuid(&uuid)));
1442 }
1443 }
1444
1445 for (i = 0; i < json->u.array.n; i++) {
1446 json->u.array.elems[i] = substitute_uuids(json->u.array.elems[i],
1447 txn);
1448 }
1449 } else if (json->type == JSON_OBJECT) {
1450 struct shash_node *node;
1451
1452 SHASH_FOR_EACH (node, json_object(json)) {
1453 node->data = substitute_uuids(node->data, txn);
1454 }
1455 }
1456 return json;
1457}
1458
1459static void
1460ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
1461{
1462 struct ovsdb_idl_row *row, *next;
1463
979821c0
BP
1464 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
1465 * ovsdb_idl_column's 'parse' function, which will call
1466 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
1467 * transaction and fail to update the graph. */
1468 txn->idl->txn = NULL;
1469
4e8e4213 1470 HMAP_FOR_EACH_SAFE (row, next, txn_node, &txn->txn_rows) {
979821c0
BP
1471 if (row->old) {
1472 if (row->written) {
1473 ovsdb_idl_row_unparse(row);
1474 ovsdb_idl_row_clear_arcs(row, false);
1475 ovsdb_idl_row_parse(row);
1476 }
1477 } else {
0196cc15 1478 ovsdb_idl_row_unparse(row);
8bc915de 1479 }
475281c0
BP
1480 ovsdb_idl_row_clear_new(row);
1481
1482 free(row->prereqs);
1483 row->prereqs = NULL;
1484
1485 free(row->written);
1486 row->written = NULL;
1487
1488 hmap_remove(&txn->txn_rows, &row->txn_node);
1489 hmap_node_nullify(&row->txn_node);
0196cc15
BP
1490 if (!row->old) {
1491 hmap_remove(&row->table->rows, &row->hmap_node);
1492 free(row);
1493 }
475281c0
BP
1494 }
1495 hmap_destroy(&txn->txn_rows);
1496 hmap_init(&txn->txn_rows);
1497}
1498
2f926787
BP
1499/* Attempts to commit 'txn'. Returns the status of the commit operation, one
1500 * of the following TXN_* constants:
1501 *
1502 * TXN_INCOMPLETE:
1503 *
1504 * The transaction is in progress, but not yet complete. The caller
1505 * should call again later, after calling ovsdb_idl_run() to let the IDL
1506 * do OVSDB protocol processing.
1507 *
1508 * TXN_UNCHANGED:
1509 *
1510 * The transaction is complete. (It didn't actually change the database,
1511 * so the IDL didn't send any request to the database server.)
1512 *
1513 * TXN_ABORTED:
1514 *
1515 * The caller previously called ovsdb_idl_txn_abort().
1516 *
1517 * TXN_SUCCESS:
1518 *
1519 * The transaction was successful. The update made by the transaction
1520 * (and possibly other changes made by other database clients) should
1521 * already be visible in the IDL.
1522 *
1523 * TXN_TRY_AGAIN:
1524 *
1525 * The transaction failed for some transient reason, e.g. because a
1526 * "verify" operation reported an inconsistency or due to a network
1527 * problem. The caller should wait for a change to the database, then
1528 * compose a new transaction, and commit the new transaction.
1529 *
1530 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
1531 * the database. It is important to use its return value *before* the
1532 * initial call to ovsdb_idl_txn_commit() as the baseline for this
1533 * purpose, because the change that one should wait for can happen after
1534 * the initial call but before the call that returns TXN_TRY_AGAIN, and
1535 * using some other baseline value in that situation could cause an
1536 * indefinite wait if the database rarely changes.
1537 *
1538 * TXN_NOT_LOCKED:
1539 *
1540 * The transaction failed because the IDL has been configured to require
1541 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
1542 * has already lost it.
1543 *
1544 * Committing a transaction rolls back all of the changes that it made to the
1545 * IDL's copy of the database. If the transaction commits successfully, then
1546 * the database server will send an update and, thus, the IDL will be updated
1547 * with the committed changes. */
475281c0
BP
1548enum ovsdb_idl_txn_status
1549ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
1550{
1551 struct ovsdb_idl_row *row;
1552 struct json *operations;
1553 bool any_updates;
475281c0
BP
1554
1555 if (txn != txn->idl->txn) {
60032110 1556 goto coverage_out;
475281c0
BP
1557 }
1558
06b6d651
BP
1559 /* If we need a lock but don't have it, give up quickly. */
1560 if (txn->idl->lock_name && !ovsdb_idl_has_lock(txn->idl)) {
1561 txn->status = TXN_NOT_LOCKED;
60032110 1562 goto disassemble_out;
06b6d651
BP
1563 }
1564
9cb53f26
BP
1565 operations = json_array_create_1(
1566 json_string_create(txn->idl->class->database));
475281c0 1567
06b6d651
BP
1568 /* Assert that we have the required lock (avoiding a race). */
1569 if (txn->idl->lock_name) {
1570 struct json *op = json_object_create();
1571 json_array_add(operations, op);
1572 json_object_put_string(op, "op", "assert");
1573 json_object_put_string(op, "lock", txn->idl->lock_name);
1574 }
1575
475281c0 1576 /* Add prerequisites and declarations of new rows. */
4e8e4213 1577 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
475281c0
BP
1578 /* XXX check that deleted rows exist even if no prereqs? */
1579 if (row->prereqs) {
1580 const struct ovsdb_idl_table_class *class = row->table->class;
1581 size_t n_columns = class->n_columns;
1582 struct json *op, *columns, *row_json;
1583 size_t idx;
1584
1585 op = json_object_create();
1586 json_array_add(operations, op);
1587 json_object_put_string(op, "op", "wait");
1588 json_object_put_string(op, "table", class->name);
1589 json_object_put(op, "timeout", json_integer_create(0));
1590 json_object_put(op, "where", where_uuid_equals(&row->uuid));
1591 json_object_put_string(op, "until", "==");
1592 columns = json_array_create_empty();
1593 json_object_put(op, "columns", columns);
1594 row_json = json_object_create();
1595 json_object_put(op, "rows", json_array_create_1(row_json));
1596
1597 BITMAP_FOR_EACH_1 (idx, n_columns, row->prereqs) {
1598 const struct ovsdb_idl_column *column = &class->columns[idx];
1599 json_array_add(columns, json_string_create(column->name));
1600 json_object_put(row_json, column->name,
1601 ovsdb_datum_to_json(&row->old[idx],
1602 &column->type));
1603 }
1604 }
475281c0
BP
1605 }
1606
1607 /* Add updates. */
1608 any_updates = false;
4e8e4213 1609 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
475281c0 1610 const struct ovsdb_idl_table_class *class = row->table->class;
475281c0 1611
d95d1510 1612 if (!row->new) {
dcd1dbc5
BP
1613 if (class->is_root) {
1614 struct json *op = json_object_create();
1615 json_object_put_string(op, "op", "delete");
1616 json_object_put_string(op, "table", class->name);
1617 json_object_put(op, "where", where_uuid_equals(&row->uuid));
1618 json_array_add(operations, op);
1619 any_updates = true;
1620 } else {
1621 /* Let ovsdb-server decide whether to really delete it. */
1622 }
d95d1510 1623 } else if (row->old != row->new) {
f0f54cb4
BP
1624 struct json *row_json;
1625 struct json *op;
1626 size_t idx;
1627
1628 op = json_object_create();
1629 json_object_put_string(op, "op", row->old ? "update" : "insert");
1630 json_object_put_string(op, "table", class->name);
1631 if (row->old) {
1632 json_object_put(op, "where", where_uuid_equals(&row->uuid));
1633 } else {
69490970
BP
1634 struct ovsdb_idl_txn_insert *insert;
1635
c15f1d11
BP
1636 any_updates = true;
1637
f0f54cb4
BP
1638 json_object_put(op, "uuid-name",
1639 json_string_create_nocopy(
1640 uuid_name_from_uuid(&row->uuid)));
69490970
BP
1641
1642 insert = xmalloc(sizeof *insert);
1643 insert->dummy = row->uuid;
9cb53f26 1644 insert->op_index = operations->u.array.n - 1;
69490970
BP
1645 uuid_zero(&insert->real);
1646 hmap_insert(&txn->inserted_rows, &insert->hmap_node,
1647 uuid_hash(&insert->dummy));
f0f54cb4
BP
1648 }
1649 row_json = json_object_create();
1650 json_object_put(op, "row", row_json);
1651
35c2ce98
JG
1652 if (row->written) {
1653 BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
1654 const struct ovsdb_idl_column *column =
1655 &class->columns[idx];
1656
1657 if (row->old
1cc618c3 1658 || !ovsdb_datum_is_default(&row->new[idx],
35c2ce98
JG
1659 &column->type)) {
1660 json_object_put(row_json, column->name,
1661 substitute_uuids(
1662 ovsdb_datum_to_json(&row->new[idx],
1663 &column->type),
1664 txn));
c15f1d11
BP
1665
1666 /* If anything really changed, consider it an update.
1667 * We can't suppress not-really-changed values earlier
1668 * or transactions would become nonatomic (see the big
1669 * comment inside ovsdb_idl_txn_write()). */
1670 if (!any_updates && row->old &&
1671 !ovsdb_datum_equals(&row->old[idx], &row->new[idx],
1672 &column->type)) {
1673 any_updates = true;
1674 }
35c2ce98 1675 }
475281c0 1676 }
f0f54cb4
BP
1677 }
1678
1679 if (!row->old || !shash_is_empty(json_object(row_json))) {
1680 json_array_add(operations, op);
f0f54cb4
BP
1681 } else {
1682 json_destroy(op);
475281c0
BP
1683 }
1684 }
1685 }
1686
b54e22e9
BP
1687 /* Add increment. */
1688 if (txn->inc_table && any_updates) {
1689 struct json *op;
1690
9cb53f26 1691 txn->inc_index = operations->u.array.n - 1;
b54e22e9
BP
1692
1693 op = json_object_create();
1694 json_object_put_string(op, "op", "mutate");
1695 json_object_put_string(op, "table", txn->inc_table);
1696 json_object_put(op, "where",
94fbe1aa
BP
1697 substitute_uuids(where_uuid_equals(&txn->inc_row),
1698 txn));
b54e22e9
BP
1699 json_object_put(op, "mutations",
1700 json_array_create_1(
1701 json_array_create_3(
1702 json_string_create(txn->inc_column),
1703 json_string_create("+="),
1704 json_integer_create(1))));
1705 json_array_add(operations, op);
1706
1707 op = json_object_create();
1708 json_object_put_string(op, "op", "select");
1709 json_object_put_string(op, "table", txn->inc_table);
1710 json_object_put(op, "where",
94fbe1aa
BP
1711 substitute_uuids(where_uuid_equals(&txn->inc_row),
1712 txn));
b54e22e9
BP
1713 json_object_put(op, "columns",
1714 json_array_create_1(json_string_create(
1715 txn->inc_column)));
1716 json_array_add(operations, op);
1717 }
1718
d171b584
BP
1719 if (txn->comment.length) {
1720 struct json *op = json_object_create();
1721 json_object_put_string(op, "op", "comment");
1722 json_object_put_string(op, "comment", ds_cstr(&txn->comment));
1723 json_array_add(operations, op);
1724 }
1725
577aebdf
BP
1726 if (txn->dry_run) {
1727 struct json *op = json_object_create();
1728 json_object_put_string(op, "op", "abort");
1729 json_array_add(operations, op);
1730 }
1731
72c6edc5 1732 if (!any_updates) {
b54e22e9 1733 txn->status = TXN_UNCHANGED;
2f3ca7ea 1734 json_destroy(operations);
72c6edc5
BP
1735 } else if (!jsonrpc_session_send(
1736 txn->idl->session,
1737 jsonrpc_create_request(
1738 "transact", operations, &txn->request_id))) {
1739 hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
1740 json_hash(txn->request_id, 0));
2096903b 1741 txn->status = TXN_INCOMPLETE;
72c6edc5 1742 } else {
854a94d9 1743 txn->status = TXN_TRY_AGAIN;
72c6edc5 1744 }
475281c0 1745
60032110 1746disassemble_out:
475281c0 1747 ovsdb_idl_txn_disassemble(txn);
60032110
RW
1748coverage_out:
1749 switch (txn->status) {
1750 case TXN_UNCOMMITTED: COVERAGE_INC(txn_uncommitted); break;
1751 case TXN_UNCHANGED: COVERAGE_INC(txn_unchanged); break;
1752 case TXN_INCOMPLETE: COVERAGE_INC(txn_incomplete); break;
1753 case TXN_ABORTED: COVERAGE_INC(txn_aborted); break;
1754 case TXN_SUCCESS: COVERAGE_INC(txn_success); break;
1755 case TXN_TRY_AGAIN: COVERAGE_INC(txn_try_again); break;
1756 case TXN_NOT_LOCKED: COVERAGE_INC(txn_not_locked); break;
1757 case TXN_ERROR: COVERAGE_INC(txn_error); break;
1758 }
1759
475281c0
BP
1760 return txn->status;
1761}
1762
af96ccd2
BP
1763/* Attempts to commit 'txn', blocking until the commit either succeeds or
1764 * fails. Returns the final commit status, which may be any TXN_* value other
2f926787
BP
1765 * than TXN_INCOMPLETE.
1766 *
1767 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
1768 * return value of ovsdb_idl_get_seqno() to change. */
af96ccd2
BP
1769enum ovsdb_idl_txn_status
1770ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
1771{
1772 enum ovsdb_idl_txn_status status;
1773
b302749b 1774 fatal_signal_run();
af96ccd2
BP
1775 while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
1776 ovsdb_idl_run(txn->idl);
1777 ovsdb_idl_wait(txn->idl);
1778 ovsdb_idl_txn_wait(txn);
1779 poll_block();
1780 }
1781 return status;
1782}
1783
2f926787
BP
1784/* Returns the final (incremented) value of the column in 'txn' that was set to
1785 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
1786 * successfully. */
b54e22e9
BP
1787int64_t
1788ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
1789{
cb22974d 1790 ovs_assert(txn->status == TXN_SUCCESS);
b54e22e9
BP
1791 return txn->inc_new_value;
1792}
1793
2f926787
BP
1794/* Aborts 'txn' without sending it to the database server. This is effective
1795 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
1796 * Otherwise, it has no effect.
1797 *
1798 * Aborting a transaction doesn't free its memory. Use
1799 * ovsdb_idl_txn_destroy() to do that. */
475281c0
BP
1800void
1801ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
1802{
1803 ovsdb_idl_txn_disassemble(txn);
2096903b 1804 if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
475281c0
BP
1805 txn->status = TXN_ABORTED;
1806 }
1807}
1808
2f926787
BP
1809/* Returns a string that reports the error status for 'txn'. The caller must
1810 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
1811 * for 'txn' may free the returned string.
1812 *
1813 * The return value is ordinarily one of the strings that
1814 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
1815 * due to an error reported by the database server, the return value is that
1816 * error. */
91e310a5
BP
1817const char *
1818ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
1819{
1820 if (txn->status != TXN_ERROR) {
1821 return ovsdb_idl_txn_status_to_string(txn->status);
1822 } else if (txn->error) {
1823 return txn->error;
1824 } else {
1825 return "no error details available";
1826 }
1827}
1828
1829static void
1830ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
1831 const struct json *json)
1832{
1833 if (txn->error == NULL) {
1834 txn->error = json_to_string(json, JSSF_SORT);
1835 }
1836}
1837
69490970
BP
1838/* For transaction 'txn' that completed successfully, finds and returns the
1839 * permanent UUID that the database assigned to a newly inserted row, given the
1840 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
1841 *
1842 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
1843 * if it was assigned by that function and then deleted by
1844 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
1845 * and then deleted within a single transaction are never sent to the database
1846 * server, so it never assigns them a permanent UUID.) */
1847const struct uuid *
1848ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *txn,
1849 const struct uuid *uuid)
1850{
1851 const struct ovsdb_idl_txn_insert *insert;
1852
cb22974d 1853 ovs_assert(txn->status == TXN_SUCCESS || txn->status == TXN_UNCHANGED);
4e8e4213 1854 HMAP_FOR_EACH_IN_BUCKET (insert, hmap_node,
69490970
BP
1855 uuid_hash(uuid), &txn->inserted_rows) {
1856 if (uuid_equals(uuid, &insert->dummy)) {
1857 return &insert->real;
1858 }
1859 }
1860 return NULL;
1861}
1862
475281c0
BP
1863static void
1864ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
1865 enum ovsdb_idl_txn_status status)
1866{
1867 txn->status = status;
1868 hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
1869}
1870
b827c67b
BP
1871/* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
1872 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
1873 * ovs-vswitchd).
1874 *
1875 * 'datum' must have the correct type for its column. The IDL does not check
1876 * that it meets schema constraints, but ovsdb-server will do so at commit time
1877 * so it had better be correct.
1878 *
1879 * A transaction must be in progress. Replication of 'column' must not have
1880 * been disabled (by calling ovsdb_idl_omit()).
1881 *
1882 * Usually this function is used indirectly through one of the "set" functions
27a32516
BP
1883 * generated by ovsdb-idlc.
1884 *
1885 * Takes ownership of what 'datum' points to (and in some cases destroys that
1886 * data before returning) but makes a copy of 'datum' itself. (Commonly
1887 * 'datum' is on the caller's stack.) */
fe19569a
BP
1888static void
1889ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
1890 const struct ovsdb_idl_column *column,
1891 struct ovsdb_datum *datum, bool owns_datum)
475281c0 1892{
ebc56baa 1893 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
9b446bfa
BP
1894 const struct ovsdb_idl_table_class *class;
1895 size_t column_idx;
8cdec725 1896 bool write_only;
9b446bfa
BP
1897
1898 if (ovsdb_idl_row_is_synthetic(row)) {
fe19569a 1899 goto discard_datum;
9b446bfa
BP
1900 }
1901
1902 class = row->table->class;
1903 column_idx = column - class->columns;
8cdec725 1904 write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
475281c0 1905
cb22974d
BP
1906 ovs_assert(row->new != NULL);
1907 ovs_assert(column_idx < class->n_columns);
1908 ovs_assert(row->old == NULL ||
1909 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
c547535a 1910
8cdec725
EJ
1911 if (row->table->idl->verify_write_only && !write_only) {
1912 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
1913 " explicitly configured not to.", class->name, column->name);
fe19569a 1914 goto discard_datum;
8cdec725
EJ
1915 }
1916
1cc618c3
BP
1917 /* If this is a write-only column and the datum being written is the same
1918 * as the one already there, just skip the update entirely. This is worth
1919 * optimizing because we have a lot of columns that get periodically
1920 * refreshed into the database but don't actually change that often.
1921 *
1922 * We don't do this for read/write columns because that would break
1923 * atomicity of transactions--some other client might have written a
c15f1d11
BP
1924 * different value in that column since we read it. (But if a whole
1925 * transaction only does writes of existing values, without making any real
1926 * changes, we will drop the whole transaction later in
1927 * ovsdb_idl_txn_commit().) */
8cdec725
EJ
1928 if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
1929 datum, &column->type)) {
fe19569a 1930 goto discard_datum;
1cc618c3
BP
1931 }
1932
475281c0
BP
1933 if (hmap_node_is_null(&row->txn_node)) {
1934 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
1935 uuid_hash(&row->uuid));
1936 }
1937 if (row->old == row->new) {
1938 row->new = xmalloc(class->n_columns * sizeof *row->new);
1939 }
1940 if (!row->written) {
1941 row->written = bitmap_allocate(class->n_columns);
1942 }
1943 if (bitmap_is_set(row->written, column_idx)) {
1944 ovsdb_datum_destroy(&row->new[column_idx], &column->type);
1945 } else {
1946 bitmap_set1(row->written, column_idx);
1947 }
fe19569a
BP
1948 if (owns_datum) {
1949 row->new[column_idx] = *datum;
1950 } else {
1951 ovsdb_datum_clone(&row->new[column_idx], datum, &column->type);
1952 }
979821c0
BP
1953 (column->unparse)(row);
1954 (column->parse)(row, &row->new[column_idx]);
fe19569a
BP
1955 return;
1956
1957discard_datum:
1958 if (owns_datum) {
1959 ovsdb_datum_destroy(datum, &column->type);
1960 }
1961}
1962
1963void
1964ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
1965 const struct ovsdb_idl_column *column,
1966 struct ovsdb_datum *datum)
1967{
1968 ovsdb_idl_txn_write__(row, column, datum, true);
1969}
1970
1971void
1972ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
1973 const struct ovsdb_idl_column *column,
1974 const struct ovsdb_datum *datum)
1975{
1976 ovsdb_idl_txn_write__(row, column,
1977 CONST_CAST(struct ovsdb_datum *, datum), false);
475281c0
BP
1978}
1979
b827c67b
BP
1980/* Causes the original contents of 'column' in 'row_' to be verified as a
1981 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
1982 * changed (or if 'row_' was deleted) between the time that the IDL originally
1983 * read its contents and the time that the transaction commits, then the
4fdfe5cc
BP
1984 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_AGAIN_WAIT or
1985 * TXN_AGAIN_NOW (depending on whether the database change has already been
1986 * received).
b827c67b
BP
1987 *
1988 * The intention is that, to ensure that no transaction commits based on dirty
1989 * reads, an application should call ovsdb_idl_txn_verify() on each data item
1990 * read as part of a read-modify-write operation.
1991 *
1992 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
1993 * value of 'column' is already known:
1994 *
1995 * - If 'row_' is a row created by the current transaction (returned by
1996 * ovsdb_idl_txn_insert()).
1997 *
1998 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
1999 * within the current transaction.
2000 *
2001 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
2002 * ovsdb_idl_txn_write() for a given read-modify-write.
2003 *
2004 * A transaction must be in progress.
2005 *
2006 * Usually this function is used indirectly through one of the "verify"
2007 * functions generated by ovsdb-idlc. */
475281c0
BP
2008void
2009ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
2010 const struct ovsdb_idl_column *column)
2011{
ebc56baa 2012 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
9b446bfa
BP
2013 const struct ovsdb_idl_table_class *class;
2014 size_t column_idx;
2015
2016 if (ovsdb_idl_row_is_synthetic(row)) {
2017 return;
2018 }
2019
2020 class = row->table->class;
2021 column_idx = column - class->columns;
475281c0 2022
cb22974d
BP
2023 ovs_assert(row->new != NULL);
2024 ovs_assert(row->old == NULL ||
2025 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
475281c0
BP
2026 if (!row->old
2027 || (row->written && bitmap_is_set(row->written, column_idx))) {
2028 return;
2029 }
2030
2031 if (hmap_node_is_null(&row->txn_node)) {
2032 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
2033 uuid_hash(&row->uuid));
2034 }
2035 if (!row->prereqs) {
2036 row->prereqs = bitmap_allocate(class->n_columns);
2037 }
2038 bitmap_set1(row->prereqs, column_idx);
2039}
2040
b827c67b
BP
2041/* Deletes 'row_' from its table. May free 'row_', so it must not be
2042 * accessed afterward.
2043 *
2044 * A transaction must be in progress.
2045 *
2046 * Usually this function is used indirectly through one of the "delete"
2047 * functions generated by ovsdb-idlc. */
475281c0 2048void
9e336f49 2049ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
475281c0 2050{
ebc56baa 2051 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
9e336f49 2052
9b446bfa
BP
2053 if (ovsdb_idl_row_is_synthetic(row)) {
2054 return;
2055 }
2056
cb22974d 2057 ovs_assert(row->new != NULL);
475281c0 2058 if (!row->old) {
0196cc15 2059 ovsdb_idl_row_unparse(row);
475281c0 2060 ovsdb_idl_row_clear_new(row);
cb22974d 2061 ovs_assert(!row->prereqs);
979821c0 2062 hmap_remove(&row->table->rows, &row->hmap_node);
475281c0
BP
2063 hmap_remove(&row->table->idl->txn->txn_rows, &row->txn_node);
2064 free(row);
c7f7adb7 2065 return;
475281c0
BP
2066 }
2067 if (hmap_node_is_null(&row->txn_node)) {
2068 hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
2069 uuid_hash(&row->uuid));
2070 }
1ebeed63
BP
2071 ovsdb_idl_row_clear_new(row);
2072 row->new = NULL;
475281c0
BP
2073}
2074
b827c67b
BP
2075/* Inserts and returns a new row in the table with the specified 'class' in the
2076 * database with open transaction 'txn'.
2077 *
2078 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
2079 * randomly generated; otherwise 'uuid' should specify a randomly generated
2080 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
2081 * 'txn' is committed, but the IDL will replace any uses of the provisional
2082 * UUID in the data to be to be committed by the UUID assigned by
2083 * ovsdb-server.
2084 *
2085 * Usually this function is used indirectly through one of the "insert"
2086 * functions generated by ovsdb-idlc. */
9e336f49 2087const struct ovsdb_idl_row *
475281c0 2088ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
ce5a3e38
BP
2089 const struct ovsdb_idl_table_class *class,
2090 const struct uuid *uuid)
475281c0
BP
2091{
2092 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);
ce5a3e38
BP
2093
2094 if (uuid) {
cb22974d 2095 ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
ce5a3e38
BP
2096 row->uuid = *uuid;
2097 } else {
2098 uuid_generate(&row->uuid);
2099 }
2100
475281c0
BP
2101 row->table = ovsdb_idl_table_from_class(txn->idl, class);
2102 row->new = xmalloc(class->n_columns * sizeof *row->new);
979821c0 2103 hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
475281c0
BP
2104 hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
2105 return row;
2106}
2107
2108static void
2109ovsdb_idl_txn_abort_all(struct ovsdb_idl *idl)
2110{
2111 struct ovsdb_idl_txn *txn;
2112
4e8e4213 2113 HMAP_FOR_EACH (txn, hmap_node, &idl->outstanding_txns) {
854a94d9 2114 ovsdb_idl_txn_complete(txn, TXN_TRY_AGAIN);
475281c0
BP
2115 }
2116}
2117
2118static struct ovsdb_idl_txn *
2119ovsdb_idl_txn_find(struct ovsdb_idl *idl, const struct json *id)
2120{
2121 struct ovsdb_idl_txn *txn;
2122
4e8e4213 2123 HMAP_FOR_EACH_WITH_HASH (txn, hmap_node,
475281c0
BP
2124 json_hash(id, 0), &idl->outstanding_txns) {
2125 if (json_equal(id, txn->request_id)) {
2126 return txn;
2127 }
2128 }
2129 return NULL;
2130}
2131
b54e22e9
BP
2132static bool
2133check_json_type(const struct json *json, enum json_type type, const char *name)
2134{
2135 if (!json) {
2136 VLOG_WARN_RL(&syntax_rl, "%s is missing", name);
2137 return false;
2138 } else if (json->type != type) {
2139 VLOG_WARN_RL(&syntax_rl, "%s is %s instead of %s",
2140 name, json_type_to_string(json->type),
2141 json_type_to_string(type));
2142 return false;
2143 } else {
2144 return true;
2145 }
2146}
2147
2148static bool
2149ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
2150 const struct json_array *results)
2151{
2152 struct json *count, *rows, *row, *column;
2153 struct shash *mutate, *select;
2154
2155 if (txn->inc_index + 2 > results->n) {
2156 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
34582733 2157 "for increment (has %"PRIuSIZE", needs %u)",
b54e22e9
BP
2158 results->n, txn->inc_index + 2);
2159 return false;
2160 }
2161
69490970 2162 /* We know that this is a JSON object because the loop in
b54e22e9
BP
2163 * ovsdb_idl_txn_process_reply() checked. */
2164 mutate = json_object(results->elems[txn->inc_index]);
2165 count = shash_find_data(mutate, "count");
2166 if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) {
2167 return false;
2168 }
2169 if (count->u.integer != 1) {
2170 VLOG_WARN_RL(&syntax_rl,
6fce4487 2171 "\"mutate\" reply \"count\" is %lld instead of 1",
b54e22e9
BP
2172 count->u.integer);
2173 return false;
2174 }
2175
2176 select = json_object(results->elems[txn->inc_index + 1]);
2177 rows = shash_find_data(select, "rows");
2178 if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) {
2179 return false;
2180 }
2181 if (rows->u.array.n != 1) {
34582733 2182 VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
b54e22e9
BP
2183 "instead of 1",
2184 rows->u.array.n);
2185 return false;
2186 }
2187 row = rows->u.array.elems[0];
2188 if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) {
2189 return false;
2190 }
2191 column = shash_find_data(json_object(row), txn->inc_column);
2192 if (!check_json_type(column, JSON_INTEGER,
2193 "\"select\" reply inc column")) {
2194 return false;
2195 }
2196 txn->inc_new_value = column->u.integer;
2197 return true;
2198}
2199
69490970
BP
2200static bool
2201ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
2202 const struct json_array *results)
2203{
bd76d25d 2204 static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT;
69490970
BP
2205 struct ovsdb_error *error;
2206 struct json *json_uuid;
2207 union ovsdb_atom uuid;
2208 struct shash *reply;
2209
2210 if (insert->op_index >= results->n) {
2211 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
34582733 2212 "for insert (has %"PRIuSIZE", needs %u)",
69490970
BP
2213 results->n, insert->op_index);
2214 return false;
2215 }
2216
2217 /* We know that this is a JSON object because the loop in
2218 * ovsdb_idl_txn_process_reply() checked. */
2219 reply = json_object(results->elems[insert->op_index]);
2220 json_uuid = shash_find_data(reply, "uuid");
2221 if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) {
2222 return false;
2223 }
2224
bd76d25d 2225 error = ovsdb_atom_from_json(&uuid, &uuid_type, json_uuid, NULL);
69490970
BP
2226 if (error) {
2227 char *s = ovsdb_error_to_string(error);
2228 VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
2229 "UUID: %s", s);
2230 free(s);
9582c4f5 2231 ovsdb_error_destroy(error);
69490970
BP
2232 return false;
2233 }
2234
2235 insert->real = uuid.uuid;
2236
2237 return true;
2238}
b54e22e9 2239
475281c0
BP
2240static bool
2241ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
2242 const struct jsonrpc_msg *msg)
2243{
2244 struct ovsdb_idl_txn *txn;
2245 enum ovsdb_idl_txn_status status;
2246
2247 txn = ovsdb_idl_txn_find(idl, msg->id);
2248 if (!txn) {
2249 return false;
2250 }
2251
2252 if (msg->type == JSONRPC_ERROR) {
2253 status = TXN_ERROR;
2254 } else if (msg->result->type != JSON_ARRAY) {
2255 VLOG_WARN_RL(&syntax_rl, "reply to \"transact\" is not JSON array");
2256 status = TXN_ERROR;
2257 } else {
69490970 2258 struct json_array *ops = &msg->result->u.array;
475281c0
BP
2259 int hard_errors = 0;
2260 int soft_errors = 0;
06b6d651 2261 int lock_errors = 0;
475281c0
BP
2262 size_t i;
2263
69490970
BP
2264 for (i = 0; i < ops->n; i++) {
2265 struct json *op = ops->elems[i];
475281c0 2266
69490970 2267 if (op->type == JSON_NULL) {
475281c0
BP
2268 /* This isn't an error in itself but indicates that some prior
2269 * operation failed, so make sure that we know about it. */
2270 soft_errors++;
69490970 2271 } else if (op->type == JSON_OBJECT) {
475281c0
BP
2272 struct json *error;
2273
69490970 2274 error = shash_find_data(json_object(op), "error");
475281c0
BP
2275 if (error) {
2276 if (error->type == JSON_STRING) {
2277 if (!strcmp(error->u.string, "timed out")) {
2278 soft_errors++;
06b6d651
BP
2279 } else if (!strcmp(error->u.string, "not owner")) {
2280 lock_errors++;
577aebdf 2281 } else if (strcmp(error->u.string, "aborted")) {
475281c0 2282 hard_errors++;
91e310a5 2283 ovsdb_idl_txn_set_error_json(txn, op);
475281c0
BP
2284 }
2285 } else {
2286 hard_errors++;
91e310a5 2287 ovsdb_idl_txn_set_error_json(txn, op);
475281c0
BP
2288 VLOG_WARN_RL(&syntax_rl,
2289 "\"error\" in reply is not JSON string");
2290 }
2291 }
2292 } else {
2293 hard_errors++;
91e310a5 2294 ovsdb_idl_txn_set_error_json(txn, op);
475281c0
BP
2295 VLOG_WARN_RL(&syntax_rl,
2296 "operation reply is not JSON null or object");
2297 }
2298 }
2299
06b6d651 2300 if (!soft_errors && !hard_errors && !lock_errors) {
69490970
BP
2301 struct ovsdb_idl_txn_insert *insert;
2302
2303 if (txn->inc_table && !ovsdb_idl_txn_process_inc_reply(txn, ops)) {
2304 hard_errors++;
2305 }
2306
4e8e4213 2307 HMAP_FOR_EACH (insert, hmap_node, &txn->inserted_rows) {
69490970
BP
2308 if (!ovsdb_idl_txn_process_insert_reply(insert, ops)) {
2309 hard_errors++;
2310 }
2311 }
b54e22e9
BP
2312 }
2313
475281c0 2314 status = (hard_errors ? TXN_ERROR
06b6d651 2315 : lock_errors ? TXN_NOT_LOCKED
854a94d9 2316 : soft_errors ? TXN_TRY_AGAIN
475281c0
BP
2317 : TXN_SUCCESS);
2318 }
2319
2320 ovsdb_idl_txn_complete(txn, status);
2321 return true;
2322}
76c91af9 2323
2f926787
BP
2324/* Returns the transaction currently active for 'row''s IDL. A transaction
2325 * must currently be active. */
76c91af9
BP
2326struct ovsdb_idl_txn *
2327ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
2328{
2329 struct ovsdb_idl_txn *txn = row->table->idl->txn;
cb22974d 2330 ovs_assert(txn != NULL);
76c91af9
BP
2331 return txn;
2332}
1e86ae6f 2333
2f926787 2334/* Returns the IDL on which 'txn' acts. */
1e86ae6f
BP
2335struct ovsdb_idl *
2336ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
2337{
2338 return txn->idl;
2339}
06b6d651
BP
2340\f
2341/* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
2342 * the database server and to avoid modifying the database when the lock cannot
2343 * be acquired (that is, when another client has the same lock).
2344 *
2345 * If 'lock_name' is NULL, drops the locking requirement and releases the
2346 * lock. */
2347void
2348ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
2349{
cb22974d
BP
2350 ovs_assert(!idl->txn);
2351 ovs_assert(hmap_is_empty(&idl->outstanding_txns));
06b6d651
BP
2352
2353 if (idl->lock_name && (!lock_name || strcmp(lock_name, idl->lock_name))) {
2354 /* Release previous lock. */
2355 ovsdb_idl_send_unlock_request(idl);
2356 free(idl->lock_name);
2357 idl->lock_name = NULL;
2358 idl->is_lock_contended = false;
2359 }
2360
2361 if (lock_name && !idl->lock_name) {
2362 /* Acquire new lock. */
2363 idl->lock_name = xstrdup(lock_name);
2364 ovsdb_idl_send_lock_request(idl);
2365 }
2366}
2367
2368/* Returns true if 'idl' is configured to obtain a lock and owns that lock.
2369 *
2370 * Locking and unlocking happens asynchronously from the database client's
2371 * point of view, so the information is only useful for optimization (e.g. if
2372 * the client doesn't have the lock then there's no point in trying to write to
2373 * the database). */
2374bool
2375ovsdb_idl_has_lock(const struct ovsdb_idl *idl)
2376{
2377 return idl->has_lock;
2378}
2379
2380/* Returns true if 'idl' is configured to obtain a lock but the database server
2381 * has indicated that some other client already owns the requested lock. */
2382bool
2383ovsdb_idl_is_lock_contended(const struct ovsdb_idl *idl)
2384{
2385 return idl->is_lock_contended;
2386}
2387
2388static void
2389ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock)
2390{
2391 if (new_has_lock && !idl->has_lock) {
2392 if (!idl->monitor_request_id) {
2393 idl->change_seqno++;
2394 } else {
2395 /* We're waiting for a monitor reply, so don't signal that the
2396 * database changed. The monitor reply will increment change_seqno
2397 * anyhow. */
2398 }
2399 idl->is_lock_contended = false;
2400 }
2401 idl->has_lock = new_has_lock;
2402}
2403
2404static void
2405ovsdb_idl_send_lock_request__(struct ovsdb_idl *idl, const char *method,
2406 struct json **idp)
2407{
2408 ovsdb_idl_update_has_lock(idl, false);
2409
2410 json_destroy(idl->lock_request_id);
2411 idl->lock_request_id = NULL;
2412
2413 if (jsonrpc_session_is_connected(idl->session)) {
2414 struct json *params;
2415
2416 params = json_array_create_1(json_string_create(idl->lock_name));
2417 jsonrpc_session_send(idl->session,
2418 jsonrpc_create_request(method, params, idp));
2419 }
2420}
1e86ae6f 2421
06b6d651
BP
2422static void
2423ovsdb_idl_send_lock_request(struct ovsdb_idl *idl)
2424{
2425 ovsdb_idl_send_lock_request__(idl, "lock", &idl->lock_request_id);
2426}
2427
2428static void
2429ovsdb_idl_send_unlock_request(struct ovsdb_idl *idl)
2430{
2431 ovsdb_idl_send_lock_request__(idl, "unlock", NULL);
2432}
2433
2434static void
2435ovsdb_idl_parse_lock_reply(struct ovsdb_idl *idl, const struct json *result)
2436{
2437 bool got_lock;
2438
2439 json_destroy(idl->lock_request_id);
2440 idl->lock_request_id = NULL;
2441
2442 if (result->type == JSON_OBJECT) {
2443 const struct json *locked;
2444
2445 locked = shash_find_data(json_object(result), "locked");
2446 got_lock = locked && locked->type == JSON_TRUE;
2447 } else {
2448 got_lock = false;
2449 }
2450
2451 ovsdb_idl_update_has_lock(idl, got_lock);
2452 if (!got_lock) {
2453 idl->is_lock_contended = true;
2454 }
2455}
2456
2457static void
2458ovsdb_idl_parse_lock_notify(struct ovsdb_idl *idl,
2459 const struct json *params,
2460 bool new_has_lock)
2461{
2462 if (idl->lock_name
2463 && params->type == JSON_ARRAY
2464 && json_array(params)->n > 0
2465 && json_array(params)->elems[0]->type == JSON_STRING) {
2466 const char *lock_name = json_string(json_array(params)->elems[0]);
2467
2468 if (!strcmp(idl->lock_name, lock_name)) {
2469 ovsdb_idl_update_has_lock(idl, new_has_lock);
2470 if (!new_has_lock) {
2471 idl->is_lock_contended = true;
2472 }
2473 }
2474 }
2475}