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"
29 #include "openvswitch/json.h"
31 #include "ovsdb/ovsdb.h"
32 #include "ovsdb/table.h"
33 #include "ovsdb-data.h"
34 #include "ovsdb-error.h"
35 #include "ovsdb-idl-provider.h"
36 #include "ovsdb-parser.h"
37 #include "poll-loop.h"
38 #include "openvswitch/shash.h"
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_MONITOR_COND_REQUESTED
,
83 IDL_S_MONITORING_COND
,
88 const struct ovsdb_idl_class
*class;
89 struct jsonrpc_session
*session
;
91 struct shash table_by_name
;
92 struct ovsdb_idl_table
*tables
; /* Contains "struct ovsdb_idl_table *"s.*/
93 unsigned int change_seqno
;
94 bool verify_write_only
;
97 unsigned int state_seqno
;
98 enum ovsdb_idl_state state
;
99 struct json
*request_id
;
102 /* Database locking. */
103 char *lock_name
; /* Name of lock we need, NULL if none. */
104 bool has_lock
; /* Has db server told us we have the lock? */
105 bool is_lock_contended
; /* Has db server told us we can't get lock? */
106 struct json
*lock_request_id
; /* JSON-RPC ID of in-flight lock request. */
108 /* Transaction support. */
109 struct ovsdb_idl_txn
*txn
;
110 struct hmap outstanding_txns
;
114 struct ovsdb_idl_txn
{
115 struct hmap_node hmap_node
;
116 struct json
*request_id
;
117 struct ovsdb_idl
*idl
;
118 struct hmap txn_rows
;
119 enum ovsdb_idl_txn_status status
;
125 const char *inc_table
;
126 const char *inc_column
;
129 unsigned int inc_index
;
130 int64_t inc_new_value
;
133 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
136 struct ovsdb_idl_txn_insert
{
137 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
138 struct uuid dummy
; /* Dummy UUID used locally. */
139 int op_index
; /* Index into transaction's operation array. */
140 struct uuid real
; /* Real UUID used by database server. */
143 enum ovsdb_update_version
{
144 OVSDB_UPDATE
, /* RFC 7047 "update" method. */
145 OVSDB_UPDATE2
/* "update2" Extension to RFC 7047.
146 See ovsdb-server(1) for more information. */
149 /* Name arrays indexed by 'enum ovsdb_update_version'. */
150 static const char *table_updates_names
[] = {"table_updates", "table_updates2"};
151 static const char *table_update_names
[] = {"table_update", "table_update2"};
152 static const char *row_update_names
[] = {"row_update", "row_update2"};
154 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
155 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
157 static void ovsdb_idl_clear(struct ovsdb_idl
*);
158 static void ovsdb_idl_send_schema_request(struct ovsdb_idl
*);
159 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl
*);
160 static void ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl
*);
161 static void ovsdb_idl_parse_update(struct ovsdb_idl
*, const struct json
*,
162 enum ovsdb_update_version
);
163 static struct ovsdb_error
*ovsdb_idl_parse_update__(struct ovsdb_idl
*,
165 enum ovsdb_update_version
);
166 static bool ovsdb_idl_process_update(struct ovsdb_idl_table
*,
168 const struct json
*old
,
169 const struct json
*new);
170 static bool ovsdb_idl_process_update2(struct ovsdb_idl_table
*,
172 const char *operation
,
173 const struct json
*row
);
174 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*, const struct json
*);
175 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
176 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*, const struct json
*);
177 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*,
178 const struct json
*);
180 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
181 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
182 const struct ovsdb_idl_table_class
*);
183 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
184 const struct uuid
*);
185 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
186 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*);
187 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
188 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*);
190 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
191 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
192 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
193 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
194 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
196 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
197 static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl
*,
198 const struct jsonrpc_msg
*msg
);
199 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
201 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
202 const struct ovsdb_idl_column
*,
203 struct ovsdb_datum
*,
205 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*,
206 const struct ovsdb_idl_column
*,
207 struct ovsdb_datum
*,
210 static void ovsdb_idl_send_lock_request(struct ovsdb_idl
*);
211 static void ovsdb_idl_send_unlock_request(struct ovsdb_idl
*);
212 static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*,
213 const struct json
*);
214 static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*,
215 const struct json
*params
,
217 static struct ovsdb_idl_table
*
218 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
219 const struct ovsdb_idl_table_class
*);
220 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
221 static void ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
);
222 static void ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
,
223 const struct ovsdb_idl_table_class
*tc
);
225 /* Creates and returns a connection to database 'remote', which should be in a
226 * form acceptable to jsonrpc_session_open(). The connection will maintain an
227 * in-memory replica of the remote database whose schema is described by
228 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
231 * Passes 'retry' to jsonrpc_session_open(). See that function for
234 * If 'monitor_everything_by_default' is true, then everything in the remote
235 * database will be replicated by default. ovsdb_idl_omit() and
236 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
239 * If 'monitor_everything_by_default' is false, then no columns or tables will
240 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
241 * must be used to choose some columns or tables to replicate.
244 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
245 bool monitor_everything_by_default
, bool retry
)
247 struct ovsdb_idl
*idl
;
248 uint8_t default_mode
;
251 default_mode
= (monitor_everything_by_default
252 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
255 idl
= xzalloc(sizeof *idl
);
257 idl
->session
= jsonrpc_session_open(remote
, retry
);
258 shash_init(&idl
->table_by_name
);
259 idl
->tables
= xmalloc(class->n_tables
* sizeof *idl
->tables
);
260 for (i
= 0; i
< class->n_tables
; i
++) {
261 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
262 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
265 shash_add_assert(&idl
->table_by_name
, tc
->name
, table
);
267 table
->modes
= xmalloc(tc
->n_columns
);
268 memset(table
->modes
, default_mode
, tc
->n_columns
);
269 table
->need_table
= false;
270 shash_init(&table
->columns
);
271 for (j
= 0; j
< tc
->n_columns
; j
++) {
272 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
274 shash_add_assert(&table
->columns
, column
->name
, column
);
276 hmap_init(&table
->rows
);
277 ovs_list_init(&table
->track_list
);
278 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
279 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
280 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
282 ovsdb_idl_condition_init(&table
->condition
, tc
);
283 table
->cond_changed
= false;
286 idl
->cond_changed
= false;
287 idl
->state_seqno
= UINT_MAX
;
288 idl
->request_id
= NULL
;
291 hmap_init(&idl
->outstanding_txns
);
292 uuid_generate(&idl
->uuid
);
297 /* Changes the remote and creates a new session. */
299 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
,
303 ovs_assert(!idl
->txn
);
304 jsonrpc_session_close(idl
->session
);
305 idl
->session
= jsonrpc_session_open(remote
, retry
);
306 idl
->state_seqno
= UINT_MAX
;
310 /* Destroys 'idl' and all of the data structures that it manages. */
312 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
317 ovs_assert(!idl
->txn
);
318 ovsdb_idl_clear(idl
);
319 jsonrpc_session_close(idl
->session
);
321 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
322 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
323 shash_destroy(&table
->columns
);
324 hmap_destroy(&table
->rows
);
327 shash_destroy(&idl
->table_by_name
);
329 json_destroy(idl
->request_id
);
330 free(idl
->lock_name
);
331 json_destroy(idl
->lock_request_id
);
332 json_destroy(idl
->schema
);
333 hmap_destroy(&idl
->outstanding_txns
);
339 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
341 bool changed
= false;
344 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
345 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
346 struct ovsdb_idl_row
*row
, *next_row
;
348 if (hmap_is_empty(&table
->rows
)) {
353 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
354 struct ovsdb_idl_arc
*arc
, *next_arc
;
356 if (!ovsdb_idl_row_is_orphan(row
)) {
357 ovsdb_idl_row_unparse(row
);
359 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
362 /* No need to do anything with dst_arcs: some node has those arcs
363 * as forward arcs and will destroy them itself. */
365 if (!ovs_list_is_empty(&row
->track_node
)) {
366 ovs_list_remove(&row
->track_node
);
369 ovsdb_idl_row_destroy(row
);
373 ovsdb_idl_track_clear(idl
);
380 /* Processes a batch of messages from the database server on 'idl'. This may
381 * cause the IDL's contents to change. The client may check for that with
382 * ovsdb_idl_get_seqno(). */
384 ovsdb_idl_run(struct ovsdb_idl
*idl
)
388 ovs_assert(!idl
->txn
);
390 ovsdb_idl_send_cond_change(idl
);
392 jsonrpc_session_run(idl
->session
);
393 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
394 struct jsonrpc_msg
*msg
;
397 seqno
= jsonrpc_session_get_seqno(idl
->session
);
398 if (idl
->state_seqno
!= seqno
) {
399 idl
->state_seqno
= seqno
;
400 json_destroy(idl
->request_id
);
401 idl
->request_id
= NULL
;
402 ovsdb_idl_txn_abort_all(idl
);
404 ovsdb_idl_send_schema_request(idl
);
405 idl
->state
= IDL_S_SCHEMA_REQUESTED
;
406 if (idl
->lock_name
) {
407 ovsdb_idl_send_lock_request(idl
);
411 msg
= jsonrpc_session_recv(idl
->session
);
416 if (msg
->type
== JSONRPC_NOTIFY
417 && !strcmp(msg
->method
, "update2")
418 && msg
->params
->type
== JSON_ARRAY
419 && msg
->params
->u
.array
.n
== 2
420 && msg
->params
->u
.array
.elems
[0]->type
== JSON_STRING
) {
421 /* Database contents changed. */
422 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
424 } else if (msg
->type
== JSONRPC_REPLY
426 && json_equal(idl
->request_id
, msg
->id
)) {
427 json_destroy(idl
->request_id
);
428 idl
->request_id
= NULL
;
430 switch (idl
->state
) {
431 case IDL_S_SCHEMA_REQUESTED
:
432 /* Reply to our "get_schema" request. */
433 idl
->schema
= json_clone(msg
->result
);
434 ovsdb_idl_send_monitor_cond_request(idl
);
435 idl
->state
= IDL_S_MONITOR_COND_REQUESTED
;
438 case IDL_S_MONITOR_REQUESTED
:
439 case IDL_S_MONITOR_COND_REQUESTED
:
440 /* Reply to our "monitor" or "monitor_cond" request. */
442 ovsdb_idl_clear(idl
);
443 if (idl
->state
== IDL_S_MONITOR_REQUESTED
) {
444 idl
->state
= IDL_S_MONITORING
;
445 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE
);
446 } else { /* IDL_S_MONITOR_COND_REQUESTED. */
447 idl
->state
= IDL_S_MONITORING_COND
;
448 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE2
);
451 /* Schema is not useful after monitor request is accepted
453 json_destroy(idl
->schema
);
457 case IDL_S_MONITORING
:
458 case IDL_S_MONITORING_COND
:
459 case IDL_S_NO_SCHEMA
:
463 } else if (msg
->type
== JSONRPC_NOTIFY
464 && !strcmp(msg
->method
, "update")
465 && msg
->params
->type
== JSON_ARRAY
466 && msg
->params
->u
.array
.n
== 2
467 && msg
->params
->u
.array
.elems
[0]->type
== JSON_STRING
) {
468 /* Database contents changed. */
469 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
471 } else if (msg
->type
== JSONRPC_REPLY
472 && idl
->lock_request_id
473 && json_equal(idl
->lock_request_id
, msg
->id
)) {
474 /* Reply to our "lock" request. */
475 ovsdb_idl_parse_lock_reply(idl
, msg
->result
);
476 } else if (msg
->type
== JSONRPC_NOTIFY
477 && !strcmp(msg
->method
, "locked")) {
478 /* We got our lock. */
479 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, true);
480 } else if (msg
->type
== JSONRPC_NOTIFY
481 && !strcmp(msg
->method
, "stolen")) {
482 /* Someone else stole our lock. */
483 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, false);
484 } else if (msg
->type
== JSONRPC_ERROR
485 && idl
->state
== IDL_S_MONITOR_COND_REQUESTED
487 && json_equal(idl
->request_id
, msg
->id
)) {
488 if (msg
->error
&& !strcmp(json_string(msg
->error
),
490 /* Fall back to using "monitor" method. */
491 json_destroy(idl
->request_id
);
492 idl
->request_id
= NULL
;
493 ovsdb_idl_send_monitor_request(idl
);
494 idl
->state
= IDL_S_MONITOR_REQUESTED
;
496 } else if (msg
->type
== JSONRPC_ERROR
497 && idl
->state
== IDL_S_SCHEMA_REQUESTED
499 && json_equal(idl
->request_id
, msg
->id
)) {
500 json_destroy(idl
->request_id
);
501 idl
->request_id
= NULL
;
502 VLOG_ERR("%s: requested schema not found",
503 jsonrpc_session_get_name(idl
->session
));
504 idl
->state
= IDL_S_NO_SCHEMA
;
505 } else if ((msg
->type
== JSONRPC_ERROR
506 || msg
->type
== JSONRPC_REPLY
)
507 && ovsdb_idl_txn_process_reply(idl
, msg
)) {
508 /* ovsdb_idl_txn_process_reply() did everything needful. */
510 /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
511 * a transaction before we receive the reply, so keep the log level
513 VLOG_DBG("%s: received unexpected %s message",
514 jsonrpc_session_get_name(idl
->session
),
515 jsonrpc_msg_type_to_string(msg
->type
));
517 jsonrpc_msg_destroy(msg
);
519 ovsdb_idl_row_destroy_postprocess(idl
);
522 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
523 * do or when activity occurs on a transaction on 'idl'. */
525 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
527 jsonrpc_session_wait(idl
->session
);
528 jsonrpc_session_recv_wait(idl
->session
);
531 /* Returns a "sequence number" that represents the state of 'idl'. When
532 * ovsdb_idl_run() changes the database, the sequence number changes. The
533 * initial fetch of the entire contents of the remote database is considered to
534 * be one kind of change. Successfully acquiring a lock, if one has been
535 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
537 * As long as the sequence number does not change, the client may continue to
538 * use any data structures it obtains from 'idl'. But when it changes, the
539 * client must not access any of these data structures again, because they
540 * could have freed or reused for other purposes.
542 * The sequence number can occasionally change even if the database does not.
543 * This happens if the connection to the database drops and reconnects, which
544 * causes the database contents to be reloaded even if they didn't change. (It
545 * could also happen if the database server sends out a "change" that reflects
546 * what the IDL already thought was in the database. The database server is
547 * not supposed to do that, but bugs could in theory cause it to do so.) */
549 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
551 return idl
->change_seqno
;
554 /* Returns true if 'idl' successfully connected to the remote database and
555 * retrieved its contents (even if the connection subsequently dropped and is
556 * in the process of reconnecting). If so, then 'idl' contains an atomic
557 * snapshot of the database's contents (but it might be arbitrarily old if the
558 * connection dropped).
560 * Returns false if 'idl' has never connected or retrieved the database's
561 * contents. If so, 'idl' is empty. */
563 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
565 return ovsdb_idl_get_seqno(idl
) != 0;
568 /* Reconfigures 'idl' so that it would reconnect to the database, if
569 * connection was dropped. */
571 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
573 jsonrpc_session_enable_reconnect(idl
->session
);
576 /* Forces 'idl' to drop its connection to the database and reconnect. In the
577 * meantime, the contents of 'idl' will not change. */
579 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
581 jsonrpc_session_force_reconnect(idl
->session
);
584 /* Some IDL users should only write to write-only columns. Furthermore,
585 * writing to a column which is not write-only can cause serious performance
586 * degradations for these users. This function causes 'idl' to reject writes
587 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
589 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
591 idl
->verify_write_only
= true;
594 /* Returns true if 'idl' is currently connected or trying to connect
595 * and a negative response to a schema request has not been received */
597 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
599 return jsonrpc_session_is_alive(idl
->session
) &&
600 idl
->state
!= IDL_S_NO_SCHEMA
;
603 /* Returns the last error reported on a connection by 'idl'. The return value
604 * is 0 only if no connection made by 'idl' has ever encountered an error and
605 * a negative response to a schema request has never been received. See
606 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
609 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
613 err
= jsonrpc_session_get_last_error(idl
->session
);
617 } else if (idl
->state
== IDL_S_NO_SCHEMA
) {
624 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
628 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
630 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
633 static unsigned char *
634 ovsdb_idl_get_mode(struct ovsdb_idl
*idl
,
635 const struct ovsdb_idl_column
*column
)
639 ovs_assert(!idl
->change_seqno
);
641 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
642 const struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
643 const struct ovsdb_idl_table_class
*tc
= table
->class;
645 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
646 return &table
->modes
[column
- tc
->columns
];
654 add_ref_table(struct ovsdb_idl
*idl
, const struct ovsdb_base_type
*base
)
656 if (base
->type
== OVSDB_TYPE_UUID
&& base
->u
.uuid
.refTableName
) {
657 struct ovsdb_idl_table
*table
;
659 table
= shash_find_data(&idl
->table_by_name
,
660 base
->u
.uuid
.refTableName
);
662 table
->need_table
= true;
664 VLOG_WARN("%s IDL class missing referenced table %s",
665 idl
->class->database
, base
->u
.uuid
.refTableName
);
670 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
671 * ensures that any tables referenced by 'column' will be replicated, even if
672 * no columns in that table are selected for replication (see
673 * ovsdb_idl_add_table() for more information).
675 * This function is only useful if 'monitor_everything_by_default' was false in
676 * the call to ovsdb_idl_create(). This function should be called between
677 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
680 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
681 const struct ovsdb_idl_column
*column
)
683 *ovsdb_idl_get_mode(idl
, column
) = OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
;
684 add_ref_table(idl
, &column
->type
.key
);
685 add_ref_table(idl
, &column
->type
.value
);
688 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
689 * no columns are selected for replication. Just the necessary data for table
690 * references will be replicated (the UUID of the rows, for instance), any
691 * columns not selected for replication will remain unreplicated.
692 * This can be useful because it allows 'idl' to keep track of what rows in the
693 * table actually exist, which in turn allows columns that reference the table
694 * to have accurate contents. (The IDL presents the database with references to
695 * rows that do not exist removed.)
697 * This function is only useful if 'monitor_everything_by_default' was false in
698 * the call to ovsdb_idl_create(). This function should be called between
699 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
702 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
703 const struct ovsdb_idl_table_class
*tc
)
707 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
708 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
710 if (table
->class == tc
) {
711 table
->need_table
= true;
719 struct ovsdb_idl_clause
{
720 struct ovs_list node
;
721 enum ovsdb_function function
;
722 const struct ovsdb_idl_column
*column
;
723 struct ovsdb_datum arg
;
727 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
729 if (clause
->function
!= OVSDB_F_TRUE
&&
730 clause
->function
!= OVSDB_F_FALSE
) {
731 const char *function
= ovsdb_function_to_string(clause
->function
);
733 return json_array_create_3(json_string_create(clause
->column
->name
),
734 json_string_create(function
),
735 ovsdb_datum_to_json(&clause
->arg
,
736 &clause
->column
->type
));
739 return json_boolean_create(clause
->function
== OVSDB_F_TRUE
?
744 ovsdb_idl_clause_free(struct ovsdb_idl_clause
*clause
)
746 if (clause
->function
!= OVSDB_F_TRUE
&&
747 clause
->function
!= OVSDB_F_FALSE
) {
748 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
751 ovs_list_remove(&clause
->node
);
755 /* Clears all of the conditional clauses from table 'tc', so that all of the
756 * rows in the table will be replicated. (This is the default, so this
757 * function has an effect only if some clauses were added to 'tc' using
758 * ovsdb_idl_condition_add_clause().) */
760 ovsdb_idl_condition_reset(struct ovsdb_idl
*idl
,
761 const struct ovsdb_idl_table_class
*tc
)
763 struct ovsdb_idl_clause
*c
, *next
;
764 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
, tc
);
766 LIST_FOR_EACH_SAFE (c
, next
, node
, &table
->condition
.clauses
) {
767 ovsdb_idl_clause_free(c
);
769 idl
->cond_changed
= table
->cond_changed
= true;
773 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
,
774 const struct ovsdb_idl_table_class
*tc
)
777 ovs_list_init(&cnd
->clauses
);
780 static struct ovsdb_idl_clause
*
781 ovsdb_idl_condition_find_clause(struct ovsdb_idl_table
*table
,
782 enum ovsdb_function function
,
783 const struct ovsdb_idl_column
*column
,
784 const struct ovsdb_datum
*arg
)
786 struct ovsdb_idl_clause
*c
;
787 LIST_FOR_EACH (c
, node
, &table
->condition
.clauses
) {
788 if (c
->function
== function
&&
789 (!column
|| (c
->column
== column
&&
790 ovsdb_datum_equals(&c
->arg
,
791 arg
, &column
->type
)))) {
798 /* Adds a clause to the condition for replicating the table with class 'tc' in
801 * By default, a table has no clauses, and in that case the IDL replicates all
802 * its rows. When a table has one or more clauses, the IDL replicates only
803 * rows that satisfy at least one clause.
805 * Two distinct of clauses can be added:
807 * - A 'function' of OVSDB_F_FALSE or OVSDB_F_TRUE adds a Boolean clause. A
808 * "false" clause by itself prevents any rows from being replicated; in
809 * combination with other clauses it has no effect. A "true" clause
810 * causes every row to be replicated, regardless of whether other clauses
811 * exist (thus, a condition that includes "true" is like a condition
812 * without any clauses at all).
814 * 'column' should be NULL and 'arg' should be an empty datum (initialized
815 * with ovsdb_datum_init_empty()).
817 * - Other 'functions' add a clause of the form "<column> <function> <arg>",
818 * e.g. "column == 5" or "column <= 10". In this case, 'arg' must have a
819 * type that is compatible with 'column'.
822 ovsdb_idl_condition_add_clause(struct ovsdb_idl
*idl
,
823 const struct ovsdb_idl_table_class
*tc
,
824 enum ovsdb_function function
,
825 const struct ovsdb_idl_column
*column
,
826 const struct ovsdb_datum
*arg
)
828 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
, tc
);
830 /* Return without doing anything, if this would be a duplicate clause. */
831 if (ovsdb_idl_condition_find_clause(table
, function
, column
, arg
)) {
835 struct ovsdb_idl_clause
*clause
= xzalloc(sizeof *clause
);
836 ovs_list_init(&clause
->node
);
837 clause
->function
= function
;
838 clause
->column
= column
;
839 ovsdb_datum_clone(&clause
->arg
, arg
,
840 column
? &column
->type
: &ovsdb_type_boolean
);
841 ovs_list_push_back(&table
->condition
.clauses
, &clause
->node
);
842 idl
->cond_changed
= table
->cond_changed
= true;
843 poll_immediate_wake();
846 /* If a clause matching (function, column, arg) is included in the condition
847 * for 'tc' within 'idl', removes it. (If this was the last clause included in
848 * the table's condition, then this means that the IDL will begin replicating
849 * every row in the table.) */
851 ovsdb_idl_condition_remove_clause(struct ovsdb_idl
*idl
,
852 const struct ovsdb_idl_table_class
*tc
,
853 enum ovsdb_function function
,
854 const struct ovsdb_idl_column
*column
,
855 const struct ovsdb_datum
*arg
)
857 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
, tc
);
858 struct ovsdb_idl_clause
*c
859 = ovsdb_idl_condition_find_clause(table
, function
, column
, arg
);
861 ovsdb_idl_clause_free(c
);
862 idl
->cond_changed
= table
->cond_changed
= true;
863 poll_immediate_wake();
868 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
870 struct json
**clauses
;
871 size_t i
= 0, n_clauses
= ovs_list_size(&cnd
->clauses
);
872 struct ovsdb_idl_clause
*c
;
874 clauses
= xmalloc(n_clauses
* sizeof *clauses
);
875 LIST_FOR_EACH (c
, node
, &cnd
->clauses
) {
876 clauses
[i
++] = ovsdb_idl_clause_to_json(c
);
879 return json_array_create(clauses
, n_clauses
);
883 ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table
*table
)
885 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
886 struct json
*monitor_cond_change_request
= json_object_create();
887 struct json
*cond_json
= ovsdb_idl_condition_to_json(cond
);
889 json_object_put(monitor_cond_change_request
, "where", cond_json
);
891 return monitor_cond_change_request
;
895 ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
)
898 char uuid
[UUID_LEN
+ 1];
899 struct json
*params
, *json_uuid
;
900 struct jsonrpc_msg
*request
;
902 if (!idl
->cond_changed
|| !jsonrpc_session_is_connected(idl
->session
) ||
903 idl
->state
!= IDL_S_MONITORING_COND
) {
907 struct json
*monitor_cond_change_requests
= NULL
;
909 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
910 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
912 if (table
->cond_changed
) {
913 struct json
*req
= ovsdb_idl_create_cond_change_req(table
);
915 if (!monitor_cond_change_requests
) {
916 monitor_cond_change_requests
= json_object_create();
918 json_object_put(monitor_cond_change_requests
,
920 json_array_create_1(req
));
922 table
->cond_changed
= false;
926 /* Send request if not empty. */
927 if (monitor_cond_change_requests
) {
928 snprintf(uuid
, sizeof uuid
, UUID_FMT
,
929 UUID_ARGS(&idl
->uuid
));
930 json_uuid
= json_string_create(uuid
);
932 /* Create a new uuid */
933 uuid_generate(&idl
->uuid
);
934 snprintf(uuid
, sizeof uuid
, UUID_FMT
,
935 UUID_ARGS(&idl
->uuid
));
936 params
= json_array_create_3(json_uuid
, json_string_create(uuid
),
937 monitor_cond_change_requests
);
939 request
= jsonrpc_create_request("monitor_cond_change", params
, NULL
);
940 jsonrpc_session_send(idl
->session
, request
);
942 idl
->cond_changed
= false;
945 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
947 * This function should be called between ovsdb_idl_create() and the first call
948 * to ovsdb_idl_run().
951 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
952 const struct ovsdb_idl_column
*column
)
954 *ovsdb_idl_get_mode(idl
, column
) &= ~OVSDB_IDL_ALERT
;
957 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
958 * OVSDB_IDL_MONITOR for details.
960 * This function should be called between ovsdb_idl_create() and the first call
961 * to ovsdb_idl_run().
964 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
966 *ovsdb_idl_get_mode(idl
, column
) = 0;
969 /* Returns the most recent IDL change sequence number that caused a
970 * insert, modify or delete update to the table with class 'table_class'.
973 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
974 const struct ovsdb_idl_table_class
*table_class
)
976 struct ovsdb_idl_table
*table
977 = ovsdb_idl_table_from_class(idl
, table_class
);
978 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
980 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
981 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
983 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
984 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
989 /* For each row that contains tracked columns, IDL stores the most
990 * recent IDL change sequence numbers associateed with insert, modify
991 * and delete updates to the table.
994 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
995 enum ovsdb_idl_change change
)
997 return row
->change_seqno
[change
];
1000 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1001 * all rows whose 'column' is modified are traced. Similarly, insert
1002 * or delete of rows having 'column' are tracked. Clients are able
1003 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1006 * This function should be called between ovsdb_idl_create() and
1007 * the first call to ovsdb_idl_run(). The column to be tracked
1008 * should have OVSDB_IDL_ALERT turned on.
1011 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1012 const struct ovsdb_idl_column
*column
)
1014 if (!(*ovsdb_idl_get_mode(idl
, column
) & OVSDB_IDL_ALERT
)) {
1015 ovsdb_idl_add_column(idl
, column
);
1017 *ovsdb_idl_get_mode(idl
, column
) |= OVSDB_IDL_TRACK
;
1021 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1025 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
1026 const struct ovsdb_idl_table_class
*tc
= &idl
->class->tables
[i
];
1028 for (j
= 0; j
< tc
->n_columns
; j
++) {
1029 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1030 ovsdb_idl_track_add_column(idl
, column
);
1035 /* Returns true if 'table' has any tracked column. */
1037 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1041 for (i
= 0; i
< table
->class->n_columns
; i
++) {
1042 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1049 /* Returns the first tracked row in table with class 'table_class'
1050 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1051 const struct ovsdb_idl_row
*
1052 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1053 const struct ovsdb_idl_table_class
*table_class
)
1055 struct ovsdb_idl_table
*table
1056 = ovsdb_idl_table_from_class(idl
, table_class
);
1058 if (!ovs_list_is_empty(&table
->track_list
)) {
1059 return CONTAINER_OF(ovs_list_front(&table
->track_list
), struct ovsdb_idl_row
, track_node
);
1064 /* Returns the next tracked row in table after the specified 'row'
1065 * (in no particular order). Returns NULL if there are no tracked rows */
1066 const struct ovsdb_idl_row
*
1067 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1069 if (row
->track_node
.next
!= &row
->table
->track_list
) {
1070 return CONTAINER_OF(row
->track_node
.next
, struct ovsdb_idl_row
, track_node
);
1076 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1077 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1079 * Function returns false if 'column' is not tracked (see
1080 * ovsdb_idl_track_add_column()).
1083 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1084 const struct ovsdb_idl_column
*column
)
1086 const struct ovsdb_idl_table_class
*class;
1089 class = row
->table
->class;
1090 column_idx
= column
- class->columns
;
1092 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1099 /* Flushes the tracked rows. Client calls this function after calling
1100 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1101 * functions. This is usually done at the end of the client's processing
1102 * loop when it is ready to do ovsdb_idl_run() again.
1105 ovsdb_idl_track_clear(const struct ovsdb_idl
*idl
)
1109 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
1110 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1112 if (!ovs_list_is_empty(&table
->track_list
)) {
1113 struct ovsdb_idl_row
*row
, *next
;
1115 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1118 row
->updated
= NULL
;
1120 ovs_list_remove(&row
->track_node
);
1121 ovs_list_init(&row
->track_node
);
1122 if (ovsdb_idl_row_is_orphan(row
)) {
1123 ovsdb_idl_row_clear_old(row
);
1133 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
)
1135 struct jsonrpc_msg
*msg
;
1137 json_destroy(idl
->request_id
);
1138 msg
= jsonrpc_create_request(
1140 json_array_create_1(json_string_create(idl
->class->database
)),
1142 jsonrpc_session_send(idl
->session
, msg
);
1146 log_error(struct ovsdb_error
*error
)
1148 char *s
= ovsdb_error_to_string(error
);
1149 VLOG_WARN("error parsing database schema: %s", s
);
1151 ovsdb_error_destroy(error
);
1154 /* Frees 'schema', which is in the format returned by parse_schema(). */
1156 free_schema(struct shash
*schema
)
1159 struct shash_node
*node
, *next
;
1161 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
1162 struct sset
*sset
= node
->data
;
1165 shash_delete(schema
, node
);
1167 shash_destroy(schema
);
1172 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1173 * 7047, to obtain the names of its rows and columns. If successful, returns
1174 * an shash whose keys are table names and whose values are ssets, where each
1175 * sset contains the names of its table's columns. On failure (due to a parse
1176 * error), returns NULL.
1178 * It would also be possible to use the general-purpose OVSDB schema parser in
1179 * ovsdb-server, but that's overkill, possibly too strict for the current use
1180 * case, and would require restructuring ovsdb-server to separate the schema
1181 * code from the rest. */
1182 static struct shash
*
1183 parse_schema(const struct json
*schema_json
)
1185 struct ovsdb_parser parser
;
1186 const struct json
*tables_json
;
1187 struct ovsdb_error
*error
;
1188 struct shash_node
*node
;
1189 struct shash
*schema
;
1191 ovsdb_parser_init(&parser
, schema_json
, "database schema");
1192 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
1193 error
= ovsdb_parser_destroy(&parser
);
1199 schema
= xmalloc(sizeof *schema
);
1201 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
1202 const char *table_name
= node
->name
;
1203 const struct json
*json
= node
->data
;
1204 const struct json
*columns_json
;
1206 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
1208 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
1209 error
= ovsdb_parser_destroy(&parser
);
1212 free_schema(schema
);
1216 struct sset
*columns
= xmalloc(sizeof *columns
);
1219 struct shash_node
*node2
;
1220 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
1221 const char *column_name
= node2
->name
;
1222 sset_add(columns
, column_name
);
1224 shash_add(schema
, table_name
, columns
);
1230 ovsdb_idl_send_monitor_request__(struct ovsdb_idl
*idl
,
1233 struct shash
*schema
;
1234 struct json
*monitor_requests
;
1235 struct jsonrpc_msg
*msg
;
1236 char uuid
[UUID_LEN
+ 1];
1239 schema
= parse_schema(idl
->schema
);
1240 monitor_requests
= json_object_create();
1241 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
1242 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1243 const struct ovsdb_idl_table_class
*tc
= table
->class;
1244 struct json
*monitor_request
, *columns
, *where
;
1245 const struct sset
*table_schema
;
1248 table_schema
= (schema
1249 ? shash_find_data(schema
, table
->class->name
)
1252 columns
= table
->need_table
? json_array_create_empty() : NULL
;
1253 for (j
= 0; j
< tc
->n_columns
; j
++) {
1254 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1255 if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
1257 && !sset_contains(table_schema
, column
->name
)) {
1258 VLOG_WARN("%s table in %s database lacks %s column "
1259 "(database needs upgrade?)",
1260 table
->class->name
, idl
->class->database
,
1265 columns
= json_array_create_empty();
1267 json_array_add(columns
, json_string_create(column
->name
));
1272 if (schema
&& !table_schema
) {
1273 VLOG_WARN("%s database lacks %s table "
1274 "(database needs upgrade?)",
1275 idl
->class->database
, table
->class->name
);
1276 json_destroy(columns
);
1280 monitor_request
= json_object_create();
1281 json_object_put(monitor_request
, "columns", columns
);
1282 if (!strcmp(method
, "monitor_cond") && table
->cond_changed
&&
1283 ovs_list_size(&table
->condition
.clauses
) > 0) {
1284 where
= ovsdb_idl_condition_to_json(&table
->condition
);
1285 json_object_put(monitor_request
, "where", where
);
1286 table
->cond_changed
= false;
1288 json_object_put(monitor_requests
, tc
->name
, monitor_request
);
1291 free_schema(schema
);
1293 json_destroy(idl
->request_id
);
1295 snprintf(uuid
, sizeof uuid
, UUID_FMT
, UUID_ARGS(&idl
->uuid
));
1296 msg
= jsonrpc_create_request(
1298 json_array_create_3(json_string_create(idl
->class->database
),
1299 json_string_create(uuid
), monitor_requests
),
1301 jsonrpc_session_send(idl
->session
, msg
);
1302 idl
->cond_changed
= false;
1306 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
)
1308 ovsdb_idl_send_monitor_request__(idl
, "monitor");
1312 log_parse_update_error(struct ovsdb_error
*error
)
1314 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1315 char *s
= ovsdb_error_to_string(error
);
1316 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1319 ovsdb_error_destroy(error
);
1323 ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl
*idl
)
1325 ovsdb_idl_send_monitor_request__(idl
, "monitor_cond");
1329 ovsdb_idl_parse_update(struct ovsdb_idl
*idl
, const struct json
*table_updates
,
1330 enum ovsdb_update_version version
)
1332 struct ovsdb_error
*error
= ovsdb_idl_parse_update__(idl
, table_updates
,
1335 log_parse_update_error(error
);
1339 static struct ovsdb_error
*
1340 ovsdb_idl_parse_update__(struct ovsdb_idl
*idl
,
1341 const struct json
*table_updates
,
1342 enum ovsdb_update_version version
)
1344 const struct shash_node
*tables_node
;
1345 const char *table_updates_name
= table_updates_names
[version
];
1346 const char *table_update_name
= table_update_names
[version
];
1347 const char *row_update_name
= row_update_names
[version
];
1349 if (table_updates
->type
!= JSON_OBJECT
) {
1350 return ovsdb_syntax_error(table_updates
, NULL
,
1351 "<%s> is not an object",
1352 table_updates_name
);
1355 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
1356 const struct json
*table_update
= tables_node
->data
;
1357 const struct shash_node
*table_node
;
1358 struct ovsdb_idl_table
*table
;
1360 table
= shash_find_data(&idl
->table_by_name
, tables_node
->name
);
1362 return ovsdb_syntax_error(
1363 table_updates
, NULL
,
1364 "<%s> includes unknown table \"%s\"",
1369 if (table_update
->type
!= JSON_OBJECT
) {
1370 return ovsdb_syntax_error(table_update
, NULL
,
1371 "<%s> for table \"%s\" is "
1374 table
->class->name
);
1376 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
1377 const struct json
*row_update
= table_node
->data
;
1378 const struct json
*old_json
, *new_json
;
1381 if (!uuid_from_string(&uuid
, table_node
->name
)) {
1382 return ovsdb_syntax_error(table_update
, NULL
,
1383 "<%s> for table \"%s\" "
1384 "contains bad UUID "
1385 "\"%s\" as member name",
1390 if (row_update
->type
!= JSON_OBJECT
) {
1391 return ovsdb_syntax_error(row_update
, NULL
,
1392 "<%s> for table \"%s\" "
1393 "contains <%s> for %s that "
1403 old_json
= shash_find_data(json_object(row_update
), "old");
1404 new_json
= shash_find_data(json_object(row_update
), "new");
1405 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
1406 return ovsdb_syntax_error(old_json
, NULL
,
1407 "\"old\" <row> is not object");
1408 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
1409 return ovsdb_syntax_error(new_json
, NULL
,
1410 "\"new\" <row> is not object");
1411 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
1412 != shash_count(json_object(row_update
))) {
1413 return ovsdb_syntax_error(row_update
, NULL
,
1414 "<row-update> contains "
1415 "unexpected member");
1416 } else if (!old_json
&& !new_json
) {
1417 return ovsdb_syntax_error(row_update
, NULL
,
1418 "<row-update> missing \"old\" "
1419 "and \"new\" members");
1422 if (ovsdb_idl_process_update(table
, &uuid
, old_json
,
1424 idl
->change_seqno
++;
1428 case OVSDB_UPDATE2
: {
1429 const char *ops
[] = {"modify", "insert", "delete", "initial"};
1430 const char *operation
;
1431 const struct json
*row
;
1434 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
1436 row
= shash_find_data(json_object(row_update
), operation
);
1439 if (ovsdb_idl_process_update2(table
, &uuid
, operation
,
1441 idl
->change_seqno
++;
1447 /* row_update2 should contain one of the objects */
1448 if (i
== ARRAY_SIZE(ops
)) {
1449 return ovsdb_syntax_error(row_update
, NULL
,
1450 "<row_update2> includes unknown "
1465 static struct ovsdb_idl_row
*
1466 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1468 struct ovsdb_idl_row
*row
;
1470 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
1471 if (uuid_equals(&row
->uuid
, uuid
)) {
1478 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1481 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
1482 const struct uuid
*uuid
, const struct json
*old
,
1483 const struct json
*new)
1485 struct ovsdb_idl_row
*row
;
1487 row
= ovsdb_idl_get_row(table
, uuid
);
1490 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1491 /* XXX perhaps we should check the 'old' values? */
1492 ovsdb_idl_delete_row(row
);
1494 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1496 UUID_ARGS(uuid
), table
->class->name
);
1502 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1503 } else if (ovsdb_idl_row_is_orphan(row
)) {
1504 ovsdb_idl_insert_row(row
, new);
1506 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1507 "table %s", UUID_ARGS(uuid
), table
->class->name
);
1508 return ovsdb_idl_modify_row(row
, new);
1513 /* XXX perhaps we should check the 'old' values? */
1514 if (!ovsdb_idl_row_is_orphan(row
)) {
1515 return ovsdb_idl_modify_row(row
, new);
1517 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1518 "referenced row "UUID_FMT
" in table %s",
1519 UUID_ARGS(uuid
), table
->class->name
);
1520 ovsdb_idl_insert_row(row
, new);
1523 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1524 "in table %s", UUID_ARGS(uuid
), table
->class->name
);
1525 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1532 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1535 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
1536 const struct uuid
*uuid
,
1537 const char *operation
,
1538 const struct json
*json_row
)
1540 struct ovsdb_idl_row
*row
;
1542 row
= ovsdb_idl_get_row(table
, uuid
);
1543 if (!strcmp(operation
, "delete")) {
1545 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1546 ovsdb_idl_delete_row(row
);
1548 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1550 UUID_ARGS(uuid
), table
->class->name
);
1553 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
1556 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
1557 } else if (ovsdb_idl_row_is_orphan(row
)) {
1558 ovsdb_idl_insert_row(row
, json_row
);
1560 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1561 "table %s", UUID_ARGS(uuid
), table
->class->name
);
1562 ovsdb_idl_delete_row(row
);
1563 ovsdb_idl_insert_row(row
, json_row
);
1565 } else if (!strcmp(operation
, "modify")) {
1568 if (!ovsdb_idl_row_is_orphan(row
)) {
1569 return ovsdb_idl_modify_row_by_diff(row
, json_row
);
1571 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1572 "referenced row "UUID_FMT
" in table %s",
1573 UUID_ARGS(uuid
), table
->class->name
);
1577 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1578 "in table %s", UUID_ARGS(uuid
), table
->class->name
);
1582 VLOG_WARN_RL(&semantic_rl
, "unknown operation %s to "
1583 "table %s", operation
, table
->class->name
);
1590 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1593 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1594 * Caller needs to provide either valid 'row_json' or 'diff', but not
1597 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1598 const struct json
*diff_json
,
1599 enum ovsdb_idl_change change
)
1601 struct ovsdb_idl_table
*table
= row
->table
;
1602 const struct ovsdb_idl_table_class
*class = table
->class;
1603 struct shash_node
*node
;
1604 bool changed
= false;
1605 bool apply_diff
= diff_json
!= NULL
;
1606 const struct json
*json
= apply_diff
? diff_json
: row_json
;
1608 SHASH_FOR_EACH (node
, json_object(json
)) {
1609 const char *column_name
= node
->name
;
1610 const struct ovsdb_idl_column
*column
;
1611 struct ovsdb_datum datum
;
1612 struct ovsdb_error
*error
;
1613 unsigned int column_idx
;
1614 struct ovsdb_datum
*old
;
1616 column
= shash_find_data(&table
->columns
, column_name
);
1618 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
1619 column_name
, UUID_ARGS(&row
->uuid
));
1623 column_idx
= column
- table
->class->columns
;
1624 old
= &row
->old
[column_idx
];
1628 struct ovsdb_datum diff
;
1630 ovs_assert(!row_json
);
1631 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
1634 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
1636 ovsdb_datum_destroy(&diff
, &column
->type
);
1639 ovs_assert(!diff_json
);
1640 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
1645 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
1646 ovsdb_datum_swap(old
, &datum
);
1647 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
1649 row
->change_seqno
[change
]
1650 = row
->table
->change_seqno
[change
]
1651 = row
->table
->idl
->change_seqno
+ 1;
1652 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
1653 if (!ovs_list_is_empty(&row
->track_node
)) {
1654 ovs_list_remove(&row
->track_node
);
1656 ovs_list_push_back(&row
->table
->track_list
,
1658 if (!row
->updated
) {
1659 row
->updated
= bitmap_allocate(class->n_columns
);
1661 bitmap_set1(row
->updated
, column_idx
);
1665 /* Didn't really change but the OVSDB monitor protocol always
1666 * includes every value in a row. */
1669 ovsdb_datum_destroy(&datum
, &column
->type
);
1671 char *s
= ovsdb_error_to_string(error
);
1672 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
1673 " in table %s: %s", column_name
,
1674 UUID_ARGS(&row
->uuid
), table
->class->name
, s
);
1676 ovsdb_error_destroy(error
);
1683 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1684 enum ovsdb_idl_change change
)
1686 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
1690 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
1691 const struct json
*diff_json
,
1692 enum ovsdb_idl_change change
)
1694 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
1697 /* When a row A refers to row B through a column with a "refTable" constraint,
1698 * but row B does not exist, row B is called an "orphan row". Orphan rows
1699 * should not persist, because the database enforces referential integrity, but
1700 * they can appear transiently as changes from the database are received (the
1701 * database doesn't try to topologically sort them and circular references mean
1702 * it isn't always possible anyhow).
1704 * This function returns true if 'row' is an orphan row, otherwise false.
1707 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
1709 return !row
->old
&& !row
->new;
1712 /* Returns true if 'row' is conceptually part of the database as modified by
1713 * the current transaction (if any), false otherwise.
1715 * This function will return true if 'row' is not an orphan (see the comment on
1716 * ovsdb_idl_row_is_orphan()) and:
1718 * - 'row' exists in the database and has not been deleted within the
1719 * current transaction (if any).
1721 * - 'row' was inserted within the current transaction and has not been
1722 * deleted. (In the latter case you should not have passed 'row' in at
1723 * all, because ovsdb_idl_txn_delete() freed it.)
1725 * This function will return false if 'row' is an orphan or if 'row' was
1726 * deleted within the current transaction.
1729 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
1731 return row
->new != NULL
;
1735 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
1737 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1740 for (i
= 0; i
< class->n_columns
; i
++) {
1741 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1742 (c
->parse
)(row
, &row
->old
[i
]);
1747 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
1749 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1752 for (i
= 0; i
< class->n_columns
; i
++) {
1753 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1759 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
1761 ovs_assert(row
->old
== row
->new);
1762 if (!ovsdb_idl_row_is_orphan(row
)) {
1763 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1766 for (i
= 0; i
< class->n_columns
; i
++) {
1767 ovsdb_datum_destroy(&row
->old
[i
], &class->columns
[i
].type
);
1770 row
->old
= row
->new = NULL
;
1775 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
1777 if (row
->old
!= row
->new) {
1779 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1783 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
1784 ovsdb_datum_destroy(&row
->new[i
], &class->columns
[i
].type
);
1789 row
->written
= NULL
;
1791 row
->new = row
->old
;
1796 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
1798 struct ovsdb_idl_arc
*arc
, *next
;
1800 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
1801 * that this causes to be unreferenced, if tracking is not enabled.
1802 * If tracking is enabled, orphaned nodes are removed from hmap but not
1805 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
1806 ovs_list_remove(&arc
->dst_node
);
1808 && ovsdb_idl_row_is_orphan(arc
->dst
)
1809 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
1810 ovsdb_idl_row_destroy(arc
->dst
);
1814 ovs_list_init(&row
->src_arcs
);
1817 /* Force nodes that reference 'row' to reparse. */
1819 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
1821 struct ovsdb_idl_arc
*arc
, *next
;
1823 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
1824 * 'arc', so we need to use the "safe" variant of list traversal. However,
1825 * calling an ovsdb_idl_column's 'parse' function will add an arc
1826 * equivalent to 'arc' to row->arcs. That could be a problem for
1827 * traversal, but it adds it at the beginning of the list to prevent us
1828 * from stumbling upon it again.
1830 * (If duplicate arcs were possible then we would need to make sure that
1831 * 'next' didn't also point into 'arc''s destination, but we forbid
1832 * duplicate arcs.) */
1833 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
1834 struct ovsdb_idl_row
*ref
= arc
->src
;
1836 ovsdb_idl_row_unparse(ref
);
1837 ovsdb_idl_row_clear_arcs(ref
, false);
1838 ovsdb_idl_row_parse(ref
);
1842 static struct ovsdb_idl_row
*
1843 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
1845 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
1846 class->row_init(row
);
1847 ovs_list_init(&row
->src_arcs
);
1848 ovs_list_init(&row
->dst_arcs
);
1849 hmap_node_nullify(&row
->txn_node
);
1850 ovs_list_init(&row
->track_node
);
1854 static struct ovsdb_idl_row
*
1855 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1857 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class);
1858 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
1861 row
->map_op_written
= NULL
;
1862 row
->map_op_lists
= NULL
;
1863 row
->set_op_written
= NULL
;
1864 row
->set_op_lists
= NULL
;
1869 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
1872 ovsdb_idl_row_clear_old(row
);
1873 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
1874 ovsdb_idl_destroy_all_map_op_lists(row
);
1875 ovsdb_idl_destroy_all_set_op_lists(row
);
1876 if (ovsdb_idl_track_is_set(row
->table
)) {
1877 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
1878 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
1879 = row
->table
->idl
->change_seqno
+ 1;
1881 if (!ovs_list_is_empty(&row
->track_node
)) {
1882 ovs_list_remove(&row
->track_node
);
1884 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
1889 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
1891 if (row
->map_op_written
) {
1892 /* Clear Map Operation Lists */
1893 size_t idx
, n_columns
;
1894 const struct ovsdb_idl_column
*columns
;
1895 const struct ovsdb_type
*type
;
1896 n_columns
= row
->table
->class->n_columns
;
1897 columns
= row
->table
->class->columns
;
1898 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
1899 type
= &columns
[idx
].type
;
1900 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
1902 free(row
->map_op_lists
);
1903 bitmap_free(row
->map_op_written
);
1904 row
->map_op_lists
= NULL
;
1905 row
->map_op_written
= NULL
;
1910 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
1912 if (row
->set_op_written
) {
1913 /* Clear Set Operation Lists */
1914 size_t idx
, n_columns
;
1915 const struct ovsdb_idl_column
*columns
;
1916 const struct ovsdb_type
*type
;
1917 n_columns
= row
->table
->class->n_columns
;
1918 columns
= row
->table
->class->columns
;
1919 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
1920 type
= &columns
[idx
].type
;
1921 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
1923 free(row
->set_op_lists
);
1924 bitmap_free(row
->set_op_written
);
1925 row
->set_op_lists
= NULL
;
1926 row
->set_op_written
= NULL
;
1931 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*idl
)
1935 for (i
= 0; i
< idl
->class->n_tables
; i
++) {
1936 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1938 if (!ovs_list_is_empty(&table
->track_list
)) {
1939 struct ovsdb_idl_row
*row
, *next
;
1941 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1942 if (!ovsdb_idl_track_is_set(row
->table
)) {
1943 ovs_list_remove(&row
->track_node
);
1952 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
1954 const struct ovsdb_idl_table_class
*class = row
->table
->class;
1957 ovs_assert(!row
->old
&& !row
->new);
1958 row
->old
= row
->new = xmalloc(class->n_columns
* sizeof *row
->old
);
1959 for (i
= 0; i
< class->n_columns
; i
++) {
1960 ovsdb_datum_init_default(&row
->old
[i
], &class->columns
[i
].type
);
1962 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
1963 ovsdb_idl_row_parse(row
);
1965 ovsdb_idl_row_reparse_backrefs(row
);
1969 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
1971 ovsdb_idl_row_unparse(row
);
1972 ovsdb_idl_row_clear_arcs(row
, true);
1973 ovsdb_idl_row_clear_old(row
);
1974 if (ovs_list_is_empty(&row
->dst_arcs
)) {
1975 ovsdb_idl_row_destroy(row
);
1977 ovsdb_idl_row_reparse_backrefs(row
);
1981 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1984 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
1988 ovsdb_idl_row_unparse(row
);
1989 ovsdb_idl_row_clear_arcs(row
, true);
1990 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
1991 ovsdb_idl_row_parse(row
);
1997 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
1998 const struct json
*diff_json
)
2002 ovsdb_idl_row_unparse(row
);
2003 ovsdb_idl_row_clear_arcs(row
, true);
2004 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
2005 OVSDB_IDL_CHANGE_MODIFY
);
2006 ovsdb_idl_row_parse(row
);
2012 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
2014 const struct ovsdb_idl_arc
*arc
;
2021 /* No duplicate arcs.
2023 * We only need to test whether the first arc in dst->dst_arcs originates
2024 * at 'src', since we add all of the arcs from a given source in a clump
2025 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
2026 * added at the front of the dst_arcs list. */
2027 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
2030 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
2031 return arc
->src
!= src
;
2034 static struct ovsdb_idl_table
*
2035 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
2036 const struct ovsdb_idl_table_class
*table_class
)
2038 return &idl
->tables
[table_class
- idl
->class->tables
];
2041 /* Called by ovsdb-idlc generated code. */
2042 struct ovsdb_idl_row
*
2043 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
2044 struct ovsdb_idl_table_class
*dst_table_class
,
2045 const struct uuid
*dst_uuid
)
2047 struct ovsdb_idl
*idl
= src
->table
->idl
;
2048 struct ovsdb_idl_table
*dst_table
;
2049 struct ovsdb_idl_arc
*arc
;
2050 struct ovsdb_idl_row
*dst
;
2052 dst_table
= ovsdb_idl_table_from_class(idl
, dst_table_class
);
2053 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
2055 /* We're being called from ovsdb_idl_txn_write(). We must not update
2056 * any arcs, because the transaction will be backed out at commit or
2057 * abort time and we don't want our graph screwed up.
2059 * Just return the destination row, if there is one and it has not been
2061 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new)) {
2066 /* We're being called from some other context. Update the graph. */
2068 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
2071 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
2072 if (may_add_arc(src
, dst
)) {
2073 /* The arc *must* be added at the front of the dst_arcs list. See
2074 * ovsdb_idl_row_reparse_backrefs() for details. */
2075 arc
= xmalloc(sizeof *arc
);
2076 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
2077 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
2082 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
2086 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
2087 * pointer to the row if there is one, otherwise a null pointer. */
2088 const struct ovsdb_idl_row
*
2089 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
2090 const struct ovsdb_idl_table_class
*tc
,
2091 const struct uuid
*uuid
)
2093 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
2096 static struct ovsdb_idl_row
*
2097 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
2099 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
2100 struct ovsdb_idl_row
*row
;
2102 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
2103 if (ovsdb_idl_row_exists(row
)) {
2110 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
2113 * Database tables are internally maintained as hash tables, so adding or
2114 * removing rows while traversing the same table can cause some rows to be
2115 * visited twice or not at apply. */
2116 const struct ovsdb_idl_row
*
2117 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
2118 const struct ovsdb_idl_table_class
*table_class
)
2120 struct ovsdb_idl_table
*table
2121 = ovsdb_idl_table_from_class(idl
, table_class
);
2122 return next_real_row(table
, hmap_first(&table
->rows
));
2125 /* Returns a row following 'row' within its table, or a null pointer if 'row'
2126 * is the last row in its table. */
2127 const struct ovsdb_idl_row
*
2128 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
2130 struct ovsdb_idl_table
*table
= row
->table
;
2132 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
2135 /* Reads and returns the value of 'column' within 'row'. If an ongoing
2136 * transaction has changed 'column''s value, the modified value is returned.
2138 * The caller must not modify or free the returned value.
2140 * Various kinds of changes can invalidate the returned value: writing to the
2141 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
2142 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
2143 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
2144 * returned value is needed for a long time, it is best to make a copy of it
2145 * with ovsdb_datum_clone(). */
2146 const struct ovsdb_datum
*
2147 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
2148 const struct ovsdb_idl_column
*column
)
2150 const struct ovsdb_idl_table_class
*class;
2153 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
2155 class = row
->table
->class;
2156 column_idx
= column
- class->columns
;
2158 ovs_assert(row
->new != NULL
);
2159 ovs_assert(column_idx
< class->n_columns
);
2161 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
2162 return &row
->new[column_idx
];
2163 } else if (row
->old
) {
2164 return &row
->old
[column_idx
];
2166 return ovsdb_datum_default(&column
->type
);
2170 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
2171 * type 'key_type' and value type 'value_type'. (Scalar and set types will
2172 * have a value type of OVSDB_TYPE_VOID.)
2174 * This is useful in code that "knows" that a particular column has a given
2175 * type, so that it will abort if someone changes the column's type without
2176 * updating the code that uses it. */
2177 const struct ovsdb_datum
*
2178 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
2179 const struct ovsdb_idl_column
*column
,
2180 enum ovsdb_atomic_type key_type OVS_UNUSED
,
2181 enum ovsdb_atomic_type value_type OVS_UNUSED
)
2183 ovs_assert(column
->type
.key
.type
== key_type
);
2184 ovs_assert(column
->type
.value
.type
== value_type
);
2186 return ovsdb_idl_read(row
, column
);
2189 /* Returns true if the field represented by 'column' in 'row' may be modified,
2190 * false if it is immutable.
2192 * Normally, whether a field is mutable is controlled by its column's schema.
2193 * However, an immutable column can be set to any initial value at the time of
2194 * insertion, so if 'row' is a new row (one that is being added as part of the
2195 * current transaction, supposing that a transaction is in progress) then even
2196 * its "immutable" fields are actually mutable. */
2198 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
2199 const struct ovsdb_idl_column
*column
)
2201 return column
->mutable || (row
->new && !row
->old
);
2204 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
2205 * to all-zero-bits by some other entity. If 'row' was set up some other way
2206 * then the return value is indeterminate. */
2208 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
2210 return row
->table
== NULL
;
2215 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
2216 enum ovsdb_idl_txn_status
);
2218 /* Returns a string representation of 'status'. The caller must not modify or
2219 * free the returned string.
2221 * The return value is probably useful only for debug log messages and unit
2224 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
2227 case TXN_UNCOMMITTED
:
2228 return "uncommitted";
2231 case TXN_INCOMPLETE
:
2232 return "incomplete";
2239 case TXN_NOT_LOCKED
:
2240 return "not locked";
2247 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
2248 * active transaction at a time. See the large comment in ovsdb-idl.h for
2249 * general information on transactions. */
2250 struct ovsdb_idl_txn
*
2251 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
2253 struct ovsdb_idl_txn
*txn
;
2255 ovs_assert(!idl
->txn
);
2256 idl
->txn
= txn
= xmalloc(sizeof *txn
);
2257 txn
->request_id
= NULL
;
2259 hmap_init(&txn
->txn_rows
);
2260 txn
->status
= TXN_UNCOMMITTED
;
2262 txn
->dry_run
= false;
2263 ds_init(&txn
->comment
);
2265 txn
->inc_table
= NULL
;
2266 txn
->inc_column
= NULL
;
2268 hmap_init(&txn
->inserted_rows
);
2273 /* Appends 's', which is treated as a printf()-type format string, to the
2274 * comments that will be passed to the OVSDB server when 'txn' is committed.
2275 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
2276 * show-log" can print in a relatively human-readable form.) */
2278 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
2282 if (txn
->comment
.length
) {
2283 ds_put_char(&txn
->comment
, '\n');
2287 ds_put_format_valist(&txn
->comment
, s
, args
);
2291 /* Marks 'txn' as a transaction that will not actually modify the database. In
2292 * almost every way, the transaction is treated like other transactions. It
2293 * must be committed or aborted like other transactions, it will be sent to the
2294 * database server like other transactions, and so on. The only difference is
2295 * that the operations sent to the database server will include, as the last
2296 * step, an "abort" operation, so that any changes made by the transaction will
2297 * not actually take effect. */
2299 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
2301 txn
->dry_run
= true;
2304 /* Causes 'txn', when committed, to increment the value of 'column' within
2305 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
2306 * successfully, the client may retrieve the final (incremented) value of
2307 * 'column' with ovsdb_idl_txn_get_increment_new_value().
2309 * If at time of commit the transaction is otherwise empty, that is, it doesn't
2310 * change the database, then 'force' is important. If 'force' is false in this
2311 * case, the IDL suppresses the increment and skips a round trip to the
2312 * database server. If 'force' is true, the IDL will still increment the
2315 * The client could accomplish something similar with ovsdb_idl_read(),
2316 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
2317 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
2318 * will never (by itself) fail because of a verify error.
2320 * The intended use is for incrementing the "next_cfg" column in the
2321 * Open_vSwitch table. */
2323 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
2324 const struct ovsdb_idl_row
*row
,
2325 const struct ovsdb_idl_column
*column
,
2328 ovs_assert(!txn
->inc_table
);
2329 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
2330 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
2332 txn
->inc_table
= row
->table
->class->name
;
2333 txn
->inc_column
= column
->name
;
2334 txn
->inc_row
= row
->uuid
;
2335 txn
->inc_force
= force
;
2338 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
2339 * has been called for 'txn' but the commit is still incomplete (that is, the
2340 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
2341 * end up committing at the database server, but the client will not be able to
2342 * get any further status information back. */
2344 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
2346 struct ovsdb_idl_txn_insert
*insert
, *next
;
2348 json_destroy(txn
->request_id
);
2349 if (txn
->status
== TXN_INCOMPLETE
) {
2350 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
2352 ovsdb_idl_txn_abort(txn
);
2353 ds_destroy(&txn
->comment
);
2355 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
2358 hmap_destroy(&txn
->inserted_rows
);
2362 /* Causes poll_block() to wake up if 'txn' has completed committing. */
2364 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
2366 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
2367 poll_immediate_wake();
2371 static struct json
*
2372 where_uuid_equals(const struct uuid
*uuid
)
2375 json_array_create_1(
2376 json_array_create_3(
2377 json_string_create("_uuid"),
2378 json_string_create("=="),
2379 json_array_create_2(
2380 json_string_create("uuid"),
2381 json_string_create_nocopy(
2382 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
2386 uuid_name_from_uuid(const struct uuid
*uuid
)
2391 name
= xasprintf("row"UUID_FMT
, UUID_ARGS(uuid
));
2392 for (p
= name
; *p
!= '\0'; p
++) {
2401 static const struct ovsdb_idl_row
*
2402 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
2404 const struct ovsdb_idl_row
*row
;
2406 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
2407 if (uuid_equals(&row
->uuid
, uuid
)) {
2414 /* XXX there must be a cleaner way to do this */
2415 static struct json
*
2416 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
2418 if (json
->type
== JSON_ARRAY
) {
2422 if (json
->u
.array
.n
== 2
2423 && json
->u
.array
.elems
[0]->type
== JSON_STRING
2424 && json
->u
.array
.elems
[1]->type
== JSON_STRING
2425 && !strcmp(json
->u
.array
.elems
[0]->u
.string
, "uuid")
2426 && uuid_from_string(&uuid
, json
->u
.array
.elems
[1]->u
.string
)) {
2427 const struct ovsdb_idl_row
*row
;
2429 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
2430 if (row
&& !row
->old
&& row
->new) {
2433 return json_array_create_2(
2434 json_string_create("named-uuid"),
2435 json_string_create_nocopy(uuid_name_from_uuid(&uuid
)));
2439 for (i
= 0; i
< json
->u
.array
.n
; i
++) {
2440 json
->u
.array
.elems
[i
] = substitute_uuids(json
->u
.array
.elems
[i
],
2443 } else if (json
->type
== JSON_OBJECT
) {
2444 struct shash_node
*node
;
2446 SHASH_FOR_EACH (node
, json_object(json
)) {
2447 node
->data
= substitute_uuids(node
->data
, txn
);
2454 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
2456 struct ovsdb_idl_row
*row
, *next
;
2458 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
2459 * ovsdb_idl_column's 'parse' function, which will call
2460 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
2461 * transaction and fail to update the graph. */
2462 txn
->idl
->txn
= NULL
;
2464 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
2465 ovsdb_idl_destroy_all_map_op_lists(row
);
2466 ovsdb_idl_destroy_all_set_op_lists(row
);
2469 ovsdb_idl_row_unparse(row
);
2470 ovsdb_idl_row_clear_arcs(row
, false);
2471 ovsdb_idl_row_parse(row
);
2474 ovsdb_idl_row_unparse(row
);
2476 ovsdb_idl_row_clear_new(row
);
2479 row
->prereqs
= NULL
;
2482 row
->written
= NULL
;
2484 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
2485 hmap_node_nullify(&row
->txn_node
);
2487 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2491 hmap_destroy(&txn
->txn_rows
);
2492 hmap_init(&txn
->txn_rows
);
2496 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
2497 struct json
*mutations
)
2499 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2501 bool any_mutations
= false;
2503 if (row
->map_op_written
) {
2504 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
2505 struct map_op_list
*map_op_list
;
2506 const struct ovsdb_idl_column
*column
;
2507 const struct ovsdb_datum
*old_datum
;
2508 enum ovsdb_atomic_type key_type
, value_type
;
2509 struct json
*mutation
, *map
, *col_name
, *mutator
;
2510 struct json
*del_set
, *ins_map
;
2511 bool any_del
, any_ins
;
2513 map_op_list
= row
->map_op_lists
[idx
];
2514 column
= &class->columns
[idx
];
2515 key_type
= column
->type
.key
.type
;
2516 value_type
= column
->type
.value
.type
;
2518 /* Get the value to be changed */
2519 if (row
->new && row
->written
&& bitmap_is_set(row
->written
,idx
)) {
2520 old_datum
= &row
->new[idx
];
2521 } else if (row
->old
!= NULL
) {
2522 old_datum
= &row
->old
[idx
];
2524 old_datum
= ovsdb_datum_default(&column
->type
);
2527 del_set
= json_array_create_empty();
2528 ins_map
= json_array_create_empty();
2532 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
2533 map_op
= map_op_list_next(map_op_list
, map_op
)) {
2535 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2536 /* Find out if value really changed. */
2537 struct ovsdb_datum
*new_datum
;
2539 new_datum
= map_op_datum(map_op
);
2540 pos
= ovsdb_datum_find_key(old_datum
,
2541 &new_datum
->keys
[0],
2543 if (ovsdb_atom_equals(&new_datum
->values
[0],
2544 &old_datum
->values
[pos
],
2546 /* No change in value. Move on to next update. */
2549 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
2550 /* Verify that there is a key to delete. */
2552 pos
= ovsdb_datum_find_key(old_datum
,
2553 &map_op_datum(map_op
)->keys
[0],
2555 if (pos
== UINT_MAX
) {
2556 /* No key to delete. Move on to next update. */
2557 VLOG_WARN("Trying to delete a key that doesn't "
2558 "exist in the map.");
2563 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
2564 map
= json_array_create_2(
2565 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2567 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2569 json_array_add(ins_map
, map
);
2571 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
2572 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2574 json_array_add(del_set
, map
);
2578 /* Generate an additional insert mutate for updates. */
2579 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2580 map
= json_array_create_2(
2581 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2583 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2585 json_array_add(ins_map
, map
);
2591 col_name
= json_string_create(column
->name
);
2592 mutator
= json_string_create("delete");
2593 map
= json_array_create_2(json_string_create("set"), del_set
);
2594 mutation
= json_array_create_3(col_name
, mutator
, map
);
2595 json_array_add(mutations
, mutation
);
2596 any_mutations
= true;
2598 json_destroy(del_set
);
2601 col_name
= json_string_create(column
->name
);
2602 mutator
= json_string_create("insert");
2603 map
= json_array_create_2(json_string_create("map"), ins_map
);
2604 mutation
= json_array_create_3(col_name
, mutator
, map
);
2605 json_array_add(mutations
, mutation
);
2606 any_mutations
= true;
2608 json_destroy(ins_map
);
2612 if (row
->set_op_written
) {
2613 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
2614 struct set_op_list
*set_op_list
;
2615 const struct ovsdb_idl_column
*column
;
2616 const struct ovsdb_datum
*old_datum
;
2617 enum ovsdb_atomic_type key_type
;
2618 struct json
*mutation
, *set
, *col_name
, *mutator
;
2619 struct json
*del_set
, *ins_set
;
2620 bool any_del
, any_ins
;
2622 set_op_list
= row
->set_op_lists
[idx
];
2623 column
= &class->columns
[idx
];
2624 key_type
= column
->type
.key
.type
;
2626 /* Get the value to be changed */
2627 if (row
->new && row
->written
&& bitmap_is_set(row
->written
,idx
)) {
2628 old_datum
= &row
->new[idx
];
2629 } else if (row
->old
!= NULL
) {
2630 old_datum
= &row
->old
[idx
];
2632 old_datum
= ovsdb_datum_default(&column
->type
);
2635 del_set
= json_array_create_empty();
2636 ins_set
= json_array_create_empty();
2640 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
2641 set_op
= set_op_list_next(set_op_list
, set_op
)) {
2642 if (set_op_type(set_op
) == SET_OP_INSERT
) {
2643 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
2645 json_array_add(ins_set
, set
);
2647 } else { /* SETP_OP_DELETE */
2648 /* Verify that there is a key to delete. */
2650 pos
= ovsdb_datum_find_key(old_datum
,
2651 &set_op_datum(set_op
)->keys
[0],
2653 if (pos
== UINT_MAX
) {
2654 /* No key to delete. Move on to next update. */
2655 VLOG_WARN("Trying to delete a key that doesn't "
2656 "exist in the set.");
2659 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
2661 json_array_add(del_set
, set
);
2666 col_name
= json_string_create(column
->name
);
2667 mutator
= json_string_create("delete");
2668 set
= json_array_create_2(json_string_create("set"), del_set
);
2669 mutation
= json_array_create_3(col_name
, mutator
, set
);
2670 json_array_add(mutations
, mutation
);
2671 any_mutations
= true;
2673 json_destroy(del_set
);
2676 col_name
= json_string_create(column
->name
);
2677 mutator
= json_string_create("insert");
2678 set
= json_array_create_2(json_string_create("set"), ins_set
);
2679 mutation
= json_array_create_3(col_name
, mutator
, set
);
2680 json_array_add(mutations
, mutation
);
2681 any_mutations
= true;
2683 json_destroy(ins_set
);
2687 return any_mutations
;
2690 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
2691 * of the following TXN_* constants:
2695 * The transaction is in progress, but not yet complete. The caller
2696 * should call again later, after calling ovsdb_idl_run() to let the IDL
2697 * do OVSDB protocol processing.
2701 * The transaction is complete. (It didn't actually change the database,
2702 * so the IDL didn't send any request to the database server.)
2706 * The caller previously called ovsdb_idl_txn_abort().
2710 * The transaction was successful. The update made by the transaction
2711 * (and possibly other changes made by other database clients) should
2712 * already be visible in the IDL.
2716 * The transaction failed for some transient reason, e.g. because a
2717 * "verify" operation reported an inconsistency or due to a network
2718 * problem. The caller should wait for a change to the database, then
2719 * compose a new transaction, and commit the new transaction.
2721 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
2722 * the database. It is important to use its return value *before* the
2723 * initial call to ovsdb_idl_txn_commit() as the baseline for this
2724 * purpose, because the change that one should wait for can happen after
2725 * the initial call but before the call that returns TXN_TRY_AGAIN, and
2726 * using some other baseline value in that situation could cause an
2727 * indefinite wait if the database rarely changes.
2731 * The transaction failed because the IDL has been configured to require
2732 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
2733 * has already lost it.
2735 * Committing a transaction rolls back all of the changes that it made to the
2736 * IDL's copy of the database. If the transaction commits successfully, then
2737 * the database server will send an update and, thus, the IDL will be updated
2738 * with the committed changes. */
2739 enum ovsdb_idl_txn_status
2740 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
2742 struct ovsdb_idl_row
*row
;
2743 struct json
*operations
;
2746 if (txn
!= txn
->idl
->txn
) {
2750 /* If we need a lock but don't have it, give up quickly. */
2751 if (txn
->idl
->lock_name
&& !ovsdb_idl_has_lock(txn
->idl
)) {
2752 txn
->status
= TXN_NOT_LOCKED
;
2753 goto disassemble_out
;
2756 operations
= json_array_create_1(
2757 json_string_create(txn
->idl
->class->database
));
2759 /* Assert that we have the required lock (avoiding a race). */
2760 if (txn
->idl
->lock_name
) {
2761 struct json
*op
= json_object_create();
2762 json_array_add(operations
, op
);
2763 json_object_put_string(op
, "op", "assert");
2764 json_object_put_string(op
, "lock", txn
->idl
->lock_name
);
2767 /* Add prerequisites and declarations of new rows. */
2768 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2769 /* XXX check that deleted rows exist even if no prereqs? */
2771 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2772 size_t n_columns
= class->n_columns
;
2773 struct json
*op
, *columns
, *row_json
;
2776 op
= json_object_create();
2777 json_array_add(operations
, op
);
2778 json_object_put_string(op
, "op", "wait");
2779 json_object_put_string(op
, "table", class->name
);
2780 json_object_put(op
, "timeout", json_integer_create(0));
2781 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2782 json_object_put_string(op
, "until", "==");
2783 columns
= json_array_create_empty();
2784 json_object_put(op
, "columns", columns
);
2785 row_json
= json_object_create();
2786 json_object_put(op
, "rows", json_array_create_1(row_json
));
2788 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
2789 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
2790 json_array_add(columns
, json_string_create(column
->name
));
2791 json_object_put(row_json
, column
->name
,
2792 ovsdb_datum_to_json(&row
->old
[idx
],
2799 any_updates
= false;
2800 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2801 const struct ovsdb_idl_table_class
*class = row
->table
->class;
2804 if (class->is_root
) {
2805 struct json
*op
= json_object_create();
2806 json_object_put_string(op
, "op", "delete");
2807 json_object_put_string(op
, "table", class->name
);
2808 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2809 json_array_add(operations
, op
);
2812 /* Let ovsdb-server decide whether to really delete it. */
2814 } else if (row
->old
!= row
->new) {
2815 struct json
*row_json
;
2819 op
= json_object_create();
2820 json_object_put_string(op
, "op", row
->old
? "update" : "insert");
2821 json_object_put_string(op
, "table", class->name
);
2823 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2825 struct ovsdb_idl_txn_insert
*insert
;
2829 json_object_put(op
, "uuid-name",
2830 json_string_create_nocopy(
2831 uuid_name_from_uuid(&row
->uuid
)));
2833 insert
= xmalloc(sizeof *insert
);
2834 insert
->dummy
= row
->uuid
;
2835 insert
->op_index
= operations
->u
.array
.n
- 1;
2836 uuid_zero(&insert
->real
);
2837 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
2838 uuid_hash(&insert
->dummy
));
2840 row_json
= json_object_create();
2841 json_object_put(op
, "row", row_json
);
2844 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
2845 const struct ovsdb_idl_column
*column
=
2846 &class->columns
[idx
];
2849 || !ovsdb_datum_is_default(&row
->new[idx
],
2851 json_object_put(row_json
, column
->name
,
2853 ovsdb_datum_to_json(&row
->new[idx
],
2857 /* If anything really changed, consider it an update.
2858 * We can't suppress not-really-changed values earlier
2859 * or transactions would become nonatomic (see the big
2860 * comment inside ovsdb_idl_txn_write()). */
2861 if (!any_updates
&& row
->old
&&
2862 !ovsdb_datum_equals(&row
->old
[idx
], &row
->new[idx
],
2870 if (!row
->old
|| !shash_is_empty(json_object(row_json
))) {
2871 json_array_add(operations
, op
);
2877 /* Add mutate operation, for partial map or partial set updates. */
2878 if (row
->map_op_written
|| row
->set_op_written
) {
2879 struct json
*op
, *mutations
;
2882 op
= json_object_create();
2883 json_object_put_string(op
, "op", "mutate");
2884 json_object_put_string(op
, "table", class->name
);
2885 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2886 mutations
= json_array_create_empty();
2887 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
2888 json_object_put(op
, "mutations", mutations
);
2890 if (any_mutations
) {
2891 op
= substitute_uuids(op
, txn
);
2892 json_array_add(operations
, op
);
2900 /* Add increment. */
2901 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
2903 txn
->inc_index
= operations
->u
.array
.n
- 1;
2905 struct json
*op
= json_object_create();
2906 json_object_put_string(op
, "op", "mutate");
2907 json_object_put_string(op
, "table", txn
->inc_table
);
2908 json_object_put(op
, "where",
2909 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
2911 json_object_put(op
, "mutations",
2912 json_array_create_1(
2913 json_array_create_3(
2914 json_string_create(txn
->inc_column
),
2915 json_string_create("+="),
2916 json_integer_create(1))));
2917 json_array_add(operations
, op
);
2919 op
= json_object_create();
2920 json_object_put_string(op
, "op", "select");
2921 json_object_put_string(op
, "table", txn
->inc_table
);
2922 json_object_put(op
, "where",
2923 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
2925 json_object_put(op
, "columns",
2926 json_array_create_1(json_string_create(
2928 json_array_add(operations
, op
);
2931 if (txn
->comment
.length
) {
2932 struct json
*op
= json_object_create();
2933 json_object_put_string(op
, "op", "comment");
2934 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
2935 json_array_add(operations
, op
);
2939 struct json
*op
= json_object_create();
2940 json_object_put_string(op
, "op", "abort");
2941 json_array_add(operations
, op
);
2945 txn
->status
= TXN_UNCHANGED
;
2946 json_destroy(operations
);
2947 } else if (!jsonrpc_session_send(
2949 jsonrpc_create_request(
2950 "transact", operations
, &txn
->request_id
))) {
2951 hmap_insert(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
,
2952 json_hash(txn
->request_id
, 0));
2953 txn
->status
= TXN_INCOMPLETE
;
2955 txn
->status
= TXN_TRY_AGAIN
;
2959 ovsdb_idl_txn_disassemble(txn
);
2961 switch (txn
->status
) {
2962 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
2963 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
2964 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
2965 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
2966 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
2967 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
2968 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
2969 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
2975 /* Attempts to commit 'txn', blocking until the commit either succeeds or
2976 * fails. Returns the final commit status, which may be any TXN_* value other
2977 * than TXN_INCOMPLETE.
2979 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
2980 * return value of ovsdb_idl_get_seqno() to change. */
2981 enum ovsdb_idl_txn_status
2982 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
2984 enum ovsdb_idl_txn_status status
;
2987 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
2988 ovsdb_idl_run(txn
->idl
);
2989 ovsdb_idl_wait(txn
->idl
);
2990 ovsdb_idl_txn_wait(txn
);
2996 /* Returns the final (incremented) value of the column in 'txn' that was set to
2997 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
3000 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
3002 ovs_assert(txn
->status
== TXN_SUCCESS
);
3003 return txn
->inc_new_value
;
3006 /* Aborts 'txn' without sending it to the database server. This is effective
3007 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
3008 * Otherwise, it has no effect.
3010 * Aborting a transaction doesn't free its memory. Use
3011 * ovsdb_idl_txn_destroy() to do that. */
3013 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
3015 ovsdb_idl_txn_disassemble(txn
);
3016 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
3017 txn
->status
= TXN_ABORTED
;
3021 /* Returns a string that reports the error status for 'txn'. The caller must
3022 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
3023 * for 'txn' may free the returned string.
3025 * The return value is ordinarily one of the strings that
3026 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
3027 * due to an error reported by the database server, the return value is that
3030 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
3032 if (txn
->status
!= TXN_ERROR
) {
3033 return ovsdb_idl_txn_status_to_string(txn
->status
);
3034 } else if (txn
->error
) {
3037 return "no error details available";
3042 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
3043 const struct json
*json
)
3045 if (txn
->error
== NULL
) {
3046 txn
->error
= json_to_string(json
, JSSF_SORT
);
3050 /* For transaction 'txn' that completed successfully, finds and returns the
3051 * permanent UUID that the database assigned to a newly inserted row, given the
3052 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
3054 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
3055 * if it was assigned by that function and then deleted by
3056 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
3057 * and then deleted within a single transaction are never sent to the database
3058 * server, so it never assigns them a permanent UUID.) */
3060 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
3061 const struct uuid
*uuid
)
3063 const struct ovsdb_idl_txn_insert
*insert
;
3065 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
3066 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
3067 uuid_hash(uuid
), &txn
->inserted_rows
) {
3068 if (uuid_equals(uuid
, &insert
->dummy
)) {
3069 return &insert
->real
;
3076 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3077 enum ovsdb_idl_txn_status status
)
3079 txn
->status
= status
;
3080 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
3083 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
3084 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
3087 * 'datum' must have the correct type for its column. The IDL does not check
3088 * that it meets schema constraints, but ovsdb-server will do so at commit time
3089 * so it had better be correct.
3091 * A transaction must be in progress. Replication of 'column' must not have
3092 * been disabled (by calling ovsdb_idl_omit()).
3094 * Usually this function is used indirectly through one of the "set" functions
3095 * generated by ovsdb-idlc.
3097 * Takes ownership of what 'datum' points to (and in some cases destroys that
3098 * data before returning) but makes a copy of 'datum' itself. (Commonly
3099 * 'datum' is on the caller's stack.) */
3101 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
3102 const struct ovsdb_idl_column
*column
,
3103 struct ovsdb_datum
*datum
, bool owns_datum
)
3105 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3106 const struct ovsdb_idl_table_class
*class;
3110 if (ovsdb_idl_row_is_synthetic(row
)) {
3114 class = row
->table
->class;
3115 column_idx
= column
- class->columns
;
3116 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
3118 ovs_assert(row
->new != NULL
);
3119 ovs_assert(column_idx
< class->n_columns
);
3120 ovs_assert(row
->old
== NULL
||
3121 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3123 if (row
->table
->idl
->verify_write_only
&& !write_only
) {
3124 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
3125 " explicitly configured not to.", class->name
, column
->name
);
3129 /* If this is a write-only column and the datum being written is the same
3130 * as the one already there, just skip the update entirely. This is worth
3131 * optimizing because we have a lot of columns that get periodically
3132 * refreshed into the database but don't actually change that often.
3134 * We don't do this for read/write columns because that would break
3135 * atomicity of transactions--some other client might have written a
3136 * different value in that column since we read it. (But if a whole
3137 * transaction only does writes of existing values, without making any real
3138 * changes, we will drop the whole transaction later in
3139 * ovsdb_idl_txn_commit().) */
3140 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
3141 datum
, &column
->type
)) {
3145 if (hmap_node_is_null(&row
->txn_node
)) {
3146 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3147 uuid_hash(&row
->uuid
));
3149 if (row
->old
== row
->new) {
3150 row
->new = xmalloc(class->n_columns
* sizeof *row
->new);
3152 if (!row
->written
) {
3153 row
->written
= bitmap_allocate(class->n_columns
);
3155 if (bitmap_is_set(row
->written
, column_idx
)) {
3156 ovsdb_datum_destroy(&row
->new[column_idx
], &column
->type
);
3158 bitmap_set1(row
->written
, column_idx
);
3161 row
->new[column_idx
] = *datum
;
3163 ovsdb_datum_clone(&row
->new[column_idx
], datum
, &column
->type
);
3165 (column
->unparse
)(row
);
3166 (column
->parse
)(row
, &row
->new[column_idx
]);
3171 ovsdb_datum_destroy(datum
, &column
->type
);
3176 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
3177 const struct ovsdb_idl_column
*column
,
3178 struct ovsdb_datum
*datum
)
3180 ovsdb_idl_txn_write__(row
, column
, datum
, true);
3184 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
3185 const struct ovsdb_idl_column
*column
,
3186 const struct ovsdb_datum
*datum
)
3188 ovsdb_idl_txn_write__(row
, column
,
3189 CONST_CAST(struct ovsdb_datum
*, datum
), false);
3192 /* Causes the original contents of 'column' in 'row_' to be verified as a
3193 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
3194 * changed (or if 'row_' was deleted) between the time that the IDL originally
3195 * read its contents and the time that the transaction commits, then the
3196 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_AGAIN_WAIT or
3197 * TXN_AGAIN_NOW (depending on whether the database change has already been
3200 * The intention is that, to ensure that no transaction commits based on dirty
3201 * reads, an application should call ovsdb_idl_txn_verify() on each data item
3202 * read as part of a read-modify-write operation.
3204 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
3205 * value of 'column' is already known:
3207 * - If 'row_' is a row created by the current transaction (returned by
3208 * ovsdb_idl_txn_insert()).
3210 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
3211 * within the current transaction.
3213 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
3214 * ovsdb_idl_txn_write() for a given read-modify-write.
3216 * A transaction must be in progress.
3218 * Usually this function is used indirectly through one of the "verify"
3219 * functions generated by ovsdb-idlc. */
3221 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
3222 const struct ovsdb_idl_column
*column
)
3224 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3225 const struct ovsdb_idl_table_class
*class;
3228 if (ovsdb_idl_row_is_synthetic(row
)) {
3232 class = row
->table
->class;
3233 column_idx
= column
- class->columns
;
3235 ovs_assert(row
->new != NULL
);
3236 ovs_assert(row
->old
== NULL
||
3237 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3239 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
3243 if (hmap_node_is_null(&row
->txn_node
)) {
3244 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3245 uuid_hash(&row
->uuid
));
3247 if (!row
->prereqs
) {
3248 row
->prereqs
= bitmap_allocate(class->n_columns
);
3250 bitmap_set1(row
->prereqs
, column_idx
);
3253 /* Deletes 'row_' from its table. May free 'row_', so it must not be
3254 * accessed afterward.
3256 * A transaction must be in progress.
3258 * Usually this function is used indirectly through one of the "delete"
3259 * functions generated by ovsdb-idlc. */
3261 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
3263 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3265 if (ovsdb_idl_row_is_synthetic(row
)) {
3269 ovs_assert(row
->new != NULL
);
3271 ovsdb_idl_row_unparse(row
);
3272 ovsdb_idl_row_clear_new(row
);
3273 ovs_assert(!row
->prereqs
);
3274 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3275 hmap_remove(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
);
3279 if (hmap_node_is_null(&row
->txn_node
)) {
3280 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3281 uuid_hash(&row
->uuid
));
3283 ovsdb_idl_row_clear_new(row
);
3287 /* Inserts and returns a new row in the table with the specified 'class' in the
3288 * database with open transaction 'txn'.
3290 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
3291 * randomly generated; otherwise 'uuid' should specify a randomly generated
3292 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
3293 * 'txn' is committed, but the IDL will replace any uses of the provisional
3294 * UUID in the data to be to be committed by the UUID assigned by
3297 * Usually this function is used indirectly through one of the "insert"
3298 * functions generated by ovsdb-idlc. */
3299 const struct ovsdb_idl_row
*
3300 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
3301 const struct ovsdb_idl_table_class
*class,
3302 const struct uuid
*uuid
)
3304 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
3307 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
3310 uuid_generate(&row
->uuid
);
3313 row
->table
= ovsdb_idl_table_from_class(txn
->idl
, class);
3314 row
->new = xmalloc(class->n_columns
* sizeof *row
->new);
3315 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
3316 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
3321 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
3323 struct ovsdb_idl_txn
*txn
;
3325 HMAP_FOR_EACH (txn
, hmap_node
, &idl
->outstanding_txns
) {
3326 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
3330 static struct ovsdb_idl_txn
*
3331 ovsdb_idl_txn_find(struct ovsdb_idl
*idl
, const struct json
*id
)
3333 struct ovsdb_idl_txn
*txn
;
3335 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
3336 json_hash(id
, 0), &idl
->outstanding_txns
) {
3337 if (json_equal(id
, txn
->request_id
)) {
3345 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
3348 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
3350 } else if (json
->type
!= type
) {
3351 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
3352 name
, json_type_to_string(json
->type
),
3353 json_type_to_string(type
));
3361 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
3362 const struct json_array
*results
)
3364 struct json
*count
, *rows
, *row
, *column
;
3365 struct shash
*mutate
, *select
;
3367 if (txn
->inc_index
+ 2 > results
->n
) {
3368 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3369 "for increment (has %"PRIuSIZE
", needs %u)",
3370 results
->n
, txn
->inc_index
+ 2);
3374 /* We know that this is a JSON object because the loop in
3375 * ovsdb_idl_txn_process_reply() checked. */
3376 mutate
= json_object(results
->elems
[txn
->inc_index
]);
3377 count
= shash_find_data(mutate
, "count");
3378 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
3381 if (count
->u
.integer
!= 1) {
3382 VLOG_WARN_RL(&syntax_rl
,
3383 "\"mutate\" reply \"count\" is %lld instead of 1",
3388 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
3389 rows
= shash_find_data(select
, "rows");
3390 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
3393 if (rows
->u
.array
.n
!= 1) {
3394 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
3399 row
= rows
->u
.array
.elems
[0];
3400 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
3403 column
= shash_find_data(json_object(row
), txn
->inc_column
);
3404 if (!check_json_type(column
, JSON_INTEGER
,
3405 "\"select\" reply inc column")) {
3408 txn
->inc_new_value
= column
->u
.integer
;
3413 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
3414 const struct json_array
*results
)
3416 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
3417 struct ovsdb_error
*error
;
3418 struct json
*json_uuid
;
3419 union ovsdb_atom uuid
;
3420 struct shash
*reply
;
3422 if (insert
->op_index
>= results
->n
) {
3423 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3424 "for insert (has %"PRIuSIZE
", needs %u)",
3425 results
->n
, insert
->op_index
);
3429 /* We know that this is a JSON object because the loop in
3430 * ovsdb_idl_txn_process_reply() checked. */
3431 reply
= json_object(results
->elems
[insert
->op_index
]);
3432 json_uuid
= shash_find_data(reply
, "uuid");
3433 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
3437 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
3439 char *s
= ovsdb_error_to_string(error
);
3440 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
3443 ovsdb_error_destroy(error
);
3447 insert
->real
= uuid
.uuid
;
3453 ovsdb_idl_txn_process_reply(struct ovsdb_idl
*idl
,
3454 const struct jsonrpc_msg
*msg
)
3456 struct ovsdb_idl_txn
*txn
;
3457 enum ovsdb_idl_txn_status status
;
3459 txn
= ovsdb_idl_txn_find(idl
, msg
->id
);
3464 if (msg
->type
== JSONRPC_ERROR
) {
3466 } else if (msg
->result
->type
!= JSON_ARRAY
) {
3467 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
3470 struct json_array
*ops
= &msg
->result
->u
.array
;
3471 int hard_errors
= 0;
3472 int soft_errors
= 0;
3473 int lock_errors
= 0;
3476 for (i
= 0; i
< ops
->n
; i
++) {
3477 struct json
*op
= ops
->elems
[i
];
3479 if (op
->type
== JSON_NULL
) {
3480 /* This isn't an error in itself but indicates that some prior
3481 * operation failed, so make sure that we know about it. */
3483 } else if (op
->type
== JSON_OBJECT
) {
3486 error
= shash_find_data(json_object(op
), "error");
3488 if (error
->type
== JSON_STRING
) {
3489 if (!strcmp(error
->u
.string
, "timed out")) {
3491 } else if (!strcmp(error
->u
.string
, "not owner")) {
3493 } else if (strcmp(error
->u
.string
, "aborted")) {
3495 ovsdb_idl_txn_set_error_json(txn
, op
);
3499 ovsdb_idl_txn_set_error_json(txn
, op
);
3500 VLOG_WARN_RL(&syntax_rl
,
3501 "\"error\" in reply is not JSON string");
3506 ovsdb_idl_txn_set_error_json(txn
, op
);
3507 VLOG_WARN_RL(&syntax_rl
,
3508 "operation reply is not JSON null or object");
3512 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
3513 struct ovsdb_idl_txn_insert
*insert
;
3515 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
3519 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
3520 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
3526 status
= (hard_errors
? TXN_ERROR
3527 : lock_errors
? TXN_NOT_LOCKED
3528 : soft_errors
? TXN_TRY_AGAIN
3532 ovsdb_idl_txn_complete(txn
, status
);
3536 /* Returns the transaction currently active for 'row''s IDL. A transaction
3537 * must currently be active. */
3538 struct ovsdb_idl_txn
*
3539 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
3541 struct ovsdb_idl_txn
*txn
= row
->table
->idl
->txn
;
3542 ovs_assert(txn
!= NULL
);
3546 /* Returns the IDL on which 'txn' acts. */
3548 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
3553 /* Blocks until 'idl' successfully connects to the remote database and
3554 * retrieves its contents. */
3556 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
3560 if (ovsdb_idl_has_ever_connected(idl
)) {
3563 ovsdb_idl_wait(idl
);
3568 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
3569 * the database server and to avoid modifying the database when the lock cannot
3570 * be acquired (that is, when another client has the same lock).
3572 * If 'lock_name' is NULL, drops the locking requirement and releases the
3575 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
3577 ovs_assert(!idl
->txn
);
3578 ovs_assert(hmap_is_empty(&idl
->outstanding_txns
));
3580 if (idl
->lock_name
&& (!lock_name
|| strcmp(lock_name
, idl
->lock_name
))) {
3581 /* Release previous lock. */
3582 ovsdb_idl_send_unlock_request(idl
);
3583 free(idl
->lock_name
);
3584 idl
->lock_name
= NULL
;
3585 idl
->is_lock_contended
= false;
3588 if (lock_name
&& !idl
->lock_name
) {
3589 /* Acquire new lock. */
3590 idl
->lock_name
= xstrdup(lock_name
);
3591 ovsdb_idl_send_lock_request(idl
);
3595 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
3597 * Locking and unlocking happens asynchronously from the database client's
3598 * point of view, so the information is only useful for optimization (e.g. if
3599 * the client doesn't have the lock then there's no point in trying to write to
3602 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
3604 return idl
->has_lock
;
3607 /* Returns true if 'idl' is configured to obtain a lock but the database server
3608 * has indicated that some other client already owns the requested lock. */
3610 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
3612 return idl
->is_lock_contended
;
3616 ovsdb_idl_update_has_lock(struct ovsdb_idl
*idl
, bool new_has_lock
)
3618 if (new_has_lock
&& !idl
->has_lock
) {
3619 if (idl
->state
== IDL_S_MONITORING
||
3620 idl
->state
== IDL_S_MONITORING_COND
) {
3621 idl
->change_seqno
++;
3623 /* We're setting up a session, so don't signal that the database
3624 * changed. Finalizing the session will increment change_seqno
3627 idl
->is_lock_contended
= false;
3629 idl
->has_lock
= new_has_lock
;
3633 ovsdb_idl_send_lock_request__(struct ovsdb_idl
*idl
, const char *method
,
3636 ovsdb_idl_update_has_lock(idl
, false);
3638 json_destroy(idl
->lock_request_id
);
3639 idl
->lock_request_id
= NULL
;
3641 if (jsonrpc_session_is_connected(idl
->session
)) {
3642 struct json
*params
;
3644 params
= json_array_create_1(json_string_create(idl
->lock_name
));
3645 jsonrpc_session_send(idl
->session
,
3646 jsonrpc_create_request(method
, params
, idp
));
3651 ovsdb_idl_send_lock_request(struct ovsdb_idl
*idl
)
3653 ovsdb_idl_send_lock_request__(idl
, "lock", &idl
->lock_request_id
);
3657 ovsdb_idl_send_unlock_request(struct ovsdb_idl
*idl
)
3659 ovsdb_idl_send_lock_request__(idl
, "unlock", NULL
);
3663 ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*idl
, const struct json
*result
)
3667 json_destroy(idl
->lock_request_id
);
3668 idl
->lock_request_id
= NULL
;
3670 if (result
->type
== JSON_OBJECT
) {
3671 const struct json
*locked
;
3673 locked
= shash_find_data(json_object(result
), "locked");
3674 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
3679 ovsdb_idl_update_has_lock(idl
, got_lock
);
3681 idl
->is_lock_contended
= true;
3686 ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*idl
,
3687 const struct json
*params
,
3691 && params
->type
== JSON_ARRAY
3692 && json_array(params
)->n
> 0
3693 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
3694 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
3696 if (!strcmp(idl
->lock_name
, lock_name
)) {
3697 ovsdb_idl_update_has_lock(idl
, new_has_lock
);
3698 if (!new_has_lock
) {
3699 idl
->is_lock_contended
= true;
3705 /* Inserts a new Map Operation into current transaction. */
3707 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
3708 const struct ovsdb_idl_column
*column
,
3709 struct ovsdb_datum
*datum
,
3710 enum map_op_type op_type
)
3712 const struct ovsdb_idl_table_class
*class;
3714 struct map_op
*map_op
;
3716 class = row
->table
->class;
3717 column_idx
= column
- class->columns
;
3719 /* Check if a map operation list exists for this column. */
3720 if (!row
->map_op_written
) {
3721 row
->map_op_written
= bitmap_allocate(class->n_columns
);
3722 row
->map_op_lists
= xzalloc(class->n_columns
*
3723 sizeof *row
->map_op_lists
);
3725 if (!row
->map_op_lists
[column_idx
]) {
3726 row
->map_op_lists
[column_idx
] = map_op_list_create();
3729 /* Add a map operation to the corresponding list. */
3730 map_op
= map_op_create(datum
, op_type
);
3731 bitmap_set1(row
->map_op_written
, column_idx
);
3732 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
3734 /* Add this row to transaction's list of rows. */
3735 if (hmap_node_is_null(&row
->txn_node
)) {
3736 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3737 uuid_hash(&row
->uuid
));
3741 /* Inserts a new Set Operation into current transaction. */
3743 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
3744 const struct ovsdb_idl_column
*column
,
3745 struct ovsdb_datum
*datum
,
3746 enum set_op_type op_type
)
3748 const struct ovsdb_idl_table_class
*class;
3750 struct set_op
*set_op
;
3752 class = row
->table
->class;
3753 column_idx
= column
- class->columns
;
3755 /* Check if a set operation list exists for this column. */
3756 if (!row
->set_op_written
) {
3757 row
->set_op_written
= bitmap_allocate(class->n_columns
);
3758 row
->set_op_lists
= xzalloc(class->n_columns
*
3759 sizeof *row
->set_op_lists
);
3761 if (!row
->set_op_lists
[column_idx
]) {
3762 row
->set_op_lists
[column_idx
] = set_op_list_create();
3765 /* Add a set operation to the corresponding list. */
3766 set_op
= set_op_create(datum
, op_type
);
3767 bitmap_set1(row
->set_op_written
, column_idx
);
3768 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
3770 /* Add this row to the transactions's list of rows. */
3771 if (hmap_node_is_null(&row
->txn_node
)) {
3772 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3773 uuid_hash(&row
->uuid
));
3778 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
3779 const struct ovsdb_idl_column
*column
,
3780 struct ovsdb_datum
*datum
)
3782 /* Verify that this column is being monitored. */
3783 unsigned int column_idx
= column
- row
->table
->class->columns
;
3784 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
3785 VLOG_WARN("cannot partially update non-monitored column");
3789 /* Verify that the update affects a single element. */
3790 if (datum
->n
!= 1) {
3791 VLOG_WARN("invalid datum for partial update");
3798 /* Inserts the value described in 'datum' into the map in 'column' in
3799 * 'row_'. If the value doesn't already exist in 'column' then it's value
3800 * is added. The value in 'datum' must be of the same type as the values
3801 * in 'column'. This function takes ownership of 'datum'.
3803 * Usually this function is used indirectly through one of the "update"
3804 * functions generated by vswitch-idl. */
3806 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
3807 const struct ovsdb_idl_column
*column
,
3808 struct ovsdb_datum
*datum
)
3810 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3811 enum set_op_type op_type
;
3813 if (!is_valid_partial_update(row
, column
, datum
)) {
3814 ovsdb_datum_destroy(datum
, &column
->type
);
3819 op_type
= SET_OP_INSERT
;
3821 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
3824 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
3825 * The value in 'datum' must be of the same type as the keys in 'column'.
3826 * This function takes ownership of 'datum'.
3828 * Usually this function is used indirectly through one of the "update"
3829 * functions generated by vswitch-idl. */
3831 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
3832 const struct ovsdb_idl_column
*column
,
3833 struct ovsdb_datum
*datum
)
3835 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3837 if (!is_valid_partial_update(row
, column
, datum
)) {
3838 struct ovsdb_type type_
= column
->type
;
3839 type_
.value
.type
= OVSDB_TYPE_VOID
;
3840 ovsdb_datum_destroy(datum
, &type_
);
3844 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
3847 /* Inserts the key-value specified in 'datum' into the map in 'column' in
3848 * 'row_'. If the key already exist in 'column', then it's value is updated
3849 * with the value in 'datum'. The key-value in 'datum' must be of the same type
3850 * as the keys-values in 'column'. This function takes ownership of 'datum'.
3852 * Usually this function is used indirectly through one of the "update"
3853 * functions generated by vswitch-idl. */
3855 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
3856 const struct ovsdb_idl_column
*column
,
3857 struct ovsdb_datum
*datum
)
3859 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3860 enum ovsdb_atomic_type key_type
;
3861 enum map_op_type op_type
;
3863 const struct ovsdb_datum
*old_datum
;
3865 if (!is_valid_partial_update(row
, column
, datum
)) {
3866 ovsdb_datum_destroy(datum
, &column
->type
);
3871 /* Find out if this is an insert or an update. */
3872 key_type
= column
->type
.key
.type
;
3873 old_datum
= ovsdb_idl_read(row
, column
);
3874 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
3875 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
3877 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
3880 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
3881 * The key in 'datum' must be of the same type as the keys in 'column'.
3882 * The value in 'datum' must be NULL. This function takes ownership of
3885 * Usually this function is used indirectly through one of the "update"
3886 * functions generated by vswitch-idl. */
3888 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
3889 const struct ovsdb_idl_column
*column
,
3890 struct ovsdb_datum
*datum
)
3892 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3894 if (!is_valid_partial_update(row
, column
, datum
)) {
3895 struct ovsdb_type type_
= column
->type
;
3896 type_
.value
.type
= OVSDB_TYPE_VOID
;
3897 ovsdb_datum_destroy(datum
, &type_
);
3901 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
3905 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
3908 ovsdb_idl_destroy(loop
->idl
);
3912 struct ovsdb_idl_txn
*
3913 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
3915 ovsdb_idl_run(loop
->idl
);
3916 loop
->open_txn
= (loop
->committing_txn
3917 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
3919 : ovsdb_idl_txn_create(loop
->idl
));
3920 return loop
->open_txn
;
3924 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
3926 if (loop
->open_txn
) {
3927 loop
->committing_txn
= loop
->open_txn
;
3928 loop
->open_txn
= NULL
;
3930 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
3933 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
3935 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
3936 if (status
!= TXN_INCOMPLETE
) {
3939 /* We want to re-evaluate the database when it's changed from
3940 * the contents that it had when we started the commit. (That
3941 * might have already happened.) */
3942 loop
->skip_seqno
= loop
->precommit_seqno
;
3943 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
3944 poll_immediate_wake();
3949 /* Possibly some work on the database was deferred because no
3950 * further transaction could proceed. Wake up again. */
3951 loop
->cur_cfg
= loop
->next_cfg
;
3952 poll_immediate_wake();
3956 loop
->cur_cfg
= loop
->next_cfg
;
3960 case TXN_NOT_LOCKED
:
3964 case TXN_UNCOMMITTED
:
3965 case TXN_INCOMPLETE
:
3968 ovsdb_idl_txn_destroy(txn
);
3969 loop
->committing_txn
= NULL
;
3973 ovsdb_idl_wait(loop
->idl
);