1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "ovsdb-idl.h"
27 #include "openvswitch/dynamic-string.h"
28 #include "fatal-signal.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"
41 #include "openvswitch/vlog.h"
43 VLOG_DEFINE_THIS_MODULE(ovsdb_idl
);
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
);
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
58 * Arcs from a row to itself are omitted, that is, src and dst are always
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.
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.
68 * The source and destination row may be in the same table or in different
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. */
78 enum ovsdb_idl_state
{
79 IDL_S_SCHEMA_REQUESTED
,
80 IDL_S_MONITOR_REQUESTED
,
82 IDL_S_MONITOR2_REQUESTED
,
88 const struct ovsdb_idl_class
*class;
89 struct jsonrpc_session
*session
;
90 struct shash table_by_name
;
91 struct ovsdb_idl_table
*tables
; /* Contains "struct ovsdb_idl_table *"s.*/
92 unsigned int change_seqno
;
93 bool verify_write_only
;
96 unsigned int state_seqno
;
97 enum ovsdb_idl_state state
;
98 struct json
*request_id
;
101 /* Database locking. */
102 char *lock_name
; /* Name of lock we need, NULL if none. */
103 bool has_lock
; /* Has db server told us we have the lock? */
104 bool is_lock_contended
; /* Has db server told us we can't get lock? */
105 struct json
*lock_request_id
; /* JSON-RPC ID of in-flight lock request. */
107 /* Transaction support. */
108 struct ovsdb_idl_txn
*txn
;
109 struct hmap outstanding_txns
;
112 struct ovsdb_idl_txn
{
113 struct hmap_node hmap_node
;
114 struct json
*request_id
;
115 struct ovsdb_idl
*idl
;
116 struct hmap txn_rows
;
117 enum ovsdb_idl_txn_status status
;
123 const char *inc_table
;
124 const char *inc_column
;
126 unsigned int inc_index
;
127 int64_t inc_new_value
;
130 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
133 struct ovsdb_idl_txn_insert
{
134 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
135 struct uuid dummy
; /* Dummy UUID used locally. */
136 int op_index
; /* Index into transaction's operation array. */
137 struct uuid real
; /* Real UUID used by database server. */
140 enum ovsdb_update_version
{
141 OVSDB_UPDATE
, /* RFC 7047 "update" method. */
142 OVSDB_UPDATE2
/* "update2" Extension to RFC 7047.
143 See ovsdb-server(1) for more information. */
146 /* Name arrays indexed by 'enum ovsdb_update_version'. */
147 static const char *table_updates_names
[] = {"table_updates", "table_updates2"};
148 static const char *table_update_names
[] = {"table_update", "table_update2"};
149 static const char *row_update_names
[] = {"row_update", "row_update2"};
151 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
152 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
154 static void ovsdb_idl_clear(struct ovsdb_idl
*);
155 static void ovsdb_idl_send_schema_request(struct ovsdb_idl
*);
156 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl
*);
157 static void ovsdb_idl_send_monitor2_request(struct ovsdb_idl
*);
158 static void ovsdb_idl_parse_update(struct ovsdb_idl
*, const struct json
*,
159 enum ovsdb_update_version
);
160 static struct ovsdb_error
*ovsdb_idl_parse_update__(struct ovsdb_idl
*,
162 enum ovsdb_update_version
);
163 static bool ovsdb_idl_process_update(struct ovsdb_idl_table
*,
165 const struct json
*old
,
166 const struct json
*new);
167 static bool ovsdb_idl_process_update2(struct ovsdb_idl_table
*,
169 const char *operation
,
170 const struct json
*row
);
171 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*, const struct json
*);
172 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
173 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*, const struct json
*);
174 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*,
175 const struct json
*);
177 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
178 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
179 const struct ovsdb_idl_table_class
*);
180 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
181 const struct uuid
*);
182 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
183 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*);
184 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
186 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
187 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
188 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
189 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
190 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
192 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
193 static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl
*,
194 const struct jsonrpc_msg
*msg
);
195 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
197 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
198 const struct ovsdb_idl_column
*,
199 struct ovsdb_datum
*,
202 static void ovsdb_idl_send_lock_request(struct ovsdb_idl
*);
203 static void ovsdb_idl_send_unlock_request(struct ovsdb_idl
*);
204 static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*,
205 const struct json
*);
206 static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*,
207 const struct json
*params
,
209 static struct ovsdb_idl_table
*
210 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
211 const struct ovsdb_idl_table_class
*);
212 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
214 /* Creates and returns a connection to database 'remote', which should be in a
215 * form acceptable to jsonrpc_session_open(). The connection will maintain an
216 * in-memory replica of the remote database whose schema is described by
217 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
220 * Passes 'retry' to jsonrpc_session_open(). See that function for
223 * If 'monitor_everything_by_default' is true, then everything in the remote
224 * database will be replicated by default. ovsdb_idl_omit() and
225 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
228 * If 'monitor_everything_by_default' is false, then no columns or tables will
229 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
230 * must be used to choose some columns or tables to replicate.
233 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
234 bool monitor_everything_by_default
, bool retry
)
236 struct ovsdb_idl
*idl
;
237 uint8_t default_mode
;
240 default_mode
= (monitor_everything_by_default
241 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
244 idl
= xzalloc(sizeof *idl
);
246 idl
->session
= jsonrpc_session_open(remote
, retry
);
247 shash_init(&idl
->table_by_name
);
248 idl
->tables
= xmalloc(class->n_tables
* sizeof *idl
->tables
);
249 for (i
= 0; i
< class->n_tables
; i
++) {
250 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
251 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
254 shash_add_assert(&idl
->table_by_name
, tc
->name
, table
);
256 table
->modes
= xmalloc(tc
->n_columns
);
257 memset(table
->modes
, default_mode
, tc
->n_columns
);
258 table
->need_table
= false;
259 shash_init(&table
->columns
);
260 for (j
= 0; j
< tc
->n_columns
; j
++) {
261 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
263 shash_add_assert(&table
->columns
, column
->name
, column
);
265 hmap_init(&table
->rows
);
266 ovs_list_init(&table
->track_list
);
267 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
268 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
269 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
273 idl
->state_seqno
= UINT_MAX
;
274 idl
->request_id
= NULL
;
277 hmap_init(&idl
->outstanding_txns
);
282 /* Changes the remote and creates a new session. */
284 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
,
288 ovs_assert(!idl
->txn
);
289 jsonrpc_session_close(idl
->session
);
290 idl
->session
= jsonrpc_session_open(remote
, retry
);
291 idl
->state_seqno
= UINT_MAX
;
295 /* Destroys 'idl' and all of the data structures that it manages. */
297 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
302 ovs_assert(!idl
->txn
);
303 ovsdb_idl_clear(idl
);
304 jsonrpc_session_close(idl
->session
);
306 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
307 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
308 shash_destroy(&table
->columns
);
309 hmap_destroy(&table
->rows
);
312 shash_destroy(&idl
->table_by_name
);
314 json_destroy(idl
->request_id
);
315 free(idl
->lock_name
);
316 json_destroy(idl
->lock_request_id
);
317 json_destroy(idl
->schema
);
318 hmap_destroy(&idl
->outstanding_txns
);
324 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
326 bool changed
= false;
329 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
330 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
331 struct ovsdb_idl_row
*row
, *next_row
;
333 if (hmap_is_empty(&table
->rows
)) {
338 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
339 struct ovsdb_idl_arc
*arc
, *next_arc
;
341 if (!ovsdb_idl_row_is_orphan(row
)) {
342 ovsdb_idl_row_unparse(row
);
344 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
347 /* No need to do anything with dst_arcs: some node has those arcs
348 * as forward arcs and will destroy them itself. */
350 if (!ovs_list_is_empty(&row
->track_node
)) {
351 ovs_list_remove(&row
->track_node
);
354 ovsdb_idl_row_destroy(row
);
358 ovsdb_idl_track_clear(idl
);
365 /* Processes a batch of messages from the database server on 'idl'. This may
366 * cause the IDL's contents to change. The client may check for that with
367 * ovsdb_idl_get_seqno(). */
369 ovsdb_idl_run(struct ovsdb_idl
*idl
)
373 ovs_assert(!idl
->txn
);
374 jsonrpc_session_run(idl
->session
);
375 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
376 struct jsonrpc_msg
*msg
;
379 seqno
= jsonrpc_session_get_seqno(idl
->session
);
380 if (idl
->state_seqno
!= seqno
) {
381 idl
->state_seqno
= seqno
;
382 json_destroy(idl
->request_id
);
383 idl
->request_id
= NULL
;
384 ovsdb_idl_txn_abort_all(idl
);
386 ovsdb_idl_send_schema_request(idl
);
387 idl
->state
= IDL_S_SCHEMA_REQUESTED
;
388 if (idl
->lock_name
) {
389 ovsdb_idl_send_lock_request(idl
);
393 msg
= jsonrpc_session_recv(idl
->session
);
398 if (msg
->type
== JSONRPC_NOTIFY
399 && !strcmp(msg
->method
, "update2")
400 && msg
->params
->type
== JSON_ARRAY
401 && msg
->params
->u
.array
.n
== 2
402 && msg
->params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
403 /* Database contents changed. */
404 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
406 } else if (msg
->type
== JSONRPC_REPLY
408 && json_equal(idl
->request_id
, msg
->id
)) {
409 json_destroy(idl
->request_id
);
410 idl
->request_id
= NULL
;
412 switch (idl
->state
) {
413 case IDL_S_SCHEMA_REQUESTED
:
414 /* Reply to our "get_schema" request. */
415 idl
->schema
= json_clone(msg
->result
);
416 ovsdb_idl_send_monitor2_request(idl
);
417 idl
->state
= IDL_S_MONITOR2_REQUESTED
;
420 case IDL_S_MONITOR_REQUESTED
:
421 case IDL_S_MONITOR2_REQUESTED
:
422 /* Reply to our "monitor" or "monitor2" request. */
424 ovsdb_idl_clear(idl
);
425 if (idl
->state
== IDL_S_MONITOR_REQUESTED
) {
426 idl
->state
= IDL_S_MONITORING
;
427 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE
);
428 } else { /* IDL_S_MONITOR2_REQUESTED. */
429 idl
->state
= IDL_S_MONITORING2
;
430 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE2
);
433 /* Schema is not useful after monitor request is accepted
435 json_destroy(idl
->schema
);
439 case IDL_S_MONITORING
:
440 case IDL_S_MONITORING2
:
441 case IDL_S_NO_SCHEMA
:
445 } else if (msg
->type
== JSONRPC_NOTIFY
446 && !strcmp(msg
->method
, "update")
447 && msg
->params
->type
== JSON_ARRAY
448 && msg
->params
->u
.array
.n
== 2
449 && msg
->params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
450 /* Database contents changed. */
451 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
453 } else if (msg
->type
== JSONRPC_REPLY
454 && idl
->lock_request_id
455 && json_equal(idl
->lock_request_id
, msg
->id
)) {
456 /* Reply to our "lock" request. */
457 ovsdb_idl_parse_lock_reply(idl
, msg
->result
);
458 } else if (msg
->type
== JSONRPC_NOTIFY
459 && !strcmp(msg
->method
, "locked")) {
460 /* We got our lock. */
461 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, true);
462 } else if (msg
->type
== JSONRPC_NOTIFY
463 && !strcmp(msg
->method
, "stolen")) {
464 /* Someone else stole our lock. */
465 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, false);
466 } else if (msg
->type
== JSONRPC_ERROR
467 && idl
->state
== IDL_S_MONITOR2_REQUESTED
469 && json_equal(idl
->request_id
, msg
->id
)) {
470 if (msg
->error
&& !strcmp(json_string(msg
->error
),
472 /* Fall back to using "monitor" method. */
473 json_destroy(idl
->request_id
);
474 idl
->request_id
= NULL
;
475 ovsdb_idl_send_monitor_request(idl
);
476 idl
->state
= IDL_S_MONITOR_REQUESTED
;
478 } else if (msg
->type
== JSONRPC_ERROR
479 && idl
->state
== IDL_S_SCHEMA_REQUESTED
481 && json_equal(idl
->request_id
, msg
->id
)) {
482 json_destroy(idl
->request_id
);
483 idl
->request_id
= NULL
;
484 VLOG_ERR("%s: requested schema not found",
485 jsonrpc_session_get_name(idl
->session
));
486 idl
->state
= IDL_S_NO_SCHEMA
;
487 } else if ((msg
->type
== JSONRPC_ERROR
488 || msg
->type
== JSONRPC_REPLY
)
489 && ovsdb_idl_txn_process_reply(idl
, msg
)) {
490 /* ovsdb_idl_txn_process_reply() did everything needful. */
492 /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
493 * a transaction before we receive the reply, so keep the log level
495 VLOG_DBG("%s: received unexpected %s message",
496 jsonrpc_session_get_name(idl
->session
),
497 jsonrpc_msg_type_to_string(msg
->type
));
499 jsonrpc_msg_destroy(msg
);
501 ovsdb_idl_row_destroy_postprocess(idl
);
504 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
505 * do or when activity occurs on a transaction on 'idl'. */
507 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
509 jsonrpc_session_wait(idl
->session
);
510 jsonrpc_session_recv_wait(idl
->session
);
513 /* Returns a "sequence number" that represents the state of 'idl'. When
514 * ovsdb_idl_run() changes the database, the sequence number changes. The
515 * initial fetch of the entire contents of the remote database is considered to
516 * be one kind of change. Successfully acquiring a lock, if one has been
517 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
519 * As long as the sequence number does not change, the client may continue to
520 * use any data structures it obtains from 'idl'. But when it changes, the
521 * client must not access any of these data structures again, because they
522 * could have freed or reused for other purposes.
524 * The sequence number can occasionally change even if the database does not.
525 * This happens if the connection to the database drops and reconnects, which
526 * causes the database contents to be reloaded even if they didn't change. (It
527 * could also happen if the database server sends out a "change" that reflects
528 * what the IDL already thought was in the database. The database server is
529 * not supposed to do that, but bugs could in theory cause it to do so.) */
531 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
533 return idl
->change_seqno
;
536 /* Returns true if 'idl' successfully connected to the remote database and
537 * retrieved its contents (even if the connection subsequently dropped and is
538 * in the process of reconnecting). If so, then 'idl' contains an atomic
539 * snapshot of the database's contents (but it might be arbitrarily old if the
540 * connection dropped).
542 * Returns false if 'idl' has never connected or retrieved the database's
543 * contents. If so, 'idl' is empty. */
545 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
547 return ovsdb_idl_get_seqno(idl
) != 0;
550 /* Reconfigures 'idl' so that it would reconnect to the database, if
551 * connection was dropped. */
553 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
555 jsonrpc_session_enable_reconnect(idl
->session
);
558 /* Forces 'idl' to drop its connection to the database and reconnect. In the
559 * meantime, the contents of 'idl' will not change. */
561 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
563 jsonrpc_session_force_reconnect(idl
->session
);
566 /* Some IDL users should only write to write-only columns. Furthermore,
567 * writing to a column which is not write-only can cause serious performance
568 * degradations for these users. This function causes 'idl' to reject writes
569 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
571 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
573 idl
->verify_write_only
= true;
576 /* Returns true if 'idl' is currently connected or trying to connect
577 * and a negative response to a schema request has not been received */
579 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
581 return jsonrpc_session_is_alive(idl
->session
) &&
582 idl
->state
!= IDL_S_NO_SCHEMA
;
585 /* Returns the last error reported on a connection by 'idl'. The return value
586 * is 0 only if no connection made by 'idl' has ever encountered an error and
587 * a negative response to a schema request has never been received. See
588 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
591 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
595 err
= jsonrpc_session_get_last_error(idl
->session
);
599 } else if (idl
->state
== IDL_S_NO_SCHEMA
) {
606 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
610 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
612 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
615 static unsigned char *
616 ovsdb_idl_get_mode(struct ovsdb_idl
*idl
,
617 const struct ovsdb_idl_column
*column
)
621 ovs_assert(!idl
->change_seqno
);
623 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
624 const struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
625 const struct ovsdb_idl_table_class
*tc
= table
->class;
627 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
628 return &table
->modes
[column
- tc
->columns
];
636 add_ref_table(struct ovsdb_idl
*idl
, const struct ovsdb_base_type
*base
)
638 if (base
->type
== OVSDB_TYPE_UUID
&& base
->u
.uuid
.refTableName
) {
639 struct ovsdb_idl_table
*table
;
641 table
= shash_find_data(&idl
->table_by_name
,
642 base
->u
.uuid
.refTableName
);
644 table
->need_table
= true;
646 VLOG_WARN("%s IDL class missing referenced table %s",
647 idl
->class->database
, base
->u
.uuid
.refTableName
);
652 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
653 * ensures that any tables referenced by 'column' will be replicated, even if
654 * no columns in that table are selected for replication (see
655 * ovsdb_idl_add_table() for more information).
657 * This function is only useful if 'monitor_everything_by_default' was false in
658 * the call to ovsdb_idl_create(). This function should be called between
659 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
662 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
663 const struct ovsdb_idl_column
*column
)
665 *ovsdb_idl_get_mode(idl
, column
) = OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
;
666 add_ref_table(idl
, &column
->type
.key
);
667 add_ref_table(idl
, &column
->type
.value
);
670 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
671 * no columns are selected for replication. Just the necessary data for table
672 * references will be replicated (the UUID of the rows, for instance), any
673 * columns not selected for replication will remain unreplicated.
674 * This can be useful because it allows 'idl' to keep track of what rows in the
675 * table actually exist, which in turn allows columns that reference the table
676 * to have accurate contents. (The IDL presents the database with references to
677 * rows that do not exist removed.)
679 * This function is only useful if 'monitor_everything_by_default' was false in
680 * the call to ovsdb_idl_create(). This function should be called between
681 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
684 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
685 const struct ovsdb_idl_table_class
*tc
)
689 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
690 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
692 if (table
->class == tc
) {
693 table
->need_table
= true;
701 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
703 * This function should be called between ovsdb_idl_create() and the first call
704 * to ovsdb_idl_run().
707 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
708 const struct ovsdb_idl_column
*column
)
710 *ovsdb_idl_get_mode(idl
, column
) &= ~OVSDB_IDL_ALERT
;
713 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
714 * OVSDB_IDL_MONITOR for details.
716 * This function should be called between ovsdb_idl_create() and the first call
717 * to ovsdb_idl_run().
720 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
722 *ovsdb_idl_get_mode(idl
, column
) = 0;
725 /* Returns the most recent IDL change sequence number that caused a
726 * insert, modify or delete update to the table with class 'table_class'.
729 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
730 const struct ovsdb_idl_table_class
*table_class
)
732 struct ovsdb_idl_table
*table
733 = ovsdb_idl_table_from_class(idl
, table_class
);
734 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
736 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
737 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
739 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
740 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
745 /* For each row that contains tracked columns, IDL stores the most
746 * recent IDL change sequence numbers associateed with insert, modify
747 * and delete updates to the table.
750 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
751 enum ovsdb_idl_change change
)
753 return row
->change_seqno
[change
];
756 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
757 * all rows whose 'column' is modified are traced. Similarly, insert
758 * or delete of rows having 'column' are tracked. Clients are able
759 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
762 * This function should be called between ovsdb_idl_create() and
763 * the first call to ovsdb_idl_run(). The column to be tracked
764 * should have OVSDB_IDL_ALERT turned on.
767 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
768 const struct ovsdb_idl_column
*column
)
770 if (!(*ovsdb_idl_get_mode(idl
, column
) & OVSDB_IDL_ALERT
)) {
771 ovsdb_idl_add_column(idl
, column
);
773 *ovsdb_idl_get_mode(idl
, column
) |= OVSDB_IDL_TRACK
;
777 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
781 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
782 const struct ovsdb_idl_table_class
*tc
= &idl
->class->tables
[i
];
784 for (j
= 0; j
< tc
->n_columns
; j
++) {
785 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
786 ovsdb_idl_track_add_column(idl
, column
);
791 /* Returns true if 'table' has any tracked column. */
793 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
797 for (i
= 0; i
< table
->class->n_columns
; i
++) {
798 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
805 /* Returns the first tracked row in table with class 'table_class'
806 * for the specified 'idl'. Returns NULL if there are no tracked rows */
807 const struct ovsdb_idl_row
*
808 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
809 const struct ovsdb_idl_table_class
*table_class
)
811 struct ovsdb_idl_table
*table
812 = ovsdb_idl_table_from_class(idl
, table_class
);
814 if (!ovs_list_is_empty(&table
->track_list
)) {
815 return CONTAINER_OF(ovs_list_front(&table
->track_list
), struct ovsdb_idl_row
, track_node
);
820 /* Returns the next tracked row in table after the specified 'row'
821 * (in no particular order). Returns NULL if there are no tracked rows */
822 const struct ovsdb_idl_row
*
823 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
825 if (row
->track_node
.next
!= &row
->table
->track_list
) {
826 return CONTAINER_OF(row
->track_node
.next
, struct ovsdb_idl_row
, track_node
);
832 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
833 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
835 * Function returns false if 'column' is not tracked (see
836 * ovsdb_idl_track_add_column()).
839 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
840 const struct ovsdb_idl_column
*column
)
842 const struct ovsdb_idl_table_class
*class;
845 class = row
->table
->class;
846 column_idx
= column
- class->columns
;
848 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
855 /* Flushes the tracked rows. Client calls this function after calling
856 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
857 * functions. This is usually done at the end of the client's processing
858 * loop when it is ready to do ovsdb_idl_run() again.
861 ovsdb_idl_track_clear(const struct ovsdb_idl
*idl
)
865 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
866 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
868 if (!ovs_list_is_empty(&table
->track_list
)) {
869 struct ovsdb_idl_row
*row
, *next
;
871 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
876 ovs_list_remove(&row
->track_node
);
877 ovs_list_init(&row
->track_node
);
878 if (ovsdb_idl_row_is_orphan(row
)) {
879 ovsdb_idl_row_clear_old(row
);
889 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
)
891 struct jsonrpc_msg
*msg
;
893 json_destroy(idl
->request_id
);
894 msg
= jsonrpc_create_request(
896 json_array_create_1(json_string_create(idl
->class->database
)),
898 jsonrpc_session_send(idl
->session
, msg
);
902 log_error(struct ovsdb_error
*error
)
904 char *s
= ovsdb_error_to_string(error
);
905 VLOG_WARN("error parsing database schema: %s", s
);
907 ovsdb_error_destroy(error
);
910 /* Frees 'schema', which is in the format returned by parse_schema(). */
912 free_schema(struct shash
*schema
)
915 struct shash_node
*node
, *next
;
917 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
918 struct sset
*sset
= node
->data
;
921 shash_delete(schema
, node
);
923 shash_destroy(schema
);
928 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
929 * 7047, to obtain the names of its rows and columns. If successful, returns
930 * an shash whose keys are table names and whose values are ssets, where each
931 * sset contains the names of its table's columns. On failure (due to a parse
932 * error), returns NULL.
934 * It would also be possible to use the general-purpose OVSDB schema parser in
935 * ovsdb-server, but that's overkill, possibly too strict for the current use
936 * case, and would require restructuring ovsdb-server to separate the schema
937 * code from the rest. */
938 static struct shash
*
939 parse_schema(const struct json
*schema_json
)
941 struct ovsdb_parser parser
;
942 const struct json
*tables_json
;
943 struct ovsdb_error
*error
;
944 struct shash_node
*node
;
945 struct shash
*schema
;
947 ovsdb_parser_init(&parser
, schema_json
, "database schema");
948 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
949 error
= ovsdb_parser_destroy(&parser
);
955 schema
= xmalloc(sizeof *schema
);
957 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
958 const char *table_name
= node
->name
;
959 const struct json
*json
= node
->data
;
960 const struct json
*columns_json
;
962 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
964 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
965 error
= ovsdb_parser_destroy(&parser
);
972 struct sset
*columns
= xmalloc(sizeof *columns
);
975 struct shash_node
*node2
;
976 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
977 const char *column_name
= node2
->name
;
978 sset_add(columns
, column_name
);
980 shash_add(schema
, table_name
, columns
);
986 ovsdb_idl_send_monitor_request__(struct ovsdb_idl
*idl
,
989 struct shash
*schema
;
990 struct json
*monitor_requests
;
991 struct jsonrpc_msg
*msg
;
994 schema
= parse_schema(idl
->schema
);
995 monitor_requests
= json_object_create();
996 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
997 const struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
998 const struct ovsdb_idl_table_class
*tc
= table
->class;
999 struct json
*monitor_request
, *columns
;
1000 const struct sset
*table_schema
;
1003 table_schema
= (schema
1004 ? shash_find_data(schema
, table
->class->name
)
1007 columns
= table
->need_table
? json_array_create_empty() : NULL
;
1008 for (j
= 0; j
< tc
->n_columns
; j
++) {
1009 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1010 if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
1012 && !sset_contains(table_schema
, column
->name
)) {
1013 VLOG_WARN("%s table in %s database lacks %s column "
1014 "(database needs upgrade?)",
1015 table
->class->name
, idl
->class->database
,
1020 columns
= json_array_create_empty();
1022 json_array_add(columns
, json_string_create(column
->name
));
1027 if (schema
&& !table_schema
) {
1028 VLOG_WARN("%s database lacks %s table "
1029 "(database needs upgrade?)",
1030 idl
->class->database
, table
->class->name
);
1031 json_destroy(columns
);
1035 monitor_request
= json_object_create();
1036 json_object_put(monitor_request
, "columns", columns
);
1037 json_object_put(monitor_requests
, tc
->name
, monitor_request
);
1040 free_schema(schema
);
1042 json_destroy(idl
->request_id
);
1043 msg
= jsonrpc_create_request(
1045 json_array_create_3(json_string_create(idl
->class->database
),
1046 json_null_create(), monitor_requests
),
1048 jsonrpc_session_send(idl
->session
, msg
);
1052 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
)
1054 ovsdb_idl_send_monitor_request__(idl
, "monitor");
1058 log_parse_update_error(struct ovsdb_error
*error
)
1060 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1061 char *s
= ovsdb_error_to_string(error
);
1062 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1065 ovsdb_error_destroy(error
);
1069 ovsdb_idl_send_monitor2_request(struct ovsdb_idl
*idl
)
1071 ovsdb_idl_send_monitor_request__(idl
, "monitor2");
1075 ovsdb_idl_parse_update(struct ovsdb_idl
*idl
, const struct json
*table_updates
,
1076 enum ovsdb_update_version version
)
1078 struct ovsdb_error
*error
= ovsdb_idl_parse_update__(idl
, table_updates
,
1081 log_parse_update_error(error
);
1085 static struct ovsdb_error
*
1086 ovsdb_idl_parse_update__(struct ovsdb_idl
*idl
,
1087 const struct json
*table_updates
,
1088 enum ovsdb_update_version version
)
1090 const struct shash_node
*tables_node
;
1091 const char *table_updates_name
= table_updates_names
[version
];
1092 const char *table_update_name
= table_update_names
[version
];
1093 const char *row_update_name
= row_update_names
[version
];
1095 if (table_updates
->type
!= JSON_OBJECT
) {
1096 return ovsdb_syntax_error(table_updates
, NULL
,
1097 "<%s> is not an object",
1098 table_updates_name
);
1101 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
1102 const struct json
*table_update
= tables_node
->data
;
1103 const struct shash_node
*table_node
;
1104 struct ovsdb_idl_table
*table
;
1106 table
= shash_find_data(&idl
->table_by_name
, tables_node
->name
);
1108 return ovsdb_syntax_error(
1109 table_updates
, NULL
,
1110 "<%s> includes unknown table \"%s\"",
1115 if (table_update
->type
!= JSON_OBJECT
) {
1116 return ovsdb_syntax_error(table_update
, NULL
,
1117 "<%s> for table \"%s\" is "
1120 table
->class->name
);
1122 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
1123 const struct json
*row_update
= table_node
->data
;
1124 const struct json
*old_json
, *new_json
;
1127 if (!uuid_from_string(&uuid
, table_node
->name
)) {
1128 return ovsdb_syntax_error(table_update
, NULL
,
1129 "<%s> for table \"%s\" "
1130 "contains bad UUID "
1131 "\"%s\" as member name",
1136 if (row_update
->type
!= JSON_OBJECT
) {
1137 return ovsdb_syntax_error(row_update
, NULL
,
1138 "<%s> for table \"%s\" "
1139 "contains <%s> for %s that "
1149 old_json
= shash_find_data(json_object(row_update
), "old");
1150 new_json
= shash_find_data(json_object(row_update
), "new");
1151 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
1152 return ovsdb_syntax_error(old_json
, NULL
,
1153 "\"old\" <row> is not object");
1154 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
1155 return ovsdb_syntax_error(new_json
, NULL
,
1156 "\"new\" <row> is not object");
1157 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
1158 != shash_count(json_object(row_update
))) {
1159 return ovsdb_syntax_error(row_update
, NULL
,
1160 "<row-update> contains "
1161 "unexpected member");
1162 } else if (!old_json
&& !new_json
) {
1163 return ovsdb_syntax_error(row_update
, NULL
,
1164 "<row-update> missing \"old\" "
1165 "and \"new\" members");
1168 if (ovsdb_idl_process_update(table
, &uuid
, old_json
,
1170 idl
->change_seqno
++;
1174 case OVSDB_UPDATE2
: {
1175 const char *ops
[] = {"modify", "insert", "delete", "initial"};
1176 const char *operation
;
1177 const struct json
*row
;
1180 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
1182 row
= shash_find_data(json_object(row_update
), operation
);
1185 if (ovsdb_idl_process_update2(table
, &uuid
, operation
,
1187 idl
->change_seqno
++;
1193 /* row_update2 should contain one of the objects */
1194 if (i
== ARRAY_SIZE(ops
)) {
1195 return ovsdb_syntax_error(row_update
, NULL
,
1196 "<row_update2> includes unknown "
1211 static struct ovsdb_idl_row
*
1212 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1214 struct ovsdb_idl_row
*row
;
1216 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
1217 if (uuid_equals(&row
->uuid
, uuid
)) {
1224 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1227 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
1228 const struct uuid
*uuid
, const struct json
*old
,
1229 const struct json
*new)
1231 struct ovsdb_idl_row
*row
;
1233 row
= ovsdb_idl_get_row(table
, uuid
);
1236 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1237 /* XXX perhaps we should check the 'old' values? */
1238 ovsdb_idl_delete_row(row
);
1240 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1242 UUID_ARGS(uuid
), table
->class->name
);
1248 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1249 } else if (ovsdb_idl_row_is_orphan(row
)) {
1250 ovsdb_idl_insert_row(row
, new);
1252 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1253 "table %s", UUID_ARGS(uuid
), table
->class->name
);
1254 return ovsdb_idl_modify_row(row
, new);
1259 /* XXX perhaps we should check the 'old' values? */
1260 if (!ovsdb_idl_row_is_orphan(row
)) {
1261 return ovsdb_idl_modify_row(row
, new);
1263 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1264 "referenced row "UUID_FMT
" in table %s",
1265 UUID_ARGS(uuid
), table
->class->name
);
1266 ovsdb_idl_insert_row(row
, new);
1269 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1270 "in table %s", UUID_ARGS(uuid
), table
->class->name
);
1271 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1278 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1281 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
1282 const struct uuid
*uuid
,
1283 const char *operation
,
1284 const struct json
*json_row
)
1286 struct ovsdb_idl_row
*row
;
1288 row
= ovsdb_idl_get_row(table
, uuid
);
1289 if (!strcmp(operation
, "delete")) {
1291 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1292 ovsdb_idl_delete_row(row
);
1294 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1296 UUID_ARGS(uuid
), table
->class->name
);
1299 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
1302 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
1303 } else if (ovsdb_idl_row_is_orphan(row
)) {
1304 ovsdb_idl_insert_row(row
, json_row
);
1306 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1307 "table %s", UUID_ARGS(uuid
), table
->class->name
);
1308 ovsdb_idl_delete_row(row
);
1309 ovsdb_idl_insert_row(row
, json_row
);
1311 } else if (!strcmp(operation
, "modify")) {
1314 if (!ovsdb_idl_row_is_orphan(row
)) {
1315 return ovsdb_idl_modify_row_by_diff(row
, json_row
);
1317 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1318 "referenced row "UUID_FMT
" in table %s",
1319 UUID_ARGS(uuid
), table
->class->name
);
1323 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1324 "in table %s", UUID_ARGS(uuid
), table
->class->name
);
1328 VLOG_WARN_RL(&semantic_rl
, "unknown operation %s to "
1329 "table %s", operation
, table
->class->name
);
1336 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1339 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1340 * Caller needs to provide either valid 'row_json' or 'diff', but not
1343 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1344 const struct json
*diff_json
,
1345 enum ovsdb_idl_change change
)
1347 struct ovsdb_idl_table
*table
= row
->table
;
1348 const struct ovsdb_idl_table_class
*class = table
->class;
1349 struct shash_node
*node
;
1350 bool changed
= false;
1351 bool apply_diff
= diff_json
!= NULL
;
1352 const struct json
*json
= apply_diff
? diff_json
: row_json
;
1354 SHASH_FOR_EACH (node
, json_object(json
)) {
1355 const char *column_name
= node
->name
;
1356 const struct ovsdb_idl_column
*column
;
1357 struct ovsdb_datum datum
;
1358 struct ovsdb_error
*error
;
1359 unsigned int column_idx
;
1360 struct ovsdb_datum
*old
;
1362 column
= shash_find_data(&table
->columns
, column_name
);
1364 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
1365 column_name
, UUID_ARGS(&row
->uuid
));
1369 column_idx
= column
- table
->class->columns
;
1370 old
= &row
->old
[column_idx
];
1374 struct ovsdb_datum diff
;
1376 ovs_assert(!row_json
);
1377 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
1380 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
1382 ovsdb_datum_destroy(&diff
, &column
->type
);
1385 ovs_assert(!diff_json
);
1386 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
1391 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
1392 ovsdb_datum_swap(old
, &datum
);
1393 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
1395 row
->change_seqno
[change
]
1396 = row
->table
->change_seqno
[change
]
1397 = row
->table
->idl
->change_seqno
+ 1;
1398 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
1399 if (!ovs_list_is_empty(&row
->track_node
)) {
1400 ovs_list_remove(&row
->track_node
);
1402 ovs_list_push_back(&row
->table
->track_list
,
1404 if (!row
->updated
) {
1405 row
->updated
= bitmap_allocate(class->n_columns
);
1407 bitmap_set1(row
->updated
, column_idx
);
1411 /* Didn't really change but the OVSDB monitor protocol always
1412 * includes every value in a row. */
1415 ovsdb_datum_destroy(&datum
, &column
->type
);
1417 char *s
= ovsdb_error_to_string(error
);
1418 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
1419 " in table %s: %s", column_name
,
1420 UUID_ARGS(&row
->uuid
), table
->class->name
, s
);
1422 ovsdb_error_destroy(error
);
1429 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1430 enum ovsdb_idl_change change
)
1432 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
1436 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
1437 const struct json
*diff_json
,
1438 enum ovsdb_idl_change change
)
1440 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
1443 /* When a row A refers to row B through a column with a "refTable" constraint,
1444 * but row B does not exist, row B is called an "orphan row". Orphan rows
1445 * should not persist, because the database enforces referential integrity, but
1446 * they can appear transiently as changes from the database are received (the
1447 * database doesn't try to topologically sort them and circular references mean
1448 * it isn't always possible anyhow).
1450 * This function returns true if 'row' is an orphan row, otherwise false.
1453 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
1455 return !row
->old
&& !row
->new;
1458 /* Returns true if 'row' is conceptually part of the database as modified by
1459 * the current transaction (if any), false otherwise.
1461 * This function will return true if 'row' is not an orphan (see the comment on
1462 * ovsdb_idl_row_is_orphan()) and:
1464 * - 'row' exists in the database and has not been deleted within the
1465 * current transaction (if any).
1467 * - 'row' was inserted within the current transaction and has not been
1468 * deleted. (In the latter case you should not have passed 'row' in at
1469 * all, because ovsdb_idl_txn_delete() freed it.)
1471 * This function will return false if 'row' is an orphan or if 'row' was
1472 * deleted within the current transaction.
1475 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
1477 return row
->new != NULL
;
1481 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
1483 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1486 for (i
= 0; i
< class->n_columns
; i
++) {
1487 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1488 (c
->parse
)(row
, &row
->old
[i
]);
1493 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
1495 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1498 for (i
= 0; i
< class->n_columns
; i
++) {
1499 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1505 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
1507 ovs_assert(row
->old
== row
->new);
1508 if (!ovsdb_idl_row_is_orphan(row
)) {
1509 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1512 for (i
= 0; i
< class->n_columns
; i
++) {
1513 ovsdb_datum_destroy(&row
->old
[i
], &class->columns
[i
].type
);
1516 row
->old
= row
->new = NULL
;
1521 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
1523 if (row
->old
!= row
->new) {
1525 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1529 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
1530 ovsdb_datum_destroy(&row
->new[i
], &class->columns
[i
].type
);
1535 row
->written
= NULL
;
1537 row
->new = row
->old
;
1542 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
1544 struct ovsdb_idl_arc
*arc
, *next
;
1546 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
1547 * that this causes to be unreferenced, if tracking is not enabled.
1548 * If tracking is enabled, orphaned nodes are removed from hmap but not
1551 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
1552 ovs_list_remove(&arc
->dst_node
);
1554 && ovsdb_idl_row_is_orphan(arc
->dst
)
1555 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
1556 ovsdb_idl_row_destroy(arc
->dst
);
1560 ovs_list_init(&row
->src_arcs
);
1563 /* Force nodes that reference 'row' to reparse. */
1565 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
1567 struct ovsdb_idl_arc
*arc
, *next
;
1569 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
1570 * 'arc', so we need to use the "safe" variant of list traversal. However,
1571 * calling an ovsdb_idl_column's 'parse' function will add an arc
1572 * equivalent to 'arc' to row->arcs. That could be a problem for
1573 * traversal, but it adds it at the beginning of the list to prevent us
1574 * from stumbling upon it again.
1576 * (If duplicate arcs were possible then we would need to make sure that
1577 * 'next' didn't also point into 'arc''s destination, but we forbid
1578 * duplicate arcs.) */
1579 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
1580 struct ovsdb_idl_row
*ref
= arc
->src
;
1582 ovsdb_idl_row_unparse(ref
);
1583 ovsdb_idl_row_clear_arcs(ref
, false);
1584 ovsdb_idl_row_parse(ref
);
1588 static struct ovsdb_idl_row
*
1589 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
1591 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
1592 class->row_init(row
);
1593 ovs_list_init(&row
->src_arcs
);
1594 ovs_list_init(&row
->dst_arcs
);
1595 hmap_node_nullify(&row
->txn_node
);
1596 ovs_list_init(&row
->track_node
);
1600 static struct ovsdb_idl_row
*
1601 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1603 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class);
1604 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
1607 row
->map_op_written
= NULL
;
1608 row
->map_op_lists
= NULL
;
1613 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
1616 ovsdb_idl_row_clear_old(row
);
1617 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
1618 ovsdb_idl_destroy_all_map_op_lists(row
);
1619 if (ovsdb_idl_track_is_set(row
->table
)) {
1620 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
1621 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
1622 = row
->table
->idl
->change_seqno
+ 1;
1624 if (!ovs_list_is_empty(&row
->track_node
)) {
1625 ovs_list_remove(&row
->track_node
);
1627 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
1632 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
1634 if (row
->map_op_written
) {
1635 /* Clear Map Operation Lists */
1636 size_t idx
, n_columns
;
1637 const struct ovsdb_idl_column
*columns
;
1638 const struct ovsdb_type
*type
;
1639 n_columns
= row
->table
->class->n_columns
;
1640 columns
= row
->table
->class->columns
;
1641 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
1642 type
= &columns
[idx
].type
;
1643 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
1645 free(row
->map_op_lists
);
1646 bitmap_free(row
->map_op_written
);
1647 row
->map_op_lists
= NULL
;
1648 row
->map_op_written
= NULL
;
1653 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*idl
)
1657 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
1658 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1660 if (!ovs_list_is_empty(&table
->track_list
)) {
1661 struct ovsdb_idl_row
*row
, *next
;
1663 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1664 if (!ovsdb_idl_track_is_set(row
->table
)) {
1665 ovs_list_remove(&row
->track_node
);
1674 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
1676 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1679 ovs_assert(!row
->old
&& !row
->new);
1680 row
->old
= row
->new = xmalloc(class->n_columns
* sizeof *row
->old
);
1681 for (i
= 0; i
< class->n_columns
; i
++) {
1682 ovsdb_datum_init_default(&row
->old
[i
], &class->columns
[i
].type
);
1684 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
1685 ovsdb_idl_row_parse(row
);
1687 ovsdb_idl_row_reparse_backrefs(row
);
1691 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
1693 ovsdb_idl_row_unparse(row
);
1694 ovsdb_idl_row_clear_arcs(row
, true);
1695 ovsdb_idl_row_clear_old(row
);
1696 if (ovs_list_is_empty(&row
->dst_arcs
)) {
1697 ovsdb_idl_row_destroy(row
);
1699 ovsdb_idl_row_reparse_backrefs(row
);
1703 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1706 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
1710 ovsdb_idl_row_unparse(row
);
1711 ovsdb_idl_row_clear_arcs(row
, true);
1712 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
1713 ovsdb_idl_row_parse(row
);
1719 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
1720 const struct json
*diff_json
)
1724 ovsdb_idl_row_unparse(row
);
1725 ovsdb_idl_row_clear_arcs(row
, true);
1726 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
1727 OVSDB_IDL_CHANGE_MODIFY
);
1728 ovsdb_idl_row_parse(row
);
1734 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
1736 const struct ovsdb_idl_arc
*arc
;
1743 /* No duplicate arcs.
1745 * We only need to test whether the first arc in dst->dst_arcs originates
1746 * at 'src', since we add all of the arcs from a given source in a clump
1747 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
1748 * added at the front of the dst_arcs list. */
1749 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
1752 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
1753 return arc
->src
!= src
;
1756 static struct ovsdb_idl_table
*
1757 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
1758 const struct ovsdb_idl_table_class
*table_class
)
1760 return &idl
->tables
[table_class
- idl
->class->tables
];
1763 /* Called by ovsdb-idlc generated code. */
1764 struct ovsdb_idl_row
*
1765 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
1766 struct ovsdb_idl_table_class
*dst_table_class
,
1767 const struct uuid
*dst_uuid
)
1769 struct ovsdb_idl
*idl
= src
->table
->idl
;
1770 struct ovsdb_idl_table
*dst_table
;
1771 struct ovsdb_idl_arc
*arc
;
1772 struct ovsdb_idl_row
*dst
;
1774 dst_table
= ovsdb_idl_table_from_class(idl
, dst_table_class
);
1775 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
1777 /* We're being called from ovsdb_idl_txn_write(). We must not update
1778 * any arcs, because the transaction will be backed out at commit or
1779 * abort time and we don't want our graph screwed up.
1781 * Just return the destination row, if there is one and it has not been
1783 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new)) {
1788 /* We're being called from some other context. Update the graph. */
1790 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
1793 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
1794 if (may_add_arc(src
, dst
)) {
1795 /* The arc *must* be added at the front of the dst_arcs list. See
1796 * ovsdb_idl_row_reparse_backrefs() for details. */
1797 arc
= xmalloc(sizeof *arc
);
1798 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
1799 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
1804 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
1808 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
1809 * pointer to the row if there is one, otherwise a null pointer. */
1810 const struct ovsdb_idl_row
*
1811 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
1812 const struct ovsdb_idl_table_class
*tc
,
1813 const struct uuid
*uuid
)
1815 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
1818 static struct ovsdb_idl_row
*
1819 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
1821 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
1822 struct ovsdb_idl_row
*row
;
1824 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
1825 if (ovsdb_idl_row_exists(row
)) {
1832 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
1835 * Database tables are internally maintained as hash tables, so adding or
1836 * removing rows while traversing the same table can cause some rows to be
1837 * visited twice or not at apply. */
1838 const struct ovsdb_idl_row
*
1839 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
1840 const struct ovsdb_idl_table_class
*table_class
)
1842 struct ovsdb_idl_table
*table
1843 = ovsdb_idl_table_from_class(idl
, table_class
);
1844 return next_real_row(table
, hmap_first(&table
->rows
));
1847 /* Returns a row following 'row' within its table, or a null pointer if 'row'
1848 * is the last row in its table. */
1849 const struct ovsdb_idl_row
*
1850 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
1852 struct ovsdb_idl_table
*table
= row
->table
;
1854 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
1857 /* Reads and returns the value of 'column' within 'row'. If an ongoing
1858 * transaction has changed 'column''s value, the modified value is returned.
1860 * The caller must not modify or free the returned value.
1862 * Various kinds of changes can invalidate the returned value: writing to the
1863 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
1864 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
1865 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
1866 * returned value is needed for a long time, it is best to make a copy of it
1867 * with ovsdb_datum_clone(). */
1868 const struct ovsdb_datum
*
1869 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
1870 const struct ovsdb_idl_column
*column
)
1872 const struct ovsdb_idl_table_class
*class;
1875 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
1877 class = row
->table
->class;
1878 column_idx
= column
- class->columns
;
1880 ovs_assert(row
->new != NULL
);
1881 ovs_assert(column_idx
< class->n_columns
);
1883 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
1884 return &row
->new[column_idx
];
1885 } else if (row
->old
) {
1886 return &row
->old
[column_idx
];
1888 return ovsdb_datum_default(&column
->type
);
1892 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
1893 * type 'key_type' and value type 'value_type'. (Scalar and set types will
1894 * have a value type of OVSDB_TYPE_VOID.)
1896 * This is useful in code that "knows" that a particular column has a given
1897 * type, so that it will abort if someone changes the column's type without
1898 * updating the code that uses it. */
1899 const struct ovsdb_datum
*
1900 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
1901 const struct ovsdb_idl_column
*column
,
1902 enum ovsdb_atomic_type key_type OVS_UNUSED
,
1903 enum ovsdb_atomic_type value_type OVS_UNUSED
)
1905 ovs_assert(column
->type
.key
.type
== key_type
);
1906 ovs_assert(column
->type
.value
.type
== value_type
);
1908 return ovsdb_idl_read(row
, column
);
1911 /* Returns true if the field represented by 'column' in 'row' may be modified,
1912 * false if it is immutable.
1914 * Normally, whether a field is mutable is controlled by its column's schema.
1915 * However, an immutable column can be set to any initial value at the time of
1916 * insertion, so if 'row' is a new row (one that is being added as part of the
1917 * current transaction, supposing that a transaction is in progress) then even
1918 * its "immutable" fields are actually mutable. */
1920 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
1921 const struct ovsdb_idl_column
*column
)
1923 return column
->mutable || (row
->new && !row
->old
);
1926 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
1927 * to all-zero-bits by some other entity. If 'row' was set up some other way
1928 * then the return value is indeterminate. */
1930 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
1932 return row
->table
== NULL
;
1937 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
1938 enum ovsdb_idl_txn_status
);
1940 /* Returns a string representation of 'status'. The caller must not modify or
1941 * free the returned string.
1943 * The return value is probably useful only for debug log messages and unit
1946 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
1949 case TXN_UNCOMMITTED
:
1950 return "uncommitted";
1953 case TXN_INCOMPLETE
:
1954 return "incomplete";
1961 case TXN_NOT_LOCKED
:
1962 return "not locked";
1969 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
1970 * active transaction at a time. See the large comment in ovsdb-idl.h for
1971 * general information on transactions. */
1972 struct ovsdb_idl_txn
*
1973 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
1975 struct ovsdb_idl_txn
*txn
;
1977 ovs_assert(!idl
->txn
);
1978 idl
->txn
= txn
= xmalloc(sizeof *txn
);
1979 txn
->request_id
= NULL
;
1981 hmap_init(&txn
->txn_rows
);
1982 txn
->status
= TXN_UNCOMMITTED
;
1984 txn
->dry_run
= false;
1985 ds_init(&txn
->comment
);
1987 txn
->inc_table
= NULL
;
1988 txn
->inc_column
= NULL
;
1990 hmap_init(&txn
->inserted_rows
);
1995 /* Appends 's', which is treated as a printf()-type format string, to the
1996 * comments that will be passed to the OVSDB server when 'txn' is committed.
1997 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
1998 * show-log" can print in a relatively human-readable form.) */
2000 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
2004 if (txn
->comment
.length
) {
2005 ds_put_char(&txn
->comment
, '\n');
2009 ds_put_format_valist(&txn
->comment
, s
, args
);
2013 /* Marks 'txn' as a transaction that will not actually modify the database. In
2014 * almost every way, the transaction is treated like other transactions. It
2015 * must be committed or aborted like other transactions, it will be sent to the
2016 * database server like other transactions, and so on. The only difference is
2017 * that the operations sent to the database server will include, as the last
2018 * step, an "abort" operation, so that any changes made by the transaction will
2019 * not actually take effect. */
2021 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
2023 txn
->dry_run
= true;
2026 /* Causes 'txn', when committed, to increment the value of 'column' within
2027 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
2028 * successfully, the client may retrieve the final (incremented) value of
2029 * 'column' with ovsdb_idl_txn_get_increment_new_value().
2031 * The client could accomplish something similar with ovsdb_idl_read(),
2032 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
2033 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
2034 * will never (by itself) fail because of a verify error.
2036 * The intended use is for incrementing the "next_cfg" column in the
2037 * Open_vSwitch table. */
2039 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
2040 const struct ovsdb_idl_row
*row
,
2041 const struct ovsdb_idl_column
*column
)
2043 ovs_assert(!txn
->inc_table
);
2044 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
2045 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
2047 txn
->inc_table
= row
->table
->class->name
;
2048 txn
->inc_column
= column
->name
;
2049 txn
->inc_row
= row
->uuid
;
2052 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
2053 * has been called for 'txn' but the commit is still incomplete (that is, the
2054 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
2055 * end up committing at the database server, but the client will not be able to
2056 * get any further status information back. */
2058 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
2060 struct ovsdb_idl_txn_insert
*insert
, *next
;
2062 json_destroy(txn
->request_id
);
2063 if (txn
->status
== TXN_INCOMPLETE
) {
2064 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
2066 ovsdb_idl_txn_abort(txn
);
2067 ds_destroy(&txn
->comment
);
2069 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
2072 hmap_destroy(&txn
->inserted_rows
);
2076 /* Causes poll_block() to wake up if 'txn' has completed committing. */
2078 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
2080 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
2081 poll_immediate_wake();
2085 static struct json
*
2086 where_uuid_equals(const struct uuid
*uuid
)
2089 json_array_create_1(
2090 json_array_create_3(
2091 json_string_create("_uuid"),
2092 json_string_create("=="),
2093 json_array_create_2(
2094 json_string_create("uuid"),
2095 json_string_create_nocopy(
2096 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
2100 uuid_name_from_uuid(const struct uuid
*uuid
)
2105 name
= xasprintf("row"UUID_FMT
, UUID_ARGS(uuid
));
2106 for (p
= name
; *p
!= '\0'; p
++) {
2115 static const struct ovsdb_idl_row
*
2116 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
2118 const struct ovsdb_idl_row
*row
;
2120 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
2121 if (uuid_equals(&row
->uuid
, uuid
)) {
2128 /* XXX there must be a cleaner way to do this */
2129 static struct json
*
2130 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
2132 if (json
->type
== JSON_ARRAY
) {
2136 if (json
->u
.array
.n
== 2
2137 && json
->u
.array
.elems
[0]->type
== JSON_STRING
2138 && json
->u
.array
.elems
[1]->type
== JSON_STRING
2139 && !strcmp(json
->u
.array
.elems
[0]->u
.string
, "uuid")
2140 && uuid_from_string(&uuid
, json
->u
.array
.elems
[1]->u
.string
)) {
2141 const struct ovsdb_idl_row
*row
;
2143 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
2144 if (row
&& !row
->old
&& row
->new) {
2147 return json_array_create_2(
2148 json_string_create("named-uuid"),
2149 json_string_create_nocopy(uuid_name_from_uuid(&uuid
)));
2153 for (i
= 0; i
< json
->u
.array
.n
; i
++) {
2154 json
->u
.array
.elems
[i
] = substitute_uuids(json
->u
.array
.elems
[i
],
2157 } else if (json
->type
== JSON_OBJECT
) {
2158 struct shash_node
*node
;
2160 SHASH_FOR_EACH (node
, json_object(json
)) {
2161 node
->data
= substitute_uuids(node
->data
, txn
);
2168 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
2170 struct ovsdb_idl_row
*row
, *next
;
2172 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
2173 * ovsdb_idl_column's 'parse' function, which will call
2174 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
2175 * transaction and fail to update the graph. */
2176 txn
->idl
->txn
= NULL
;
2178 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
2179 ovsdb_idl_destroy_all_map_op_lists(row
);
2182 ovsdb_idl_row_unparse(row
);
2183 ovsdb_idl_row_clear_arcs(row
, false);
2184 ovsdb_idl_row_parse(row
);
2187 ovsdb_idl_row_unparse(row
);
2189 ovsdb_idl_row_clear_new(row
);
2192 row
->prereqs
= NULL
;
2195 row
->written
= NULL
;
2197 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
2198 hmap_node_nullify(&row
->txn_node
);
2200 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2204 hmap_destroy(&txn
->txn_rows
);
2205 hmap_init(&txn
->txn_rows
);
2209 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
2210 struct json
*mutations
)
2212 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2214 bool any_mutations
= false;
2216 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
2217 struct map_op_list
*map_op_list
;
2218 const struct ovsdb_idl_column
*column
;
2219 const struct ovsdb_datum
*old_datum
;
2220 enum ovsdb_atomic_type key_type
, value_type
;
2221 struct json
*mutation
, *map
, *col_name
, *mutator
;
2222 struct json
*del_set
, *ins_map
;
2223 bool any_del
, any_ins
;
2225 map_op_list
= row
->map_op_lists
[idx
];
2226 column
= &class->columns
[idx
];
2227 key_type
= column
->type
.key
.type
;
2228 value_type
= column
->type
.value
.type
;
2230 /* Get the value to be changed */
2231 if (row
->new && row
->written
&& bitmap_is_set(row
->written
,idx
)) {
2232 old_datum
= &row
->new[idx
];
2233 } else if (row
->old
!= NULL
) {
2234 old_datum
= &row
->old
[idx
];
2236 old_datum
= ovsdb_datum_default(&column
->type
);
2239 del_set
= json_array_create_empty();
2240 ins_map
= json_array_create_empty();
2244 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
2245 map_op
= map_op_list_next(map_op_list
, map_op
)) {
2247 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2248 /* Find out if value really changed. */
2249 struct ovsdb_datum
*new_datum
;
2251 new_datum
= map_op_datum(map_op
);
2252 pos
= ovsdb_datum_find_key(old_datum
,
2253 &new_datum
->keys
[0],
2255 if (ovsdb_atom_equals(&new_datum
->values
[0],
2256 &old_datum
->values
[pos
],
2258 /* No change in value. Move on to next update. */
2261 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
2262 /* Verify that there is a key to delete. */
2264 pos
= ovsdb_datum_find_key(old_datum
,
2265 &map_op_datum(map_op
)->keys
[0],
2267 if (pos
== UINT_MAX
) {
2268 /* No key to delete. Move on to next update. */
2269 VLOG_WARN("Trying to delete a key that doesn't "
2270 "exist in the map.");
2275 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
2276 map
= json_array_create_2(
2277 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2279 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2281 json_array_add(ins_map
, map
);
2283 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
2284 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2286 json_array_add(del_set
, map
);
2290 /* Generate an additional insert mutate for updates. */
2291 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2292 map
= json_array_create_2(
2293 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2295 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2297 json_array_add(ins_map
, map
);
2303 col_name
= json_string_create(column
->name
);
2304 mutator
= json_string_create("delete");
2305 map
= json_array_create_2(json_string_create("set"), del_set
);
2306 mutation
= json_array_create_3(col_name
, mutator
, map
);
2307 json_array_add(mutations
, mutation
);
2308 any_mutations
= true;
2310 json_destroy(del_set
);
2313 col_name
= json_string_create(column
->name
);
2314 mutator
= json_string_create("insert");
2315 map
= json_array_create_2(json_string_create("map"), ins_map
);
2316 mutation
= json_array_create_3(col_name
, mutator
, map
);
2317 json_array_add(mutations
, mutation
);
2318 any_mutations
= true;
2320 json_destroy(ins_map
);
2323 return any_mutations
;
2326 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
2327 * of the following TXN_* constants:
2331 * The transaction is in progress, but not yet complete. The caller
2332 * should call again later, after calling ovsdb_idl_run() to let the IDL
2333 * do OVSDB protocol processing.
2337 * The transaction is complete. (It didn't actually change the database,
2338 * so the IDL didn't send any request to the database server.)
2342 * The caller previously called ovsdb_idl_txn_abort().
2346 * The transaction was successful. The update made by the transaction
2347 * (and possibly other changes made by other database clients) should
2348 * already be visible in the IDL.
2352 * The transaction failed for some transient reason, e.g. because a
2353 * "verify" operation reported an inconsistency or due to a network
2354 * problem. The caller should wait for a change to the database, then
2355 * compose a new transaction, and commit the new transaction.
2357 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
2358 * the database. It is important to use its return value *before* the
2359 * initial call to ovsdb_idl_txn_commit() as the baseline for this
2360 * purpose, because the change that one should wait for can happen after
2361 * the initial call but before the call that returns TXN_TRY_AGAIN, and
2362 * using some other baseline value in that situation could cause an
2363 * indefinite wait if the database rarely changes.
2367 * The transaction failed because the IDL has been configured to require
2368 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
2369 * has already lost it.
2371 * Committing a transaction rolls back all of the changes that it made to the
2372 * IDL's copy of the database. If the transaction commits successfully, then
2373 * the database server will send an update and, thus, the IDL will be updated
2374 * with the committed changes. */
2375 enum ovsdb_idl_txn_status
2376 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
2378 struct ovsdb_idl_row
*row
;
2379 struct json
*operations
;
2382 if (txn
!= txn
->idl
->txn
) {
2386 /* If we need a lock but don't have it, give up quickly. */
2387 if (txn
->idl
->lock_name
&& !ovsdb_idl_has_lock(txn
->idl
)) {
2388 txn
->status
= TXN_NOT_LOCKED
;
2389 goto disassemble_out
;
2392 operations
= json_array_create_1(
2393 json_string_create(txn
->idl
->class->database
));
2395 /* Assert that we have the required lock (avoiding a race). */
2396 if (txn
->idl
->lock_name
) {
2397 struct json
*op
= json_object_create();
2398 json_array_add(operations
, op
);
2399 json_object_put_string(op
, "op", "assert");
2400 json_object_put_string(op
, "lock", txn
->idl
->lock_name
);
2403 /* Add prerequisites and declarations of new rows. */
2404 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2405 /* XXX check that deleted rows exist even if no prereqs? */
2407 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2408 size_t n_columns
= class->n_columns
;
2409 struct json
*op
, *columns
, *row_json
;
2412 op
= json_object_create();
2413 json_array_add(operations
, op
);
2414 json_object_put_string(op
, "op", "wait");
2415 json_object_put_string(op
, "table", class->name
);
2416 json_object_put(op
, "timeout", json_integer_create(0));
2417 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2418 json_object_put_string(op
, "until", "==");
2419 columns
= json_array_create_empty();
2420 json_object_put(op
, "columns", columns
);
2421 row_json
= json_object_create();
2422 json_object_put(op
, "rows", json_array_create_1(row_json
));
2424 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
2425 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
2426 json_array_add(columns
, json_string_create(column
->name
));
2427 json_object_put(row_json
, column
->name
,
2428 ovsdb_datum_to_json(&row
->old
[idx
],
2435 any_updates
= false;
2436 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2437 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2440 if (class->is_root
) {
2441 struct json
*op
= json_object_create();
2442 json_object_put_string(op
, "op", "delete");
2443 json_object_put_string(op
, "table", class->name
);
2444 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2445 json_array_add(operations
, op
);
2448 /* Let ovsdb-server decide whether to really delete it. */
2450 } else if (row
->old
!= row
->new) {
2451 struct json
*row_json
;
2455 op
= json_object_create();
2456 json_object_put_string(op
, "op", row
->old
? "update" : "insert");
2457 json_object_put_string(op
, "table", class->name
);
2459 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2461 struct ovsdb_idl_txn_insert
*insert
;
2465 json_object_put(op
, "uuid-name",
2466 json_string_create_nocopy(
2467 uuid_name_from_uuid(&row
->uuid
)));
2469 insert
= xmalloc(sizeof *insert
);
2470 insert
->dummy
= row
->uuid
;
2471 insert
->op_index
= operations
->u
.array
.n
- 1;
2472 uuid_zero(&insert
->real
);
2473 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
2474 uuid_hash(&insert
->dummy
));
2476 row_json
= json_object_create();
2477 json_object_put(op
, "row", row_json
);
2480 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
2481 const struct ovsdb_idl_column
*column
=
2482 &class->columns
[idx
];
2485 || !ovsdb_datum_is_default(&row
->new[idx
],
2487 json_object_put(row_json
, column
->name
,
2489 ovsdb_datum_to_json(&row
->new[idx
],
2493 /* If anything really changed, consider it an update.
2494 * We can't suppress not-really-changed values earlier
2495 * or transactions would become nonatomic (see the big
2496 * comment inside ovsdb_idl_txn_write()). */
2497 if (!any_updates
&& row
->old
&&
2498 !ovsdb_datum_equals(&row
->old
[idx
], &row
->new[idx
],
2506 if (!row
->old
|| !shash_is_empty(json_object(row_json
))) {
2507 json_array_add(operations
, op
);
2513 /* Add mutate operation, for partial map updates. */
2514 if (row
->map_op_written
) {
2515 struct json
*op
, *mutations
;
2518 op
= json_object_create();
2519 json_object_put_string(op
, "op", "mutate");
2520 json_object_put_string(op
, "table", class->name
);
2521 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2522 mutations
= json_array_create_empty();
2523 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
2524 json_object_put(op
, "mutations", mutations
);
2526 if (any_mutations
) {
2527 op
= substitute_uuids(op
, txn
);
2528 json_array_add(operations
, op
);
2536 /* Add increment. */
2537 if (txn
->inc_table
&& any_updates
) {
2540 txn
->inc_index
= operations
->u
.array
.n
- 1;
2542 op
= json_object_create();
2543 json_object_put_string(op
, "op", "mutate");
2544 json_object_put_string(op
, "table", txn
->inc_table
);
2545 json_object_put(op
, "where",
2546 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
2548 json_object_put(op
, "mutations",
2549 json_array_create_1(
2550 json_array_create_3(
2551 json_string_create(txn
->inc_column
),
2552 json_string_create("+="),
2553 json_integer_create(1))));
2554 json_array_add(operations
, op
);
2556 op
= json_object_create();
2557 json_object_put_string(op
, "op", "select");
2558 json_object_put_string(op
, "table", txn
->inc_table
);
2559 json_object_put(op
, "where",
2560 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
2562 json_object_put(op
, "columns",
2563 json_array_create_1(json_string_create(
2565 json_array_add(operations
, op
);
2568 if (txn
->comment
.length
) {
2569 struct json
*op
= json_object_create();
2570 json_object_put_string(op
, "op", "comment");
2571 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
2572 json_array_add(operations
, op
);
2576 struct json
*op
= json_object_create();
2577 json_object_put_string(op
, "op", "abort");
2578 json_array_add(operations
, op
);
2582 txn
->status
= TXN_UNCHANGED
;
2583 json_destroy(operations
);
2584 } else if (!jsonrpc_session_send(
2586 jsonrpc_create_request(
2587 "transact", operations
, &txn
->request_id
))) {
2588 hmap_insert(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
,
2589 json_hash(txn
->request_id
, 0));
2590 txn
->status
= TXN_INCOMPLETE
;
2592 txn
->status
= TXN_TRY_AGAIN
;
2596 ovsdb_idl_txn_disassemble(txn
);
2598 switch (txn
->status
) {
2599 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
2600 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
2601 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
2602 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
2603 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
2604 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
2605 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
2606 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
2612 /* Attempts to commit 'txn', blocking until the commit either succeeds or
2613 * fails. Returns the final commit status, which may be any TXN_* value other
2614 * than TXN_INCOMPLETE.
2616 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
2617 * return value of ovsdb_idl_get_seqno() to change. */
2618 enum ovsdb_idl_txn_status
2619 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
2621 enum ovsdb_idl_txn_status status
;
2624 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
2625 ovsdb_idl_run(txn
->idl
);
2626 ovsdb_idl_wait(txn
->idl
);
2627 ovsdb_idl_txn_wait(txn
);
2633 /* Returns the final (incremented) value of the column in 'txn' that was set to
2634 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
2637 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
2639 ovs_assert(txn
->status
== TXN_SUCCESS
);
2640 return txn
->inc_new_value
;
2643 /* Aborts 'txn' without sending it to the database server. This is effective
2644 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
2645 * Otherwise, it has no effect.
2647 * Aborting a transaction doesn't free its memory. Use
2648 * ovsdb_idl_txn_destroy() to do that. */
2650 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
2652 ovsdb_idl_txn_disassemble(txn
);
2653 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
2654 txn
->status
= TXN_ABORTED
;
2658 /* Returns a string that reports the error status for 'txn'. The caller must
2659 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
2660 * for 'txn' may free the returned string.
2662 * The return value is ordinarily one of the strings that
2663 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
2664 * due to an error reported by the database server, the return value is that
2667 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
2669 if (txn
->status
!= TXN_ERROR
) {
2670 return ovsdb_idl_txn_status_to_string(txn
->status
);
2671 } else if (txn
->error
) {
2674 return "no error details available";
2679 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
2680 const struct json
*json
)
2682 if (txn
->error
== NULL
) {
2683 txn
->error
= json_to_string(json
, JSSF_SORT
);
2687 /* For transaction 'txn' that completed successfully, finds and returns the
2688 * permanent UUID that the database assigned to a newly inserted row, given the
2689 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
2691 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
2692 * if it was assigned by that function and then deleted by
2693 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
2694 * and then deleted within a single transaction are never sent to the database
2695 * server, so it never assigns them a permanent UUID.) */
2697 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
2698 const struct uuid
*uuid
)
2700 const struct ovsdb_idl_txn_insert
*insert
;
2702 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
2703 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
2704 uuid_hash(uuid
), &txn
->inserted_rows
) {
2705 if (uuid_equals(uuid
, &insert
->dummy
)) {
2706 return &insert
->real
;
2713 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
2714 enum ovsdb_idl_txn_status status
)
2716 txn
->status
= status
;
2717 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
2720 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
2721 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
2724 * 'datum' must have the correct type for its column. The IDL does not check
2725 * that it meets schema constraints, but ovsdb-server will do so at commit time
2726 * so it had better be correct.
2728 * A transaction must be in progress. Replication of 'column' must not have
2729 * been disabled (by calling ovsdb_idl_omit()).
2731 * Usually this function is used indirectly through one of the "set" functions
2732 * generated by ovsdb-idlc.
2734 * Takes ownership of what 'datum' points to (and in some cases destroys that
2735 * data before returning) but makes a copy of 'datum' itself. (Commonly
2736 * 'datum' is on the caller's stack.) */
2738 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
2739 const struct ovsdb_idl_column
*column
,
2740 struct ovsdb_datum
*datum
, bool owns_datum
)
2742 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2743 const struct ovsdb_idl_table_class
*class;
2747 if (ovsdb_idl_row_is_synthetic(row
)) {
2751 class = row
->table
->class;
2752 column_idx
= column
- class->columns
;
2753 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
2755 ovs_assert(row
->new != NULL
);
2756 ovs_assert(column_idx
< class->n_columns
);
2757 ovs_assert(row
->old
== NULL
||
2758 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
2760 if (row
->table
->idl
->verify_write_only
&& !write_only
) {
2761 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
2762 " explicitly configured not to.", class->name
, column
->name
);
2766 /* If this is a write-only column and the datum being written is the same
2767 * as the one already there, just skip the update entirely. This is worth
2768 * optimizing because we have a lot of columns that get periodically
2769 * refreshed into the database but don't actually change that often.
2771 * We don't do this for read/write columns because that would break
2772 * atomicity of transactions--some other client might have written a
2773 * different value in that column since we read it. (But if a whole
2774 * transaction only does writes of existing values, without making any real
2775 * changes, we will drop the whole transaction later in
2776 * ovsdb_idl_txn_commit().) */
2777 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
2778 datum
, &column
->type
)) {
2782 if (hmap_node_is_null(&row
->txn_node
)) {
2783 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
2784 uuid_hash(&row
->uuid
));
2786 if (row
->old
== row
->new) {
2787 row
->new = xmalloc(class->n_columns
* sizeof *row
->new);
2789 if (!row
->written
) {
2790 row
->written
= bitmap_allocate(class->n_columns
);
2792 if (bitmap_is_set(row
->written
, column_idx
)) {
2793 ovsdb_datum_destroy(&row
->new[column_idx
], &column
->type
);
2795 bitmap_set1(row
->written
, column_idx
);
2798 row
->new[column_idx
] = *datum
;
2800 ovsdb_datum_clone(&row
->new[column_idx
], datum
, &column
->type
);
2802 (column
->unparse
)(row
);
2803 (column
->parse
)(row
, &row
->new[column_idx
]);
2808 ovsdb_datum_destroy(datum
, &column
->type
);
2813 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
2814 const struct ovsdb_idl_column
*column
,
2815 struct ovsdb_datum
*datum
)
2817 ovsdb_idl_txn_write__(row
, column
, datum
, true);
2821 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
2822 const struct ovsdb_idl_column
*column
,
2823 const struct ovsdb_datum
*datum
)
2825 ovsdb_idl_txn_write__(row
, column
,
2826 CONST_CAST(struct ovsdb_datum
*, datum
), false);
2829 /* Causes the original contents of 'column' in 'row_' to be verified as a
2830 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
2831 * changed (or if 'row_' was deleted) between the time that the IDL originally
2832 * read its contents and the time that the transaction commits, then the
2833 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_AGAIN_WAIT or
2834 * TXN_AGAIN_NOW (depending on whether the database change has already been
2837 * The intention is that, to ensure that no transaction commits based on dirty
2838 * reads, an application should call ovsdb_idl_txn_verify() on each data item
2839 * read as part of a read-modify-write operation.
2841 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
2842 * value of 'column' is already known:
2844 * - If 'row_' is a row created by the current transaction (returned by
2845 * ovsdb_idl_txn_insert()).
2847 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
2848 * within the current transaction.
2850 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
2851 * ovsdb_idl_txn_write() for a given read-modify-write.
2853 * A transaction must be in progress.
2855 * Usually this function is used indirectly through one of the "verify"
2856 * functions generated by ovsdb-idlc. */
2858 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
2859 const struct ovsdb_idl_column
*column
)
2861 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2862 const struct ovsdb_idl_table_class
*class;
2865 if (ovsdb_idl_row_is_synthetic(row
)) {
2869 class = row
->table
->class;
2870 column_idx
= column
- class->columns
;
2872 ovs_assert(row
->new != NULL
);
2873 ovs_assert(row
->old
== NULL
||
2874 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
2876 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
2880 if (hmap_node_is_null(&row
->txn_node
)) {
2881 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
2882 uuid_hash(&row
->uuid
));
2884 if (!row
->prereqs
) {
2885 row
->prereqs
= bitmap_allocate(class->n_columns
);
2887 bitmap_set1(row
->prereqs
, column_idx
);
2890 /* Deletes 'row_' from its table. May free 'row_', so it must not be
2891 * accessed afterward.
2893 * A transaction must be in progress.
2895 * Usually this function is used indirectly through one of the "delete"
2896 * functions generated by ovsdb-idlc. */
2898 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
2900 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2902 if (ovsdb_idl_row_is_synthetic(row
)) {
2906 ovs_assert(row
->new != NULL
);
2908 ovsdb_idl_row_unparse(row
);
2909 ovsdb_idl_row_clear_new(row
);
2910 ovs_assert(!row
->prereqs
);
2911 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2912 hmap_remove(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
);
2916 if (hmap_node_is_null(&row
->txn_node
)) {
2917 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
2918 uuid_hash(&row
->uuid
));
2920 ovsdb_idl_row_clear_new(row
);
2924 /* Inserts and returns a new row in the table with the specified 'class' in the
2925 * database with open transaction 'txn'.
2927 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
2928 * randomly generated; otherwise 'uuid' should specify a randomly generated
2929 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
2930 * 'txn' is committed, but the IDL will replace any uses of the provisional
2931 * UUID in the data to be to be committed by the UUID assigned by
2934 * Usually this function is used indirectly through one of the "insert"
2935 * functions generated by ovsdb-idlc. */
2936 const struct ovsdb_idl_row
*
2937 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
2938 const struct ovsdb_idl_table_class
*class,
2939 const struct uuid
*uuid
)
2941 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
2944 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
2947 uuid_generate(&row
->uuid
);
2950 row
->table
= ovsdb_idl_table_from_class(txn
->idl
, class);
2951 row
->new = xmalloc(class->n_columns
* sizeof *row
->new);
2952 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
2953 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
2958 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
2960 struct ovsdb_idl_txn
*txn
;
2962 HMAP_FOR_EACH (txn
, hmap_node
, &idl
->outstanding_txns
) {
2963 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
2967 static struct ovsdb_idl_txn
*
2968 ovsdb_idl_txn_find(struct ovsdb_idl
*idl
, const struct json
*id
)
2970 struct ovsdb_idl_txn
*txn
;
2972 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
2973 json_hash(id
, 0), &idl
->outstanding_txns
) {
2974 if (json_equal(id
, txn
->request_id
)) {
2982 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
2985 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
2987 } else if (json
->type
!= type
) {
2988 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
2989 name
, json_type_to_string(json
->type
),
2990 json_type_to_string(type
));
2998 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
2999 const struct json_array
*results
)
3001 struct json
*count
, *rows
, *row
, *column
;
3002 struct shash
*mutate
, *select
;
3004 if (txn
->inc_index
+ 2 > results
->n
) {
3005 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3006 "for increment (has %"PRIuSIZE
", needs %u)",
3007 results
->n
, txn
->inc_index
+ 2);
3011 /* We know that this is a JSON object because the loop in
3012 * ovsdb_idl_txn_process_reply() checked. */
3013 mutate
= json_object(results
->elems
[txn
->inc_index
]);
3014 count
= shash_find_data(mutate
, "count");
3015 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
3018 if (count
->u
.integer
!= 1) {
3019 VLOG_WARN_RL(&syntax_rl
,
3020 "\"mutate\" reply \"count\" is %lld instead of 1",
3025 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
3026 rows
= shash_find_data(select
, "rows");
3027 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
3030 if (rows
->u
.array
.n
!= 1) {
3031 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
3036 row
= rows
->u
.array
.elems
[0];
3037 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
3040 column
= shash_find_data(json_object(row
), txn
->inc_column
);
3041 if (!check_json_type(column
, JSON_INTEGER
,
3042 "\"select\" reply inc column")) {
3045 txn
->inc_new_value
= column
->u
.integer
;
3050 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
3051 const struct json_array
*results
)
3053 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
3054 struct ovsdb_error
*error
;
3055 struct json
*json_uuid
;
3056 union ovsdb_atom uuid
;
3057 struct shash
*reply
;
3059 if (insert
->op_index
>= results
->n
) {
3060 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3061 "for insert (has %"PRIuSIZE
", needs %u)",
3062 results
->n
, insert
->op_index
);
3066 /* We know that this is a JSON object because the loop in
3067 * ovsdb_idl_txn_process_reply() checked. */
3068 reply
= json_object(results
->elems
[insert
->op_index
]);
3069 json_uuid
= shash_find_data(reply
, "uuid");
3070 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
3074 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
3076 char *s
= ovsdb_error_to_string(error
);
3077 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
3080 ovsdb_error_destroy(error
);
3084 insert
->real
= uuid
.uuid
;
3090 ovsdb_idl_txn_process_reply(struct ovsdb_idl
*idl
,
3091 const struct jsonrpc_msg
*msg
)
3093 struct ovsdb_idl_txn
*txn
;
3094 enum ovsdb_idl_txn_status status
;
3096 txn
= ovsdb_idl_txn_find(idl
, msg
->id
);
3101 if (msg
->type
== JSONRPC_ERROR
) {
3103 } else if (msg
->result
->type
!= JSON_ARRAY
) {
3104 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
3107 struct json_array
*ops
= &msg
->result
->u
.array
;
3108 int hard_errors
= 0;
3109 int soft_errors
= 0;
3110 int lock_errors
= 0;
3113 for (i
= 0; i
< ops
->n
; i
++) {
3114 struct json
*op
= ops
->elems
[i
];
3116 if (op
->type
== JSON_NULL
) {
3117 /* This isn't an error in itself but indicates that some prior
3118 * operation failed, so make sure that we know about it. */
3120 } else if (op
->type
== JSON_OBJECT
) {
3123 error
= shash_find_data(json_object(op
), "error");
3125 if (error
->type
== JSON_STRING
) {
3126 if (!strcmp(error
->u
.string
, "timed out")) {
3128 } else if (!strcmp(error
->u
.string
, "not owner")) {
3130 } else if (strcmp(error
->u
.string
, "aborted")) {
3132 ovsdb_idl_txn_set_error_json(txn
, op
);
3136 ovsdb_idl_txn_set_error_json(txn
, op
);
3137 VLOG_WARN_RL(&syntax_rl
,
3138 "\"error\" in reply is not JSON string");
3143 ovsdb_idl_txn_set_error_json(txn
, op
);
3144 VLOG_WARN_RL(&syntax_rl
,
3145 "operation reply is not JSON null or object");
3149 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
3150 struct ovsdb_idl_txn_insert
*insert
;
3152 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
3156 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
3157 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
3163 status
= (hard_errors
? TXN_ERROR
3164 : lock_errors
? TXN_NOT_LOCKED
3165 : soft_errors
? TXN_TRY_AGAIN
3169 ovsdb_idl_txn_complete(txn
, status
);
3173 /* Returns the transaction currently active for 'row''s IDL. A transaction
3174 * must currently be active. */
3175 struct ovsdb_idl_txn
*
3176 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
3178 struct ovsdb_idl_txn
*txn
= row
->table
->idl
->txn
;
3179 ovs_assert(txn
!= NULL
);
3183 /* Returns the IDL on which 'txn' acts. */
3185 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
3190 /* Blocks until 'idl' successfully connects to the remote database and
3191 * retrieves its contents. */
3193 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
3197 if (ovsdb_idl_has_ever_connected(idl
)) {
3200 ovsdb_idl_wait(idl
);
3205 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
3206 * the database server and to avoid modifying the database when the lock cannot
3207 * be acquired (that is, when another client has the same lock).
3209 * If 'lock_name' is NULL, drops the locking requirement and releases the
3212 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
3214 ovs_assert(!idl
->txn
);
3215 ovs_assert(hmap_is_empty(&idl
->outstanding_txns
));
3217 if (idl
->lock_name
&& (!lock_name
|| strcmp(lock_name
, idl
->lock_name
))) {
3218 /* Release previous lock. */
3219 ovsdb_idl_send_unlock_request(idl
);
3220 free(idl
->lock_name
);
3221 idl
->lock_name
= NULL
;
3222 idl
->is_lock_contended
= false;
3225 if (lock_name
&& !idl
->lock_name
) {
3226 /* Acquire new lock. */
3227 idl
->lock_name
= xstrdup(lock_name
);
3228 ovsdb_idl_send_lock_request(idl
);
3232 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
3234 * Locking and unlocking happens asynchronously from the database client's
3235 * point of view, so the information is only useful for optimization (e.g. if
3236 * the client doesn't have the lock then there's no point in trying to write to
3239 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
3241 return idl
->has_lock
;
3244 /* Returns true if 'idl' is configured to obtain a lock but the database server
3245 * has indicated that some other client already owns the requested lock. */
3247 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
3249 return idl
->is_lock_contended
;
3253 ovsdb_idl_update_has_lock(struct ovsdb_idl
*idl
, bool new_has_lock
)
3255 if (new_has_lock
&& !idl
->has_lock
) {
3256 if (idl
->state
== IDL_S_MONITORING
||
3257 idl
->state
== IDL_S_MONITORING2
) {
3258 idl
->change_seqno
++;
3260 /* We're setting up a session, so don't signal that the database
3261 * changed. Finalizing the session will increment change_seqno
3264 idl
->is_lock_contended
= false;
3266 idl
->has_lock
= new_has_lock
;
3270 ovsdb_idl_send_lock_request__(struct ovsdb_idl
*idl
, const char *method
,
3273 ovsdb_idl_update_has_lock(idl
, false);
3275 json_destroy(idl
->lock_request_id
);
3276 idl
->lock_request_id
= NULL
;
3278 if (jsonrpc_session_is_connected(idl
->session
)) {
3279 struct json
*params
;
3281 params
= json_array_create_1(json_string_create(idl
->lock_name
));
3282 jsonrpc_session_send(idl
->session
,
3283 jsonrpc_create_request(method
, params
, idp
));
3288 ovsdb_idl_send_lock_request(struct ovsdb_idl
*idl
)
3290 ovsdb_idl_send_lock_request__(idl
, "lock", &idl
->lock_request_id
);
3294 ovsdb_idl_send_unlock_request(struct ovsdb_idl
*idl
)
3296 ovsdb_idl_send_lock_request__(idl
, "unlock", NULL
);
3300 ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*idl
, const struct json
*result
)
3304 json_destroy(idl
->lock_request_id
);
3305 idl
->lock_request_id
= NULL
;
3307 if (result
->type
== JSON_OBJECT
) {
3308 const struct json
*locked
;
3310 locked
= shash_find_data(json_object(result
), "locked");
3311 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
3316 ovsdb_idl_update_has_lock(idl
, got_lock
);
3318 idl
->is_lock_contended
= true;
3323 ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*idl
,
3324 const struct json
*params
,
3328 && params
->type
== JSON_ARRAY
3329 && json_array(params
)->n
> 0
3330 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
3331 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
3333 if (!strcmp(idl
->lock_name
, lock_name
)) {
3334 ovsdb_idl_update_has_lock(idl
, new_has_lock
);
3335 if (!new_has_lock
) {
3336 idl
->is_lock_contended
= true;
3342 /* Inserts a new Map Operation into current transaction. */
3344 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
3345 const struct ovsdb_idl_column
*column
,
3346 struct ovsdb_datum
*datum
,
3347 enum map_op_type op_type
)
3349 const struct ovsdb_idl_table_class
*class;
3351 struct map_op
*map_op
;
3353 class = row
->table
->class;
3354 column_idx
= column
- class->columns
;
3356 /* Check if a map operation list exists for this column. */
3357 if (!row
->map_op_written
) {
3358 row
->map_op_written
= bitmap_allocate(class->n_columns
);
3359 row
->map_op_lists
= xzalloc(class->n_columns
*
3360 sizeof *row
->map_op_lists
);
3362 if (!row
->map_op_lists
[column_idx
]) {
3363 row
->map_op_lists
[column_idx
] = map_op_list_create();
3366 /* Add a map operation to the corresponding list. */
3367 map_op
= map_op_create(datum
, op_type
);
3368 bitmap_set1(row
->map_op_written
, column_idx
);
3369 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
3371 /* Add this row to transaction's list of rows. */
3372 if (hmap_node_is_null(&row
->txn_node
)) {
3373 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3374 uuid_hash(&row
->uuid
));
3379 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
3380 const struct ovsdb_idl_column
*column
,
3381 struct ovsdb_datum
*datum
)
3383 /* Verify that this column is being monitored. */
3384 unsigned int column_idx
= column
- row
->table
->class->columns
;
3385 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
3386 VLOG_WARN("cannot partially update non-monitored column");
3390 /* Verify that the update affects a single element. */
3391 if (datum
->n
!= 1) {
3392 VLOG_WARN("invalid datum for partial update");
3399 /* Inserts the key-value specified in 'datum' into the map in 'column' in
3400 * 'row_'. If the key already exist in 'column', then it's value is updated
3401 * with the value in 'datum'. The key-value in 'datum' must be of the same type
3402 * as the keys-values in 'column'. This function takes ownership of 'datum'.
3404 * Usually this function is used indirectly through one of the "update"
3405 * functions generated by vswitch-idl. */
3407 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
3408 const struct ovsdb_idl_column
*column
,
3409 struct ovsdb_datum
*datum
)
3411 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3412 enum ovsdb_atomic_type key_type
;
3413 enum map_op_type op_type
;
3415 const struct ovsdb_datum
*old_datum
;
3417 if (!is_valid_partial_update(row
, column
, datum
)) {
3418 ovsdb_datum_destroy(datum
, &column
->type
);
3423 /* Find out if this is an insert or an update. */
3424 key_type
= column
->type
.key
.type
;
3425 old_datum
= ovsdb_idl_read(row
, column
);
3426 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
3427 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
3429 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
3432 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
3433 * The key in 'datum' must be of the same type as the keys in 'column'.
3434 * The value in 'datum' must be NULL. This function takes ownership of
3437 * Usually this function is used indirectly through one of the "update"
3438 * functions generated by vswitch-idl. */
3440 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
3441 const struct ovsdb_idl_column
*column
,
3442 struct ovsdb_datum
*datum
)
3444 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3446 if (!is_valid_partial_update(row
, column
, datum
)) {
3447 struct ovsdb_type type_
= column
->type
;
3448 type_
.value
.type
= OVSDB_TYPE_VOID
;
3449 ovsdb_datum_destroy(datum
, &type_
);
3453 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
3457 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
3460 ovsdb_idl_destroy(loop
->idl
);
3464 struct ovsdb_idl_txn
*
3465 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
3467 ovsdb_idl_run(loop
->idl
);
3468 loop
->open_txn
= (loop
->committing_txn
3469 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
3471 : ovsdb_idl_txn_create(loop
->idl
));
3472 return loop
->open_txn
;
3476 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
3478 if (loop
->open_txn
) {
3479 loop
->committing_txn
= loop
->open_txn
;
3480 loop
->open_txn
= NULL
;
3482 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
3485 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
3487 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
3488 if (status
!= TXN_INCOMPLETE
) {
3491 /* We want to re-evaluate the database when it's changed from
3492 * the contents that it had when we started the commit. (That
3493 * might have already happened.) */
3494 loop
->skip_seqno
= loop
->precommit_seqno
;
3495 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
3496 poll_immediate_wake();
3501 /* If the database has already changed since we started the
3502 * commit, re-evaluate it immediately to avoid missing a change
3504 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->precommit_seqno
) {
3505 poll_immediate_wake();
3511 case TXN_NOT_LOCKED
:
3515 case TXN_UNCOMMITTED
:
3516 case TXN_INCOMPLETE
:
3520 ovsdb_idl_txn_destroy(txn
);
3521 loop
->committing_txn
= NULL
;
3525 ovsdb_idl_wait(loop
->idl
);