1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
2 * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "ovsdb-idl.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "openvswitch/json.h"
33 #include "ovsdb/ovsdb.h"
34 #include "ovsdb/table.h"
36 #include "ovsdb-data.h"
37 #include "ovsdb-error.h"
38 #include "ovsdb-idl-provider.h"
39 #include "ovsdb-parser.h"
40 #include "ovsdb-server-idl.h"
41 #include "ovsdb-session.h"
42 #include "openvswitch/poll-loop.h"
43 #include "openvswitch/shash.h"
49 #include "openvswitch/vlog.h"
51 VLOG_DEFINE_THIS_MODULE(ovsdb_idl
);
53 COVERAGE_DEFINE(txn_uncommitted
);
54 COVERAGE_DEFINE(txn_unchanged
);
55 COVERAGE_DEFINE(txn_incomplete
);
56 COVERAGE_DEFINE(txn_aborted
);
57 COVERAGE_DEFINE(txn_success
);
58 COVERAGE_DEFINE(txn_try_again
);
59 COVERAGE_DEFINE(txn_not_locked
);
60 COVERAGE_DEFINE(txn_error
);
62 /* An arc from one idl_row to another. When row A contains a UUID that
63 * references row B, this is represented by an arc from A (the source) to B
66 * Arcs from a row to itself are omitted, that is, src and dst are always
69 * Arcs are never duplicated, that is, even if there are multiple references
70 * from A to B, there is only a single arc from A to B.
72 * Arcs are directed: an arc from A to B is the converse of an an arc from B to
73 * A. Both an arc and its converse may both be present, if each row refers
74 * to the other circularly.
76 * The source and destination row may be in the same table or in different
79 struct ovsdb_idl_arc
{
80 struct ovs_list src_node
; /* In src->src_arcs list. */
81 struct ovs_list dst_node
; /* In dst->dst_arcs list. */
82 struct ovsdb_idl_row
*src
; /* Source row. */
83 struct ovsdb_idl_row
*dst
; /* Destination row. */
88 const struct ovsdb_idl_class
*class_
;
89 struct shash table_by_name
; /* Contains "struct ovsdb_idl_table *"s.*/
90 struct ovsdb_idl_table
*tables
; /* Array of ->class_->n_tables elements. */
91 unsigned int change_seqno
;
92 struct ovsdb_idl_txn
*txn
;
93 struct hmap outstanding_txns
;
94 bool verify_write_only
;
97 static struct ovsdb_cs_ops ovsdb_idl_cs_ops
;
99 struct ovsdb_idl_txn
{
100 struct hmap_node hmap_node
;
101 struct json
*request_id
;
102 struct ovsdb_idl
*idl
;
103 struct hmap txn_rows
;
104 enum ovsdb_idl_txn_status status
;
110 const char *inc_table
;
111 const char *inc_column
;
114 unsigned int inc_index
;
115 int64_t inc_new_value
;
118 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
121 struct ovsdb_idl_txn_insert
{
122 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
123 struct uuid dummy
; /* Dummy UUID used locally. */
124 int op_index
; /* Index into transaction's operation array. */
125 struct uuid real
; /* Real UUID used by database server. */
128 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
129 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
130 static struct vlog_rate_limit other_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
133 OVSDB_IDL_UPDATE_DB_CHANGED
,
134 OVSDB_IDL_UPDATE_NO_CHANGES
,
135 OVSDB_IDL_UPDATE_INCONSISTENT
,
137 static void ovsdb_idl_clear(struct ovsdb_idl
*);
138 static enum update_result
ovsdb_idl_process_update(
139 struct ovsdb_idl_table
*, const struct ovsdb_cs_row_update
*);
140 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*,
141 const struct shash
*values
);
142 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
143 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*,
144 const struct shash
*values
, bool xor);
145 static void ovsdb_idl_parse_update(struct ovsdb_idl
*,
146 const struct ovsdb_cs_update_event
*);
148 static void ovsdb_idl_txn_process_reply(struct ovsdb_idl
*,
149 const struct jsonrpc_msg
*);
151 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
152 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
153 const struct ovsdb_idl_table_class
*);
154 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
155 const struct uuid
*);
156 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
157 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*);
158 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
159 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*);
161 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
162 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
163 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
164 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
165 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
167 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
168 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
170 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
171 const struct ovsdb_idl_column
*,
172 struct ovsdb_datum
*,
174 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*,
175 const struct ovsdb_idl_column
*,
176 struct ovsdb_datum
*,
179 static struct ovsdb_idl_table
*
180 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
181 const struct ovsdb_idl_table_class
*);
182 static struct ovsdb_idl_table
*
183 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
184 const struct ovsdb_idl_table_class
*);
185 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
186 static void ovsdb_idl_track_clear__(struct ovsdb_idl
*, bool flush_all
);
188 static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*);
189 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*);
190 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*);
191 static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop
*loop
,
192 bool *may_need_wakeup
);
194 /* Creates and returns a connection to database 'remote', which should be in a
195 * form acceptable to jsonrpc_session_open(). The connection will maintain an
196 * in-memory replica of the remote database whose schema is described by
197 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
200 * Passes 'retry' to jsonrpc_session_open(). See that function for
203 * If 'monitor_everything_by_default' is true, then everything in the remote
204 * database will be replicated by default. ovsdb_idl_omit() and
205 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
208 * If 'monitor_everything_by_default' is false, then no columns or tables will
209 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
210 * must be used to choose some columns or tables to replicate.
213 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
214 bool monitor_everything_by_default
, bool retry
)
216 struct ovsdb_idl
*idl
= ovsdb_idl_create_unconnected(
217 class, monitor_everything_by_default
);
218 ovsdb_idl_set_remote(idl
, remote
, retry
);
222 /* Creates and returns a connection to an in-memory replica of the remote
223 * database whose schema is described by 'class'. (Ordinarily 'class' is
224 * compiled from an OVSDB schema automatically by ovsdb-idlc.)
226 * Use ovsdb_idl_set_remote() to configure the database to which to connect.
227 * Until a remote is configured, no data can be retrieved.
229 * If 'monitor_everything_by_default' is true, then everything in the remote
230 * database will be replicated by default. ovsdb_idl_omit() and
231 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
234 * If 'monitor_everything_by_default' is false, then no columns or tables will
235 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
236 * must be used to choose some columns or tables to replicate.
239 ovsdb_idl_create_unconnected(const struct ovsdb_idl_class
*class,
240 bool monitor_everything_by_default
)
242 struct ovsdb_idl
*idl
= xmalloc(sizeof *idl
);
243 *idl
= (struct ovsdb_idl
) {
244 .cs
= ovsdb_cs_create(class->database
, 3, &ovsdb_idl_cs_ops
, idl
),
246 .table_by_name
= SHASH_INITIALIZER(&idl
->table_by_name
),
247 .tables
= xmalloc(class->n_tables
* sizeof *idl
->tables
),
250 .outstanding_txns
= HMAP_INITIALIZER(&idl
->outstanding_txns
),
251 .verify_write_only
= false,
254 uint8_t default_mode
= (monitor_everything_by_default
255 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
257 for (size_t i
= 0; i
< class->n_tables
; i
++) {
258 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
259 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
261 shash_add_assert(&idl
->table_by_name
, tc
->name
, table
);
263 table
->modes
= xmalloc(tc
->n_columns
);
264 memset(table
->modes
, default_mode
, tc
->n_columns
);
265 table
->need_table
= false;
266 shash_init(&table
->columns
);
267 ovs_list_init(&table
->indexes
);
268 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
269 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
271 shash_add_assert(&table
->columns
, column
->name
, column
);
273 hmap_init(&table
->rows
);
274 ovs_list_init(&table
->track_list
);
275 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
276 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
277 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
284 /* Changes the remote and creates a new session.
286 * If 'retry' is true, the connection to the remote will automatically retry
287 * when it fails. If 'retry' is false, the connection is one-time. */
289 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
, bool retry
)
291 ovsdb_cs_set_remote(idl
->cs
, remote
, retry
);
294 /* Set whether the order of remotes should be shuffled, when there
295 * are more than one remotes. The setting doesn't take effect
296 * until the next time when ovsdb_idl_set_remote() is called. */
298 ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl
*idl
, bool shuffle
)
300 ovsdb_cs_set_shuffle_remotes(idl
->cs
, shuffle
);
303 /* Reset min_index to 0. This prevents a situation where the client
304 * thinks all databases have stale data, when they actually have all
305 * been destroyed and rebuilt from scratch.
308 ovsdb_idl_reset_min_index(struct ovsdb_idl
*idl
)
310 ovsdb_cs_reset_min_index(idl
->cs
);
313 /* Destroys 'idl' and all of the data structures that it manages. */
315 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
318 ovs_assert(!idl
->txn
);
320 ovsdb_idl_txn_abort_all(idl
);
321 hmap_destroy(&idl
->outstanding_txns
);
323 ovsdb_idl_clear(idl
);
324 ovsdb_cs_destroy(idl
->cs
);
325 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
326 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
327 ovsdb_idl_destroy_indexes(table
);
328 shash_destroy(&table
->columns
);
329 hmap_destroy(&table
->rows
);
332 shash_destroy(&idl
->table_by_name
);
338 /* By default, or if 'leader_only' is true, when 'idl' connects to a clustered
339 * database, the IDL will avoid servers other than the cluster leader. This
340 * ensures that any data that it reads and reports is up-to-date. If
341 * 'leader_only' is false, the IDL will accept any server in the cluster, which
342 * means that for read-only transactions it can report and act on stale data
343 * (transactions that modify the database are always serialized even with false
344 * 'leader_only'). Refer to Understanding Cluster Consistency in ovsdb(7) for
345 * more information. */
347 ovsdb_idl_set_leader_only(struct ovsdb_idl
*idl
, bool leader_only
)
349 ovsdb_cs_set_leader_only(idl
->cs
, leader_only
);
353 ovsdb_idl_clear(struct ovsdb_idl
*db
)
355 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
356 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
357 struct ovsdb_idl_row
*row
, *next_row
;
359 if (hmap_is_empty(&table
->rows
)) {
363 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
364 struct ovsdb_idl_arc
*arc
, *next_arc
;
366 if (!ovsdb_idl_row_is_orphan(row
)) {
367 ovsdb_idl_remove_from_indexes(row
);
368 ovsdb_idl_row_unparse(row
);
370 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
373 /* No need to do anything with dst_arcs: some node has those arcs
374 * as forward arcs and will destroy them itself. */
376 ovsdb_idl_row_destroy(row
);
379 ovsdb_idl_row_destroy_postprocess(db
);
381 ovsdb_idl_track_clear__(db
, true);
385 /* Processes a batch of messages from the database server on 'idl'. This may
386 * cause the IDL's contents to change. The client may check for that with
387 * ovsdb_idl_get_seqno(). */
389 ovsdb_idl_run(struct ovsdb_idl
*idl
)
391 ovs_assert(!idl
->txn
);
393 struct ovs_list events
;
394 ovsdb_cs_run(idl
->cs
, &events
);
396 struct ovsdb_cs_event
*event
;
397 LIST_FOR_EACH_POP (event
, list_node
, &events
) {
398 switch (event
->type
) {
399 case OVSDB_CS_EVENT_TYPE_RECONNECT
:
400 ovsdb_idl_txn_abort_all(idl
);
403 case OVSDB_CS_EVENT_TYPE_LOCKED
:
404 /* If the client couldn't run a transaction because it didn't have
405 * the lock, this will encourage it to try again. */
409 case OVSDB_CS_EVENT_TYPE_UPDATE
:
410 ovsdb_idl_parse_update(idl
, &event
->update
);
413 case OVSDB_CS_EVENT_TYPE_TXN_REPLY
:
414 ovsdb_idl_txn_process_reply(idl
, event
->txn_reply
);
417 ovsdb_cs_event_destroy(event
);
420 ovsdb_idl_row_destroy_postprocess(idl
);
423 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
424 * do or when activity occurs on a transaction on 'idl'. */
426 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
428 ovsdb_cs_wait(idl
->cs
);
431 /* Returns a "sequence number" that represents the state of 'idl'. When
432 * ovsdb_idl_run() changes the database, the sequence number changes. The
433 * initial fetch of the entire contents of the remote database is considered to
434 * be one kind of change. Successfully acquiring a lock, if one has been
435 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
437 * As long as the sequence number does not change, the client may continue to
438 * use any data structures it obtains from 'idl'. But when it changes, the
439 * client must not access any of these data structures again, because they
440 * could have freed or reused for other purposes.
442 * The sequence number can occasionally change even if the database does not.
443 * This happens if the connection to the database drops and reconnects, which
444 * causes the database contents to be reloaded even if they didn't change. (It
445 * could also happen if the database server sends out a "change" that reflects
446 * what the IDL already thought was in the database. The database server is
447 * not supposed to do that, but bugs could in theory cause it to do so.) */
449 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
451 return idl
->change_seqno
;
454 /* Returns a "sequence number" that represents the number of conditional
455 * monitoring updates successfully received by the OVSDB server of an IDL
458 * ovsdb_idl_set_condition() sets a new condition that is different from
459 * the current condtion, the next expected "sequence number" is returned.
461 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
462 * the return value of ovsdb_idl_set_condition(), The client is
464 * - The ovsdb_idl_set_condition() changes has been acknowledged by
467 * - 'idl' now contains the content matches the new conditions. */
469 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl
*idl
)
471 return ovsdb_cs_get_condition_seqno(idl
->cs
);
474 /* Returns true if 'idl' successfully connected to the remote database and
475 * retrieved its contents (even if the connection subsequently dropped and is
476 * in the process of reconnecting). If so, then 'idl' contains an atomic
477 * snapshot of the database's contents (but it might be arbitrarily old if the
478 * connection dropped).
480 * Returns false if 'idl' has never connected or retrieved the database's
481 * contents. If so, 'idl' is empty. */
483 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
485 return ovsdb_idl_get_seqno(idl
) != 0;
488 /* Reconfigures 'idl' so that it would reconnect to the database, if
489 * connection was dropped. */
491 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
493 ovsdb_cs_enable_reconnect(idl
->cs
);
496 /* Forces 'idl' to drop its connection to the database and reconnect. In the
497 * meantime, the contents of 'idl' will not change. */
499 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
501 ovsdb_cs_force_reconnect(idl
->cs
);
504 /* Some IDL users should only write to write-only columns. Furthermore,
505 * writing to a column which is not write-only can cause serious performance
506 * degradations for these users. This function causes 'idl' to reject writes
507 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
509 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
511 idl
->verify_write_only
= true;
514 /* Returns true if 'idl' is currently connected or trying to connect
515 * and a negative response to a schema request has not been received */
517 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
519 return ovsdb_cs_is_alive(idl
->cs
);
523 ovsdb_idl_is_connected(const struct ovsdb_idl
*idl
)
525 return ovsdb_cs_is_connected(idl
->cs
);
528 /* Returns the last error reported on a connection by 'idl'. The return value
529 * is 0 only if no connection made by 'idl' has ever encountered an error and
530 * a negative response to a schema request has never been received. See
531 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
534 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
536 return ovsdb_cs_get_last_error(idl
->cs
);
539 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
543 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
545 ovsdb_cs_set_probe_interval(idl
->cs
, probe_interval
);
549 find_uuid_in_array(const struct uuid
*target
,
550 const struct uuid
*array
, size_t n
)
552 for (size_t i
= 0; i
< n
; i
++) {
553 if (uuid_equals(&array
[i
], target
)) {
561 array_contains_uuid(const struct uuid
*target
,
562 const struct uuid
*array
, size_t n
)
564 return find_uuid_in_array(target
, array
, n
) != SIZE_MAX
;
568 remove_uuid_from_array(const struct uuid
*target
,
569 struct uuid
*array
, size_t *n
)
571 size_t i
= find_uuid_in_array(target
, array
, *n
);
573 array
[i
] = array
[--*n
];
581 add_row_references(const struct ovsdb_base_type
*type
,
582 const union ovsdb_atom
*atoms
, size_t n_atoms
,
583 const struct uuid
*exclude_uuid
,
584 struct uuid
**dstsp
, size_t *n_dstsp
,
585 size_t *allocated_dstsp
)
587 if (type
->type
!= OVSDB_TYPE_UUID
|| !type
->uuid
.refTableName
) {
591 for (size_t i
= 0; i
< n_atoms
; i
++) {
592 const struct uuid
*uuid
= &atoms
[i
].uuid
;
593 if (!uuid_equals(uuid
, exclude_uuid
)
594 && !array_contains_uuid(uuid
, *dstsp
, *n_dstsp
)) {
595 if (*n_dstsp
>= *allocated_dstsp
) {
596 *dstsp
= x2nrealloc(*dstsp
, allocated_dstsp
,
600 (*dstsp
)[*n_dstsp
] = *uuid
;
606 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
607 * reference from one row to a different row should be reflected as a "struct
608 * ovsdb_idl_arc" between those rows.
610 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
611 * thus it is only for use in test programs. */
613 ovsdb_idl_check_consistency(const struct ovsdb_idl
*idl
)
615 /* Consistency is broken while a transaction is in progress. */
622 struct uuid
*dsts
= NULL
;
623 size_t allocated_dsts
= 0;
625 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
626 const struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
627 const struct ovsdb_idl_table_class
*class = table
->class_
;
629 const struct ovsdb_idl_row
*row
;
630 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
632 if (row
->new_datum
) {
633 size_t n_columns
= shash_count(&row
->table
->columns
);
634 for (size_t j
= 0; j
< n_columns
; j
++) {
635 const struct ovsdb_type
*type
= &class->columns
[j
].type
;
636 const struct ovsdb_datum
*datum
= &row
->new_datum
[j
];
637 add_row_references(&type
->key
,
638 datum
->keys
, datum
->n
, &row
->uuid
,
639 &dsts
, &n_dsts
, &allocated_dsts
);
640 add_row_references(&type
->value
,
641 datum
->values
, datum
->n
, &row
->uuid
,
642 &dsts
, &n_dsts
, &allocated_dsts
);
645 const struct ovsdb_idl_arc
*arc
;
646 LIST_FOR_EACH (arc
, src_node
, &row
->src_arcs
) {
647 if (!remove_uuid_from_array(&arc
->dst
->uuid
,
649 VLOG_ERR("unexpected arc from %s row "UUID_FMT
" to %s "
652 UUID_ARGS(&row
->uuid
),
653 arc
->dst
->table
->class_
->name
,
654 UUID_ARGS(&arc
->dst
->uuid
));
658 for (size_t j
= 0; j
< n_dsts
; j
++) {
659 VLOG_ERR("%s row "UUID_FMT
" missing arc to row "UUID_FMT
,
660 table
->class_
->name
, UUID_ARGS(&row
->uuid
),
661 UUID_ARGS(&dsts
[j
]));
671 ovsdb_idl_compose_monitor_request(const struct json
*schema_json
, void *idl_
)
673 struct ovsdb_idl
*idl
= idl_
;
675 struct shash
*schema
= ovsdb_cs_parse_schema(schema_json
);
676 struct json
*monitor_requests
= json_object_create();
678 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
679 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
680 const struct ovsdb_idl_table_class
*tc
= table
->class_
;
681 struct json
*monitor_request
;
682 const struct sset
*table_schema
683 = schema
? shash_find_data(schema
, table
->class_
->name
) : NULL
;
686 = table
->need_table
? json_array_create_empty() : NULL
;
687 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
688 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
689 bool idl_has_column
= (table_schema
&&
690 sset_contains(table_schema
, column
->name
));
691 if (column
->is_synthetic
) {
692 if (idl_has_column
) {
693 VLOG_WARN("%s table in %s database has synthetic "
694 "column %s", table
->class_
->name
,
695 idl
->class_
->database
, column
->name
);
697 } else if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
698 if (table_schema
&& !idl_has_column
) {
699 VLOG_WARN("%s table in %s database lacks %s column "
700 "(database needs upgrade?)",
701 table
->class_
->name
, idl
->class_
->database
,
706 columns
= json_array_create_empty();
708 json_array_add(columns
, json_string_create(column
->name
));
713 if (schema
&& !table_schema
) {
714 VLOG_WARN("%s database lacks %s table "
715 "(database needs upgrade?)",
716 idl
->class_
->database
, table
->class_
->name
);
717 json_destroy(columns
);
721 monitor_request
= json_object_create();
722 json_object_put(monitor_request
, "columns", columns
);
723 json_object_put(monitor_requests
, tc
->name
,
724 json_array_create_1(monitor_request
));
727 ovsdb_cs_free_schema(schema
);
729 return monitor_requests
;
732 static struct ovsdb_cs_ops ovsdb_idl_cs_ops
= {
733 ovsdb_idl_compose_monitor_request
,
736 const struct ovsdb_idl_class
*
737 ovsdb_idl_get_class(const struct ovsdb_idl
*idl
)
742 /* Given 'column' in some table in 'class', returns the table's class. */
743 const struct ovsdb_idl_table_class
*
744 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class
*class,
745 const struct ovsdb_idl_column
*column
)
747 for (size_t i
= 0; i
< class->n_tables
; i
++) {
748 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
749 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
757 /* Given 'column' in some table in 'idl', returns the table. */
758 static struct ovsdb_idl_table
*
759 ovsdb_idl_table_from_column(struct ovsdb_idl
*idl
,
760 const struct ovsdb_idl_column
*column
)
762 const struct ovsdb_idl_table_class
*tc
=
763 ovsdb_idl_table_class_from_column(idl
->class_
, column
);
764 return &idl
->tables
[tc
- idl
->class_
->tables
];
767 static unsigned char *
768 ovsdb_idl_get_mode(struct ovsdb_idl
*idl
,
769 const struct ovsdb_idl_column
*column
)
771 ovs_assert(!idl
->change_seqno
);
773 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(idl
,
775 return &table
->modes
[column
- table
->class_
->columns
];
779 ovsdb_idl_set_mode(struct ovsdb_idl
*idl
,
780 const struct ovsdb_idl_column
*column
,
783 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(idl
,
785 size_t column_idx
= column
- table
->class_
->columns
;
787 if (table
->modes
[column_idx
] != mode
) {
788 *ovsdb_idl_get_mode(idl
, column
) = mode
;
793 add_ref_table(struct ovsdb_idl
*idl
, const struct ovsdb_base_type
*base
)
795 if (base
->type
== OVSDB_TYPE_UUID
&& base
->uuid
.refTableName
) {
796 struct ovsdb_idl_table
*table
;
798 table
= shash_find_data(&idl
->table_by_name
, base
->uuid
.refTableName
);
800 table
->need_table
= true;
802 VLOG_WARN("%s IDL class missing referenced table %s",
803 idl
->class_
->database
, base
->uuid
.refTableName
);
808 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
809 * ensures that any tables referenced by 'column' will be replicated, even if
810 * no columns in that table are selected for replication (see
811 * ovsdb_idl_add_table() for more information).
813 * This function is only useful if 'monitor_everything_by_default' was false in
814 * the call to ovsdb_idl_create(). This function should be called between
815 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
818 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
819 const struct ovsdb_idl_column
*column
)
821 ovsdb_idl_set_mode(idl
, column
, OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
);
822 add_ref_table(idl
, &column
->type
.key
);
823 add_ref_table(idl
, &column
->type
.value
);
826 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
827 * no columns are selected for replication. Just the necessary data for table
828 * references will be replicated (the UUID of the rows, for instance), any
829 * columns not selected for replication will remain unreplicated.
830 * This can be useful because it allows 'idl' to keep track of what rows in the
831 * table actually exist, which in turn allows columns that reference the table
832 * to have accurate contents. (The IDL presents the database with references to
833 * rows that do not exist removed.)
835 * This function is only useful if 'monitor_everything_by_default' was false in
836 * the call to ovsdb_idl_create(). This function should be called between
837 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
840 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
841 const struct ovsdb_idl_table_class
*tc
)
843 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
844 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
846 if (table
->class_
== tc
) {
847 table
->need_table
= true;
855 /* A single clause within an ovsdb_idl_condition. */
856 struct ovsdb_idl_clause
{
857 struct hmap_node hmap_node
; /* In struct ovsdb_idl_condition. */
858 enum ovsdb_function function
; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
859 const struct ovsdb_idl_column
*column
; /* Must be nonnull. */
860 struct ovsdb_datum arg
; /* Has ovsdb_type ->column->type. */
864 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause
*clause
)
866 uint32_t hash
= hash_pointer(clause
->column
, clause
->function
);
867 return ovsdb_datum_hash(&clause
->arg
, &clause
->column
->type
, hash
);
871 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause
*a
,
872 const struct ovsdb_idl_clause
*b
)
874 return (a
->function
== b
->function
875 && a
->column
== b
->column
876 && ovsdb_datum_equals(&a
->arg
, &b
->arg
, &a
->column
->type
));
880 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
882 const char *function
= ovsdb_function_to_string(clause
->function
);
883 return json_array_create_3(json_string_create(clause
->column
->name
),
884 json_string_create(function
),
885 ovsdb_datum_to_json(&clause
->arg
,
886 &clause
->column
->type
));
890 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause
*clause
)
893 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
898 /* ovsdb_idl_condition. */
901 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
)
903 hmap_init(&cnd
->clauses
);
904 cnd
->is_true
= false;
908 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition
*cond
)
911 ovsdb_idl_condition_clear(cond
);
912 hmap_destroy(&cond
->clauses
);
917 ovsdb_idl_condition_clear(struct ovsdb_idl_condition
*cond
)
919 struct ovsdb_idl_clause
*clause
, *next
;
920 HMAP_FOR_EACH_SAFE (clause
, next
, hmap_node
, &cond
->clauses
) {
921 hmap_remove(&cond
->clauses
, &clause
->hmap_node
);
922 ovsdb_idl_clause_destroy(clause
);
924 cond
->is_true
= false;
928 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition
*condition
)
930 return condition
->is_true
;
933 static struct ovsdb_idl_clause
*
934 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition
*condition
,
935 const struct ovsdb_idl_clause
*target
,
938 struct ovsdb_idl_clause
*clause
;
939 HMAP_FOR_EACH_WITH_HASH (clause
, hmap_node
, hash
, &condition
->clauses
) {
940 if (ovsdb_idl_clause_equals(clause
, target
)) {
948 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition
*condition
,
949 const struct ovsdb_idl_clause
*src
,
952 struct ovsdb_idl_clause
*clause
= xmalloc(sizeof *clause
);
953 clause
->function
= src
->function
;
954 clause
->column
= src
->column
;
955 ovsdb_datum_clone(&clause
->arg
, &src
->arg
, &src
->column
->type
);
956 hmap_insert(&condition
->clauses
, &clause
->hmap_node
, hash
);
959 /* Adds a clause to the condition for replicating the table with class 'tc' in
962 * The IDL replicates only rows in a table that satisfy at least one clause in
963 * the table's condition. The default condition for a table has a single
964 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
965 * the table. When the IDL client replaces the default condition by one of its
966 * own, the condition can have any number of clauses. If it has no conditions,
967 * then no rows are replicated.
969 * Two distinct of clauses can usefully be added:
971 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
972 * replicated, regardless of whether other clauses exist. 'column' and
975 * - Binary 'functions' add a clause of the form "<column> <function>
976 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
977 * have a type that is compatible with 'column'.
980 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition
*condition
,
981 enum ovsdb_function function
,
982 const struct ovsdb_idl_column
*column
,
983 const struct ovsdb_datum
*arg
)
985 if (condition
->is_true
) {
986 /* Adding a clause to an always-true condition has no effect. */
987 } else if (function
== OVSDB_F_TRUE
) {
988 ovsdb_idl_condition_add_clause_true(condition
);
989 } else if (function
== OVSDB_F_FALSE
) {
990 /* Adding a "false" clause never has any effect. */
992 struct ovsdb_idl_clause clause
= {
993 .function
= function
,
997 uint32_t hash
= ovsdb_idl_clause_hash(&clause
);
998 if (!ovsdb_idl_condition_find_clause(condition
, &clause
, hash
)) {
999 ovsdb_idl_condition_add_clause__(condition
, &clause
, hash
);
1005 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition
*condition
)
1007 if (!condition
->is_true
) {
1008 ovsdb_idl_condition_clear(condition
);
1009 condition
->is_true
= true;
1013 static struct json
*
1014 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
1020 size_t n
= hmap_count(&cnd
->clauses
);
1022 return json_array_create_1(json_boolean_create(false));
1025 struct json
**clauses
= xmalloc(n
* sizeof *clauses
);
1026 const struct ovsdb_idl_clause
*clause
;
1028 HMAP_FOR_EACH (clause
, hmap_node
, &cnd
->clauses
) {
1029 clauses
[i
++] = ovsdb_idl_clause_to_json(clause
);
1032 return json_array_create(clauses
, n
);
1035 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1036 * arranges to send the new condition to the database server.
1038 * Return the next conditional update sequence number. When this
1039 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1040 * contains rows that match the 'condition'. */
1042 ovsdb_idl_set_condition(struct ovsdb_idl
*idl
,
1043 const struct ovsdb_idl_table_class
*tc
,
1044 const struct ovsdb_idl_condition
*condition
)
1046 struct json
*cond_json
= ovsdb_idl_condition_to_json(condition
);
1047 unsigned int seqno
= ovsdb_cs_set_condition(idl
->cs
, tc
->name
, cond_json
);
1048 json_destroy(cond_json
);
1052 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'idl'.
1054 * This function should be called between ovsdb_idl_create() and the first call
1055 * to ovsdb_idl_run().
1058 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
1059 const struct ovsdb_idl_column
*column
)
1061 *ovsdb_idl_get_mode(idl
, column
) &= ~(OVSDB_IDL_ALERT
| OVSDB_IDL_TRACK
);
1064 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1065 * OVSDB_IDL_MONITOR for details.
1067 * This function should be called between ovsdb_idl_create() and the first call
1068 * to ovsdb_idl_run().
1071 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
1073 *ovsdb_idl_get_mode(idl
, column
) = 0;
1076 /* Returns the most recent IDL change sequence number that caused a
1077 * insert, modify or delete update to the table with class 'table_class'.
1080 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
1081 const struct ovsdb_idl_table_class
*table_class
)
1083 struct ovsdb_idl_table
*table
1084 = ovsdb_idl_table_from_class(idl
, table_class
);
1085 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
1087 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
1088 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
1090 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
1091 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
1096 /* For each row that contains tracked columns, IDL stores the most
1097 * recent IDL change sequence numbers associateed with insert, modify
1098 * and delete updates to the table.
1101 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
1102 enum ovsdb_idl_change change
)
1104 return row
->change_seqno
[change
];
1107 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1108 * all rows whose 'column' is modified are traced. Similarly, insert
1109 * or delete of rows having 'column' are tracked. Clients are able
1110 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1113 * This function should be called between ovsdb_idl_create() and
1114 * the first call to ovsdb_idl_run(). The column to be tracked
1115 * should have OVSDB_IDL_ALERT turned on.
1118 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1119 const struct ovsdb_idl_column
*column
)
1121 if (!(*ovsdb_idl_get_mode(idl
, column
) & OVSDB_IDL_ALERT
)) {
1122 ovsdb_idl_add_column(idl
, column
);
1124 *ovsdb_idl_get_mode(idl
, column
) |= OVSDB_IDL_TRACK
;
1128 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1132 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1133 const struct ovsdb_idl_table_class
*tc
= &idl
->class_
->tables
[i
];
1135 for (j
= 0; j
< tc
->n_columns
; j
++) {
1136 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1137 ovsdb_idl_track_add_column(idl
, column
);
1142 /* Returns true if 'table' has any tracked column. */
1144 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1148 for (i
= 0; i
< table
->class_
->n_columns
; i
++) {
1149 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1156 /* Returns the first tracked row in table with class 'table_class'
1157 * for the specified 'idl'. Returns NULL if there are no tracked rows.
1158 * Pure orphan rows, i.e. rows that never had any datum, are skipped. */
1159 const struct ovsdb_idl_row
*
1160 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1161 const struct ovsdb_idl_table_class
*table_class
)
1163 struct ovsdb_idl_table
*table
1164 = ovsdb_idl_table_from_class(idl
, table_class
);
1165 struct ovsdb_idl_row
*row
;
1167 LIST_FOR_EACH (row
, track_node
, &table
->track_list
) {
1168 if (!ovsdb_idl_row_is_orphan(row
) || row
->tracked_old_datum
) {
1175 /* Returns the next tracked row in table after the specified 'row'
1176 * (in no particular order). Returns NULL if there are no tracked rows.
1177 * Pure orphan rows, i.e. rows that never had any datum, are skipped. */
1178 const struct ovsdb_idl_row
*
1179 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1181 struct ovsdb_idl_table
*table
= row
->table
;
1183 LIST_FOR_EACH_CONTINUE (row
, track_node
, &table
->track_list
) {
1184 if (!ovsdb_idl_row_is_orphan(row
) || row
->tracked_old_datum
) {
1191 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1192 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1194 * Function returns false if 'column' is not tracked (see
1195 * ovsdb_idl_track_add_column()).
1198 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1199 const struct ovsdb_idl_column
*column
)
1201 const struct ovsdb_idl_table_class
*class;
1204 class = row
->table
->class_
;
1205 column_idx
= column
- class->columns
;
1207 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1215 ovsdb_idl_track_clear__(struct ovsdb_idl
*idl
, bool flush_all
)
1219 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1220 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1222 if (!ovs_list_is_empty(&table
->track_list
)) {
1223 struct ovsdb_idl_row
*row
, *next
;
1225 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1228 row
->updated
= NULL
;
1231 row
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
] =
1232 row
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
] =
1233 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
1235 ovs_list_remove(&row
->track_node
);
1236 ovs_list_init(&row
->track_node
);
1237 if (ovsdb_idl_row_is_orphan(row
)) {
1238 ovsdb_idl_row_unparse(row
);
1239 if (row
->tracked_old_datum
) {
1240 const struct ovsdb_idl_table_class
*class =
1242 for (size_t c
= 0; c
< class->n_columns
; c
++) {
1243 ovsdb_datum_destroy(&row
->tracked_old_datum
[c
],
1244 &class->columns
[c
].type
);
1246 free(row
->tracked_old_datum
);
1247 row
->tracked_old_datum
= NULL
;
1250 /* Rows that were reused as orphan after being processed
1251 * for deletion are still in the table hmap and will be
1252 * cleaned up when their src arcs are removed. These rows
1253 * will not be reported anymore as "deleted" to IDL
1256 * The exception is when 'destroy' is explicitly set to
1257 * 'true' which usually happens when the complete IDL
1258 * contents are being flushed.
1260 if (flush_all
|| ovs_list_is_empty(&row
->dst_arcs
)) {
1269 /* Flushes the tracked rows. Client calls this function after calling
1270 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1271 * functions. This is usually done at the end of the client's processing
1272 * loop when it is ready to do ovsdb_idl_run() again.
1275 ovsdb_idl_track_clear(struct ovsdb_idl
*idl
)
1277 ovsdb_idl_track_clear__(idl
, false);
1281 log_parse_update_error(struct ovsdb_error
*error
)
1283 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1284 char *s
= ovsdb_error_to_string(error
);
1285 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1288 ovsdb_error_destroy(error
);
1291 static struct ovsdb_error
*
1292 ovsdb_idl_parse_update__(struct ovsdb_idl
*idl
,
1293 const struct ovsdb_cs_db_update
*du
)
1295 for (size_t i
= 0; i
< du
->n
; i
++) {
1296 const struct ovsdb_cs_table_update
*tu
= &du
->table_updates
[i
];
1298 struct ovsdb_idl_table
*table
= shash_find_data(&idl
->table_by_name
,
1301 return ovsdb_syntax_error(
1302 NULL
, NULL
, "update to unknown table \"%s\"", tu
->table_name
);
1305 for (size_t j
= 0; j
< tu
->n
; j
++) {
1306 const struct ovsdb_cs_row_update
*ru
= &tu
->row_updates
[j
];
1307 switch (ovsdb_idl_process_update(table
, ru
)) {
1308 case OVSDB_IDL_UPDATE_DB_CHANGED
:
1309 idl
->change_seqno
++;
1311 case OVSDB_IDL_UPDATE_NO_CHANGES
:
1313 case OVSDB_IDL_UPDATE_INCONSISTENT
:
1314 ovsdb_cs_flag_inconsistency(idl
->cs
);
1315 return ovsdb_error(NULL
,
1316 "row update received for inconsistent "
1317 "IDL: reconnecting IDL and resync all "
1327 ovsdb_idl_parse_update(struct ovsdb_idl
*idl
,
1328 const struct ovsdb_cs_update_event
*update
)
1330 if (update
->monitor_reply
) {
1331 /* XXX This isn't semantically required, because we only need to
1332 * increment change_seqno if there's a real change, which we'll do
1333 * below, but older versions of the IDL always incremented change_seqno
1334 * when a monitor reply was received and if we don't do it then tests
1336 idl
->change_seqno
++;
1339 struct ovsdb_cs_db_update
*du
;
1340 struct ovsdb_error
*error
= ovsdb_cs_parse_db_update(
1341 update
->table_updates
, update
->version
, &du
);
1343 if (update
->clear
) {
1344 ovsdb_idl_clear(idl
);
1346 error
= ovsdb_idl_parse_update__(idl
, du
);
1348 ovsdb_cs_db_update_destroy(du
);
1350 log_parse_update_error(error
);
1354 static struct ovsdb_idl_row
*
1355 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1357 struct ovsdb_idl_row
*row
;
1359 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
1360 if (uuid_equals(&row
->uuid
, uuid
)) {
1367 /* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
1368 * OVSDB_IDL_MODE_RW changed.
1370 * Some IDL inconsistencies can be detected when processing updates:
1371 * - trying to insert an already existing row
1372 * - trying to update a missing row
1373 * - trying to delete a non existent row
1375 * In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
1376 * Even though the IDL client could recover, it's best to report the
1377 * inconsistent state because the state the server is in is unknown so the
1378 * safest thing to do is to retry (potentially connecting to a new server).
1380 * Returns OVSDB_IDL_UPDATE_NO_CHANGES otherwise.
1382 static enum update_result
1383 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
1384 const struct ovsdb_cs_row_update
*ru
)
1386 const struct uuid
*uuid
= &ru
->row_uuid
;
1387 struct ovsdb_idl_row
*row
= ovsdb_idl_get_row(table
, uuid
);
1390 case OVSDB_CS_ROW_DELETE
:
1391 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1392 /* XXX perhaps we should check the 'old' values? */
1393 ovsdb_idl_delete_row(row
);
1395 VLOG_ERR_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1397 UUID_ARGS(uuid
), table
->class_
->name
);
1398 return OVSDB_IDL_UPDATE_INCONSISTENT
;
1402 case OVSDB_CS_ROW_INSERT
:
1404 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
),
1406 } else if (ovsdb_idl_row_is_orphan(row
)) {
1407 ovsdb_idl_insert_row(row
, ru
->columns
);
1409 VLOG_ERR_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1410 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1411 return OVSDB_IDL_UPDATE_INCONSISTENT
;
1415 case OVSDB_CS_ROW_UPDATE
:
1416 case OVSDB_CS_ROW_XOR
:
1418 if (!ovsdb_idl_row_is_orphan(row
)) {
1419 return ovsdb_idl_modify_row(row
, ru
->columns
,
1420 ru
->type
== OVSDB_CS_ROW_XOR
)
1421 ? OVSDB_IDL_UPDATE_DB_CHANGED
1422 : OVSDB_IDL_UPDATE_NO_CHANGES
;
1424 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing but "
1425 "referenced row "UUID_FMT
" in table %s",
1426 UUID_ARGS(uuid
), table
->class_
->name
);
1427 return OVSDB_IDL_UPDATE_INCONSISTENT
;
1430 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1431 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1432 return OVSDB_IDL_UPDATE_INCONSISTENT
;
1440 return OVSDB_IDL_UPDATE_DB_CHANGED
;
1443 /* Recursively add rows to tracked change lists for all rows that reference
1446 add_tracked_change_for_references(struct ovsdb_idl_row
*row
)
1448 const struct ovsdb_idl_arc
*arc
;
1449 LIST_FOR_EACH (arc
, dst_node
, &row
->dst_arcs
) {
1450 struct ovsdb_idl_row
*ref
= arc
->src
;
1452 if (ovs_list_is_empty(&ref
->track_node
) &&
1453 ovsdb_idl_track_is_set(ref
->table
)) {
1454 ovs_list_push_back(&ref
->table
->track_list
,
1457 ref
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
1458 = ref
->table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
1459 = ref
->table
->idl
->change_seqno
+ 1;
1461 add_tracked_change_for_references(ref
);
1467 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1470 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1471 * Caller needs to provide either valid 'row_json' or 'diff', but not
1474 ovsdb_idl_row_change(struct ovsdb_idl_row
*row
, const struct shash
*values
,
1475 bool xor, enum ovsdb_idl_change change
)
1477 struct ovsdb_idl_table
*table
= row
->table
;
1478 const struct ovsdb_idl_table_class
*class = table
->class_
;
1479 struct shash_node
*node
;
1480 bool changed
= false;
1482 SHASH_FOR_EACH (node
, values
) {
1483 const char *column_name
= node
->name
;
1484 const struct ovsdb_idl_column
*column
;
1485 struct ovsdb_datum datum
;
1486 struct ovsdb_error
*error
;
1487 unsigned int column_idx
;
1488 struct ovsdb_datum
*old
;
1490 column
= shash_find_data(&table
->columns
, column_name
);
1492 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
1493 column_name
, UUID_ARGS(&row
->uuid
));
1497 column_idx
= column
- table
->class_
->columns
;
1498 old
= &row
->old_datum
[column_idx
];
1502 struct ovsdb_datum diff
;
1504 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
1507 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
1509 ovsdb_datum_destroy(&diff
, &column
->type
);
1512 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
1517 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
1518 ovsdb_datum_swap(old
, &datum
);
1519 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
1521 row
->change_seqno
[change
]
1522 = row
->table
->change_seqno
[change
]
1523 = row
->table
->idl
->change_seqno
+ 1;
1525 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
1526 if (ovs_list_is_empty(&row
->track_node
) &&
1527 ovsdb_idl_track_is_set(row
->table
)) {
1528 ovs_list_push_back(&row
->table
->track_list
,
1532 add_tracked_change_for_references(row
);
1533 if (!row
->updated
) {
1534 row
->updated
= bitmap_allocate(class->n_columns
);
1536 bitmap_set1(row
->updated
, column_idx
);
1540 /* Didn't really change but the OVSDB monitor protocol always
1541 * includes every value in a row. */
1544 ovsdb_datum_destroy(&datum
, &column
->type
);
1546 char *s
= ovsdb_error_to_string_free(error
);
1547 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
1548 " in table %s: %s", column_name
,
1549 UUID_ARGS(&row
->uuid
), table
->class_
->name
, s
);
1556 /* When a row A refers to row B through a column with a "refTable" constraint,
1557 * but row B does not exist, row B is called an "orphan row". Orphan rows
1558 * should not persist, because the database enforces referential integrity, but
1559 * they can appear transiently as changes from the database are received (the
1560 * database doesn't try to topologically sort them and circular references mean
1561 * it isn't always possible anyhow).
1563 * This function returns true if 'row' is an orphan row, otherwise false.
1566 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
1568 return !row
->old_datum
&& !row
->new_datum
;
1571 /* Returns true if 'row' is conceptually part of the database as modified by
1572 * the current transaction (if any), false otherwise.
1574 * This function will return true if 'row' is not an orphan (see the comment on
1575 * ovsdb_idl_row_is_orphan()) and:
1577 * - 'row' exists in the database and has not been deleted within the
1578 * current transaction (if any).
1580 * - 'row' was inserted within the current transaction and has not been
1581 * deleted. (In the latter case you should not have passed 'row' in at
1582 * all, because ovsdb_idl_txn_delete() freed it.)
1584 * This function will return false if 'row' is an orphan or if 'row' was
1585 * deleted within the current transaction.
1588 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
1590 return row
->new_datum
!= NULL
;
1594 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
1596 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
1600 ovsdb_idl_row_unparse(row
);
1602 for (i
= 0; i
< class->n_columns
; i
++) {
1603 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1604 (c
->parse
)(row
, &row
->old_datum
[i
]);
1610 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
1612 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
1618 for (i
= 0; i
< class->n_columns
; i
++) {
1619 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
1622 row
->parsed
= false;
1625 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
1626 * table indexes over one or more columns in the IDL. These indexes provide
1627 * the ability to retrieve rows matching a particular search criteria and to
1628 * iterate over a subset of rows in a defined order.
1631 /* Generic comparator that can compare each index, using the custom
1632 * configuration (an struct ovsdb_idl_index) passed to it.
1633 * Not intended for direct usage.
1636 ovsdb_idl_index_generic_comparer(const void *a
,
1637 const void *b
, const void *conf
)
1639 const struct ovsdb_idl_column
*column
;
1640 const struct ovsdb_idl_index
*index
;
1643 index
= CONST_CAST(struct ovsdb_idl_index
*, conf
);
1649 for (i
= 0; i
< index
->n_columns
; i
++) {
1651 if (index
->columns
[i
].comparer
) {
1652 val
= index
->columns
[i
].comparer(a
, b
);
1654 column
= index
->columns
[i
].column
;
1655 const struct ovsdb_idl_row
*row_a
, *row_b
;
1656 row_a
= CONST_CAST(struct ovsdb_idl_row
*, a
);
1657 row_b
= CONST_CAST(struct ovsdb_idl_row
*, b
);
1658 const struct ovsdb_datum
*datum_a
, *datum_b
;
1659 datum_a
= ovsdb_idl_read(row_a
, column
);
1660 datum_b
= ovsdb_idl_read(row_b
, column
);
1661 val
= ovsdb_datum_compare_3way(datum_a
, datum_b
, &column
->type
);
1665 return index
->columns
[i
].order
== OVSDB_INDEX_ASC
? val
: -val
;
1669 /* If ins_del is true then a row is being inserted into or deleted from
1670 * the index list. In this case, we augment the search key with
1671 * additional values (row UUID and memory address) to create a unique
1672 * search key in order to locate the correct entry efficiently and to
1673 * ensure that the correct entry is deleted in the case of a "delete"
1676 if (index
->ins_del
) {
1677 const struct ovsdb_idl_row
*row_a
, *row_b
;
1679 row_a
= (const struct ovsdb_idl_row
*) a
;
1680 row_b
= (const struct ovsdb_idl_row
*) b
;
1681 int value
= uuid_compare_3way(&row_a
->uuid
, &row_b
->uuid
);
1683 return value
? value
: (a
< b
) - (a
> b
);
1689 /* Creates a new index for the given 'idl' and with the 'n' specified
1692 * All indexes must be created before the first call to ovsdb_idl_run(). */
1693 struct ovsdb_idl_index
*
1694 ovsdb_idl_index_create(struct ovsdb_idl
*idl
,
1695 const struct ovsdb_idl_index_column
*columns
,
1700 struct ovsdb_idl_index
*index
= xzalloc(sizeof *index
);
1702 index
->table
= ovsdb_idl_table_from_column(idl
, columns
[0].column
);
1703 for (size_t i
= 0; i
< n
; i
++) {
1704 const struct ovsdb_idl_index_column
*c
= &columns
[i
];
1705 ovs_assert(ovsdb_idl_table_from_column(idl
,
1706 c
->column
) == index
->table
);
1707 ovs_assert(*ovsdb_idl_get_mode(idl
, c
->column
) & OVSDB_IDL_MONITOR
);
1710 index
->columns
= xmemdup(columns
, n
* sizeof *columns
);
1711 index
->n_columns
= n
;
1712 index
->skiplist
= skiplist_create(ovsdb_idl_index_generic_comparer
, index
);
1714 ovs_list_push_back(&index
->table
->indexes
, &index
->node
);
1719 struct ovsdb_idl_index
*
1720 ovsdb_idl_index_create1(struct ovsdb_idl
*idl
,
1721 const struct ovsdb_idl_column
*column1
)
1723 const struct ovsdb_idl_index_column columns
[] = {
1724 { .column
= column1
},
1726 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
1729 struct ovsdb_idl_index
*
1730 ovsdb_idl_index_create2(struct ovsdb_idl
*idl
,
1731 const struct ovsdb_idl_column
*column1
,
1732 const struct ovsdb_idl_column
*column2
)
1734 const struct ovsdb_idl_index_column columns
[] = {
1735 { .column
= column1
},
1736 { .column
= column2
},
1738 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
1742 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
)
1744 struct ovsdb_idl_index
*index
, *next
;
1745 LIST_FOR_EACH_SAFE (index
, next
, node
, &table
->indexes
) {
1746 skiplist_destroy(index
->skiplist
, NULL
);
1747 free(index
->columns
);
1753 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*row
)
1755 struct ovsdb_idl_table
*table
= row
->table
;
1756 struct ovsdb_idl_index
*index
;
1757 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
1758 index
->ins_del
= true;
1759 skiplist_insert(index
->skiplist
, row
);
1760 index
->ins_del
= false;
1765 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*row
)
1767 struct ovsdb_idl_table
*table
= row
->table
;
1768 struct ovsdb_idl_index
*index
;
1769 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
1770 index
->ins_del
= true;
1771 skiplist_delete(index
->skiplist
, row
);
1772 index
->ins_del
= false;
1776 /* Writes a datum in an ovsdb_idl_row, and updates the corresponding field in
1777 * the table record. Not intended for direct usage. */
1779 ovsdb_idl_index_write(struct ovsdb_idl_row
*const_row
,
1780 const struct ovsdb_idl_column
*column
,
1781 struct ovsdb_datum
*datum
,
1782 const struct ovsdb_idl_table_class
*class)
1784 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, const_row
);
1785 size_t column_idx
= column
- class->columns
;
1787 if (bitmap_is_set(row
->written
, column_idx
)) {
1788 free(row
->new_datum
[column_idx
].values
);
1789 free(row
->new_datum
[column_idx
].keys
);
1791 bitmap_set1(row
->written
, column_idx
);
1793 row
->new_datum
[column_idx
] = *datum
;
1794 (column
->unparse
)(row
);
1795 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
1798 /* Magic UUID for index rows */
1799 static const struct uuid index_row_uuid
= {
1800 .parts
= {0xdeadbeef,
1805 /* Check if a row is an index row */
1807 is_index_row(const struct ovsdb_idl_row
*row
)
1809 return uuid_equals(&row
->uuid
, &index_row_uuid
);
1812 /* Initializes a row for use in an indexed query.
1813 * Not intended for direct usage.
1815 struct ovsdb_idl_row
*
1816 ovsdb_idl_index_init_row(struct ovsdb_idl_index
*index
)
1818 const struct ovsdb_idl_table_class
*class = index
->table
->class_
;
1819 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
1820 class->row_init(row
);
1821 row
->uuid
= index_row_uuid
;
1822 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
1823 row
->written
= bitmap_allocate(class->n_columns
);
1824 row
->table
= index
->table
;
1825 /* arcs are not used for index row, but it doesn't harm to initialize */
1826 ovs_list_init(&row
->src_arcs
);
1827 ovs_list_init(&row
->dst_arcs
);
1831 /* Destroys 'row_' and frees all associated memory. This function is intended
1832 * to be used indirectly through one of the "index_destroy_row" functions
1833 * generated by ovsdb-idlc.
1836 ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row
*row_
)
1838 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
1839 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
1840 const struct ovsdb_idl_column
*c
;
1843 ovs_assert(is_index_row(row_
));
1844 ovs_assert(ovs_list_is_empty(&row_
->src_arcs
));
1845 ovs_assert(ovs_list_is_empty(&row_
->dst_arcs
));
1846 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
1847 c
= &class->columns
[i
];
1849 free(row
->new_datum
[i
].values
);
1850 free(row
->new_datum
[i
].keys
);
1852 free(row
->new_datum
);
1857 struct ovsdb_idl_row
*
1858 ovsdb_idl_index_find(struct ovsdb_idl_index
*index
,
1859 const struct ovsdb_idl_row
*target
)
1861 return skiplist_get_data(skiplist_find(index
->skiplist
, target
));
1864 struct ovsdb_idl_cursor
1865 ovsdb_idl_cursor_first(struct ovsdb_idl_index
*index
)
1867 struct skiplist_node
*node
= skiplist_first(index
->skiplist
);
1868 return (struct ovsdb_idl_cursor
) { index
, node
};
1871 struct ovsdb_idl_cursor
1872 ovsdb_idl_cursor_first_eq(struct ovsdb_idl_index
*index
,
1873 const struct ovsdb_idl_row
*target
)
1875 struct skiplist_node
*node
= skiplist_find(index
->skiplist
, target
);
1876 return (struct ovsdb_idl_cursor
) { index
, node
};
1879 struct ovsdb_idl_cursor
1880 ovsdb_idl_cursor_first_ge(struct ovsdb_idl_index
*index
,
1881 const struct ovsdb_idl_row
*target
)
1883 struct skiplist_node
*node
= (target
1884 ? skiplist_forward_to(index
->skiplist
,
1886 : skiplist_first(index
->skiplist
));
1887 return (struct ovsdb_idl_cursor
) { index
, node
};
1891 ovsdb_idl_cursor_next(struct ovsdb_idl_cursor
*cursor
)
1893 cursor
->position
= skiplist_next(cursor
->position
);
1897 ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor
*cursor
)
1899 struct ovsdb_idl_row
*data
= skiplist_get_data(cursor
->position
);
1900 struct skiplist_node
*next_position
= skiplist_next(cursor
->position
);
1901 struct ovsdb_idl_row
*next_data
= skiplist_get_data(next_position
);
1902 cursor
->position
= (!ovsdb_idl_index_compare(cursor
->index
,
1904 ? next_position
: NULL
);
1907 struct ovsdb_idl_row
*
1908 ovsdb_idl_cursor_data(struct ovsdb_idl_cursor
*cursor
)
1910 return skiplist_get_data(cursor
->position
);
1913 /* Returns the result of comparing two rows using the comparison function
1919 * When the pointer to either row is NULL, this function considers NULL to be
1920 * greater than any other value, and NULL == NULL.
1923 ovsdb_idl_index_compare(struct ovsdb_idl_index
*index
,
1924 const struct ovsdb_idl_row
*a
,
1925 const struct ovsdb_idl_row
*b
)
1928 return ovsdb_idl_index_generic_comparer(a
, b
, index
);
1929 } else if (!a
&& !b
) {
1939 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
1941 ovs_assert(row
->old_datum
== row
->new_datum
);
1942 if (!ovsdb_idl_row_is_orphan(row
)) {
1943 if (ovsdb_idl_track_is_set(row
->table
) && !row
->tracked_old_datum
) {
1944 row
->tracked_old_datum
= row
->old_datum
;
1946 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
1949 for (i
= 0; i
< class->n_columns
; i
++) {
1950 ovsdb_datum_destroy(&row
->old_datum
[i
],
1951 &class->columns
[i
].type
);
1953 free(row
->old_datum
);
1955 row
->old_datum
= row
->new_datum
= NULL
;
1960 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
1962 if (row
->old_datum
!= row
->new_datum
) {
1963 if (row
->new_datum
) {
1964 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
1968 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
1969 ovsdb_datum_destroy(&row
->new_datum
[i
],
1970 &class->columns
[i
].type
);
1973 free(row
->new_datum
);
1975 row
->written
= NULL
;
1977 row
->new_datum
= row
->old_datum
;
1982 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
1984 struct ovsdb_idl_arc
*arc
, *next
;
1986 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
1987 * that this causes to be unreferenced.
1989 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
1990 ovs_list_remove(&arc
->dst_node
);
1992 && ovsdb_idl_row_is_orphan(arc
->dst
)
1993 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
1994 ovsdb_idl_row_destroy(arc
->dst
);
1998 ovs_list_init(&row
->src_arcs
);
2001 /* Force nodes that reference 'row' to reparse. */
2003 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
2005 struct ovsdb_idl_arc
*arc
, *next
;
2007 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2008 * 'arc', so we need to use the "safe" variant of list traversal. However,
2009 * calling an ovsdb_idl_column's 'parse' function will add an arc
2010 * equivalent to 'arc' to row->arcs. That could be a problem for
2011 * traversal, but it adds it at the beginning of the list to prevent us
2012 * from stumbling upon it again.
2014 * (If duplicate arcs were possible then we would need to make sure that
2015 * 'next' didn't also point into 'arc''s destination, but we forbid
2016 * duplicate arcs.) */
2017 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
2018 struct ovsdb_idl_row
*ref
= arc
->src
;
2020 ovsdb_idl_row_unparse(ref
);
2021 ovsdb_idl_row_clear_arcs(ref
, false);
2022 ovsdb_idl_row_parse(ref
);
2026 static struct ovsdb_idl_row
*
2027 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
2029 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2030 class->row_init(row
);
2031 ovs_list_init(&row
->src_arcs
);
2032 ovs_list_init(&row
->dst_arcs
);
2033 hmap_node_nullify(&row
->txn_node
);
2034 ovs_list_init(&row
->track_node
);
2038 static struct ovsdb_idl_row
*
2039 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2041 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class_
);
2042 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
2045 row
->map_op_written
= NULL
;
2046 row
->map_op_lists
= NULL
;
2047 row
->set_op_written
= NULL
;
2048 row
->set_op_lists
= NULL
;
2053 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
2056 ovsdb_idl_row_clear_old(row
);
2057 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2058 ovsdb_idl_destroy_all_map_op_lists(row
);
2059 ovsdb_idl_destroy_all_set_op_lists(row
);
2060 if (ovsdb_idl_track_is_set(row
->table
)) {
2061 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2062 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2063 = row
->table
->idl
->change_seqno
+ 1;
2065 if (ovs_list_is_empty(&row
->track_node
)) {
2066 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
2072 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
2074 if (row
->map_op_written
) {
2075 /* Clear Map Operation Lists */
2076 size_t idx
, n_columns
;
2077 const struct ovsdb_idl_column
*columns
;
2078 const struct ovsdb_type
*type
;
2079 n_columns
= row
->table
->class_
->n_columns
;
2080 columns
= row
->table
->class_
->columns
;
2081 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
2082 type
= &columns
[idx
].type
;
2083 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
2085 free(row
->map_op_lists
);
2086 bitmap_free(row
->map_op_written
);
2087 row
->map_op_lists
= NULL
;
2088 row
->map_op_written
= NULL
;
2093 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
2095 if (row
->set_op_written
) {
2096 /* Clear Set Operation Lists */
2097 size_t idx
, n_columns
;
2098 const struct ovsdb_idl_column
*columns
;
2099 const struct ovsdb_type
*type
;
2100 n_columns
= row
->table
->class_
->n_columns
;
2101 columns
= row
->table
->class_
->columns
;
2102 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
2103 type
= &columns
[idx
].type
;
2104 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
2106 free(row
->set_op_lists
);
2107 bitmap_free(row
->set_op_written
);
2108 row
->set_op_lists
= NULL
;
2109 row
->set_op_written
= NULL
;
2114 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*idl
)
2116 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
2117 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
2119 if (!ovs_list_is_empty(&table
->track_list
)) {
2120 struct ovsdb_idl_row
*row
, *next
;
2122 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
2123 if (!ovsdb_idl_track_is_set(row
->table
)) {
2124 ovs_list_remove(&row
->track_node
);
2125 ovsdb_idl_row_unparse(row
);
2134 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct shash
*data
)
2136 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2137 size_t i
, datum_size
;
2139 ovs_assert(!row
->old_datum
&& !row
->new_datum
);
2140 datum_size
= class->n_columns
* sizeof *row
->old_datum
;
2141 row
->old_datum
= row
->new_datum
= xmalloc(datum_size
);
2142 for (i
= 0; i
< class->n_columns
; i
++) {
2143 ovsdb_datum_init_default(&row
->old_datum
[i
], &class->columns
[i
].type
);
2145 ovsdb_idl_row_change(row
, data
, false, OVSDB_IDL_CHANGE_INSERT
);
2146 ovsdb_idl_row_parse(row
);
2148 ovsdb_idl_row_reparse_backrefs(row
);
2149 ovsdb_idl_add_to_indexes(row
);
2153 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
2155 ovsdb_idl_remove_from_indexes(row
);
2156 ovsdb_idl_row_clear_arcs(row
, true);
2157 ovsdb_idl_row_clear_old(row
);
2158 if (ovs_list_is_empty(&row
->dst_arcs
)) {
2159 ovsdb_idl_row_destroy(row
);
2161 ovsdb_idl_row_reparse_backrefs(row
);
2165 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2168 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct shash
*values
,
2171 ovsdb_idl_remove_from_indexes(row
);
2172 ovsdb_idl_row_unparse(row
);
2173 ovsdb_idl_row_clear_arcs(row
, true);
2174 bool changed
= ovsdb_idl_row_change(row
, values
, xor,
2175 OVSDB_IDL_CHANGE_MODIFY
);
2176 ovsdb_idl_row_parse(row
);
2177 ovsdb_idl_add_to_indexes(row
);
2183 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
2185 const struct ovsdb_idl_arc
*arc
;
2192 /* No duplicate arcs.
2194 * We only need to test whether the first arc in dst->dst_arcs originates
2195 * at 'src', since we add all of the arcs from a given source in a clump
2196 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
2197 * added at the front of the dst_arcs list. */
2198 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
2201 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
2202 return arc
->src
!= src
;
2205 static struct ovsdb_idl_table
*
2206 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
2207 const struct ovsdb_idl_table_class
*table_class
)
2209 ptrdiff_t idx
= table_class
- idl
->class_
->tables
;
2210 return idx
>= 0 && idx
< idl
->class_
->n_tables
? &idl
->tables
[idx
] : NULL
;
2213 /* Called by ovsdb-idlc generated code. */
2214 struct ovsdb_idl_row
*
2215 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
2216 const struct ovsdb_idl_table_class
*dst_table_class
,
2217 const struct uuid
*dst_uuid
)
2219 struct ovsdb_idl
*idl
= src
->table
->idl
;
2220 struct ovsdb_idl_table
*dst_table
;
2221 struct ovsdb_idl_arc
*arc
;
2222 struct ovsdb_idl_row
*dst
;
2224 dst_table
= ovsdb_idl_table_from_class(idl
, dst_table_class
);
2225 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
2226 if (idl
->txn
|| is_index_row(src
)) {
2227 /* There are two cases we should not update any arcs:
2229 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
2230 * any arcs, because the transaction will be backed out at commit or
2231 * abort time and we don't want our graph screwed up.
2233 * 2. The row is used as an index for querying purpose only.
2235 * In these cases, just return the destination row, if there is one and
2236 * it has not been deleted. */
2237 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new_datum
)) {
2242 /* We're being called from some other context. Update the graph. */
2244 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
2247 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
2248 if (may_add_arc(src
, dst
)) {
2249 /* The arc *must* be added at the front of the dst_arcs list. See
2250 * ovsdb_idl_row_reparse_backrefs() for details. */
2251 arc
= xmalloc(sizeof *arc
);
2252 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
2253 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
2258 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
2262 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
2263 * pointer to the row if there is one, otherwise a null pointer. */
2264 const struct ovsdb_idl_row
*
2265 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
2266 const struct ovsdb_idl_table_class
*tc
,
2267 const struct uuid
*uuid
)
2269 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
2272 static struct ovsdb_idl_row
*
2273 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
2275 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
2276 struct ovsdb_idl_row
*row
;
2278 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
2279 if (ovsdb_idl_row_exists(row
)) {
2286 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
2289 * Database tables are internally maintained as hash tables, so adding or
2290 * removing rows while traversing the same table can cause some rows to be
2291 * visited twice or not at apply. */
2292 const struct ovsdb_idl_row
*
2293 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
2294 const struct ovsdb_idl_table_class
*table_class
)
2296 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
,
2298 return next_real_row(table
, hmap_first(&table
->rows
));
2301 /* Returns a row following 'row' within its table, or a null pointer if 'row'
2302 * is the last row in its table. */
2303 const struct ovsdb_idl_row
*
2304 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
2306 struct ovsdb_idl_table
*table
= row
->table
;
2308 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
2311 /* Reads and returns the value of 'column' within 'row'. If an ongoing
2312 * transaction has changed 'column''s value, the modified value is returned.
2314 * The caller must not modify or free the returned value.
2316 * Various kinds of changes can invalidate the returned value: writing to the
2317 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
2318 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
2319 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
2320 * returned value is needed for a long time, it is best to make a copy of it
2321 * with ovsdb_datum_clone(). */
2322 const struct ovsdb_datum
*
2323 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
2324 const struct ovsdb_idl_column
*column
)
2326 const struct ovsdb_idl_table_class
*class;
2329 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
2331 class = row
->table
->class_
;
2332 column_idx
= column
- class->columns
;
2334 ovs_assert(row
->new_datum
!= NULL
);
2335 ovs_assert(column_idx
< class->n_columns
);
2337 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
2338 return &row
->new_datum
[column_idx
];
2339 } else if (row
->old_datum
) {
2340 return &row
->old_datum
[column_idx
];
2342 return ovsdb_datum_default(&column
->type
);
2346 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
2347 * type 'key_type' and value type 'value_type'. (Scalar and set types will
2348 * have a value type of OVSDB_TYPE_VOID.)
2350 * This is useful in code that "knows" that a particular column has a given
2351 * type, so that it will abort if someone changes the column's type without
2352 * updating the code that uses it. */
2353 const struct ovsdb_datum
*
2354 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
2355 const struct ovsdb_idl_column
*column
,
2356 enum ovsdb_atomic_type key_type OVS_UNUSED
,
2357 enum ovsdb_atomic_type value_type OVS_UNUSED
)
2359 ovs_assert(column
->type
.key
.type
== key_type
);
2360 ovs_assert(column
->type
.value
.type
== value_type
);
2362 return ovsdb_idl_read(row
, column
);
2365 /* Returns true if the field represented by 'column' in 'row' may be modified,
2366 * false if it is immutable.
2368 * Normally, whether a field is mutable is controlled by its column's schema.
2369 * However, an immutable column can be set to any initial value at the time of
2370 * insertion, so if 'row' is a new row (one that is being added as part of the
2371 * current transaction, supposing that a transaction is in progress) then even
2372 * its "immutable" fields are actually mutable. */
2374 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
2375 const struct ovsdb_idl_column
*column
)
2377 return column
->is_mutable
|| (row
->new_datum
&& !row
->old_datum
);
2380 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
2381 * to all-zero-bits by some other entity. If 'row' was set up some other way
2382 * then the return value is indeterminate. */
2384 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
2386 return row
->table
== NULL
;
2391 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
2392 enum ovsdb_idl_txn_status
);
2394 /* Returns a string representation of 'status'. The caller must not modify or
2395 * free the returned string.
2397 * The return value is probably useful only for debug log messages and unit
2400 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
2403 case TXN_UNCOMMITTED
:
2404 return "uncommitted";
2407 case TXN_INCOMPLETE
:
2408 return "incomplete";
2415 case TXN_NOT_LOCKED
:
2416 return "not locked";
2423 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
2424 * active transaction at a time. See the large comment in ovsdb-idl.h for
2425 * general information on transactions. */
2426 struct ovsdb_idl_txn
*
2427 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
2429 struct ovsdb_idl_txn
*txn
;
2431 ovs_assert(!idl
->txn
);
2432 idl
->txn
= txn
= xmalloc(sizeof *txn
);
2433 txn
->request_id
= NULL
;
2435 hmap_init(&txn
->txn_rows
);
2436 txn
->status
= TXN_UNCOMMITTED
;
2438 txn
->dry_run
= false;
2439 ds_init(&txn
->comment
);
2441 txn
->inc_table
= NULL
;
2442 txn
->inc_column
= NULL
;
2444 hmap_init(&txn
->inserted_rows
);
2449 /* Appends 's', which is treated as a printf()-type format string, to the
2450 * comments that will be passed to the OVSDB server when 'txn' is committed.
2451 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
2452 * show-log" can print in a relatively human-readable form.) */
2454 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
2458 if (txn
->comment
.length
) {
2459 ds_put_char(&txn
->comment
, '\n');
2463 ds_put_format_valist(&txn
->comment
, s
, args
);
2467 /* Marks 'txn' as a transaction that will not actually modify the database. In
2468 * almost every way, the transaction is treated like other transactions. It
2469 * must be committed or aborted like other transactions, it will be sent to the
2470 * database server like other transactions, and so on. The only difference is
2471 * that the operations sent to the database server will include, as the last
2472 * step, an "abort" operation, so that any changes made by the transaction will
2473 * not actually take effect. */
2475 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
2477 txn
->dry_run
= true;
2480 /* Causes 'txn', when committed, to increment the value of 'column' within
2481 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
2482 * successfully, the client may retrieve the final (incremented) value of
2483 * 'column' with ovsdb_idl_txn_get_increment_new_value().
2485 * If at time of commit the transaction is otherwise empty, that is, it doesn't
2486 * change the database, then 'force' is important. If 'force' is false in this
2487 * case, the IDL suppresses the increment and skips a round trip to the
2488 * database server. If 'force' is true, the IDL will still increment the
2491 * The client could accomplish something similar with ovsdb_idl_read(),
2492 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
2493 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
2494 * will never (by itself) fail because of a verify error.
2496 * The intended use is for incrementing the "next_cfg" column in the
2497 * Open_vSwitch table. */
2499 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
2500 const struct ovsdb_idl_row
*row
,
2501 const struct ovsdb_idl_column
*column
,
2504 ovs_assert(!txn
->inc_table
);
2505 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
2506 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
2508 txn
->inc_table
= row
->table
->class_
->name
;
2509 txn
->inc_column
= column
->name
;
2510 txn
->inc_row
= row
->uuid
;
2511 txn
->inc_force
= force
;
2514 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
2515 * has been called for 'txn' but the commit is still incomplete (that is, the
2516 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
2517 * end up committing at the database server, but the client will not be able to
2518 * get any further status information back. */
2520 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
2522 struct ovsdb_idl_txn_insert
*insert
, *next
;
2524 if (txn
->status
== TXN_INCOMPLETE
) {
2525 ovsdb_cs_forget_transaction(txn
->idl
->cs
, txn
->request_id
);
2526 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
2528 json_destroy(txn
->request_id
);
2529 ovsdb_idl_txn_abort(txn
);
2530 ds_destroy(&txn
->comment
);
2532 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
2535 hmap_destroy(&txn
->inserted_rows
);
2539 /* Causes poll_block() to wake up if 'txn' has completed committing. */
2541 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
2543 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
2544 poll_immediate_wake();
2548 static struct json
*
2549 where_uuid_equals(const struct uuid
*uuid
)
2552 json_array_create_1(
2553 json_array_create_3(
2554 json_string_create("_uuid"),
2555 json_string_create("=="),
2556 json_array_create_2(
2557 json_string_create("uuid"),
2558 json_string_create_nocopy(
2559 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
2562 static const struct ovsdb_idl_row
*
2563 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
2565 const struct ovsdb_idl_row
*row
;
2567 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
2568 if (uuid_equals(&row
->uuid
, uuid
)) {
2575 /* XXX there must be a cleaner way to do this */
2576 static struct json
*
2577 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
2579 if (json
->type
== JSON_ARRAY
) {
2583 if (json
->array
.n
== 2
2584 && json
->array
.elems
[0]->type
== JSON_STRING
2585 && json
->array
.elems
[1]->type
== JSON_STRING
2586 && !strcmp(json
->array
.elems
[0]->string
, "uuid")
2587 && uuid_from_string(&uuid
, json
->array
.elems
[1]->string
)) {
2588 const struct ovsdb_idl_row
*row
;
2590 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
2591 if (row
&& !row
->old_datum
&& row
->new_datum
) {
2594 return json_array_create_2(
2595 json_string_create("named-uuid"),
2596 json_string_create_nocopy(ovsdb_data_row_name(&uuid
)));
2600 for (i
= 0; i
< json
->array
.n
; i
++) {
2601 json
->array
.elems
[i
] = substitute_uuids(json
->array
.elems
[i
],
2604 } else if (json
->type
== JSON_OBJECT
) {
2605 struct shash_node
*node
;
2607 SHASH_FOR_EACH (node
, json_object(json
)) {
2608 node
->data
= substitute_uuids(node
->data
, txn
);
2615 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
2617 struct ovsdb_idl_row
*row
, *next
;
2619 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
2620 * ovsdb_idl_column's 'parse' function, which will call
2621 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
2622 * transaction and fail to update the graph. */
2623 txn
->idl
->txn
= NULL
;
2625 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
2626 enum { INSERTED
, MODIFIED
, DELETED
} op
2627 = (!row
->new_datum
? DELETED
2628 : !row
->old_datum
? INSERTED
2631 if (op
!= DELETED
) {
2632 ovsdb_idl_remove_from_indexes(row
);
2635 ovsdb_idl_destroy_all_map_op_lists(row
);
2636 ovsdb_idl_destroy_all_set_op_lists(row
);
2637 if (op
!= INSERTED
) {
2639 ovsdb_idl_row_unparse(row
);
2640 ovsdb_idl_row_clear_arcs(row
, false);
2641 ovsdb_idl_row_parse(row
);
2644 ovsdb_idl_row_unparse(row
);
2646 ovsdb_idl_row_clear_new(row
);
2649 row
->prereqs
= NULL
;
2652 row
->written
= NULL
;
2654 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
2655 hmap_node_nullify(&row
->txn_node
);
2656 if (op
!= INSERTED
) {
2657 ovsdb_idl_add_to_indexes(row
);
2659 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2663 hmap_destroy(&txn
->txn_rows
);
2664 hmap_init(&txn
->txn_rows
);
2668 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
2669 struct json
*mutations
)
2671 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2673 bool any_mutations
= false;
2675 if (row
->map_op_written
) {
2676 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
2677 struct map_op_list
*map_op_list
;
2678 const struct ovsdb_idl_column
*column
;
2679 const struct ovsdb_datum
*old_datum
;
2680 enum ovsdb_atomic_type key_type
, value_type
;
2681 struct json
*mutation
, *map
, *col_name
, *mutator
;
2682 struct json
*del_set
, *ins_map
;
2683 bool any_del
, any_ins
;
2685 map_op_list
= row
->map_op_lists
[idx
];
2686 column
= &class->columns
[idx
];
2687 key_type
= column
->type
.key
.type
;
2688 value_type
= column
->type
.value
.type
;
2690 /* Get the value to be changed */
2691 if (row
->new_datum
&& row
->written
2692 && bitmap_is_set(row
->written
,idx
)) {
2693 old_datum
= &row
->new_datum
[idx
];
2694 } else if (row
->old_datum
!= NULL
) {
2695 old_datum
= &row
->old_datum
[idx
];
2697 old_datum
= ovsdb_datum_default(&column
->type
);
2700 del_set
= json_array_create_empty();
2701 ins_map
= json_array_create_empty();
2705 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
2706 map_op
= map_op_list_next(map_op_list
, map_op
)) {
2708 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2709 /* Find out if value really changed. */
2710 struct ovsdb_datum
*new_datum
;
2712 new_datum
= map_op_datum(map_op
);
2713 pos
= ovsdb_datum_find_key(old_datum
,
2714 &new_datum
->keys
[0],
2716 if (ovsdb_atom_equals(&new_datum
->values
[0],
2717 &old_datum
->values
[pos
],
2719 /* No change in value. Move on to next update. */
2722 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
2723 /* Verify that there is a key to delete. */
2725 pos
= ovsdb_datum_find_key(old_datum
,
2726 &map_op_datum(map_op
)->keys
[0],
2728 if (pos
== UINT_MAX
) {
2729 /* No key to delete. Move on to next update. */
2730 VLOG_WARN("Trying to delete a key that doesn't "
2731 "exist in the map.");
2736 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
2737 map
= json_array_create_2(
2738 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2740 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2742 json_array_add(ins_map
, map
);
2744 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
2745 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2747 json_array_add(del_set
, map
);
2751 /* Generate an additional insert mutate for updates. */
2752 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
2753 map
= json_array_create_2(
2754 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
2756 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
2758 json_array_add(ins_map
, map
);
2764 col_name
= json_string_create(column
->name
);
2765 mutator
= json_string_create("delete");
2766 map
= json_array_create_2(json_string_create("set"), del_set
);
2767 mutation
= json_array_create_3(col_name
, mutator
, map
);
2768 json_array_add(mutations
, mutation
);
2769 any_mutations
= true;
2771 json_destroy(del_set
);
2774 col_name
= json_string_create(column
->name
);
2775 mutator
= json_string_create("insert");
2776 map
= json_array_create_2(json_string_create("map"), ins_map
);
2777 mutation
= json_array_create_3(col_name
, mutator
, map
);
2778 json_array_add(mutations
, mutation
);
2779 any_mutations
= true;
2781 json_destroy(ins_map
);
2785 if (row
->set_op_written
) {
2786 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
2787 struct set_op_list
*set_op_list
;
2788 const struct ovsdb_idl_column
*column
;
2789 const struct ovsdb_datum
*old_datum
;
2790 enum ovsdb_atomic_type key_type
;
2791 struct json
*mutation
, *set
, *col_name
, *mutator
;
2792 struct json
*del_set
, *ins_set
;
2793 bool any_del
, any_ins
;
2795 set_op_list
= row
->set_op_lists
[idx
];
2796 column
= &class->columns
[idx
];
2797 key_type
= column
->type
.key
.type
;
2799 /* Get the value to be changed */
2800 if (row
->new_datum
&& row
->written
2801 && bitmap_is_set(row
->written
,idx
)) {
2802 old_datum
= &row
->new_datum
[idx
];
2803 } else if (row
->old_datum
!= NULL
) {
2804 old_datum
= &row
->old_datum
[idx
];
2806 old_datum
= ovsdb_datum_default(&column
->type
);
2809 del_set
= json_array_create_empty();
2810 ins_set
= json_array_create_empty();
2814 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
2815 set_op
= set_op_list_next(set_op_list
, set_op
)) {
2816 if (set_op_type(set_op
) == SET_OP_INSERT
) {
2817 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
2819 json_array_add(ins_set
, set
);
2821 } else { /* SETP_OP_DELETE */
2822 /* Verify that there is a key to delete. */
2824 pos
= ovsdb_datum_find_key(old_datum
,
2825 &set_op_datum(set_op
)->keys
[0],
2827 if (pos
== UINT_MAX
) {
2828 /* No key to delete. Move on to next update. */
2829 VLOG_WARN("Trying to delete a key that doesn't "
2830 "exist in the set.");
2833 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
2835 json_array_add(del_set
, set
);
2840 col_name
= json_string_create(column
->name
);
2841 mutator
= json_string_create("delete");
2842 set
= json_array_create_2(json_string_create("set"), del_set
);
2843 mutation
= json_array_create_3(col_name
, mutator
, set
);
2844 json_array_add(mutations
, mutation
);
2845 any_mutations
= true;
2847 json_destroy(del_set
);
2850 col_name
= json_string_create(column
->name
);
2851 mutator
= json_string_create("insert");
2852 set
= json_array_create_2(json_string_create("set"), ins_set
);
2853 mutation
= json_array_create_3(col_name
, mutator
, set
);
2854 json_array_add(mutations
, mutation
);
2855 any_mutations
= true;
2857 json_destroy(ins_set
);
2861 return any_mutations
;
2864 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
2865 * of the following TXN_* constants:
2869 * The transaction is in progress, but not yet complete. The caller
2870 * should call again later, after calling ovsdb_idl_run() to let the IDL
2871 * do OVSDB protocol processing.
2875 * The transaction is complete. (It didn't actually change the database,
2876 * so the IDL didn't send any request to the database server.)
2880 * The caller previously called ovsdb_idl_txn_abort().
2884 * The transaction was successful. The update made by the transaction
2885 * (and possibly other changes made by other database clients) should
2886 * already be visible in the IDL.
2890 * The transaction failed for some transient reason, e.g. because a
2891 * "verify" operation reported an inconsistency or due to a network
2892 * problem. The caller should wait for a change to the database, then
2893 * compose a new transaction, and commit the new transaction.
2895 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
2896 * the database. It is important to use its return value *before* the
2897 * initial call to ovsdb_idl_txn_commit() as the baseline for this
2898 * purpose, because the change that one should wait for can happen after
2899 * the initial call but before the call that returns TXN_TRY_AGAIN, and
2900 * using some other baseline value in that situation could cause an
2901 * indefinite wait if the database rarely changes.
2905 * The transaction failed because the IDL has been configured to require
2906 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
2907 * has already lost it.
2909 * Committing a transaction rolls back all of the changes that it made to the
2910 * IDL's copy of the database. If the transaction commits successfully, then
2911 * the database server will send an update and, thus, the IDL will be updated
2912 * with the committed changes. */
2913 enum ovsdb_idl_txn_status
2914 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
2916 struct ovsdb_idl
*idl
= txn
->idl
;
2917 if (txn
!= idl
->txn
) {
2919 } else if (!ovsdb_cs_may_send_transaction(idl
->cs
)) {
2920 txn
->status
= TXN_TRY_AGAIN
;
2921 goto disassemble_out
;
2922 } else if (ovsdb_cs_get_lock(idl
->cs
) && !ovsdb_cs_has_lock(idl
->cs
)) {
2923 txn
->status
= TXN_NOT_LOCKED
;
2924 goto disassemble_out
;
2927 struct json
*operations
= json_array_create_1(
2928 json_string_create(idl
->class_
->database
));
2930 /* Add prerequisites and declarations of new rows. */
2931 struct ovsdb_idl_row
*row
;
2932 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2933 /* XXX check that deleted rows exist even if no prereqs? */
2935 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2936 size_t n_columns
= class->n_columns
;
2937 struct json
*op
, *columns
, *row_json
;
2940 op
= json_object_create();
2941 json_array_add(operations
, op
);
2942 json_object_put_string(op
, "op", "wait");
2943 json_object_put_string(op
, "table", class->name
);
2944 json_object_put(op
, "timeout", json_integer_create(0));
2945 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
2946 json_object_put_string(op
, "until", "==");
2947 columns
= json_array_create_empty();
2948 json_object_put(op
, "columns", columns
);
2949 row_json
= json_object_create();
2950 json_object_put(op
, "rows", json_array_create_1(row_json
));
2952 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
2953 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
2954 json_array_add(columns
, json_string_create(column
->name
));
2955 json_object_put(row_json
, column
->name
,
2956 ovsdb_datum_to_json(&row
->old_datum
[idx
],
2963 bool any_updates
= false;
2965 /* For tables constrained to have only a single row (a fairly common OVSDB
2966 * pattern for storing global data), identify whether we're inserting a
2967 * row. If so, then verify that the table is empty before inserting the
2968 * row. This gives us a clear verification-related failure if there was an
2969 * insertion race with another client. */
2970 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
2971 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
2972 if (table
->class_
->is_singleton
) {
2973 /* Count the number of rows in the table before and after our
2974 * transaction commits. This is O(n) in the number of rows in the
2975 * table, but that's OK since we know that the table should only
2977 size_t initial_rows
= 0;
2978 size_t final_rows
= 0;
2979 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
2980 initial_rows
+= row
->old_datum
!= NULL
;
2981 final_rows
+= row
->new_datum
!= NULL
;
2984 if (initial_rows
== 0 && final_rows
== 1) {
2985 struct json
*op
= json_object_create();
2986 json_array_add(operations
, op
);
2987 json_object_put_string(op
, "op", "wait");
2988 json_object_put_string(op
, "table", table
->class_
->name
);
2989 json_object_put(op
, "where", json_array_create_empty());
2990 json_object_put(op
, "timeout", json_integer_create(0));
2991 json_object_put_string(op
, "until", "==");
2992 json_object_put(op
, "rows", json_array_create_empty());
2997 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
2998 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3000 if (!row
->new_datum
) {
3001 if (class->is_root
) {
3002 struct json
*op
= json_object_create();
3003 json_object_put_string(op
, "op", "delete");
3004 json_object_put_string(op
, "table", class->name
);
3005 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3006 json_array_add(operations
, op
);
3009 /* Let ovsdb-server decide whether to really delete it. */
3011 } else if (row
->old_datum
!= row
->new_datum
) {
3012 struct json
*row_json
;
3015 struct json
*op
= json_object_create();
3016 json_object_put_string(op
, "op",
3017 row
->old_datum
? "update" : "insert");
3018 json_object_put_string(op
, "table", class->name
);
3019 if (row
->old_datum
) {
3020 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3022 struct ovsdb_idl_txn_insert
*insert
;
3026 json_object_put(op
, "uuid-name",
3027 json_string_create_nocopy(
3028 ovsdb_data_row_name(&row
->uuid
)));
3030 insert
= xmalloc(sizeof *insert
);
3031 insert
->dummy
= row
->uuid
;
3032 insert
->op_index
= operations
->array
.n
- 1;
3033 uuid_zero(&insert
->real
);
3034 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
3035 uuid_hash(&insert
->dummy
));
3037 row_json
= json_object_create();
3038 json_object_put(op
, "row", row_json
);
3041 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
3042 const struct ovsdb_idl_column
*column
=
3043 &class->columns
[idx
];
3046 || !ovsdb_datum_is_default(&row
->new_datum
[idx
],
3050 value
= ovsdb_datum_to_json(&row
->new_datum
[idx
],
3052 json_object_put(row_json
, column
->name
,
3053 substitute_uuids(value
, txn
));
3055 /* If anything really changed, consider it an update.
3056 * We can't suppress not-really-changed values earlier
3057 * or transactions would become nonatomic (see the big
3058 * comment inside ovsdb_idl_txn_write()). */
3059 if (!any_updates
&& row
->old_datum
&&
3060 !ovsdb_datum_equals(&row
->old_datum
[idx
],
3061 &row
->new_datum
[idx
],
3069 if (!row
->old_datum
|| !shash_is_empty(json_object(row_json
))) {
3070 json_array_add(operations
, op
);
3076 /* Add mutate operation, for partial map or partial set updates. */
3077 if (row
->map_op_written
|| row
->set_op_written
) {
3078 struct json
*op
, *mutations
;
3081 op
= json_object_create();
3082 json_object_put_string(op
, "op", "mutate");
3083 json_object_put_string(op
, "table", class->name
);
3084 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3085 mutations
= json_array_create_empty();
3086 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
3087 json_object_put(op
, "mutations", mutations
);
3089 if (any_mutations
) {
3090 op
= substitute_uuids(op
, txn
);
3091 json_array_add(operations
, op
);
3099 /* Add increment. */
3100 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
3102 txn
->inc_index
= operations
->array
.n
- 1;
3104 struct json
*op
= json_object_create();
3105 json_object_put_string(op
, "op", "mutate");
3106 json_object_put_string(op
, "table", txn
->inc_table
);
3107 json_object_put(op
, "where",
3108 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
3110 json_object_put(op
, "mutations",
3111 json_array_create_1(
3112 json_array_create_3(
3113 json_string_create(txn
->inc_column
),
3114 json_string_create("+="),
3115 json_integer_create(1))));
3116 json_array_add(operations
, op
);
3118 op
= json_object_create();
3119 json_object_put_string(op
, "op", "select");
3120 json_object_put_string(op
, "table", txn
->inc_table
);
3121 json_object_put(op
, "where",
3122 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
3124 json_object_put(op
, "columns",
3125 json_array_create_1(json_string_create(
3127 json_array_add(operations
, op
);
3130 if (txn
->comment
.length
) {
3131 struct json
*op
= json_object_create();
3132 json_object_put_string(op
, "op", "comment");
3133 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
3134 json_array_add(operations
, op
);
3138 struct json
*op
= json_object_create();
3139 json_object_put_string(op
, "op", "abort");
3140 json_array_add(operations
, op
);
3144 txn
->status
= TXN_UNCHANGED
;
3145 json_destroy(operations
);
3147 txn
->request_id
= ovsdb_cs_send_transaction(idl
->cs
, operations
);
3148 if (txn
->request_id
) {
3149 hmap_insert(&idl
->outstanding_txns
, &txn
->hmap_node
,
3150 json_hash(txn
->request_id
, 0));
3151 txn
->status
= TXN_INCOMPLETE
;
3153 txn
->status
= TXN_TRY_AGAIN
;
3158 ovsdb_idl_txn_disassemble(txn
);
3160 switch (txn
->status
) {
3161 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
3162 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
3163 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
3164 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
3165 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
3166 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
3167 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
3168 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
3174 /* Attempts to commit 'txn', blocking until the commit either succeeds or
3175 * fails. Returns the final commit status, which may be any TXN_* value other
3176 * than TXN_INCOMPLETE.
3178 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
3179 * return value of ovsdb_idl_get_seqno() to change. */
3180 enum ovsdb_idl_txn_status
3181 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
3183 enum ovsdb_idl_txn_status status
;
3186 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
3187 ovsdb_idl_run(txn
->idl
);
3188 ovsdb_idl_wait(txn
->idl
);
3189 ovsdb_idl_txn_wait(txn
);
3195 /* Returns the final (incremented) value of the column in 'txn' that was set to
3196 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
3199 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
3201 ovs_assert(txn
->status
== TXN_SUCCESS
);
3202 return txn
->inc_new_value
;
3205 /* Aborts 'txn' without sending it to the database server. This is effective
3206 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
3207 * Otherwise, it has no effect.
3209 * Aborting a transaction doesn't free its memory. Use
3210 * ovsdb_idl_txn_destroy() to do that. */
3212 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
3214 ovsdb_idl_txn_disassemble(txn
);
3215 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
3216 txn
->status
= TXN_ABORTED
;
3220 /* Returns a string that reports the error status for 'txn'. The caller must
3221 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
3222 * for 'txn' may free the returned string.
3224 * The return value is ordinarily one of the strings that
3225 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
3226 * due to an error reported by the database server, the return value is that
3229 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
3231 if (txn
->status
!= TXN_ERROR
) {
3232 return ovsdb_idl_txn_status_to_string(txn
->status
);
3233 } else if (txn
->error
) {
3236 return "no error details available";
3241 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
3242 const struct json
*json
)
3244 if (json
&& txn
->error
== NULL
) {
3245 txn
->error
= json_to_string(json
, JSSF_SORT
);
3249 /* For transaction 'txn' that completed successfully, finds and returns the
3250 * permanent UUID that the database assigned to a newly inserted row, given the
3251 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
3253 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
3254 * if it was assigned by that function and then deleted by
3255 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
3256 * and then deleted within a single transaction are never sent to the database
3257 * server, so it never assigns them a permanent UUID.) */
3259 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
3260 const struct uuid
*uuid
)
3262 const struct ovsdb_idl_txn_insert
*insert
;
3264 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
3265 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
3266 uuid_hash(uuid
), &txn
->inserted_rows
) {
3267 if (uuid_equals(uuid
, &insert
->dummy
)) {
3268 return &insert
->real
;
3275 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3276 enum ovsdb_idl_txn_status status
)
3278 txn
->status
= status
;
3279 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
3283 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
3284 const struct ovsdb_idl_column
*column
,
3285 struct ovsdb_datum
*datum
, bool owns_datum
)
3287 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3288 const struct ovsdb_idl_table_class
*class;
3292 ovs_assert(!column
->is_synthetic
);
3293 if (ovsdb_idl_row_is_synthetic(row
)) {
3297 class = row
->table
->class_
;
3298 column_idx
= column
- class->columns
;
3299 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
3301 ovs_assert(row
->new_datum
!= NULL
);
3302 ovs_assert(column_idx
< class->n_columns
);
3303 ovs_assert(row
->old_datum
== NULL
||
3304 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3306 if (row
->table
->idl
->verify_write_only
&& !write_only
) {
3307 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
3308 " explicitly configured not to.", class->name
, column
->name
);
3312 /* If this is a write-only column and the datum being written is the same
3313 * as the one already there, just skip the update entirely. This is worth
3314 * optimizing because we have a lot of columns that get periodically
3315 * refreshed into the database but don't actually change that often.
3317 * We don't do this for read/write columns because that would break
3318 * atomicity of transactions--some other client might have written a
3319 * different value in that column since we read it. (But if a whole
3320 * transaction only does writes of existing values, without making any real
3321 * changes, we will drop the whole transaction later in
3322 * ovsdb_idl_txn_commit().) */
3323 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
3324 datum
, &column
->type
)) {
3328 bool index_row
= is_index_row(row
);
3330 ovsdb_idl_remove_from_indexes(row
);
3332 if (hmap_node_is_null(&row
->txn_node
)) {
3333 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3334 uuid_hash(&row
->uuid
));
3336 if (row
->old_datum
== row
->new_datum
) {
3337 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
3339 if (!row
->written
) {
3340 row
->written
= bitmap_allocate(class->n_columns
);
3342 if (bitmap_is_set(row
->written
, column_idx
)) {
3343 ovsdb_datum_destroy(&row
->new_datum
[column_idx
], &column
->type
);
3345 bitmap_set1(row
->written
, column_idx
);
3348 row
->new_datum
[column_idx
] = *datum
;
3350 ovsdb_datum_clone(&row
->new_datum
[column_idx
], datum
, &column
->type
);
3352 (column
->unparse
)(row
);
3353 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
3356 ovsdb_idl_add_to_indexes(row
);
3362 ovsdb_datum_destroy(datum
, &column
->type
);
3366 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
3367 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
3370 * 'datum' must have the correct type for its column, but it needs not be
3371 * sorted or unique because this function will take care of that. The IDL does
3372 * not check that it meets schema constraints, but ovsdb-server will do so at
3373 * commit time so it had better be correct.
3375 * A transaction must be in progress. Replication of 'column' must not have
3376 * been disabled (by calling ovsdb_idl_omit()).
3378 * Usually this function is used indirectly through one of the "set" functions
3379 * generated by ovsdb-idlc.
3381 * Takes ownership of what 'datum' points to (and in some cases destroys that
3382 * data before returning) but makes a copy of 'datum' itself. (Commonly
3383 * 'datum' is on the caller's stack.) */
3385 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
3386 const struct ovsdb_idl_column
*column
,
3387 struct ovsdb_datum
*datum
)
3389 ovsdb_datum_sort_unique(datum
,
3390 column
->type
.key
.type
, column
->type
.value
.type
);
3391 ovsdb_idl_txn_write__(row
, column
, datum
, true);
3394 /* Similar to ovsdb_idl_txn_write(), except:
3396 * - The caller retains ownership of 'datum' and what it points to.
3398 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
3399 * ovsdb_datum_sort_unique().) */
3401 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
3402 const struct ovsdb_idl_column
*column
,
3403 const struct ovsdb_datum
*datum
)
3405 ovsdb_idl_txn_write__(row
, column
,
3406 CONST_CAST(struct ovsdb_datum
*, datum
), false);
3409 /* Causes the original contents of 'column' in 'row_' to be verified as a
3410 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
3411 * changed (or if 'row_' was deleted) between the time that the IDL originally
3412 * read its contents and the time that the transaction commits, then the
3413 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
3415 * The intention is that, to ensure that no transaction commits based on dirty
3416 * reads, an application should call ovsdb_idl_txn_verify() on each data item
3417 * read as part of a read-modify-write operation.
3419 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
3420 * value of 'column' is already known:
3422 * - If 'row_' is a row created by the current transaction (returned by
3423 * ovsdb_idl_txn_insert()).
3425 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
3426 * within the current transaction.
3428 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
3429 * ovsdb_idl_txn_write() for a given read-modify-write.
3431 * A transaction must be in progress.
3433 * Usually this function is used indirectly through one of the "verify"
3434 * functions generated by ovsdb-idlc. */
3436 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
3437 const struct ovsdb_idl_column
*column
)
3439 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3440 const struct ovsdb_idl_table_class
*class;
3443 if (ovsdb_idl_row_is_synthetic(row
)) {
3447 class = row
->table
->class_
;
3448 column_idx
= column
- class->columns
;
3450 ovs_assert(row
->new_datum
!= NULL
);
3451 ovs_assert(row
->old_datum
== NULL
||
3452 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3454 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
3458 if (hmap_node_is_null(&row
->txn_node
)) {
3459 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3460 uuid_hash(&row
->uuid
));
3462 if (!row
->prereqs
) {
3463 row
->prereqs
= bitmap_allocate(class->n_columns
);
3465 bitmap_set1(row
->prereqs
, column_idx
);
3468 /* Deletes 'row_' from its table. May free 'row_', so it must not be
3469 * accessed afterward.
3471 * A transaction must be in progress.
3473 * Usually this function is used indirectly through one of the "delete"
3474 * functions generated by ovsdb-idlc. */
3476 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
3478 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3480 if (ovsdb_idl_row_is_synthetic(row
)) {
3484 ovs_assert(row
->new_datum
!= NULL
);
3485 ovs_assert(!is_index_row(row_
));
3486 ovsdb_idl_remove_from_indexes(row_
);
3487 if (!row
->old_datum
) {
3488 ovsdb_idl_row_unparse(row
);
3489 ovsdb_idl_row_clear_new(row
);
3490 ovs_assert(!row
->prereqs
);
3491 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3492 hmap_remove(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
);
3496 if (hmap_node_is_null(&row
->txn_node
)) {
3497 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3498 uuid_hash(&row
->uuid
));
3500 ovsdb_idl_row_clear_new(row
);
3501 row
->new_datum
= NULL
;
3504 /* Inserts and returns a new row in the table with the specified 'class' in the
3505 * database with open transaction 'txn'.
3507 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
3508 * randomly generated; otherwise 'uuid' should specify a randomly generated
3509 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
3510 * 'txn' is committed, but the IDL will replace any uses of the provisional
3511 * UUID in the data to be to be committed by the UUID assigned by
3514 * Usually this function is used indirectly through one of the "insert"
3515 * functions generated by ovsdb-idlc. */
3516 const struct ovsdb_idl_row
*
3517 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
3518 const struct ovsdb_idl_table_class
*class,
3519 const struct uuid
*uuid
)
3521 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
3524 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
3527 uuid_generate(&row
->uuid
);
3530 row
->table
= ovsdb_idl_table_from_class(txn
->idl
, class);
3531 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
3532 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
3533 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
3534 ovsdb_idl_add_to_indexes(row
);
3540 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
3542 struct ovsdb_idl_txn
*txn
;
3544 HMAP_FOR_EACH (txn
, hmap_node
, &idl
->outstanding_txns
) {
3545 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
3549 static struct ovsdb_idl_txn
*
3550 ovsdb_idl_txn_find(struct ovsdb_idl
*idl
, const struct json
*id
)
3552 struct ovsdb_idl_txn
*txn
;
3554 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
3555 json_hash(id
, 0), &idl
->outstanding_txns
) {
3556 if (json_equal(id
, txn
->request_id
)) {
3564 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
3567 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
3569 } else if (json
->type
!= type
) {
3570 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
3571 name
, json_type_to_string(json
->type
),
3572 json_type_to_string(type
));
3580 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
3581 const struct json_array
*results
)
3583 struct json
*count
, *rows
, *row
, *column
;
3584 struct shash
*mutate
, *select
;
3586 if (txn
->inc_index
+ 2 > results
->n
) {
3587 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3588 "for increment (has %"PRIuSIZE
", needs %u)",
3589 results
->n
, txn
->inc_index
+ 2);
3593 /* We know that this is a JSON object because the loop in
3594 * ovsdb_idl_txn_process_reply() checked. */
3595 mutate
= json_object(results
->elems
[txn
->inc_index
]);
3596 count
= shash_find_data(mutate
, "count");
3597 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
3600 if (count
->integer
!= 1) {
3601 VLOG_WARN_RL(&syntax_rl
,
3602 "\"mutate\" reply \"count\" is %lld instead of 1",
3607 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
3608 rows
= shash_find_data(select
, "rows");
3609 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
3612 if (rows
->array
.n
!= 1) {
3613 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
3618 row
= rows
->array
.elems
[0];
3619 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
3622 column
= shash_find_data(json_object(row
), txn
->inc_column
);
3623 if (!check_json_type(column
, JSON_INTEGER
,
3624 "\"select\" reply inc column")) {
3627 txn
->inc_new_value
= column
->integer
;
3632 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
3633 const struct json_array
*results
)
3635 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
3636 struct ovsdb_error
*error
;
3637 struct json
*json_uuid
;
3638 union ovsdb_atom uuid
;
3639 struct shash
*reply
;
3641 if (insert
->op_index
>= results
->n
) {
3642 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
3643 "for insert (has %"PRIuSIZE
", needs %u)",
3644 results
->n
, insert
->op_index
);
3648 /* We know that this is a JSON object because the loop in
3649 * ovsdb_idl_txn_process_reply() checked. */
3650 reply
= json_object(results
->elems
[insert
->op_index
]);
3651 json_uuid
= shash_find_data(reply
, "uuid");
3652 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
3656 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
3658 char *s
= ovsdb_error_to_string_free(error
);
3659 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
3665 insert
->real
= uuid
.uuid
;
3671 ovsdb_idl_txn_process_reply(struct ovsdb_idl
*idl
,
3672 const struct jsonrpc_msg
*msg
)
3674 struct ovsdb_idl_txn
*txn
= ovsdb_idl_txn_find(idl
, msg
->id
);
3679 enum ovsdb_idl_txn_status status
;
3680 if (msg
->type
== JSONRPC_ERROR
) {
3682 && msg
->error
->type
== JSON_STRING
3683 && !strcmp(json_string(msg
->error
), "canceled")) {
3684 /* ovsdb-server uses this error message to indicate that the
3685 * transaction was canceled because the database in question was
3686 * removed, converted, etc. */
3687 status
= TXN_TRY_AGAIN
;
3690 ovsdb_idl_txn_set_error_json(txn
, msg
->error
);
3692 } else if (msg
->result
->type
!= JSON_ARRAY
) {
3693 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
3695 ovsdb_idl_txn_set_error_json(txn
, msg
->result
);
3697 struct json_array
*ops
= &msg
->result
->array
;
3698 int hard_errors
= 0;
3699 int soft_errors
= 0;
3700 int lock_errors
= 0;
3703 for (i
= 0; i
< ops
->n
; i
++) {
3704 struct json
*op
= ops
->elems
[i
];
3706 if (op
->type
== JSON_NULL
) {
3707 /* This isn't an error in itself but indicates that some prior
3708 * operation failed, so make sure that we know about it. */
3710 } else if (op
->type
== JSON_OBJECT
) {
3713 error
= shash_find_data(json_object(op
), "error");
3715 if (error
->type
== JSON_STRING
) {
3716 if (!strcmp(error
->string
, "timed out")) {
3718 } else if (!strcmp(error
->string
,
3719 "unknown database")) {
3720 ovsdb_cs_flag_inconsistency(idl
->cs
);
3722 } else if (!strcmp(error
->string
, "not owner")) {
3724 } else if (!strcmp(error
->string
, "not allowed")) {
3726 ovsdb_idl_txn_set_error_json(txn
, op
);
3727 } else if (strcmp(error
->string
, "aborted")) {
3729 ovsdb_idl_txn_set_error_json(txn
, op
);
3730 VLOG_WARN_RL(&other_rl
,
3731 "transaction error: %s", txn
->error
);
3735 ovsdb_idl_txn_set_error_json(txn
, op
);
3736 VLOG_WARN_RL(&syntax_rl
,
3737 "\"error\" in reply is not JSON string");
3742 ovsdb_idl_txn_set_error_json(txn
, op
);
3743 VLOG_WARN_RL(&syntax_rl
,
3744 "operation reply is not JSON null or object");
3748 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
3749 struct ovsdb_idl_txn_insert
*insert
;
3751 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
3755 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
3756 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
3762 status
= (hard_errors
? TXN_ERROR
3763 : lock_errors
? TXN_NOT_LOCKED
3764 : soft_errors
? TXN_TRY_AGAIN
3768 ovsdb_idl_txn_complete(txn
, status
);
3771 /* Returns the transaction currently active for 'row''s IDL. A transaction
3772 * must currently be active. */
3773 struct ovsdb_idl_txn
*
3774 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
3776 struct ovsdb_idl_txn
*txn
= row
->table
->idl
->txn
;
3777 ovs_assert(txn
!= NULL
);
3781 /* Returns the IDL on which 'txn' acts. */
3783 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
3788 /* Blocks until 'idl' successfully connects to the remote database and
3789 * retrieves its contents. */
3791 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
3795 if (ovsdb_idl_has_ever_connected(idl
)) {
3798 ovsdb_idl_wait(idl
);
3803 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
3804 * the database server and to avoid modifying the database when the lock cannot
3805 * be acquired (that is, when another client has the same lock).
3807 * If 'lock_name' is NULL, drops the locking requirement and releases the
3810 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
3812 ovsdb_cs_set_lock(idl
->cs
, lock_name
);
3815 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
3817 * Locking and unlocking happens asynchronously from the database client's
3818 * point of view, so the information is only useful for optimization (e.g. if
3819 * the client doesn't have the lock then there's no point in trying to write to
3822 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
3824 return ovsdb_cs_has_lock(idl
->cs
);
3827 /* Returns true if 'idl' is configured to obtain a lock but the database server
3828 * has indicated that some other client already owns the requested lock. */
3830 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
3832 return ovsdb_cs_is_lock_contended(idl
->cs
);
3835 /* Inserts a new Map Operation into current transaction. */
3837 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
3838 const struct ovsdb_idl_column
*column
,
3839 struct ovsdb_datum
*datum
,
3840 enum map_op_type op_type
)
3842 const struct ovsdb_idl_table_class
*class;
3844 struct map_op
*map_op
;
3846 class = row
->table
->class_
;
3847 column_idx
= column
- class->columns
;
3849 /* Check if a map operation list exists for this column. */
3850 if (!row
->map_op_written
) {
3851 row
->map_op_written
= bitmap_allocate(class->n_columns
);
3852 row
->map_op_lists
= xzalloc(class->n_columns
*
3853 sizeof *row
->map_op_lists
);
3855 if (!row
->map_op_lists
[column_idx
]) {
3856 row
->map_op_lists
[column_idx
] = map_op_list_create();
3859 /* Add a map operation to the corresponding list. */
3860 map_op
= map_op_create(datum
, op_type
);
3861 bitmap_set1(row
->map_op_written
, column_idx
);
3862 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
3864 /* Add this row to transaction's list of rows. */
3865 if (hmap_node_is_null(&row
->txn_node
)) {
3866 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3867 uuid_hash(&row
->uuid
));
3871 /* Inserts a new Set Operation into current transaction. */
3873 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
3874 const struct ovsdb_idl_column
*column
,
3875 struct ovsdb_datum
*datum
,
3876 enum set_op_type op_type
)
3878 const struct ovsdb_idl_table_class
*class;
3880 struct set_op
*set_op
;
3882 class = row
->table
->class_
;
3883 column_idx
= column
- class->columns
;
3885 /* Check if a set operation list exists for this column. */
3886 if (!row
->set_op_written
) {
3887 row
->set_op_written
= bitmap_allocate(class->n_columns
);
3888 row
->set_op_lists
= xzalloc(class->n_columns
*
3889 sizeof *row
->set_op_lists
);
3891 if (!row
->set_op_lists
[column_idx
]) {
3892 row
->set_op_lists
[column_idx
] = set_op_list_create();
3895 /* Add a set operation to the corresponding list. */
3896 set_op
= set_op_create(datum
, op_type
);
3897 bitmap_set1(row
->set_op_written
, column_idx
);
3898 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
3900 /* Add this row to the transactions's list of rows. */
3901 if (hmap_node_is_null(&row
->txn_node
)) {
3902 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3903 uuid_hash(&row
->uuid
));
3908 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
3909 const struct ovsdb_idl_column
*column
,
3910 struct ovsdb_datum
*datum
)
3912 /* Verify that this column is being monitored. */
3913 unsigned int column_idx
= column
- row
->table
->class_
->columns
;
3914 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
3915 VLOG_WARN("cannot partially update non-monitored column");
3919 /* Verify that the update affects a single element. */
3920 if (datum
->n
!= 1) {
3921 VLOG_WARN("invalid datum for partial update");
3928 /* Inserts the value described in 'datum' into the map in 'column' in
3929 * 'row_'. If the value doesn't already exist in 'column' then it's value
3930 * is added. The value in 'datum' must be of the same type as the values
3931 * in 'column'. This function takes ownership of 'datum'.
3933 * Usually this function is used indirectly through one of the "update"
3934 * functions generated by vswitch-idl. */
3936 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
3937 const struct ovsdb_idl_column
*column
,
3938 struct ovsdb_datum
*datum
)
3940 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3941 enum set_op_type op_type
;
3943 if (!is_valid_partial_update(row
, column
, datum
)) {
3944 ovsdb_datum_destroy(datum
, &column
->type
);
3949 op_type
= SET_OP_INSERT
;
3951 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
3954 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
3955 * The value in 'datum' must be of the same type as the keys in 'column'.
3956 * This function takes ownership of 'datum'.
3958 * Usually this function is used indirectly through one of the "update"
3959 * functions generated by vswitch-idl. */
3961 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
3962 const struct ovsdb_idl_column
*column
,
3963 struct ovsdb_datum
*datum
)
3965 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3967 if (!is_valid_partial_update(row
, column
, datum
)) {
3968 struct ovsdb_type type_
= column
->type
;
3969 type_
.value
.type
= OVSDB_TYPE_VOID
;
3970 ovsdb_datum_destroy(datum
, &type_
);
3974 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
3977 /* Inserts the key-value specified in 'datum' into the map in 'column' in
3978 * 'row_'. If the key already exist in 'column', then it's value is updated
3979 * with the value in 'datum'. The key-value in 'datum' must be of the same type
3980 * as the keys-values in 'column'. This function takes ownership of 'datum'.
3982 * Usually this function is used indirectly through one of the "update"
3983 * functions generated by vswitch-idl. */
3985 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
3986 const struct ovsdb_idl_column
*column
,
3987 struct ovsdb_datum
*datum
)
3989 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3990 enum ovsdb_atomic_type key_type
;
3991 enum map_op_type op_type
;
3993 const struct ovsdb_datum
*old_datum
;
3995 if (!is_valid_partial_update(row
, column
, datum
)) {
3996 ovsdb_datum_destroy(datum
, &column
->type
);
4001 /* Find out if this is an insert or an update. */
4002 key_type
= column
->type
.key
.type
;
4003 old_datum
= ovsdb_idl_read(row
, column
);
4004 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
4005 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
4007 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
4010 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
4011 * The key in 'datum' must be of the same type as the keys in 'column'.
4012 * The value in 'datum' must be NULL. This function takes ownership of
4015 * Usually this function is used indirectly through one of the "update"
4016 * functions generated by vswitch-idl. */
4018 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
4019 const struct ovsdb_idl_column
*column
,
4020 struct ovsdb_datum
*datum
)
4022 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4024 if (!is_valid_partial_update(row
, column
, datum
)) {
4025 struct ovsdb_type type_
= column
->type
;
4026 type_
.value
.type
= OVSDB_TYPE_VOID
;
4027 ovsdb_datum_destroy(datum
, &type_
);
4031 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
4035 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
4038 ovsdb_idl_destroy(loop
->idl
);
4042 struct ovsdb_idl_txn
*
4043 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
4045 ovsdb_idl_run(loop
->idl
);
4047 /* See if we can commit the loop->committing_txn. */
4048 if (loop
->committing_txn
) {
4049 ovsdb_idl_try_commit_loop_txn(loop
, NULL
);
4052 loop
->open_txn
= (loop
->committing_txn
4053 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
4055 : ovsdb_idl_txn_create(loop
->idl
));
4056 if (loop
->open_txn
) {
4057 ovsdb_idl_txn_add_comment(loop
->open_txn
, "%s", program_name
);
4059 return loop
->open_txn
;
4062 /* Attempts to commit the current transaction, if one is open.
4064 * If a transaction was open, in this or a previous iteration of the main loop,
4065 * and had not before finished committing (successfully or unsuccessfully), the
4066 * return value is one of:
4068 * 1: The transaction committed successfully (or it did not change anything in
4070 * 0: The transaction failed.
4071 * -1: The commit is still in progress.
4073 * Thus, the return value is -1 if the transaction is in progress and otherwise
4074 * true for success, false for failure.
4076 * (In the corner case where the IDL sends a transaction to the database and
4077 * the database commits it, and the connection between the IDL and the database
4078 * drops before the IDL receives the message confirming the commit, this
4079 * function can return 0 even though the transaction succeeded.)
4082 ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop
*loop
,
4083 bool *may_need_wakeup
)
4085 if (!loop
->committing_txn
) {
4086 /* Not a meaningful return value: no transaction was in progress. */
4091 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
4093 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
4094 if (status
!= TXN_INCOMPLETE
) {
4097 /* We want to re-evaluate the database when it's changed from
4098 * the contents that it had when we started the commit. (That
4099 * might have already happened.) */
4100 loop
->skip_seqno
= loop
->precommit_seqno
;
4101 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
4102 && may_need_wakeup
) {
4103 *may_need_wakeup
= true;
4109 /* Possibly some work on the database was deferred because no
4110 * further transaction could proceed. Wake up again. */
4112 loop
->cur_cfg
= loop
->next_cfg
;
4113 if (may_need_wakeup
) {
4114 *may_need_wakeup
= true;
4120 loop
->cur_cfg
= loop
->next_cfg
;
4124 case TXN_NOT_LOCKED
:
4129 case TXN_UNCOMMITTED
:
4130 case TXN_INCOMPLETE
:
4134 ovsdb_idl_txn_destroy(txn
);
4135 loop
->committing_txn
= NULL
;
4143 /* Attempts to commit the current transaction, if one is open, and sets up the
4144 * poll loop to wake up when some more work might be needed.
4146 * If a transaction was open, in this or a previous iteration of the main loop,
4147 * and had not before finished committing (successfully or unsuccessfully), the
4148 * return value is one of:
4150 * 1: The transaction committed successfully (or it did not change anything in
4152 * 0: The transaction failed.
4153 * -1: The commit is still in progress.
4155 * Thus, the return value is -1 if the transaction is in progress and otherwise
4156 * true for success, false for failure.
4158 * (In the corner case where the IDL sends a transaction to the database and
4159 * the database commits it, and the connection between the IDL and the database
4160 * drops before the IDL receives the message confirming the commit, this
4161 * function can return 0 even though the transaction succeeded.)
4164 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
4166 if (loop
->open_txn
) {
4167 loop
->committing_txn
= loop
->open_txn
;
4168 loop
->open_txn
= NULL
;
4170 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
4173 bool may_need_wakeup
= false;
4174 int retval
= ovsdb_idl_try_commit_loop_txn(loop
, &may_need_wakeup
);
4175 if (may_need_wakeup
) {
4176 poll_immediate_wake();
4178 ovsdb_idl_wait(loop
->idl
);