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"
35 #include "ovsdb-data.h"
36 #include "ovsdb-error.h"
37 #include "ovsdb-idl-provider.h"
38 #include "ovsdb-parser.h"
39 #include "ovsdb-server-idl.h"
40 #include "ovsdb-session.h"
41 #include "openvswitch/poll-loop.h"
42 #include "openvswitch/shash.h"
48 #include "openvswitch/vlog.h"
50 VLOG_DEFINE_THIS_MODULE(ovsdb_idl
);
52 COVERAGE_DEFINE(txn_uncommitted
);
53 COVERAGE_DEFINE(txn_unchanged
);
54 COVERAGE_DEFINE(txn_incomplete
);
55 COVERAGE_DEFINE(txn_aborted
);
56 COVERAGE_DEFINE(txn_success
);
57 COVERAGE_DEFINE(txn_try_again
);
58 COVERAGE_DEFINE(txn_not_locked
);
59 COVERAGE_DEFINE(txn_error
);
61 /* An arc from one idl_row to another. When row A contains a UUID that
62 * references row B, this is represented by an arc from A (the source) to B
65 * Arcs from a row to itself are omitted, that is, src and dst are always
68 * Arcs are never duplicated, that is, even if there are multiple references
69 * from A to B, there is only a single arc from A to B.
71 * Arcs are directed: an arc from A to B is the converse of an an arc from B to
72 * A. Both an arc and its converse may both be present, if each row refers
73 * to the other circularly.
75 * The source and destination row may be in the same table or in different
78 struct ovsdb_idl_arc
{
79 struct ovs_list src_node
; /* In src->src_arcs list. */
80 struct ovs_list dst_node
; /* In dst->dst_arcs list. */
81 struct ovsdb_idl_row
*src
; /* Source row. */
82 struct ovsdb_idl_row
*dst
; /* Destination row. */
85 /* Connection state machine.
87 * When a JSON-RPC session connects, the IDL sends a "monitor_cond" request for
88 * the Database table in the _Server database and transitions to the
89 * IDL_S_SERVER_MONITOR_COND_REQUESTED state. If the session drops and
90 * reconnects, or if the IDL receives a "monitor_canceled" notification for a
91 * table it is monitoring, the IDL starts over again in the same way. */
92 #define OVSDB_IDL_STATES \
93 /* Waits for "get_schema" reply, then sends "monitor_cond" \
94 * request for the Database table in the _Server database, whose \
95 * details are informed by the schema, and transitions to \
96 * IDL_S_SERVER_MONITOR_COND_REQUESTED. */ \
97 OVSDB_IDL_STATE(SERVER_SCHEMA_REQUESTED) \
99 /* Waits for "monitor_cond" reply for the Database table: \
101 * - If the reply indicates success, and the Database table has a \
102 * row for the IDL database: \
104 * * If the row indicates that this is a clustered database \
105 * that is not connected to the cluster, closes the \
106 * connection. The next connection attempt has a chance at \
107 * picking a connected server. \
109 * * Otherwise, sends a "monitor_cond_since" request for the IDL \
110 * database whose details are informed by the schema \
111 * (obtained from the row), and transitions to \
112 * IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED. \
114 * - If the reply indicates success, but the Database table does \
115 * not have a row for the IDL database, transitions to \
118 * - If the reply indicates failure, sends a "get_schema" request \
119 * for the IDL database and transitions to \
120 * IDL_S_DATA_SCHEMA_REQUESTED. */ \
121 OVSDB_IDL_STATE(SERVER_MONITOR_COND_REQUESTED) \
123 /* Waits for "get_schema" reply, then sends "monitor_cond" \
124 * request whose details are informed by the schema, and \
125 * transitions to IDL_S_DATA_MONITOR_COND_REQUESTED. */ \
126 OVSDB_IDL_STATE(DATA_SCHEMA_REQUESTED) \
128 /* Waits for "monitor_cond_since" reply. If successful, replaces \
129 * the IDL contents by the data carried in the reply and \
130 * transitions to IDL_S_MONITORING. On failure, sends a \
131 * "monitor_cond" request and transitions to \
132 * IDL_S_DATA_MONITOR_COND_REQUESTED. */ \
133 OVSDB_IDL_STATE(DATA_MONITOR_COND_SINCE_REQUESTED) \
135 /* Waits for "monitor_cond" reply. If successful, replaces the \
136 * IDL contents by the data carried in the reply and transitions \
137 * to IDL_S_MONITORING. On failure, sends a "monitor" request \
138 * and transitions to IDL_S_DATA_MONITOR_REQUESTED. */ \
139 OVSDB_IDL_STATE(DATA_MONITOR_COND_REQUESTED) \
141 /* Waits for "monitor" reply. If successful, replaces the IDL \
142 * contents by the data carried in the reply and transitions to \
143 * IDL_S_MONITORING. On failure, transitions to IDL_S_ERROR. */ \
144 OVSDB_IDL_STATE(DATA_MONITOR_REQUESTED) \
146 /* State that processes "update", "update2" or "update3" \
147 * notifications for the main database (and the Database table \
148 * in _Server if available). \
150 * If we're monitoring the Database table and we get notified \
151 * that the IDL database has been deleted, we close the \
152 * connection (which will restart the state machine). */ \
153 OVSDB_IDL_STATE(MONITORING) \
155 /* Terminal error state that indicates that nothing useful can be \
156 * done, for example because the database server doesn't actually \
157 * have the desired database. We maintain the session with the \
158 * database server anyway. If it starts serving the database \
159 * that we want, or if someone fixes and restarts the database, \
160 * then it will kill the session and we will automatically \
161 * reconnect and try again. */ \
162 OVSDB_IDL_STATE(ERROR) \
164 /* Terminal state that indicates we connected to a useless server \
165 * in a cluster, e.g. one that is partitioned from the rest of \
166 * the cluster. We're waiting to retry. */ \
167 OVSDB_IDL_STATE(RETRY)
169 enum ovsdb_idl_state
{
170 #define OVSDB_IDL_STATE(NAME) IDL_S_##NAME,
172 #undef OVSDB_IDL_STATE
175 static const char *ovsdb_idl_state_to_string(enum ovsdb_idl_state
);
177 enum ovsdb_idl_monitor_method
{
178 OVSDB_IDL_MM_MONITOR
,
179 OVSDB_IDL_MM_MONITOR_COND
,
180 OVSDB_IDL_MM_MONITOR_COND_SINCE
183 enum ovsdb_idl_monitoring
{
184 OVSDB_IDL_NOT_MONITORING
, /* Database is not being monitored. */
185 OVSDB_IDL_MONITORING
, /* Database has "monitor" outstanding. */
186 OVSDB_IDL_MONITORING_COND
, /* Database has "monitor_cond" outstanding. */
187 OVSDB_IDL_MONITORING_COND_SINCE
, /* Database has "monitor_cond_since"
191 struct ovsdb_idl_db
{
192 struct ovsdb_idl
*idl
;
195 const struct ovsdb_idl_class
*class_
;
196 struct shash table_by_name
; /* Contains "struct ovsdb_idl_table *"s.*/
197 struct ovsdb_idl_table
*tables
; /* Array of ->class_->n_tables elements. */
198 struct json
*monitor_id
;
199 unsigned int change_seqno
;
200 struct ovsdb_idl_txn
*txn
;
201 struct hmap outstanding_txns
;
202 bool verify_write_only
;
204 enum ovsdb_idl_monitoring monitoring
;
206 /* True if any of the tables' monitoring conditions has changed. */
209 unsigned int cond_seqno
; /* Keep track of condition clauses changes
210 over a single conditional monitoring session.
211 Reverts to zero when idl session
214 /* Database locking. */
215 char *lock_name
; /* Name of lock we need, NULL if none. */
216 bool has_lock
; /* Has db server told us we have the lock? */
217 bool is_lock_contended
; /* Has db server told us we can't get lock? */
218 struct json
*lock_request_id
; /* JSON-RPC ID of in-flight lock request. */
220 /* Last db txn id, used for fast resync through monitor_cond_since */
224 static void ovsdb_idl_db_track_clear(struct ovsdb_idl_db
*, bool flush_all
);
225 static void ovsdb_idl_db_add_column(struct ovsdb_idl_db
*,
226 const struct ovsdb_idl_column
*);
227 static void ovsdb_idl_db_omit(struct ovsdb_idl_db
*,
228 const struct ovsdb_idl_column
*);
229 static void ovsdb_idl_db_omit_alert(struct ovsdb_idl_db
*,
230 const struct ovsdb_idl_column
*);
231 static unsigned int ovsdb_idl_db_set_condition(
232 struct ovsdb_idl_db
*, const struct ovsdb_idl_table_class
*,
233 const struct ovsdb_idl_condition
*);
235 static void ovsdb_idl_send_schema_request(struct ovsdb_idl
*,
236 struct ovsdb_idl_db
*);
237 static void ovsdb_idl_send_db_change_aware(struct ovsdb_idl
*);
238 static bool ovsdb_idl_check_server_db(struct ovsdb_idl
*);
239 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl
*,
240 struct ovsdb_idl_db
*,
241 enum ovsdb_idl_monitor_method
);
242 static void ovsdb_idl_db_clear(struct ovsdb_idl_db
*db
);
243 static void ovsdb_idl_db_ack_condition(struct ovsdb_idl_db
*db
);
244 static void ovsdb_idl_db_sync_condition(struct ovsdb_idl_db
*db
);
245 static void ovsdb_idl_condition_move(struct ovsdb_idl_condition
**dst
,
246 struct ovsdb_idl_condition
**src
);
249 struct ovsdb_idl_db server
;
250 struct ovsdb_idl_db data
;
254 *'state_seqno' is a snapshot of the session's sequence number as returned
255 * jsonrpc_session_get_seqno(session), so if it differs from the value that
256 * function currently returns then the session has reconnected and the
257 * state machine must restart. */
258 struct jsonrpc_session
*session
; /* Connection to the server. */
259 char *remote
; /* 'session' remote name. */
260 enum ovsdb_idl_state state
; /* Current session state. */
261 unsigned int state_seqno
; /* See above. */
262 struct json
*request_id
; /* JSON ID for request awaiting reply. */
268 bool shuffle_remotes
;
271 static void ovsdb_idl_transition_at(struct ovsdb_idl
*, enum ovsdb_idl_state
,
273 #define ovsdb_idl_transition(IDL, STATE) \
274 ovsdb_idl_transition_at(IDL, STATE, OVS_SOURCE_LOCATOR)
276 static void ovsdb_idl_retry_at(struct ovsdb_idl
*, const char *where
);
277 #define ovsdb_idl_retry(IDL) ovsdb_idl_retry_at(IDL, OVS_SOURCE_LOCATOR)
279 struct ovsdb_idl_txn
{
280 struct hmap_node hmap_node
;
281 struct json
*request_id
;
282 struct ovsdb_idl_db
*db
;
283 struct hmap txn_rows
;
284 enum ovsdb_idl_txn_status status
;
290 const char *inc_table
;
291 const char *inc_column
;
294 unsigned int inc_index
;
295 int64_t inc_new_value
;
298 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
301 struct ovsdb_idl_txn_insert
{
302 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
303 struct uuid dummy
; /* Dummy UUID used locally. */
304 int op_index
; /* Index into transaction's operation array. */
305 struct uuid real
; /* Real UUID used by database server. */
308 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
309 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
310 static struct vlog_rate_limit other_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
312 static void ovsdb_idl_clear(struct ovsdb_idl
*);
313 static void ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db
*,
314 const struct json
*result
,
315 enum ovsdb_idl_monitor_method method
);
316 static bool ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db
*,
317 const struct jsonrpc_msg
*);
318 static bool ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl
*,
319 struct ovsdb_idl_db
*,
320 const struct jsonrpc_msg
*);
321 static void ovsdb_idl_db_parse_update(struct ovsdb_idl_db
*,
322 const struct json
*table_updates
,
323 enum ovsdb_idl_monitor_method method
);
325 OVSDB_IDL_UPDATE_DB_CHANGED
,
326 OVSDB_IDL_UPDATE_NO_CHANGES
,
327 OVSDB_IDL_UPDATE_INCONSISTENT
,
329 static enum update_result
ovsdb_idl_process_update(struct ovsdb_idl_table
*,
331 const struct json
*old
,
332 const struct json
*new);
333 static enum update_result
ovsdb_idl_process_update2(struct ovsdb_idl_table
*,
335 const char *operation
,
336 const struct json
*row
);
337 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*, const struct json
*);
338 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
339 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*, const struct json
*);
340 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*,
341 const struct json
*);
343 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
344 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
345 const struct ovsdb_idl_table_class
*);
346 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
347 const struct uuid
*);
348 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
349 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db
*);
350 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
351 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*);
353 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
354 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
355 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
356 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
357 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
359 static void ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db
*);
360 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
361 static bool ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db
*,
362 const struct jsonrpc_msg
*msg
);
363 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
365 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
366 const struct ovsdb_idl_column
*,
367 struct ovsdb_datum
*,
369 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*,
370 const struct ovsdb_idl_column
*,
371 struct ovsdb_datum
*,
374 static bool ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db
*,
375 const struct jsonrpc_msg
*);
376 static struct jsonrpc_msg
*ovsdb_idl_db_compose_lock_request(
377 struct ovsdb_idl_db
*);
378 static struct jsonrpc_msg
*ovsdb_idl_db_compose_unlock_request(
379 struct ovsdb_idl_db
*);
380 static void ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db
*,
381 const struct json
*);
382 static bool ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db
*,
383 const struct json
*params
,
385 static struct ovsdb_idl_table
*
386 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db
*,
387 const struct ovsdb_idl_table_class
*);
388 static struct ovsdb_idl_table
*
389 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
390 const struct ovsdb_idl_table_class
*);
391 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
392 static void ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
);
394 static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*);
395 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*);
396 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*);
397 static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop
*loop
,
398 bool *may_need_wakeup
);
401 ovsdb_idl_db_init(struct ovsdb_idl_db
*db
, const struct ovsdb_idl_class
*class,
402 struct ovsdb_idl
*parent
, bool monitor_everything_by_default
)
404 memset(db
, 0, sizeof *db
);
406 uint8_t default_mode
= (monitor_everything_by_default
407 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
412 shash_init(&db
->table_by_name
);
413 db
->tables
= xmalloc(class->n_tables
* sizeof *db
->tables
);
414 for (size_t i
= 0; i
< class->n_tables
; i
++) {
415 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
416 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
418 shash_add_assert(&db
->table_by_name
, tc
->name
, table
);
420 table
->modes
= xmalloc(tc
->n_columns
);
421 memset(table
->modes
, default_mode
, tc
->n_columns
);
422 table
->need_table
= false;
423 shash_init(&table
->columns
);
424 ovs_list_init(&table
->indexes
);
425 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
426 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
428 shash_add_assert(&table
->columns
, column
->name
, column
);
430 hmap_init(&table
->rows
);
431 ovs_list_init(&table
->track_list
);
432 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
433 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
434 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
436 table
->ack_cond
= NULL
;
437 table
->req_cond
= NULL
;
438 table
->new_cond
= xmalloc(sizeof *table
->new_cond
);
439 ovsdb_idl_condition_init(table
->new_cond
);
440 ovsdb_idl_condition_add_clause_true(table
->new_cond
);
442 db
->monitor_id
= json_array_create_2(json_string_create("monid"),
443 json_string_create(class->database
));
444 hmap_init(&db
->outstanding_txns
);
447 /* Creates and returns a connection to database 'remote', which should be in a
448 * form acceptable to jsonrpc_session_open(). The connection will maintain an
449 * in-memory replica of the remote database whose schema is described by
450 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
453 * Passes 'retry' to jsonrpc_session_open(). See that function for
456 * If 'monitor_everything_by_default' is true, then everything in the remote
457 * database will be replicated by default. ovsdb_idl_omit() and
458 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
461 * If 'monitor_everything_by_default' is false, then no columns or tables will
462 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
463 * must be used to choose some columns or tables to replicate.
466 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
467 bool monitor_everything_by_default
, bool retry
)
469 struct ovsdb_idl
*idl
= ovsdb_idl_create_unconnected(
470 class, monitor_everything_by_default
);
471 ovsdb_idl_set_remote(idl
, remote
, retry
);
475 /* Creates and returns a connection to an in-memory replica of the remote
476 * database whose schema is described by 'class'. (Ordinarily 'class' is
477 * compiled from an OVSDB schema automatically by ovsdb-idlc.)
479 * Use ovsdb_idl_set_remote() to configure the database to which to connect.
480 * Until a remote is configured, no data can be retrieved.
482 * If 'monitor_everything_by_default' is true, then everything in the remote
483 * database will be replicated by default. ovsdb_idl_omit() and
484 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
487 * If 'monitor_everything_by_default' is false, then no columns or tables will
488 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
489 * must be used to choose some columns or tables to replicate.
492 ovsdb_idl_create_unconnected(const struct ovsdb_idl_class
*class,
493 bool monitor_everything_by_default
)
495 struct ovsdb_idl
*idl
;
497 idl
= xzalloc(sizeof *idl
);
498 ovsdb_idl_db_init(&idl
->server
, &serverrec_idl_class
, idl
, true);
499 ovsdb_idl_db_init(&idl
->data
, class, idl
, monitor_everything_by_default
);
500 idl
->state_seqno
= UINT_MAX
;
501 idl
->request_id
= NULL
;
502 idl
->leader_only
= true;
503 idl
->shuffle_remotes
= true;
505 /* Monitor the Database table in the _Server database.
507 * We monitor only the row for 'class', or the row that has the
509 struct ovsdb_idl_condition cond
;
510 ovsdb_idl_condition_init(&cond
);
511 if (!uuid_is_zero(&idl
->cid
)) {
512 serverrec_database_add_clause_cid(&cond
, OVSDB_F_EQ
, &idl
->cid
, 1);
514 serverrec_database_add_clause_name(&cond
, OVSDB_F_EQ
, class->database
);
516 ovsdb_idl_db_set_condition(&idl
->server
, &serverrec_table_database
, &cond
);
517 ovsdb_idl_condition_destroy(&cond
);
522 /* Changes the remote and creates a new session.
524 * If 'retry' is true, the connection to the remote will automatically retry
525 * when it fails. If 'retry' is false, the connection is one-time. */
527 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
, bool retry
)
530 && ((remote
!= NULL
) != (idl
->remote
!= NULL
)
531 || (remote
&& idl
->remote
&& strcmp(remote
, idl
->remote
)))) {
532 ovs_assert(!idl
->data
.txn
);
534 /* Close the old session, if any. */
536 jsonrpc_session_close(idl
->session
);
543 /* Open new session, if any. */
545 struct svec remotes
= SVEC_EMPTY_INITIALIZER
;
546 ovsdb_session_parse_remote(remote
, &remotes
, &idl
->cid
);
547 if (idl
->shuffle_remotes
) {
548 svec_shuffle(&remotes
);
550 idl
->session
= jsonrpc_session_open_multiple(&remotes
, retry
);
551 svec_destroy(&remotes
);
553 idl
->state_seqno
= UINT_MAX
;
555 idl
->remote
= xstrdup(remote
);
560 /* Set whether the order of remotes should be shuffled, when there
561 * are more than one remotes. The setting doesn't take effect
562 * until the next time when ovsdb_idl_set_remote() is called. */
564 ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl
*idl
, bool shuffle
)
566 idl
->shuffle_remotes
= shuffle
;
569 /* Reset min_index to 0. This prevents a situation where the client
570 * thinks all databases have stale data, when they actually have all
571 * been destroyed and rebuilt from scratch.
574 ovsdb_idl_reset_min_index(struct ovsdb_idl
*idl
)
580 ovsdb_idl_db_destroy(struct ovsdb_idl_db
*db
)
582 struct ovsdb_idl_condition
*null_cond
= NULL
;
583 ovs_assert(!db
->txn
);
584 ovsdb_idl_db_txn_abort_all(db
);
585 ovsdb_idl_db_clear(db
);
586 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
587 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
588 ovsdb_idl_condition_move(&table
->ack_cond
, &null_cond
);
589 ovsdb_idl_condition_move(&table
->req_cond
, &null_cond
);
590 ovsdb_idl_condition_move(&table
->new_cond
, &null_cond
);
591 ovsdb_idl_destroy_indexes(table
);
592 shash_destroy(&table
->columns
);
593 hmap_destroy(&table
->rows
);
596 shash_destroy(&db
->table_by_name
);
598 json_destroy(db
->schema
);
599 hmap_destroy(&db
->outstanding_txns
);
601 json_destroy(db
->lock_request_id
);
602 json_destroy(db
->monitor_id
);
605 /* Destroys 'idl' and all of the data structures that it manages. */
607 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
610 ovsdb_idl_clear(idl
);
611 jsonrpc_session_close(idl
->session
);
612 ovsdb_idl_db_destroy(&idl
->server
);
613 ovsdb_idl_db_destroy(&idl
->data
);
614 json_destroy(idl
->request_id
);
620 /* By default, or if 'leader_only' is true, when 'idl' connects to a clustered
621 * database, the IDL will avoid servers other than the cluster leader. This
622 * ensures that any data that it reads and reports is up-to-date. If
623 * 'leader_only' is false, the IDL will accept any server in the cluster, which
624 * means that for read-only transactions it can report and act on stale data
625 * (transactions that modify the database are always serialized even with false
626 * 'leader_only'). Refer to Understanding Cluster Consistency in ovsdb(7) for
627 * more information. */
629 ovsdb_idl_set_leader_only(struct ovsdb_idl
*idl
, bool leader_only
)
631 idl
->leader_only
= leader_only
;
632 if (leader_only
&& idl
->server
.monitoring
) {
633 ovsdb_idl_check_server_db(idl
);
638 ovsdb_idl_db_clear(struct ovsdb_idl_db
*db
)
640 bool changed
= false;
643 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
644 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
645 struct ovsdb_idl_row
*row
, *next_row
;
647 if (hmap_is_empty(&table
->rows
)) {
652 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
653 struct ovsdb_idl_arc
*arc
, *next_arc
;
655 if (!ovsdb_idl_row_is_orphan(row
)) {
656 ovsdb_idl_remove_from_indexes(row
);
657 ovsdb_idl_row_unparse(row
);
659 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
662 /* No need to do anything with dst_arcs: some node has those arcs
663 * as forward arcs and will destroy them itself. */
665 ovsdb_idl_row_destroy(row
);
668 ovsdb_idl_row_destroy_postprocess(db
);
671 ovsdb_idl_db_track_clear(db
, true);
679 ovsdb_idl_state_to_string(enum ovsdb_idl_state state
)
682 #define OVSDB_IDL_STATE(NAME) case IDL_S_##NAME: return #NAME;
684 #undef OVSDB_IDL_STATE
685 default: return "<unknown>";
690 ovsdb_idl_retry_at(struct ovsdb_idl
*idl
, const char *where
)
692 ovsdb_idl_force_reconnect(idl
);
693 ovsdb_idl_transition_at(idl
, IDL_S_RETRY
, where
);
697 ovsdb_idl_transition_at(struct ovsdb_idl
*idl
, enum ovsdb_idl_state new_state
,
700 VLOG_DBG("%s: %s -> %s at %s",
701 idl
->session
? jsonrpc_session_get_name(idl
->session
) : "void",
702 ovsdb_idl_state_to_string(idl
->state
),
703 ovsdb_idl_state_to_string(new_state
),
705 idl
->state
= new_state
;
709 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
711 ovsdb_idl_db_clear(&idl
->data
);
715 ovsdb_idl_send_request(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*request
)
717 json_destroy(idl
->request_id
);
718 idl
->request_id
= json_clone(request
->id
);
720 jsonrpc_session_send(idl
->session
, request
);
722 jsonrpc_msg_destroy(request
);
727 ovsdb_idl_restart_fsm(struct ovsdb_idl
*idl
)
729 /* Resync data DB table conditions to avoid missing updates due to
730 * conditions that were in flight or changed locally while the connection
733 ovsdb_idl_db_sync_condition(&idl
->data
);
735 ovsdb_idl_send_schema_request(idl
, &idl
->server
);
736 ovsdb_idl_transition(idl
, IDL_S_SERVER_SCHEMA_REQUESTED
);
737 idl
->data
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
738 idl
->server
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
742 ovsdb_idl_process_response(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
744 bool ok
= msg
->type
== JSONRPC_REPLY
;
746 && idl
->state
!= IDL_S_SERVER_SCHEMA_REQUESTED
747 && idl
->state
!= IDL_S_SERVER_MONITOR_COND_REQUESTED
748 && idl
->state
!= IDL_S_DATA_MONITOR_COND_REQUESTED
749 && idl
->state
!= IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED
) {
750 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
751 char *s
= jsonrpc_msg_to_string(msg
);
752 VLOG_INFO_RL(&rl
, "%s: received unexpected %s response in "
753 "%s state: %s", jsonrpc_session_get_name(idl
->session
),
754 jsonrpc_msg_type_to_string(msg
->type
),
755 ovsdb_idl_state_to_string(idl
->state
),
758 ovsdb_idl_retry(idl
);
762 switch (idl
->state
) {
763 case IDL_S_SERVER_SCHEMA_REQUESTED
:
765 json_destroy(idl
->server
.schema
);
766 idl
->server
.schema
= json_clone(msg
->result
);
767 ovsdb_idl_send_monitor_request(idl
, &idl
->server
,
768 OVSDB_IDL_MM_MONITOR_COND
);
769 ovsdb_idl_transition(idl
, IDL_S_SERVER_MONITOR_COND_REQUESTED
);
771 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
772 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
776 case IDL_S_SERVER_MONITOR_COND_REQUESTED
:
778 idl
->server
.monitoring
= OVSDB_IDL_MONITORING_COND
;
779 ovsdb_idl_db_parse_monitor_reply(&idl
->server
, msg
->result
,
780 OVSDB_IDL_MM_MONITOR_COND
);
781 if (ovsdb_idl_check_server_db(idl
)) {
782 ovsdb_idl_send_db_change_aware(idl
);
785 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
786 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
790 case IDL_S_DATA_SCHEMA_REQUESTED
:
791 json_destroy(idl
->data
.schema
);
792 idl
->data
.schema
= json_clone(msg
->result
);
793 ovsdb_idl_send_monitor_request(idl
, &idl
->data
,
794 OVSDB_IDL_MM_MONITOR_COND
);
795 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
798 case IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED
:
800 /* "monitor_cond_since" not supported. Try "monitor_cond". */
801 ovsdb_idl_send_monitor_request(idl
, &idl
->data
,
802 OVSDB_IDL_MM_MONITOR_COND
);
803 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
805 idl
->data
.monitoring
= OVSDB_IDL_MONITORING_COND_SINCE
;
806 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
807 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
,
808 OVSDB_IDL_MM_MONITOR_COND_SINCE
);
812 case IDL_S_DATA_MONITOR_COND_REQUESTED
:
814 /* "monitor_cond" not supported. Try "monitor". */
815 ovsdb_idl_send_monitor_request(idl
, &idl
->data
,
816 OVSDB_IDL_MM_MONITOR
);
817 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_REQUESTED
);
819 idl
->data
.monitoring
= OVSDB_IDL_MONITORING_COND
;
820 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
821 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
,
822 OVSDB_IDL_MM_MONITOR_COND
);
826 case IDL_S_DATA_MONITOR_REQUESTED
:
827 idl
->data
.monitoring
= OVSDB_IDL_MONITORING
;
828 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
829 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
,
830 OVSDB_IDL_MM_MONITOR
);
831 idl
->data
.change_seqno
++;
834 case IDL_S_MONITORING
:
835 /* We don't normally have a request outstanding in this state. If we
836 * do, it's a "monitor_cond_change", which means that the conditional
837 * monitor clauses were updated.
839 * Mark the last requested conditions as acked and if further
840 * condition changes were pending, send them now. */
841 ovsdb_idl_db_ack_condition(&idl
->data
);
842 ovsdb_idl_send_cond_change(idl
);
843 idl
->data
.cond_seqno
++;
848 /* Nothing to do in this state. */
857 ovsdb_idl_process_msg(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
859 bool is_response
= (msg
->type
== JSONRPC_REPLY
||
860 msg
->type
== JSONRPC_ERROR
);
862 /* Process a reply to an outstanding request. */
864 && idl
->request_id
&& json_equal(idl
->request_id
, msg
->id
)) {
865 json_destroy(idl
->request_id
);
866 idl
->request_id
= NULL
;
867 ovsdb_idl_process_response(idl
, msg
);
871 /* Process database contents updates. */
872 if (ovsdb_idl_db_parse_update_rpc(&idl
->data
, msg
)) {
875 if (idl
->server
.monitoring
876 && ovsdb_idl_db_parse_update_rpc(&idl
->server
, msg
)) {
877 ovsdb_idl_check_server_db(idl
);
881 if (ovsdb_idl_handle_monitor_canceled(idl
, &idl
->data
, msg
)
882 || (idl
->server
.monitoring
883 && ovsdb_idl_handle_monitor_canceled(idl
, &idl
->server
, msg
))) {
887 /* Process "lock" replies and related notifications. */
888 if (ovsdb_idl_db_process_lock_replies(&idl
->data
, msg
)) {
892 /* Process response to a database transaction we submitted. */
893 if (is_response
&& ovsdb_idl_db_txn_process_reply(&idl
->data
, msg
)) {
897 /* Unknown message. Log at a low level because this can happen if
898 * ovsdb_idl_txn_destroy() is called to destroy a transaction
899 * before we receive the reply.
901 * (We could sort those out from other kinds of unknown messages by
902 * using distinctive IDs for transactions, if it seems valuable to
903 * do so, and then it would be possible to use different log
905 char *s
= jsonrpc_msg_to_string(msg
);
906 VLOG_DBG("%s: received unexpected %s message: %s",
907 jsonrpc_session_get_name(idl
->session
),
908 jsonrpc_msg_type_to_string(msg
->type
), s
);
912 /* Processes a batch of messages from the database server on 'idl'. This may
913 * cause the IDL's contents to change. The client may check for that with
914 * ovsdb_idl_get_seqno(). */
916 ovsdb_idl_run(struct ovsdb_idl
*idl
)
919 ovsdb_idl_txn_abort_all(idl
);
925 ovs_assert(!idl
->data
.txn
);
927 ovsdb_idl_send_cond_change(idl
);
929 jsonrpc_session_run(idl
->session
);
930 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
931 struct jsonrpc_msg
*msg
;
934 seqno
= jsonrpc_session_get_seqno(idl
->session
);
935 if (idl
->state_seqno
!= seqno
) {
936 idl
->state_seqno
= seqno
;
937 ovsdb_idl_txn_abort_all(idl
);
938 ovsdb_idl_restart_fsm(idl
);
940 if (idl
->data
.lock_name
) {
941 jsonrpc_session_send(
943 ovsdb_idl_db_compose_lock_request(&idl
->data
));
947 msg
= jsonrpc_session_recv(idl
->session
);
951 ovsdb_idl_process_msg(idl
, msg
);
952 jsonrpc_msg_destroy(msg
);
954 ovsdb_idl_row_destroy_postprocess(&idl
->data
);
957 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
958 * do or when activity occurs on a transaction on 'idl'. */
960 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
965 jsonrpc_session_wait(idl
->session
);
966 jsonrpc_session_recv_wait(idl
->session
);
969 /* Returns a "sequence number" that represents the state of 'idl'. When
970 * ovsdb_idl_run() changes the database, the sequence number changes. The
971 * initial fetch of the entire contents of the remote database is considered to
972 * be one kind of change. Successfully acquiring a lock, if one has been
973 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
975 * As long as the sequence number does not change, the client may continue to
976 * use any data structures it obtains from 'idl'. But when it changes, the
977 * client must not access any of these data structures again, because they
978 * could have freed or reused for other purposes.
980 * The sequence number can occasionally change even if the database does not.
981 * This happens if the connection to the database drops and reconnects, which
982 * causes the database contents to be reloaded even if they didn't change. (It
983 * could also happen if the database server sends out a "change" that reflects
984 * what the IDL already thought was in the database. The database server is
985 * not supposed to do that, but bugs could in theory cause it to do so.) */
987 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
989 return idl
->data
.change_seqno
;
992 /* Returns a "sequence number" that represents the number of conditional
993 * monitoring updates successfully received by the OVSDB server of an IDL
996 * ovsdb_idl_set_condition() sets a new condition that is different from
997 * the current condtion, the next expected "sequence number" is returned.
999 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
1000 * the return value of ovsdb_idl_set_condition(), The client is
1002 * - The ovsdb_idl_set_condition() changes has been acknowledged by
1005 * - 'idl' now contains the content matches the new conditions. */
1007 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl
*idl
)
1009 return idl
->data
.cond_seqno
;
1012 /* Returns true if 'idl' successfully connected to the remote database and
1013 * retrieved its contents (even if the connection subsequently dropped and is
1014 * in the process of reconnecting). If so, then 'idl' contains an atomic
1015 * snapshot of the database's contents (but it might be arbitrarily old if the
1016 * connection dropped).
1018 * Returns false if 'idl' has never connected or retrieved the database's
1019 * contents. If so, 'idl' is empty. */
1021 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
1023 return ovsdb_idl_get_seqno(idl
) != 0;
1026 /* Reconfigures 'idl' so that it would reconnect to the database, if
1027 * connection was dropped. */
1029 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
1032 jsonrpc_session_enable_reconnect(idl
->session
);
1036 /* Forces 'idl' to drop its connection to the database and reconnect. In the
1037 * meantime, the contents of 'idl' will not change. */
1039 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
1042 jsonrpc_session_force_reconnect(idl
->session
);
1046 /* Some IDL users should only write to write-only columns. Furthermore,
1047 * writing to a column which is not write-only can cause serious performance
1048 * degradations for these users. This function causes 'idl' to reject writes
1049 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
1051 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
1053 idl
->data
.verify_write_only
= true;
1056 /* Returns true if 'idl' is currently connected or trying to connect
1057 * and a negative response to a schema request has not been received */
1059 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
1061 return idl
->session
&& jsonrpc_session_is_alive(idl
->session
) &&
1062 idl
->state
!= IDL_S_ERROR
;
1066 ovsdb_idl_is_connected(const struct ovsdb_idl
*idl
)
1068 return idl
->session
&& jsonrpc_session_is_connected(idl
->session
);
1071 /* Returns the last error reported on a connection by 'idl'. The return value
1072 * is 0 only if no connection made by 'idl' has ever encountered an error and
1073 * a negative response to a schema request has never been received. See
1074 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
1075 * interpretation. */
1077 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
1079 int err
= idl
->session
? jsonrpc_session_get_last_error(idl
->session
) : 0;
1082 } else if (idl
->state
== IDL_S_ERROR
) {
1089 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
1093 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
1096 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
1101 find_uuid_in_array(const struct uuid
*target
,
1102 const struct uuid
*array
, size_t n
)
1104 for (size_t i
= 0; i
< n
; i
++) {
1105 if (uuid_equals(&array
[i
], target
)) {
1113 array_contains_uuid(const struct uuid
*target
,
1114 const struct uuid
*array
, size_t n
)
1116 return find_uuid_in_array(target
, array
, n
) != SIZE_MAX
;
1120 remove_uuid_from_array(const struct uuid
*target
,
1121 struct uuid
*array
, size_t *n
)
1123 size_t i
= find_uuid_in_array(target
, array
, *n
);
1124 if (i
!= SIZE_MAX
) {
1125 array
[i
] = array
[--*n
];
1133 add_row_references(const struct ovsdb_base_type
*type
,
1134 const union ovsdb_atom
*atoms
, size_t n_atoms
,
1135 const struct uuid
*exclude_uuid
,
1136 struct uuid
**dstsp
, size_t *n_dstsp
,
1137 size_t *allocated_dstsp
)
1139 if (type
->type
!= OVSDB_TYPE_UUID
|| !type
->uuid
.refTableName
) {
1143 for (size_t i
= 0; i
< n_atoms
; i
++) {
1144 const struct uuid
*uuid
= &atoms
[i
].uuid
;
1145 if (!uuid_equals(uuid
, exclude_uuid
)
1146 && !array_contains_uuid(uuid
, *dstsp
, *n_dstsp
)) {
1147 if (*n_dstsp
>= *allocated_dstsp
) {
1148 *dstsp
= x2nrealloc(*dstsp
, allocated_dstsp
,
1152 (*dstsp
)[*n_dstsp
] = *uuid
;
1158 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
1159 * reference from one row to a different row should be reflected as a "struct
1160 * ovsdb_idl_arc" between those rows.
1162 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
1163 * thus it is only for use in test programs. */
1165 ovsdb_idl_check_consistency(const struct ovsdb_idl
*idl
)
1167 /* Consistency is broken while a transaction is in progress. */
1168 if (!idl
->data
.txn
) {
1174 struct uuid
*dsts
= NULL
;
1175 size_t allocated_dsts
= 0;
1177 for (size_t i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1178 const struct ovsdb_idl_table
*table
= &idl
->data
.tables
[i
];
1179 const struct ovsdb_idl_table_class
*class = table
->class_
;
1181 const struct ovsdb_idl_row
*row
;
1182 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
1184 if (row
->new_datum
) {
1185 size_t n_columns
= shash_count(&row
->table
->columns
);
1186 for (size_t j
= 0; j
< n_columns
; j
++) {
1187 const struct ovsdb_type
*type
= &class->columns
[j
].type
;
1188 const struct ovsdb_datum
*datum
= &row
->new_datum
[j
];
1189 add_row_references(&type
->key
,
1190 datum
->keys
, datum
->n
, &row
->uuid
,
1191 &dsts
, &n_dsts
, &allocated_dsts
);
1192 add_row_references(&type
->value
,
1193 datum
->values
, datum
->n
, &row
->uuid
,
1194 &dsts
, &n_dsts
, &allocated_dsts
);
1197 const struct ovsdb_idl_arc
*arc
;
1198 LIST_FOR_EACH (arc
, src_node
, &row
->src_arcs
) {
1199 if (!remove_uuid_from_array(&arc
->dst
->uuid
,
1201 VLOG_ERR("unexpected arc from %s row "UUID_FMT
" to %s "
1203 table
->class_
->name
,
1204 UUID_ARGS(&row
->uuid
),
1205 arc
->dst
->table
->class_
->name
,
1206 UUID_ARGS(&arc
->dst
->uuid
));
1210 for (size_t j
= 0; j
< n_dsts
; j
++) {
1211 VLOG_ERR("%s row "UUID_FMT
" missing arc to row "UUID_FMT
,
1212 table
->class_
->name
, UUID_ARGS(&row
->uuid
),
1213 UUID_ARGS(&dsts
[j
]));
1222 const struct ovsdb_idl_class
*
1223 ovsdb_idl_get_class(const struct ovsdb_idl
*idl
)
1225 return idl
->data
.class_
;
1228 /* Given 'column' in some table in 'class', returns the table's class. */
1229 const struct ovsdb_idl_table_class
*
1230 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class
*class,
1231 const struct ovsdb_idl_column
*column
)
1233 for (size_t i
= 0; i
< class->n_tables
; i
++) {
1234 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
1235 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
1243 /* Given 'column' in some table in 'db', returns the table. */
1244 static struct ovsdb_idl_table
*
1245 ovsdb_idl_table_from_column(struct ovsdb_idl_db
*db
,
1246 const struct ovsdb_idl_column
*column
)
1248 const struct ovsdb_idl_table_class
*tc
=
1249 ovsdb_idl_table_class_from_column(db
->class_
, column
);
1250 return &db
->tables
[tc
- db
->class_
->tables
];
1253 static unsigned char *
1254 ovsdb_idl_db_get_mode(struct ovsdb_idl_db
*db
,
1255 const struct ovsdb_idl_column
*column
)
1257 ovs_assert(!db
->change_seqno
);
1259 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1261 return &table
->modes
[column
- table
->class_
->columns
];
1265 ovsdb_idl_db_set_mode(struct ovsdb_idl_db
*db
,
1266 const struct ovsdb_idl_column
*column
,
1269 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1271 size_t column_idx
= column
- table
->class_
->columns
;
1273 if (table
->modes
[column_idx
] != mode
) {
1274 *ovsdb_idl_db_get_mode(db
, column
) = mode
;
1279 add_ref_table(struct ovsdb_idl_db
*db
, const struct ovsdb_base_type
*base
)
1281 if (base
->type
== OVSDB_TYPE_UUID
&& base
->uuid
.refTableName
) {
1282 struct ovsdb_idl_table
*table
;
1284 table
= shash_find_data(&db
->table_by_name
, base
->uuid
.refTableName
);
1286 table
->need_table
= true;
1288 VLOG_WARN("%s IDL class missing referenced table %s",
1289 db
->class_
->database
, base
->uuid
.refTableName
);
1295 ovsdb_idl_db_add_column(struct ovsdb_idl_db
*db
,
1296 const struct ovsdb_idl_column
*column
)
1298 ovsdb_idl_db_set_mode(db
, column
, OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
);
1299 add_ref_table(db
, &column
->type
.key
);
1300 add_ref_table(db
, &column
->type
.value
);
1303 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
1304 * ensures that any tables referenced by 'column' will be replicated, even if
1305 * no columns in that table are selected for replication (see
1306 * ovsdb_idl_add_table() for more information).
1308 * This function is only useful if 'monitor_everything_by_default' was false in
1309 * the call to ovsdb_idl_create(). This function should be called between
1310 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1313 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
1314 const struct ovsdb_idl_column
*column
)
1316 ovsdb_idl_db_add_column(&idl
->data
, column
);
1320 ovsdb_idl_db_add_table(struct ovsdb_idl_db
*db
,
1321 const struct ovsdb_idl_table_class
*tc
)
1325 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1326 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1328 if (table
->class_
== tc
) {
1329 table
->need_table
= true;
1337 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
1338 * no columns are selected for replication. Just the necessary data for table
1339 * references will be replicated (the UUID of the rows, for instance), any
1340 * columns not selected for replication will remain unreplicated.
1341 * This can be useful because it allows 'idl' to keep track of what rows in the
1342 * table actually exist, which in turn allows columns that reference the table
1343 * to have accurate contents. (The IDL presents the database with references to
1344 * rows that do not exist removed.)
1346 * This function is only useful if 'monitor_everything_by_default' was false in
1347 * the call to ovsdb_idl_create(). This function should be called between
1348 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1351 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
1352 const struct ovsdb_idl_table_class
*tc
)
1354 ovsdb_idl_db_add_table(&idl
->data
, tc
);
1357 /* A single clause within an ovsdb_idl_condition. */
1358 struct ovsdb_idl_clause
{
1359 struct hmap_node hmap_node
; /* In struct ovsdb_idl_condition. */
1360 enum ovsdb_function function
; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
1361 const struct ovsdb_idl_column
*column
; /* Must be nonnull. */
1362 struct ovsdb_datum arg
; /* Has ovsdb_type ->column->type. */
1366 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause
*clause
)
1368 uint32_t hash
= hash_pointer(clause
->column
, clause
->function
);
1369 return ovsdb_datum_hash(&clause
->arg
, &clause
->column
->type
, hash
);
1373 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause
*a
,
1374 const struct ovsdb_idl_clause
*b
)
1376 return (a
->function
== b
->function
1377 && a
->column
== b
->column
1378 && ovsdb_datum_equals(&a
->arg
, &b
->arg
, &a
->column
->type
));
1381 static struct json
*
1382 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
1384 const char *function
= ovsdb_function_to_string(clause
->function
);
1385 return json_array_create_3(json_string_create(clause
->column
->name
),
1386 json_string_create(function
),
1387 ovsdb_datum_to_json(&clause
->arg
,
1388 &clause
->column
->type
));
1392 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause
*clause
)
1395 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
1400 /* ovsdb_idl_condition. */
1403 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
)
1405 hmap_init(&cnd
->clauses
);
1406 cnd
->is_true
= false;
1410 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition
*cond
)
1413 ovsdb_idl_condition_clear(cond
);
1414 hmap_destroy(&cond
->clauses
);
1419 ovsdb_idl_condition_clear(struct ovsdb_idl_condition
*cond
)
1421 struct ovsdb_idl_clause
*clause
, *next
;
1422 HMAP_FOR_EACH_SAFE (clause
, next
, hmap_node
, &cond
->clauses
) {
1423 hmap_remove(&cond
->clauses
, &clause
->hmap_node
);
1424 ovsdb_idl_clause_destroy(clause
);
1426 cond
->is_true
= false;
1430 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition
*condition
)
1432 return condition
->is_true
;
1435 static struct ovsdb_idl_clause
*
1436 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition
*condition
,
1437 const struct ovsdb_idl_clause
*target
,
1440 struct ovsdb_idl_clause
*clause
;
1441 HMAP_FOR_EACH_WITH_HASH (clause
, hmap_node
, hash
, &condition
->clauses
) {
1442 if (ovsdb_idl_clause_equals(clause
, target
)) {
1450 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition
*condition
,
1451 const struct ovsdb_idl_clause
*src
,
1454 struct ovsdb_idl_clause
*clause
= xmalloc(sizeof *clause
);
1455 clause
->function
= src
->function
;
1456 clause
->column
= src
->column
;
1457 ovsdb_datum_clone(&clause
->arg
, &src
->arg
, &src
->column
->type
);
1458 hmap_insert(&condition
->clauses
, &clause
->hmap_node
, hash
);
1461 /* Adds a clause to the condition for replicating the table with class 'tc' in
1464 * The IDL replicates only rows in a table that satisfy at least one clause in
1465 * the table's condition. The default condition for a table has a single
1466 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1467 * the table. When the IDL client replaces the default condition by one of its
1468 * own, the condition can have any number of clauses. If it has no conditions,
1469 * then no rows are replicated.
1471 * Two distinct of clauses can usefully be added:
1473 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1474 * replicated, regardless of whether other clauses exist. 'column' and
1475 * 'arg' are ignored.
1477 * - Binary 'functions' add a clause of the form "<column> <function>
1478 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1479 * have a type that is compatible with 'column'.
1482 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition
*condition
,
1483 enum ovsdb_function function
,
1484 const struct ovsdb_idl_column
*column
,
1485 const struct ovsdb_datum
*arg
)
1487 if (condition
->is_true
) {
1488 /* Adding a clause to an always-true condition has no effect. */
1489 } else if (function
== OVSDB_F_TRUE
) {
1490 ovsdb_idl_condition_add_clause_true(condition
);
1491 } else if (function
== OVSDB_F_FALSE
) {
1492 /* Adding a "false" clause never has any effect. */
1494 struct ovsdb_idl_clause clause
= {
1495 .function
= function
,
1499 uint32_t hash
= ovsdb_idl_clause_hash(&clause
);
1500 if (!ovsdb_idl_condition_find_clause(condition
, &clause
, hash
)) {
1501 ovsdb_idl_condition_add_clause__(condition
, &clause
, hash
);
1507 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition
*condition
)
1509 if (!condition
->is_true
) {
1510 ovsdb_idl_condition_clear(condition
);
1511 condition
->is_true
= true;
1516 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition
*a
,
1517 const struct ovsdb_idl_condition
*b
)
1519 if (hmap_count(&a
->clauses
) != hmap_count(&b
->clauses
)) {
1522 if (a
->is_true
!= b
->is_true
) {
1526 const struct ovsdb_idl_clause
*clause
;
1527 HMAP_FOR_EACH (clause
, hmap_node
, &a
->clauses
) {
1528 if (!ovsdb_idl_condition_find_clause(b
, clause
,
1529 clause
->hmap_node
.hash
)) {
1537 ovsdb_idl_condition_clone(struct ovsdb_idl_condition
**dst
,
1538 const struct ovsdb_idl_condition
*src
)
1541 ovsdb_idl_condition_destroy(*dst
);
1543 *dst
= xmalloc(sizeof **dst
);
1545 ovsdb_idl_condition_init(*dst
);
1547 (*dst
)->is_true
= src
->is_true
;
1549 const struct ovsdb_idl_clause
*clause
;
1550 HMAP_FOR_EACH (clause
, hmap_node
, &src
->clauses
) {
1551 ovsdb_idl_condition_add_clause__(*dst
, clause
, clause
->hmap_node
.hash
);
1556 ovsdb_idl_condition_move(struct ovsdb_idl_condition
**dst
,
1557 struct ovsdb_idl_condition
**src
)
1560 ovsdb_idl_condition_destroy(*dst
);
1568 ovsdb_idl_db_set_condition(struct ovsdb_idl_db
*db
,
1569 const struct ovsdb_idl_table_class
*tc
,
1570 const struct ovsdb_idl_condition
*condition
)
1572 struct ovsdb_idl_condition
*table_cond
;
1573 struct ovsdb_idl_table
*table
= ovsdb_idl_db_table_from_class(db
, tc
);
1574 unsigned int curr_seqno
= db
->cond_seqno
;
1576 /* Compare the new condition to the last known condition which can be
1577 * either "new" (not sent yet), "requested" or "acked", in this order.
1579 if (table
->new_cond
) {
1580 table_cond
= table
->new_cond
;
1581 } else if (table
->req_cond
) {
1582 table_cond
= table
->req_cond
;
1584 table_cond
= table
->ack_cond
;
1586 ovs_assert(table_cond
);
1588 if (!ovsdb_idl_condition_equals(condition
, table_cond
)) {
1589 ovsdb_idl_condition_clone(&table
->new_cond
, condition
);
1590 db
->cond_changed
= true;
1591 poll_immediate_wake();
1594 /* Conditions will be up to date when we receive replies for already
1595 * requested and new conditions, if any. */
1596 return curr_seqno
+ (table
->new_cond
? 1 : 0) + (table
->req_cond
? 1 : 0);
1599 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1600 * arranges to send the new condition to the database server.
1602 * Return the next conditional update sequence number. When this
1603 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1604 * contains rows that match the 'condition'. */
1606 ovsdb_idl_set_condition(struct ovsdb_idl
*idl
,
1607 const struct ovsdb_idl_table_class
*tc
,
1608 const struct ovsdb_idl_condition
*condition
)
1610 return ovsdb_idl_db_set_condition(&idl
->data
, tc
, condition
);
1613 static struct json
*
1614 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
1617 return json_array_create_empty();
1620 size_t n
= hmap_count(&cnd
->clauses
);
1622 return json_array_create_1(json_boolean_create(false));
1625 struct json
**clauses
= xmalloc(n
* sizeof *clauses
);
1626 const struct ovsdb_idl_clause
*clause
;
1628 HMAP_FOR_EACH (clause
, hmap_node
, &cnd
->clauses
) {
1629 clauses
[i
++] = ovsdb_idl_clause_to_json(clause
);
1632 return json_array_create(clauses
, n
);
1635 static struct json
*
1636 ovsdb_idl_create_cond_change_req(const struct ovsdb_idl_condition
*cond
)
1638 struct json
*monitor_cond_change_request
= json_object_create();
1639 struct json
*cond_json
= ovsdb_idl_condition_to_json(cond
);
1641 json_object_put(monitor_cond_change_request
, "where", cond_json
);
1643 return monitor_cond_change_request
;
1646 static struct jsonrpc_msg
*
1647 ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db
*db
)
1649 if (!db
->cond_changed
) {
1653 struct json
*monitor_cond_change_requests
= NULL
;
1654 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1655 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1657 /* Always use the most recent conditions set by the IDL client when
1658 * requesting monitor_cond_change, i.e., table->new_cond.
1660 if (table
->new_cond
) {
1662 ovsdb_idl_create_cond_change_req(table
->new_cond
);
1664 if (!monitor_cond_change_requests
) {
1665 monitor_cond_change_requests
= json_object_create();
1667 json_object_put(monitor_cond_change_requests
,
1668 table
->class_
->name
,
1669 json_array_create_1(req
));
1671 /* Mark the new condition as requested by moving it to req_cond.
1672 * If there's already requested condition that's a bug.
1674 ovs_assert(table
->req_cond
== NULL
);
1675 ovsdb_idl_condition_move(&table
->req_cond
, &table
->new_cond
);
1679 if (!monitor_cond_change_requests
) {
1683 db
->cond_changed
= false;
1684 struct json
*params
= json_array_create_3(json_clone(db
->monitor_id
),
1685 json_clone(db
->monitor_id
),
1686 monitor_cond_change_requests
);
1687 return jsonrpc_create_request("monitor_cond_change", params
, NULL
);
1690 /* Marks all requested table conditions in 'db' as acked by the server.
1691 * It should be called when the server replies to monitor_cond_change
1695 ovsdb_idl_db_ack_condition(struct ovsdb_idl_db
*db
)
1697 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1698 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1700 if (table
->req_cond
) {
1701 ovsdb_idl_condition_move(&table
->ack_cond
, &table
->req_cond
);
1706 /* Should be called when the IDL fsm is restarted and resyncs table conditions
1707 * based on the state the DB is in:
1708 * - if a non-zero last_id is available for the DB then upon reconnect
1709 * the IDL should first request acked conditions to avoid missing updates
1710 * about records that were added before the transaction with
1711 * txn-id == last_id. If there were requested condition changes in flight
1712 * (i.e., req_cond not NULL) and the IDL client didn't set new conditions
1713 * (i.e., new_cond is NULL) then move req_cond to new_cond to trigger a
1714 * follow up monitor_cond_change request.
1715 * - if there's no last_id available for the DB then it's safe to use the
1716 * latest conditions set by the IDL client even if they weren't acked yet.
1719 ovsdb_idl_db_sync_condition(struct ovsdb_idl_db
*db
)
1721 bool ack_all
= uuid_is_zero(&db
->last_id
);
1723 db
->cond_changed
= false;
1724 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1725 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1727 /* When monitor_cond_since requests will be issued, the
1728 * table->ack_cond condition will be added to the "where" clause".
1729 * Follow up monitor_cond_change requests will use table->new_cond.
1732 if (table
->new_cond
) {
1733 ovsdb_idl_condition_move(&table
->req_cond
, &table
->new_cond
);
1736 if (table
->req_cond
) {
1737 ovsdb_idl_condition_move(&table
->ack_cond
, &table
->req_cond
);
1740 /* If there was no "unsent" condition but instead a
1741 * monitor_cond_change request was in flight, move table->req_cond
1742 * to table->new_cond and set db->cond_changed to trigger a new
1743 * monitor_cond_change request.
1745 * However, if a new condition has been set by the IDL client,
1746 * monitor_cond_change will be sent anyway and will use the most
1747 * recent table->new_cond so there's no need to update it here.
1749 if (table
->req_cond
&& !table
->new_cond
) {
1750 ovsdb_idl_condition_move(&table
->new_cond
, &table
->req_cond
);
1751 db
->cond_changed
= true;
1758 ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
)
1760 /* When 'idl->request_id' is not NULL, there is an outstanding
1761 * conditional monitoring update request that we have not heard
1762 * from the server yet. Don't generate another request in this case. */
1763 if (!jsonrpc_session_is_connected(idl
->session
)
1764 || idl
->data
.monitoring
== OVSDB_IDL_MONITORING
1765 || idl
->request_id
) {
1769 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_cond_change(&idl
->data
);
1771 idl
->request_id
= json_clone(msg
->id
);
1772 jsonrpc_session_send(idl
->session
, msg
);
1776 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'db'.
1778 * This function should be called between ovsdb_idl_create() and the first call
1779 * to ovsdb_idl_run().
1782 ovsdb_idl_db_omit_alert(struct ovsdb_idl_db
*db
,
1783 const struct ovsdb_idl_column
*column
)
1785 *ovsdb_idl_db_get_mode(db
, column
) &= ~(OVSDB_IDL_ALERT
| OVSDB_IDL_TRACK
);
1788 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'idl'.
1790 * This function should be called between ovsdb_idl_create() and the first call
1791 * to ovsdb_idl_run().
1794 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
1795 const struct ovsdb_idl_column
*column
)
1797 ovsdb_idl_db_omit_alert(&idl
->data
, column
);
1801 ovsdb_idl_db_omit(struct ovsdb_idl_db
*db
,
1802 const struct ovsdb_idl_column
*column
)
1804 *ovsdb_idl_db_get_mode(db
, column
) = 0;
1807 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1808 * OVSDB_IDL_MONITOR for details.
1810 * This function should be called between ovsdb_idl_create() and the first call
1811 * to ovsdb_idl_run().
1814 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
1816 ovsdb_idl_db_omit(&idl
->data
, column
);
1819 /* Returns the most recent IDL change sequence number that caused a
1820 * insert, modify or delete update to the table with class 'table_class'.
1823 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
1824 const struct ovsdb_idl_table_class
*table_class
)
1826 struct ovsdb_idl_table
*table
1827 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1828 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
1830 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
1831 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
1833 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
1834 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
1839 /* For each row that contains tracked columns, IDL stores the most
1840 * recent IDL change sequence numbers associateed with insert, modify
1841 * and delete updates to the table.
1844 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
1845 enum ovsdb_idl_change change
)
1847 return row
->change_seqno
[change
];
1850 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1851 * all rows whose 'column' is modified are traced. Similarly, insert
1852 * or delete of rows having 'column' are tracked. Clients are able
1853 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1856 * This function should be called between ovsdb_idl_create() and
1857 * the first call to ovsdb_idl_run(). The column to be tracked
1858 * should have OVSDB_IDL_ALERT turned on.
1861 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1862 const struct ovsdb_idl_column
*column
)
1864 if (!(*ovsdb_idl_db_get_mode(&idl
->data
, column
) & OVSDB_IDL_ALERT
)) {
1865 ovsdb_idl_add_column(idl
, column
);
1867 *ovsdb_idl_db_get_mode(&idl
->data
, column
) |= OVSDB_IDL_TRACK
;
1871 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1875 for (i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1876 const struct ovsdb_idl_table_class
*tc
= &idl
->data
.class_
->tables
[i
];
1878 for (j
= 0; j
< tc
->n_columns
; j
++) {
1879 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1880 ovsdb_idl_track_add_column(idl
, column
);
1885 /* Returns true if 'table' has any tracked column. */
1887 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1891 for (i
= 0; i
< table
->class_
->n_columns
; i
++) {
1892 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1899 /* Returns the first tracked row in table with class 'table_class'
1900 * for the specified 'idl'. Returns NULL if there are no tracked rows.
1901 * Pure orphan rows, i.e. rows that never had any datum, are skipped. */
1902 const struct ovsdb_idl_row
*
1903 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1904 const struct ovsdb_idl_table_class
*table_class
)
1906 struct ovsdb_idl_table
*table
1907 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1908 struct ovsdb_idl_row
*row
;
1910 LIST_FOR_EACH (row
, track_node
, &table
->track_list
) {
1911 if (!ovsdb_idl_row_is_orphan(row
) || row
->tracked_old_datum
) {
1918 /* Returns the next tracked row in table after the specified 'row'
1919 * (in no particular order). Returns NULL if there are no tracked rows.
1920 * Pure orphan rows, i.e. rows that never had any datum, are skipped.*/
1921 const struct ovsdb_idl_row
*
1922 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1924 struct ovsdb_idl_table
*table
= row
->table
;
1926 LIST_FOR_EACH_CONTINUE (row
, track_node
, &table
->track_list
) {
1927 if (!ovsdb_idl_row_is_orphan(row
) || row
->tracked_old_datum
) {
1934 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1935 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1937 * Function returns false if 'column' is not tracked (see
1938 * ovsdb_idl_track_add_column()).
1941 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1942 const struct ovsdb_idl_column
*column
)
1944 const struct ovsdb_idl_table_class
*class;
1947 class = row
->table
->class_
;
1948 column_idx
= column
- class->columns
;
1950 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1957 /* Flushes the tracked rows. Client calls this function after calling
1958 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1959 * functions. This is usually done at the end of the client's processing
1960 * loop when it is ready to do ovsdb_idl_run() again.
1963 ovsdb_idl_db_track_clear(struct ovsdb_idl_db
*db
, bool flush_all
)
1967 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1968 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1970 if (!ovs_list_is_empty(&table
->track_list
)) {
1971 struct ovsdb_idl_row
*row
, *next
;
1973 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1976 row
->updated
= NULL
;
1979 row
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
] =
1980 row
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
] =
1981 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
1983 ovs_list_remove(&row
->track_node
);
1984 ovs_list_init(&row
->track_node
);
1985 if (ovsdb_idl_row_is_orphan(row
)) {
1986 ovsdb_idl_row_unparse(row
);
1987 if (row
->tracked_old_datum
) {
1988 const struct ovsdb_idl_table_class
*class =
1990 for (size_t c
= 0; c
< class->n_columns
; c
++) {
1991 ovsdb_datum_destroy(&row
->tracked_old_datum
[c
],
1992 &class->columns
[c
].type
);
1994 free(row
->tracked_old_datum
);
1995 row
->tracked_old_datum
= NULL
;
1998 /* Rows that were reused as orphan after being processed
1999 * for deletion are still in the table hmap and will be
2000 * cleaned up when their src arcs are removed. These rows
2001 * will not be reported anymore as "deleted" to IDL
2004 * The exception is when 'destroy' is explicitly set to
2005 * 'true' which usually happens when the complete IDL
2006 * contents are being flushed.
2008 if (flush_all
|| ovs_list_is_empty(&row
->dst_arcs
)) {
2017 /* Flushes the tracked rows. Client calls this function after calling
2018 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
2019 * functions. This is usually done at the end of the client's processing
2020 * loop when it is ready to do ovsdb_idl_run() again.
2023 ovsdb_idl_track_clear(struct ovsdb_idl
*idl
)
2025 ovsdb_idl_db_track_clear(&idl
->data
, false);
2029 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
,
2030 struct ovsdb_idl_db
*db
)
2032 ovsdb_idl_send_request(idl
, jsonrpc_create_request(
2034 json_array_create_1(json_string_create(
2035 db
->class_
->database
)),
2040 ovsdb_idl_send_db_change_aware(struct ovsdb_idl
*idl
)
2042 struct jsonrpc_msg
*msg
= jsonrpc_create_request(
2043 "set_db_change_aware", json_array_create_1(json_boolean_create(true)),
2045 jsonrpc_session_send(idl
->session
, msg
);
2049 ovsdb_idl_check_server_db(struct ovsdb_idl
*idl
)
2051 const struct serverrec_database
*database
;
2052 SERVERREC_DATABASE_FOR_EACH (database
, idl
) {
2053 if (uuid_is_zero(&idl
->cid
)
2054 ? !strcmp(database
->name
, idl
->data
.class_
->database
)
2055 : database
->n_cid
&& uuid_equals(database
->cid
, &idl
->cid
)) {
2060 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
2061 const char *server_name
= jsonrpc_session_get_name(idl
->session
);
2064 VLOG_INFO_RL(&rl
, "%s: server does not have %s database",
2065 server_name
, idl
->data
.class_
->database
);
2066 } else if (!strcmp(database
->model
, "clustered")) {
2067 uint64_t index
= database
->n_index
? *database
->index
: 0;
2069 if (!database
->schema
) {
2070 VLOG_INFO("%s: clustered database server has not yet joined "
2071 "cluster; trying another server", server_name
);
2072 } else if (!database
->connected
) {
2073 VLOG_INFO("%s: clustered database server is disconnected "
2074 "from cluster; trying another server", server_name
);
2075 } else if (idl
->leader_only
&& !database
->leader
) {
2076 VLOG_INFO("%s: clustered database server is not cluster "
2077 "leader; trying another server", server_name
);
2078 } else if (index
< idl
->min_index
) {
2079 VLOG_WARN("%s: clustered database server has stale data; "
2080 "trying another server", server_name
);
2082 idl
->min_index
= index
;
2089 ovsdb_idl_retry(idl
);
2093 if (idl
->state
== IDL_S_SERVER_MONITOR_COND_REQUESTED
) {
2094 json_destroy(idl
->data
.schema
);
2095 idl
->data
.schema
= json_from_string(database
->schema
);
2096 ovsdb_idl_send_monitor_request(idl
, &idl
->data
,
2097 OVSDB_IDL_MM_MONITOR_COND_SINCE
);
2098 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED
);
2104 log_error(struct ovsdb_error
*error
)
2106 char *s
= ovsdb_error_to_string_free(error
);
2107 VLOG_WARN("error parsing database schema: %s", s
);
2111 /* Frees 'schema', which is in the format returned by parse_schema(). */
2113 free_schema(struct shash
*schema
)
2116 struct shash_node
*node
, *next
;
2118 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
2119 struct sset
*sset
= node
->data
;
2122 shash_delete(schema
, node
);
2124 shash_destroy(schema
);
2129 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
2130 * 7047, to obtain the names of its rows and columns. If successful, returns
2131 * an shash whose keys are table names and whose values are ssets, where each
2132 * sset contains the names of its table's columns. On failure (due to a parse
2133 * error), returns NULL.
2135 * It would also be possible to use the general-purpose OVSDB schema parser in
2136 * ovsdb-server, but that's overkill, possibly too strict for the current use
2137 * case, and would require restructuring ovsdb-server to separate the schema
2138 * code from the rest. */
2139 static struct shash
*
2140 parse_schema(const struct json
*schema_json
)
2142 struct ovsdb_parser parser
;
2143 const struct json
*tables_json
;
2144 struct ovsdb_error
*error
;
2145 struct shash_node
*node
;
2146 struct shash
*schema
;
2148 ovsdb_parser_init(&parser
, schema_json
, "database schema");
2149 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
2150 error
= ovsdb_parser_destroy(&parser
);
2156 schema
= xmalloc(sizeof *schema
);
2158 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
2159 const char *table_name
= node
->name
;
2160 const struct json
*json
= node
->data
;
2161 const struct json
*columns_json
;
2163 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
2165 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
2166 error
= ovsdb_parser_destroy(&parser
);
2169 free_schema(schema
);
2173 struct sset
*columns
= xmalloc(sizeof *columns
);
2176 struct shash_node
*node2
;
2177 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
2178 const char *column_name
= node2
->name
;
2179 sset_add(columns
, column_name
);
2181 shash_add(schema
, table_name
, columns
);
2187 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
, struct ovsdb_idl_db
*db
,
2188 enum ovsdb_idl_monitor_method monitor_method
)
2190 struct shash
*schema
= parse_schema(db
->schema
);
2191 struct json
*monitor_requests
= json_object_create();
2193 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
2194 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
2195 const struct ovsdb_idl_table_class
*tc
= table
->class_
;
2196 struct json
*monitor_request
;
2197 const struct sset
*table_schema
2198 = schema
? shash_find_data(schema
, table
->class_
->name
) : NULL
;
2200 struct json
*columns
2201 = table
->need_table
? json_array_create_empty() : NULL
;
2202 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
2203 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
2204 bool db_has_column
= (table_schema
&&
2205 sset_contains(table_schema
, column
->name
));
2206 if (column
->is_synthetic
) {
2207 if (db_has_column
) {
2208 VLOG_WARN("%s table in %s database has synthetic "
2209 "column %s", table
->class_
->name
,
2210 db
->class_
->database
, column
->name
);
2212 } else if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
2213 if (table_schema
&& !db_has_column
) {
2214 VLOG_WARN("%s table in %s database lacks %s column "
2215 "(database needs upgrade?)",
2216 table
->class_
->name
, db
->class_
->database
,
2221 columns
= json_array_create_empty();
2223 json_array_add(columns
, json_string_create(column
->name
));
2228 if (schema
&& !table_schema
) {
2229 VLOG_WARN("%s database lacks %s table "
2230 "(database needs upgrade?)",
2231 db
->class_
->database
, table
->class_
->name
);
2232 json_destroy(columns
);
2236 monitor_request
= json_object_create();
2237 json_object_put(monitor_request
, "columns", columns
);
2239 /* Always use acked conditions when requesting
2240 * monitor_cond/monitor_cond_since.
2242 const struct ovsdb_idl_condition
*cond
= table
->ack_cond
;
2243 if ((monitor_method
== OVSDB_IDL_MM_MONITOR_COND
||
2244 monitor_method
== OVSDB_IDL_MM_MONITOR_COND_SINCE
) &&
2245 cond
&& !ovsdb_idl_condition_is_true(cond
)) {
2246 json_object_put(monitor_request
, "where",
2247 ovsdb_idl_condition_to_json(cond
));
2249 json_object_put(monitor_requests
, tc
->name
,
2250 json_array_create_1(monitor_request
));
2253 free_schema(schema
);
2255 struct json
*params
= json_array_create_3(
2256 json_string_create(db
->class_
->database
),
2257 json_clone(db
->monitor_id
),
2260 switch (monitor_method
) {
2261 case OVSDB_IDL_MM_MONITOR
:
2264 case OVSDB_IDL_MM_MONITOR_COND
:
2265 method
= "monitor_cond";
2267 case OVSDB_IDL_MM_MONITOR_COND_SINCE
:
2268 method
= "monitor_cond_since";
2269 struct json
*json_last_id
= json_string_create_nocopy(
2270 xasprintf(UUID_FMT
, UUID_ARGS(&db
->last_id
)));
2271 json_array_add(params
, json_last_id
);
2277 ovsdb_idl_send_request(idl
, jsonrpc_create_request(method
, params
, NULL
));
2281 log_parse_update_error(struct ovsdb_error
*error
)
2283 if (!VLOG_DROP_WARN(&syntax_rl
)) {
2284 char *s
= ovsdb_error_to_string(error
);
2285 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
2288 ovsdb_error_destroy(error
);
2292 ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db
*db
,
2293 const struct json
*result
,
2294 enum ovsdb_idl_monitor_method method
)
2297 const struct json
*table_updates
= result
;
2298 bool clear_db
= true;
2299 if (method
== OVSDB_IDL_MM_MONITOR_COND_SINCE
) {
2300 if (result
->type
!= JSON_ARRAY
|| result
->array
.n
!= 3) {
2301 struct ovsdb_error
*error
= ovsdb_syntax_error(result
, NULL
,
2302 "Response of monitor_cond_since must "
2303 "be an array with 3 elements.");
2304 log_parse_update_error(error
);
2308 bool found
= json_boolean(result
->array
.elems
[0]);
2313 const char *last_id
= json_string(result
->array
.elems
[1]);
2314 if (!uuid_from_string(&db
->last_id
, last_id
)) {
2315 struct ovsdb_error
*error
= ovsdb_syntax_error(result
, NULL
,
2316 "Last-id %s is not in UUID format.",
2318 log_parse_update_error(error
);
2322 table_updates
= result
->array
.elems
[2];
2325 ovsdb_idl_db_clear(db
);
2327 ovsdb_idl_db_parse_update(db
, table_updates
, method
);
2331 ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db
*db
,
2332 const struct jsonrpc_msg
*msg
)
2334 if (msg
->type
!= JSONRPC_NOTIFY
) {
2338 enum ovsdb_idl_monitor_method mm
;
2340 if (!strcmp(msg
->method
, "update")) {
2341 mm
= OVSDB_IDL_MM_MONITOR
;
2343 } else if (!strcmp(msg
->method
, "update2")) {
2344 mm
= OVSDB_IDL_MM_MONITOR_COND
;
2346 } else if (!strcmp(msg
->method
, "update3")) {
2347 mm
= OVSDB_IDL_MM_MONITOR_COND_SINCE
;
2353 struct json
*params
= msg
->params
;
2354 if (params
->type
!= JSON_ARRAY
|| params
->array
.n
!= n
) {
2355 struct ovsdb_error
*error
= ovsdb_syntax_error(params
, NULL
,
2356 "%s must be an array with %u elements.",
2358 log_parse_update_error(error
);
2362 if (!json_equal(params
->array
.elems
[0], db
->monitor_id
)) {
2366 struct json
*table_updates
= params
->array
.elems
[1];
2367 if (!strcmp(msg
->method
, "update3")) {
2368 table_updates
= params
->array
.elems
[2];
2369 const char *last_id
= json_string(params
->array
.elems
[1]);
2370 if (!uuid_from_string(&db
->last_id
, last_id
)) {
2371 struct ovsdb_error
*error
= ovsdb_syntax_error(params
, NULL
,
2372 "Last-id %s is not in UUID format.",
2374 log_parse_update_error(error
);
2378 ovsdb_idl_db_parse_update(db
, table_updates
, mm
);
2383 ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl
*idl
,
2384 struct ovsdb_idl_db
*db
,
2385 const struct jsonrpc_msg
*msg
)
2387 if (msg
->type
!= JSONRPC_NOTIFY
2388 || strcmp(msg
->method
, "monitor_canceled")
2389 || msg
->params
->type
!= JSON_ARRAY
2390 || msg
->params
->array
.n
!= 1
2391 || !json_equal(msg
->params
->array
.elems
[0], db
->monitor_id
)) {
2395 db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2397 /* Cancel the other monitor and restart the FSM from the top.
2399 * Maybe a more sophisticated response would be better in some cases, but
2400 * it doesn't seem worth optimizing yet. (Although this is already more
2401 * sophisticated than just dropping the connection and reconnecting.) */
2402 struct ovsdb_idl_db
*other_db
2403 = db
== &idl
->data
? &idl
->server
: &idl
->data
;
2404 if (other_db
->monitoring
) {
2405 jsonrpc_session_send(
2407 jsonrpc_create_request(
2409 json_array_create_1(json_clone(other_db
->monitor_id
)), NULL
));
2410 other_db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2412 ovsdb_idl_restart_fsm(idl
);
2417 static struct ovsdb_error
*
2418 ovsdb_idl_db_parse_update__(struct ovsdb_idl_db
*db
,
2419 const struct json
*table_updates
,
2420 enum ovsdb_idl_monitor_method method
)
2422 const struct shash_node
*tables_node
;
2423 const char *version_suffix
;
2425 case OVSDB_IDL_MM_MONITOR
:
2426 version_suffix
= "";
2428 case OVSDB_IDL_MM_MONITOR_COND
:
2429 case OVSDB_IDL_MM_MONITOR_COND_SINCE
:
2430 version_suffix
= "2";
2436 if (table_updates
->type
!= JSON_OBJECT
) {
2437 return ovsdb_syntax_error(table_updates
, NULL
,
2438 "<table_updates%s> is not an object",
2442 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
2443 const struct json
*table_update
= tables_node
->data
;
2444 const struct shash_node
*table_node
;
2445 struct ovsdb_idl_table
*table
;
2447 table
= shash_find_data(&db
->table_by_name
, tables_node
->name
);
2449 return ovsdb_syntax_error(
2450 table_updates
, NULL
,
2451 "<table_updates%s> includes unknown table \"%s\"",
2452 version_suffix
, tables_node
->name
);
2455 if (table_update
->type
!= JSON_OBJECT
) {
2456 return ovsdb_syntax_error(table_update
, NULL
,
2457 "<table_update%s> for table \"%s\" is "
2459 version_suffix
, table
->class_
->name
);
2461 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
2462 enum update_result result
= OVSDB_IDL_UPDATE_NO_CHANGES
;
2463 const struct json
*row_update
= table_node
->data
;
2466 if (!uuid_from_string(&uuid
, table_node
->name
)) {
2467 return ovsdb_syntax_error(table_update
, NULL
,
2468 "<table_update%s> for table \"%s\" "
2469 "contains bad UUID "
2470 "\"%s\" as member name",
2472 table
->class_
->name
,
2475 if (row_update
->type
!= JSON_OBJECT
) {
2476 return ovsdb_syntax_error(row_update
, NULL
,
2477 "<table_update%s> for table \"%s\" "
2478 "contains <row_update%s> for %s "
2479 "that is not an object",
2480 version_suffix
, table
->class_
->name
,
2481 version_suffix
, table_node
->name
);
2484 if (method
== OVSDB_IDL_MM_MONITOR_COND
||
2485 method
== OVSDB_IDL_MM_MONITOR_COND_SINCE
) {
2486 const char *ops
[] = {"modify", "insert", "delete", "initial"};
2487 const char *operation
;
2488 const struct json
*row
;
2491 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
2493 row
= shash_find_data(json_object(row_update
), operation
);
2499 result
= ovsdb_idl_process_update2(table
, &uuid
,
2504 /* row_update2 should contain one of the objects */
2505 if (i
== ARRAY_SIZE(ops
)) {
2506 return ovsdb_syntax_error(row_update
, NULL
,
2507 "<row_update2> includes unknown "
2511 const struct json
*old_json
, *new_json
;
2513 old_json
= shash_find_data(json_object(row_update
), "old");
2514 new_json
= shash_find_data(json_object(row_update
), "new");
2515 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
2516 return ovsdb_syntax_error(old_json
, NULL
,
2517 "\"old\" <row> is not object");
2518 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
2519 return ovsdb_syntax_error(new_json
, NULL
,
2520 "\"new\" <row> is not object");
2521 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
2522 != shash_count(json_object(row_update
))) {
2523 return ovsdb_syntax_error(row_update
, NULL
,
2524 "<row-update> contains "
2525 "unexpected member");
2526 } else if (!old_json
&& !new_json
) {
2527 return ovsdb_syntax_error(row_update
, NULL
,
2528 "<row-update> missing \"old\" "
2529 "and \"new\" members");
2532 result
= ovsdb_idl_process_update(table
, &uuid
, old_json
,
2537 case OVSDB_IDL_UPDATE_DB_CHANGED
:
2540 case OVSDB_IDL_UPDATE_NO_CHANGES
:
2542 case OVSDB_IDL_UPDATE_INCONSISTENT
:
2543 memset(&db
->last_id
, 0, sizeof db
->last_id
);
2544 ovsdb_idl_retry(db
->idl
);
2545 return ovsdb_error(NULL
,
2546 "<row_update%s> received for inconsistent "
2547 "IDL: reconnecting IDL and resync all "
2558 ovsdb_idl_db_parse_update(struct ovsdb_idl_db
*db
,
2559 const struct json
*table_updates
,
2560 enum ovsdb_idl_monitor_method method
)
2562 struct ovsdb_error
*error
= ovsdb_idl_db_parse_update__(db
, table_updates
,
2565 log_parse_update_error(error
);
2569 static struct ovsdb_idl_row
*
2570 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2572 struct ovsdb_idl_row
*row
;
2574 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
2575 if (uuid_equals(&row
->uuid
, uuid
)) {
2582 /* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
2583 * OVSDB_IDL_MODE_RW changed.
2585 * Some IDL inconsistencies can be detected when processing updates:
2586 * - trying to insert an already existing row
2587 * - trying to update a missing row
2588 * - trying to delete a non existent row
2590 * In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
2591 * Even though the IDL client could recover, it's best to report the
2592 * inconsistent state because the state the server is in is unknown so the
2593 * safest thing to do is to retry (potentially connecting to a new server).
2595 * Returns OVSDB_IDL_UPDATE_NO_CHANGES otherwise.
2597 static enum update_result
2598 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
2599 const struct uuid
*uuid
, const struct json
*old
,
2600 const struct json
*new)
2602 struct ovsdb_idl_row
*row
;
2604 row
= ovsdb_idl_get_row(table
, uuid
);
2607 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2608 /* XXX perhaps we should check the 'old' values? */
2609 ovsdb_idl_delete_row(row
);
2611 VLOG_ERR_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2613 UUID_ARGS(uuid
), table
->class_
->name
);
2614 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2619 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
2620 } else if (ovsdb_idl_row_is_orphan(row
)) {
2621 ovsdb_idl_insert_row(row
, new);
2623 VLOG_ERR_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2624 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2625 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2630 /* XXX perhaps we should check the 'old' values? */
2631 if (!ovsdb_idl_row_is_orphan(row
)) {
2632 return ovsdb_idl_modify_row(row
, new)
2633 ? OVSDB_IDL_UPDATE_DB_CHANGED
2634 : OVSDB_IDL_UPDATE_NO_CHANGES
;
2636 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing but "
2637 "referenced row "UUID_FMT
" in table %s",
2638 UUID_ARGS(uuid
), table
->class_
->name
);
2639 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2642 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2643 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2644 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2648 return OVSDB_IDL_UPDATE_DB_CHANGED
;
2651 /* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
2652 * OVSDB_IDL_MODE_RW changed.
2654 * Some IDL inconsistencies can be detected when processing updates:
2655 * - trying to insert an already existing row
2656 * - trying to update a missing row
2657 * - trying to delete a non existent row
2659 * In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
2660 * Even though the IDL client could recover, it's best to report the
2661 * inconsistent state because the state the server is in is unknown so the
2662 * safest thing to do is to retry (potentially connecting to a new server).
2664 * Otherwise OVSDB_IDL_UPDATE_NO_CHANGES is returned.
2666 static enum update_result
2667 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
2668 const struct uuid
*uuid
,
2669 const char *operation
,
2670 const struct json
*json_row
)
2672 struct ovsdb_idl_row
*row
;
2674 row
= ovsdb_idl_get_row(table
, uuid
);
2675 if (!strcmp(operation
, "delete")) {
2677 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2678 ovsdb_idl_delete_row(row
);
2680 VLOG_ERR_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2682 UUID_ARGS(uuid
), table
->class_
->name
);
2683 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2685 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
2688 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
2689 } else if (ovsdb_idl_row_is_orphan(row
)) {
2690 ovsdb_idl_insert_row(row
, json_row
);
2692 VLOG_ERR_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2693 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2694 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2696 } else if (!strcmp(operation
, "modify")) {
2699 if (!ovsdb_idl_row_is_orphan(row
)) {
2700 return ovsdb_idl_modify_row_by_diff(row
, json_row
)
2701 ? OVSDB_IDL_UPDATE_DB_CHANGED
2702 : OVSDB_IDL_UPDATE_NO_CHANGES
;
2704 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing but "
2705 "referenced row "UUID_FMT
" in table %s",
2706 UUID_ARGS(uuid
), table
->class_
->name
);
2707 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2710 VLOG_ERR_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2711 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2712 return OVSDB_IDL_UPDATE_INCONSISTENT
;
2715 VLOG_ERR_RL(&semantic_rl
, "unknown operation %s to "
2716 "table %s", operation
, table
->class_
->name
);
2717 return OVSDB_IDL_UPDATE_NO_CHANGES
;
2720 return OVSDB_IDL_UPDATE_DB_CHANGED
;
2723 /* Recursively add rows to tracked change lists for all rows that reference
2726 add_tracked_change_for_references(struct ovsdb_idl_row
*row
)
2728 const struct ovsdb_idl_arc
*arc
;
2729 LIST_FOR_EACH (arc
, dst_node
, &row
->dst_arcs
) {
2730 struct ovsdb_idl_row
*ref
= arc
->src
;
2732 if (ovs_list_is_empty(&ref
->track_node
) &&
2733 ovsdb_idl_track_is_set(ref
->table
)) {
2734 ovs_list_push_back(&ref
->table
->track_list
,
2737 ref
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
2738 = ref
->table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
2739 = ref
->table
->db
->change_seqno
+ 1;
2741 add_tracked_change_for_references(ref
);
2747 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2750 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
2751 * Caller needs to provide either valid 'row_json' or 'diff', but not
2754 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2755 const struct json
*diff_json
,
2756 enum ovsdb_idl_change change
)
2758 struct ovsdb_idl_table
*table
= row
->table
;
2759 const struct ovsdb_idl_table_class
*class = table
->class_
;
2760 struct shash_node
*node
;
2761 bool changed
= false;
2762 bool apply_diff
= diff_json
!= NULL
;
2763 const struct json
*json
= apply_diff
? diff_json
: row_json
;
2765 SHASH_FOR_EACH (node
, json_object(json
)) {
2766 const char *column_name
= node
->name
;
2767 const struct ovsdb_idl_column
*column
;
2768 struct ovsdb_datum datum
;
2769 struct ovsdb_error
*error
;
2770 unsigned int column_idx
;
2771 struct ovsdb_datum
*old
;
2773 column
= shash_find_data(&table
->columns
, column_name
);
2775 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
2776 column_name
, UUID_ARGS(&row
->uuid
));
2780 column_idx
= column
- table
->class_
->columns
;
2781 old
= &row
->old_datum
[column_idx
];
2785 struct ovsdb_datum diff
;
2787 ovs_assert(!row_json
);
2788 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
2791 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
2793 ovsdb_datum_destroy(&diff
, &column
->type
);
2796 ovs_assert(!diff_json
);
2797 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
2802 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
2803 ovsdb_datum_swap(old
, &datum
);
2804 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
2806 row
->change_seqno
[change
]
2807 = row
->table
->change_seqno
[change
]
2808 = row
->table
->db
->change_seqno
+ 1;
2810 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
2811 if (ovs_list_is_empty(&row
->track_node
) &&
2812 ovsdb_idl_track_is_set(row
->table
)) {
2813 ovs_list_push_back(&row
->table
->track_list
,
2817 add_tracked_change_for_references(row
);
2818 if (!row
->updated
) {
2819 row
->updated
= bitmap_allocate(class->n_columns
);
2821 bitmap_set1(row
->updated
, column_idx
);
2825 /* Didn't really change but the OVSDB monitor protocol always
2826 * includes every value in a row. */
2829 ovsdb_datum_destroy(&datum
, &column
->type
);
2831 char *s
= ovsdb_error_to_string_free(error
);
2832 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
2833 " in table %s: %s", column_name
,
2834 UUID_ARGS(&row
->uuid
), table
->class_
->name
, s
);
2842 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2843 enum ovsdb_idl_change change
)
2845 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
2849 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
2850 const struct json
*diff_json
,
2851 enum ovsdb_idl_change change
)
2853 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
2856 /* When a row A refers to row B through a column with a "refTable" constraint,
2857 * but row B does not exist, row B is called an "orphan row". Orphan rows
2858 * should not persist, because the database enforces referential integrity, but
2859 * they can appear transiently as changes from the database are received (the
2860 * database doesn't try to topologically sort them and circular references mean
2861 * it isn't always possible anyhow).
2863 * This function returns true if 'row' is an orphan row, otherwise false.
2866 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
2868 return !row
->old_datum
&& !row
->new_datum
;
2871 /* Returns true if 'row' is conceptually part of the database as modified by
2872 * the current transaction (if any), false otherwise.
2874 * This function will return true if 'row' is not an orphan (see the comment on
2875 * ovsdb_idl_row_is_orphan()) and:
2877 * - 'row' exists in the database and has not been deleted within the
2878 * current transaction (if any).
2880 * - 'row' was inserted within the current transaction and has not been
2881 * deleted. (In the latter case you should not have passed 'row' in at
2882 * all, because ovsdb_idl_txn_delete() freed it.)
2884 * This function will return false if 'row' is an orphan or if 'row' was
2885 * deleted within the current transaction.
2888 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
2890 return row
->new_datum
!= NULL
;
2894 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
2896 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2900 ovsdb_idl_row_unparse(row
);
2902 for (i
= 0; i
< class->n_columns
; i
++) {
2903 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2904 (c
->parse
)(row
, &row
->old_datum
[i
]);
2910 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
2912 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2918 for (i
= 0; i
< class->n_columns
; i
++) {
2919 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2922 row
->parsed
= false;
2925 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2926 * table indexes over one or more columns in the IDL. These indexes provide
2927 * the ability to retrieve rows matching a particular search criteria and to
2928 * iterate over a subset of rows in a defined order.
2931 /* Generic comparator that can compare each index, using the custom
2932 * configuration (an struct ovsdb_idl_index) passed to it.
2933 * Not intended for direct usage.
2936 ovsdb_idl_index_generic_comparer(const void *a
,
2937 const void *b
, const void *conf
)
2939 const struct ovsdb_idl_column
*column
;
2940 const struct ovsdb_idl_index
*index
;
2943 index
= CONST_CAST(struct ovsdb_idl_index
*, conf
);
2949 for (i
= 0; i
< index
->n_columns
; i
++) {
2951 if (index
->columns
[i
].comparer
) {
2952 val
= index
->columns
[i
].comparer(a
, b
);
2954 column
= index
->columns
[i
].column
;
2955 const struct ovsdb_idl_row
*row_a
, *row_b
;
2956 row_a
= CONST_CAST(struct ovsdb_idl_row
*, a
);
2957 row_b
= CONST_CAST(struct ovsdb_idl_row
*, b
);
2958 const struct ovsdb_datum
*datum_a
, *datum_b
;
2959 datum_a
= ovsdb_idl_read(row_a
, column
);
2960 datum_b
= ovsdb_idl_read(row_b
, column
);
2961 val
= ovsdb_datum_compare_3way(datum_a
, datum_b
, &column
->type
);
2965 return index
->columns
[i
].order
== OVSDB_INDEX_ASC
? val
: -val
;
2969 /* If ins_del is true then a row is being inserted into or deleted from
2970 * the index list. In this case, we augment the search key with
2971 * additional values (row UUID and memory address) to create a unique
2972 * search key in order to locate the correct entry efficiently and to
2973 * ensure that the correct entry is deleted in the case of a "delete"
2976 if (index
->ins_del
) {
2977 const struct ovsdb_idl_row
*row_a
, *row_b
;
2979 row_a
= (const struct ovsdb_idl_row
*) a
;
2980 row_b
= (const struct ovsdb_idl_row
*) b
;
2981 int value
= uuid_compare_3way(&row_a
->uuid
, &row_b
->uuid
);
2983 return value
? value
: (a
< b
) - (a
> b
);
2989 static struct ovsdb_idl_index
*
2990 ovsdb_idl_db_index_create(struct ovsdb_idl_db
*db
,
2991 const struct ovsdb_idl_index_column
*columns
,
2996 struct ovsdb_idl_index
*index
= xzalloc(sizeof *index
);
2998 index
->table
= ovsdb_idl_table_from_column(db
, columns
[0].column
);
2999 for (size_t i
= 0; i
< n
; i
++) {
3000 const struct ovsdb_idl_index_column
*c
= &columns
[i
];
3001 ovs_assert(ovsdb_idl_table_from_column(db
, c
->column
) == index
->table
);
3002 ovs_assert(*ovsdb_idl_db_get_mode(db
, c
->column
) & OVSDB_IDL_MONITOR
);
3005 index
->columns
= xmemdup(columns
, n
* sizeof *columns
);
3006 index
->n_columns
= n
;
3007 index
->skiplist
= skiplist_create(ovsdb_idl_index_generic_comparer
, index
);
3009 ovs_list_push_back(&index
->table
->indexes
, &index
->node
);
3014 /* Creates a new index for the given 'idl' and with the 'n' specified
3017 * All indexes must be created before the first call to ovsdb_idl_run(). */
3018 struct ovsdb_idl_index
*
3019 ovsdb_idl_index_create(struct ovsdb_idl
*idl
,
3020 const struct ovsdb_idl_index_column
*columns
,
3023 return ovsdb_idl_db_index_create(&idl
->data
, columns
, n
);
3026 struct ovsdb_idl_index
*
3027 ovsdb_idl_index_create1(struct ovsdb_idl
*idl
,
3028 const struct ovsdb_idl_column
*column1
)
3030 const struct ovsdb_idl_index_column columns
[] = {
3031 { .column
= column1
},
3033 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
3036 struct ovsdb_idl_index
*
3037 ovsdb_idl_index_create2(struct ovsdb_idl
*idl
,
3038 const struct ovsdb_idl_column
*column1
,
3039 const struct ovsdb_idl_column
*column2
)
3041 const struct ovsdb_idl_index_column columns
[] = {
3042 { .column
= column1
},
3043 { .column
= column2
},
3045 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
3049 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
)
3051 struct ovsdb_idl_index
*index
, *next
;
3052 LIST_FOR_EACH_SAFE (index
, next
, node
, &table
->indexes
) {
3053 skiplist_destroy(index
->skiplist
, NULL
);
3054 free(index
->columns
);
3060 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*row
)
3062 struct ovsdb_idl_table
*table
= row
->table
;
3063 struct ovsdb_idl_index
*index
;
3064 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
3065 index
->ins_del
= true;
3066 skiplist_insert(index
->skiplist
, row
);
3067 index
->ins_del
= false;
3072 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*row
)
3074 struct ovsdb_idl_table
*table
= row
->table
;
3075 struct ovsdb_idl_index
*index
;
3076 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
3077 index
->ins_del
= true;
3078 skiplist_delete(index
->skiplist
, row
);
3079 index
->ins_del
= false;
3083 /* Writes a datum in an ovsdb_idl_row, and updates the corresponding field in
3084 * the table record. Not intended for direct usage. */
3086 ovsdb_idl_index_write(struct ovsdb_idl_row
*const_row
,
3087 const struct ovsdb_idl_column
*column
,
3088 struct ovsdb_datum
*datum
,
3089 const struct ovsdb_idl_table_class
*class)
3091 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, const_row
);
3092 size_t column_idx
= column
- class->columns
;
3094 if (bitmap_is_set(row
->written
, column_idx
)) {
3095 free(row
->new_datum
[column_idx
].values
);
3096 free(row
->new_datum
[column_idx
].keys
);
3098 bitmap_set1(row
->written
, column_idx
);
3100 row
->new_datum
[column_idx
] = *datum
;
3101 (column
->unparse
)(row
);
3102 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
3105 /* Magic UUID for index rows */
3106 static const struct uuid index_row_uuid
= {
3107 .parts
= {0xdeadbeef,
3112 /* Check if a row is an index row */
3114 is_index_row(const struct ovsdb_idl_row
*row
)
3116 return uuid_equals(&row
->uuid
, &index_row_uuid
);
3119 /* Initializes a row for use in an indexed query.
3120 * Not intended for direct usage.
3122 struct ovsdb_idl_row
*
3123 ovsdb_idl_index_init_row(struct ovsdb_idl_index
*index
)
3125 const struct ovsdb_idl_table_class
*class = index
->table
->class_
;
3126 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
3127 class->row_init(row
);
3128 row
->uuid
= index_row_uuid
;
3129 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
3130 row
->written
= bitmap_allocate(class->n_columns
);
3131 row
->table
= index
->table
;
3132 /* arcs are not used for index row, but it doesn't harm to initialize */
3133 ovs_list_init(&row
->src_arcs
);
3134 ovs_list_init(&row
->dst_arcs
);
3138 /* Destroys 'row_' and frees all associated memory. This function is intended
3139 * to be used indirectly through one of the "index_destroy_row" functions
3140 * generated by ovsdb-idlc.
3143 ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row
*row_
)
3145 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3146 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3147 const struct ovsdb_idl_column
*c
;
3150 ovs_assert(is_index_row(row_
));
3151 ovs_assert(ovs_list_is_empty(&row_
->src_arcs
));
3152 ovs_assert(ovs_list_is_empty(&row_
->dst_arcs
));
3153 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
3154 c
= &class->columns
[i
];
3156 free(row
->new_datum
[i
].values
);
3157 free(row
->new_datum
[i
].keys
);
3159 free(row
->new_datum
);
3164 struct ovsdb_idl_row
*
3165 ovsdb_idl_index_find(struct ovsdb_idl_index
*index
,
3166 const struct ovsdb_idl_row
*target
)
3168 return skiplist_get_data(skiplist_find(index
->skiplist
, target
));
3171 struct ovsdb_idl_cursor
3172 ovsdb_idl_cursor_first(struct ovsdb_idl_index
*index
)
3174 struct skiplist_node
*node
= skiplist_first(index
->skiplist
);
3175 return (struct ovsdb_idl_cursor
) { index
, node
};
3178 struct ovsdb_idl_cursor
3179 ovsdb_idl_cursor_first_eq(struct ovsdb_idl_index
*index
,
3180 const struct ovsdb_idl_row
*target
)
3182 struct skiplist_node
*node
= skiplist_find(index
->skiplist
, target
);
3183 return (struct ovsdb_idl_cursor
) { index
, node
};
3186 struct ovsdb_idl_cursor
3187 ovsdb_idl_cursor_first_ge(struct ovsdb_idl_index
*index
,
3188 const struct ovsdb_idl_row
*target
)
3190 struct skiplist_node
*node
= (target
3191 ? skiplist_forward_to(index
->skiplist
,
3193 : skiplist_first(index
->skiplist
));
3194 return (struct ovsdb_idl_cursor
) { index
, node
};
3198 ovsdb_idl_cursor_next(struct ovsdb_idl_cursor
*cursor
)
3200 cursor
->position
= skiplist_next(cursor
->position
);
3204 ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor
*cursor
)
3206 struct ovsdb_idl_row
*data
= skiplist_get_data(cursor
->position
);
3207 struct skiplist_node
*next_position
= skiplist_next(cursor
->position
);
3208 struct ovsdb_idl_row
*next_data
= skiplist_get_data(next_position
);
3209 cursor
->position
= (!ovsdb_idl_index_compare(cursor
->index
,
3211 ? next_position
: NULL
);
3214 struct ovsdb_idl_row
*
3215 ovsdb_idl_cursor_data(struct ovsdb_idl_cursor
*cursor
)
3217 return skiplist_get_data(cursor
->position
);
3220 /* Returns the result of comparing two rows using the comparison function
3226 * When the pointer to either row is NULL, this function considers NULL to be
3227 * greater than any other value, and NULL == NULL.
3230 ovsdb_idl_index_compare(struct ovsdb_idl_index
*index
,
3231 const struct ovsdb_idl_row
*a
,
3232 const struct ovsdb_idl_row
*b
)
3235 return ovsdb_idl_index_generic_comparer(a
, b
, index
);
3236 } else if (!a
&& !b
) {
3246 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
3248 ovs_assert(row
->old_datum
== row
->new_datum
);
3249 if (!ovsdb_idl_row_is_orphan(row
)) {
3250 if (ovsdb_idl_track_is_set(row
->table
) && !row
->tracked_old_datum
) {
3251 row
->tracked_old_datum
= row
->old_datum
;
3253 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3256 for (i
= 0; i
< class->n_columns
; i
++) {
3257 ovsdb_datum_destroy(&row
->old_datum
[i
],
3258 &class->columns
[i
].type
);
3260 free(row
->old_datum
);
3262 row
->old_datum
= row
->new_datum
= NULL
;
3267 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
3269 if (row
->old_datum
!= row
->new_datum
) {
3270 if (row
->new_datum
) {
3271 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3275 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
3276 ovsdb_datum_destroy(&row
->new_datum
[i
],
3277 &class->columns
[i
].type
);
3280 free(row
->new_datum
);
3282 row
->written
= NULL
;
3284 row
->new_datum
= row
->old_datum
;
3289 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
3291 struct ovsdb_idl_arc
*arc
, *next
;
3293 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
3294 * that this causes to be unreferenced.
3296 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
3297 ovs_list_remove(&arc
->dst_node
);
3299 && ovsdb_idl_row_is_orphan(arc
->dst
)
3300 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
3301 ovsdb_idl_row_destroy(arc
->dst
);
3305 ovs_list_init(&row
->src_arcs
);
3308 /* Force nodes that reference 'row' to reparse. */
3310 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
3312 struct ovsdb_idl_arc
*arc
, *next
;
3314 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
3315 * 'arc', so we need to use the "safe" variant of list traversal. However,
3316 * calling an ovsdb_idl_column's 'parse' function will add an arc
3317 * equivalent to 'arc' to row->arcs. That could be a problem for
3318 * traversal, but it adds it at the beginning of the list to prevent us
3319 * from stumbling upon it again.
3321 * (If duplicate arcs were possible then we would need to make sure that
3322 * 'next' didn't also point into 'arc''s destination, but we forbid
3323 * duplicate arcs.) */
3324 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
3325 struct ovsdb_idl_row
*ref
= arc
->src
;
3327 ovsdb_idl_row_unparse(ref
);
3328 ovsdb_idl_row_clear_arcs(ref
, false);
3329 ovsdb_idl_row_parse(ref
);
3333 static struct ovsdb_idl_row
*
3334 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
3336 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
3337 class->row_init(row
);
3338 ovs_list_init(&row
->src_arcs
);
3339 ovs_list_init(&row
->dst_arcs
);
3340 hmap_node_nullify(&row
->txn_node
);
3341 ovs_list_init(&row
->track_node
);
3345 static struct ovsdb_idl_row
*
3346 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
3348 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class_
);
3349 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
3352 row
->map_op_written
= NULL
;
3353 row
->map_op_lists
= NULL
;
3354 row
->set_op_written
= NULL
;
3355 row
->set_op_lists
= NULL
;
3360 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
3363 ovsdb_idl_row_clear_old(row
);
3364 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3365 ovsdb_idl_destroy_all_map_op_lists(row
);
3366 ovsdb_idl_destroy_all_set_op_lists(row
);
3367 if (ovsdb_idl_track_is_set(row
->table
)) {
3368 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
3369 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
3370 = row
->table
->db
->change_seqno
+ 1;
3372 if (ovs_list_is_empty(&row
->track_node
)) {
3373 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
3379 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
3381 if (row
->map_op_written
) {
3382 /* Clear Map Operation Lists */
3383 size_t idx
, n_columns
;
3384 const struct ovsdb_idl_column
*columns
;
3385 const struct ovsdb_type
*type
;
3386 n_columns
= row
->table
->class_
->n_columns
;
3387 columns
= row
->table
->class_
->columns
;
3388 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
3389 type
= &columns
[idx
].type
;
3390 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
3392 free(row
->map_op_lists
);
3393 bitmap_free(row
->map_op_written
);
3394 row
->map_op_lists
= NULL
;
3395 row
->map_op_written
= NULL
;
3400 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
3402 if (row
->set_op_written
) {
3403 /* Clear Set Operation Lists */
3404 size_t idx
, n_columns
;
3405 const struct ovsdb_idl_column
*columns
;
3406 const struct ovsdb_type
*type
;
3407 n_columns
= row
->table
->class_
->n_columns
;
3408 columns
= row
->table
->class_
->columns
;
3409 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
3410 type
= &columns
[idx
].type
;
3411 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
3413 free(row
->set_op_lists
);
3414 bitmap_free(row
->set_op_written
);
3415 row
->set_op_lists
= NULL
;
3416 row
->set_op_written
= NULL
;
3421 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db
*db
)
3425 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
3426 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
3428 if (!ovs_list_is_empty(&table
->track_list
)) {
3429 struct ovsdb_idl_row
*row
, *next
;
3431 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
3432 if (!ovsdb_idl_track_is_set(row
->table
)) {
3433 ovs_list_remove(&row
->track_node
);
3434 ovsdb_idl_row_unparse(row
);
3443 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
3445 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3446 size_t i
, datum_size
;
3448 ovs_assert(!row
->old_datum
&& !row
->new_datum
);
3449 datum_size
= class->n_columns
* sizeof *row
->old_datum
;
3450 row
->old_datum
= row
->new_datum
= xmalloc(datum_size
);
3451 for (i
= 0; i
< class->n_columns
; i
++) {
3452 ovsdb_datum_init_default(&row
->old_datum
[i
], &class->columns
[i
].type
);
3454 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
3455 ovsdb_idl_row_parse(row
);
3457 ovsdb_idl_row_reparse_backrefs(row
);
3458 ovsdb_idl_add_to_indexes(row
);
3462 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
3464 ovsdb_idl_remove_from_indexes(row
);
3465 ovsdb_idl_row_clear_arcs(row
, true);
3466 ovsdb_idl_row_clear_old(row
);
3467 if (ovs_list_is_empty(&row
->dst_arcs
)) {
3468 ovsdb_idl_row_destroy(row
);
3470 ovsdb_idl_row_reparse_backrefs(row
);
3474 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
3477 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
3481 ovsdb_idl_remove_from_indexes(row
);
3482 ovsdb_idl_row_unparse(row
);
3483 ovsdb_idl_row_clear_arcs(row
, true);
3484 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
3485 ovsdb_idl_row_parse(row
);
3486 ovsdb_idl_add_to_indexes(row
);
3492 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
3493 const struct json
*diff_json
)
3497 ovsdb_idl_remove_from_indexes(row
);
3498 ovsdb_idl_row_unparse(row
);
3499 ovsdb_idl_row_clear_arcs(row
, true);
3500 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
3501 OVSDB_IDL_CHANGE_MODIFY
);
3502 ovsdb_idl_row_parse(row
);
3503 ovsdb_idl_add_to_indexes(row
);
3509 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
3511 const struct ovsdb_idl_arc
*arc
;
3518 /* No duplicate arcs.
3520 * We only need to test whether the first arc in dst->dst_arcs originates
3521 * at 'src', since we add all of the arcs from a given source in a clump
3522 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
3523 * added at the front of the dst_arcs list. */
3524 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
3527 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
3528 return arc
->src
!= src
;
3531 static struct ovsdb_idl_table
*
3532 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db
*db
,
3533 const struct ovsdb_idl_table_class
*table_class
)
3535 ptrdiff_t idx
= table_class
- db
->class_
->tables
;
3536 return idx
>= 0 && idx
< db
->class_
->n_tables
? &db
->tables
[idx
] : NULL
;
3539 static struct ovsdb_idl_table
*
3540 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
3541 const struct ovsdb_idl_table_class
*table_class
)
3543 struct ovsdb_idl_table
*table
;
3545 table
= ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
3547 table
= ovsdb_idl_db_table_from_class(&idl
->server
, table_class
);
3553 /* Called by ovsdb-idlc generated code. */
3554 struct ovsdb_idl_row
*
3555 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
3556 const struct ovsdb_idl_table_class
*dst_table_class
,
3557 const struct uuid
*dst_uuid
)
3559 struct ovsdb_idl_db
*db
= src
->table
->db
;
3560 struct ovsdb_idl_table
*dst_table
;
3561 struct ovsdb_idl_arc
*arc
;
3562 struct ovsdb_idl_row
*dst
;
3564 dst_table
= ovsdb_idl_db_table_from_class(db
, dst_table_class
);
3565 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
3566 if (db
->txn
|| is_index_row(src
)) {
3567 /* There are two cases we should not update any arcs:
3569 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
3570 * any arcs, because the transaction will be backed out at commit or
3571 * abort time and we don't want our graph screwed up.
3573 * 2. The row is used as an index for querying purpose only.
3575 * In these cases, just return the destination row, if there is one and
3576 * it has not been deleted. */
3577 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new_datum
)) {
3582 /* We're being called from some other context. Update the graph. */
3584 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
3587 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
3588 if (may_add_arc(src
, dst
)) {
3589 /* The arc *must* be added at the front of the dst_arcs list. See
3590 * ovsdb_idl_row_reparse_backrefs() for details. */
3591 arc
= xmalloc(sizeof *arc
);
3592 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
3593 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
3598 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
3602 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
3603 * pointer to the row if there is one, otherwise a null pointer. */
3604 const struct ovsdb_idl_row
*
3605 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
3606 const struct ovsdb_idl_table_class
*tc
,
3607 const struct uuid
*uuid
)
3609 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
3612 static struct ovsdb_idl_row
*
3613 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
3615 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
3616 struct ovsdb_idl_row
*row
;
3618 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
3619 if (ovsdb_idl_row_exists(row
)) {
3626 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
3629 * Database tables are internally maintained as hash tables, so adding or
3630 * removing rows while traversing the same table can cause some rows to be
3631 * visited twice or not at apply. */
3632 const struct ovsdb_idl_row
*
3633 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
3634 const struct ovsdb_idl_table_class
*table_class
)
3636 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
,
3638 return next_real_row(table
, hmap_first(&table
->rows
));
3641 /* Returns a row following 'row' within its table, or a null pointer if 'row'
3642 * is the last row in its table. */
3643 const struct ovsdb_idl_row
*
3644 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
3646 struct ovsdb_idl_table
*table
= row
->table
;
3648 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
3651 /* Reads and returns the value of 'column' within 'row'. If an ongoing
3652 * transaction has changed 'column''s value, the modified value is returned.
3654 * The caller must not modify or free the returned value.
3656 * Various kinds of changes can invalidate the returned value: writing to the
3657 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
3658 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
3659 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
3660 * returned value is needed for a long time, it is best to make a copy of it
3661 * with ovsdb_datum_clone(). */
3662 const struct ovsdb_datum
*
3663 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
3664 const struct ovsdb_idl_column
*column
)
3666 const struct ovsdb_idl_table_class
*class;
3669 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
3671 class = row
->table
->class_
;
3672 column_idx
= column
- class->columns
;
3674 ovs_assert(row
->new_datum
!= NULL
);
3675 ovs_assert(column_idx
< class->n_columns
);
3677 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
3678 return &row
->new_datum
[column_idx
];
3679 } else if (row
->old_datum
) {
3680 return &row
->old_datum
[column_idx
];
3682 return ovsdb_datum_default(&column
->type
);
3686 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
3687 * type 'key_type' and value type 'value_type'. (Scalar and set types will
3688 * have a value type of OVSDB_TYPE_VOID.)
3690 * This is useful in code that "knows" that a particular column has a given
3691 * type, so that it will abort if someone changes the column's type without
3692 * updating the code that uses it. */
3693 const struct ovsdb_datum
*
3694 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
3695 const struct ovsdb_idl_column
*column
,
3696 enum ovsdb_atomic_type key_type OVS_UNUSED
,
3697 enum ovsdb_atomic_type value_type OVS_UNUSED
)
3699 ovs_assert(column
->type
.key
.type
== key_type
);
3700 ovs_assert(column
->type
.value
.type
== value_type
);
3702 return ovsdb_idl_read(row
, column
);
3705 /* Returns true if the field represented by 'column' in 'row' may be modified,
3706 * false if it is immutable.
3708 * Normally, whether a field is mutable is controlled by its column's schema.
3709 * However, an immutable column can be set to any initial value at the time of
3710 * insertion, so if 'row' is a new row (one that is being added as part of the
3711 * current transaction, supposing that a transaction is in progress) then even
3712 * its "immutable" fields are actually mutable. */
3714 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
3715 const struct ovsdb_idl_column
*column
)
3717 return column
->is_mutable
|| (row
->new_datum
&& !row
->old_datum
);
3720 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
3721 * to all-zero-bits by some other entity. If 'row' was set up some other way
3722 * then the return value is indeterminate. */
3724 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
3726 return row
->table
== NULL
;
3731 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3732 enum ovsdb_idl_txn_status
);
3734 /* Returns a string representation of 'status'. The caller must not modify or
3735 * free the returned string.
3737 * The return value is probably useful only for debug log messages and unit
3740 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
3743 case TXN_UNCOMMITTED
:
3744 return "uncommitted";
3747 case TXN_INCOMPLETE
:
3748 return "incomplete";
3755 case TXN_NOT_LOCKED
:
3756 return "not locked";
3763 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
3764 * active transaction at a time. See the large comment in ovsdb-idl.h for
3765 * general information on transactions. */
3766 struct ovsdb_idl_txn
*
3767 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
3769 struct ovsdb_idl_txn
*txn
;
3771 ovs_assert(!idl
->data
.txn
);
3772 idl
->data
.txn
= txn
= xmalloc(sizeof *txn
);
3773 txn
->request_id
= NULL
;
3774 txn
->db
= &idl
->data
;
3775 hmap_init(&txn
->txn_rows
);
3776 txn
->status
= TXN_UNCOMMITTED
;
3778 txn
->dry_run
= false;
3779 ds_init(&txn
->comment
);
3781 txn
->inc_table
= NULL
;
3782 txn
->inc_column
= NULL
;
3784 hmap_init(&txn
->inserted_rows
);
3789 /* Appends 's', which is treated as a printf()-type format string, to the
3790 * comments that will be passed to the OVSDB server when 'txn' is committed.
3791 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
3792 * show-log" can print in a relatively human-readable form.) */
3794 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
3798 if (txn
->comment
.length
) {
3799 ds_put_char(&txn
->comment
, '\n');
3803 ds_put_format_valist(&txn
->comment
, s
, args
);
3807 /* Marks 'txn' as a transaction that will not actually modify the database. In
3808 * almost every way, the transaction is treated like other transactions. It
3809 * must be committed or aborted like other transactions, it will be sent to the
3810 * database server like other transactions, and so on. The only difference is
3811 * that the operations sent to the database server will include, as the last
3812 * step, an "abort" operation, so that any changes made by the transaction will
3813 * not actually take effect. */
3815 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
3817 txn
->dry_run
= true;
3820 /* Causes 'txn', when committed, to increment the value of 'column' within
3821 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3822 * successfully, the client may retrieve the final (incremented) value of
3823 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3825 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3826 * change the database, then 'force' is important. If 'force' is false in this
3827 * case, the IDL suppresses the increment and skips a round trip to the
3828 * database server. If 'force' is true, the IDL will still increment the
3831 * The client could accomplish something similar with ovsdb_idl_read(),
3832 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3833 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3834 * will never (by itself) fail because of a verify error.
3836 * The intended use is for incrementing the "next_cfg" column in the
3837 * Open_vSwitch table. */
3839 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
3840 const struct ovsdb_idl_row
*row
,
3841 const struct ovsdb_idl_column
*column
,
3844 ovs_assert(!txn
->inc_table
);
3845 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
3846 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
3848 txn
->inc_table
= row
->table
->class_
->name
;
3849 txn
->inc_column
= column
->name
;
3850 txn
->inc_row
= row
->uuid
;
3851 txn
->inc_force
= force
;
3854 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3855 * has been called for 'txn' but the commit is still incomplete (that is, the
3856 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3857 * end up committing at the database server, but the client will not be able to
3858 * get any further status information back. */
3860 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
3862 struct ovsdb_idl_txn_insert
*insert
, *next
;
3864 json_destroy(txn
->request_id
);
3865 if (txn
->status
== TXN_INCOMPLETE
) {
3866 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
3868 ovsdb_idl_txn_abort(txn
);
3869 ds_destroy(&txn
->comment
);
3871 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
3874 hmap_destroy(&txn
->inserted_rows
);
3878 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3880 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
3882 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
3883 poll_immediate_wake();
3887 static struct json
*
3888 where_uuid_equals(const struct uuid
*uuid
)
3891 json_array_create_1(
3892 json_array_create_3(
3893 json_string_create("_uuid"),
3894 json_string_create("=="),
3895 json_array_create_2(
3896 json_string_create("uuid"),
3897 json_string_create_nocopy(
3898 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
3901 static const struct ovsdb_idl_row
*
3902 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
3904 const struct ovsdb_idl_row
*row
;
3906 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
3907 if (uuid_equals(&row
->uuid
, uuid
)) {
3914 /* XXX there must be a cleaner way to do this */
3915 static struct json
*
3916 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
3918 if (json
->type
== JSON_ARRAY
) {
3922 if (json
->array
.n
== 2
3923 && json
->array
.elems
[0]->type
== JSON_STRING
3924 && json
->array
.elems
[1]->type
== JSON_STRING
3925 && !strcmp(json
->array
.elems
[0]->string
, "uuid")
3926 && uuid_from_string(&uuid
, json
->array
.elems
[1]->string
)) {
3927 const struct ovsdb_idl_row
*row
;
3929 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
3930 if (row
&& !row
->old_datum
&& row
->new_datum
) {
3933 return json_array_create_2(
3934 json_string_create("named-uuid"),
3935 json_string_create_nocopy(ovsdb_data_row_name(&uuid
)));
3939 for (i
= 0; i
< json
->array
.n
; i
++) {
3940 json
->array
.elems
[i
] = substitute_uuids(json
->array
.elems
[i
],
3943 } else if (json
->type
== JSON_OBJECT
) {
3944 struct shash_node
*node
;
3946 SHASH_FOR_EACH (node
, json_object(json
)) {
3947 node
->data
= substitute_uuids(node
->data
, txn
);
3954 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
3956 struct ovsdb_idl_row
*row
, *next
;
3958 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3959 * ovsdb_idl_column's 'parse' function, which will call
3960 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3961 * transaction and fail to update the graph. */
3962 txn
->db
->txn
= NULL
;
3964 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
3965 enum { INSERTED
, MODIFIED
, DELETED
} op
3966 = (!row
->new_datum
? DELETED
3967 : !row
->old_datum
? INSERTED
3970 if (op
!= DELETED
) {
3971 ovsdb_idl_remove_from_indexes(row
);
3974 ovsdb_idl_destroy_all_map_op_lists(row
);
3975 ovsdb_idl_destroy_all_set_op_lists(row
);
3976 if (op
!= INSERTED
) {
3978 ovsdb_idl_row_unparse(row
);
3979 ovsdb_idl_row_clear_arcs(row
, false);
3980 ovsdb_idl_row_parse(row
);
3983 ovsdb_idl_row_unparse(row
);
3985 ovsdb_idl_row_clear_new(row
);
3988 row
->prereqs
= NULL
;
3991 row
->written
= NULL
;
3993 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
3994 hmap_node_nullify(&row
->txn_node
);
3995 if (op
!= INSERTED
) {
3996 ovsdb_idl_add_to_indexes(row
);
3998 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
4002 hmap_destroy(&txn
->txn_rows
);
4003 hmap_init(&txn
->txn_rows
);
4007 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
4008 struct json
*mutations
)
4010 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
4012 bool any_mutations
= false;
4014 if (row
->map_op_written
) {
4015 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
4016 struct map_op_list
*map_op_list
;
4017 const struct ovsdb_idl_column
*column
;
4018 const struct ovsdb_datum
*old_datum
;
4019 enum ovsdb_atomic_type key_type
, value_type
;
4020 struct json
*mutation
, *map
, *col_name
, *mutator
;
4021 struct json
*del_set
, *ins_map
;
4022 bool any_del
, any_ins
;
4024 map_op_list
= row
->map_op_lists
[idx
];
4025 column
= &class->columns
[idx
];
4026 key_type
= column
->type
.key
.type
;
4027 value_type
= column
->type
.value
.type
;
4029 /* Get the value to be changed */
4030 if (row
->new_datum
&& row
->written
4031 && bitmap_is_set(row
->written
,idx
)) {
4032 old_datum
= &row
->new_datum
[idx
];
4033 } else if (row
->old_datum
!= NULL
) {
4034 old_datum
= &row
->old_datum
[idx
];
4036 old_datum
= ovsdb_datum_default(&column
->type
);
4039 del_set
= json_array_create_empty();
4040 ins_map
= json_array_create_empty();
4044 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
4045 map_op
= map_op_list_next(map_op_list
, map_op
)) {
4047 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
4048 /* Find out if value really changed. */
4049 struct ovsdb_datum
*new_datum
;
4051 new_datum
= map_op_datum(map_op
);
4052 pos
= ovsdb_datum_find_key(old_datum
,
4053 &new_datum
->keys
[0],
4055 if (ovsdb_atom_equals(&new_datum
->values
[0],
4056 &old_datum
->values
[pos
],
4058 /* No change in value. Move on to next update. */
4061 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
4062 /* Verify that there is a key to delete. */
4064 pos
= ovsdb_datum_find_key(old_datum
,
4065 &map_op_datum(map_op
)->keys
[0],
4067 if (pos
== UINT_MAX
) {
4068 /* No key to delete. Move on to next update. */
4069 VLOG_WARN("Trying to delete a key that doesn't "
4070 "exist in the map.");
4075 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
4076 map
= json_array_create_2(
4077 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
4079 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
4081 json_array_add(ins_map
, map
);
4083 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
4084 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
4086 json_array_add(del_set
, map
);
4090 /* Generate an additional insert mutate for updates. */
4091 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
4092 map
= json_array_create_2(
4093 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
4095 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
4097 json_array_add(ins_map
, map
);
4103 col_name
= json_string_create(column
->name
);
4104 mutator
= json_string_create("delete");
4105 map
= json_array_create_2(json_string_create("set"), del_set
);
4106 mutation
= json_array_create_3(col_name
, mutator
, map
);
4107 json_array_add(mutations
, mutation
);
4108 any_mutations
= true;
4110 json_destroy(del_set
);
4113 col_name
= json_string_create(column
->name
);
4114 mutator
= json_string_create("insert");
4115 map
= json_array_create_2(json_string_create("map"), ins_map
);
4116 mutation
= json_array_create_3(col_name
, mutator
, map
);
4117 json_array_add(mutations
, mutation
);
4118 any_mutations
= true;
4120 json_destroy(ins_map
);
4124 if (row
->set_op_written
) {
4125 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
4126 struct set_op_list
*set_op_list
;
4127 const struct ovsdb_idl_column
*column
;
4128 const struct ovsdb_datum
*old_datum
;
4129 enum ovsdb_atomic_type key_type
;
4130 struct json
*mutation
, *set
, *col_name
, *mutator
;
4131 struct json
*del_set
, *ins_set
;
4132 bool any_del
, any_ins
;
4134 set_op_list
= row
->set_op_lists
[idx
];
4135 column
= &class->columns
[idx
];
4136 key_type
= column
->type
.key
.type
;
4138 /* Get the value to be changed */
4139 if (row
->new_datum
&& row
->written
4140 && bitmap_is_set(row
->written
,idx
)) {
4141 old_datum
= &row
->new_datum
[idx
];
4142 } else if (row
->old_datum
!= NULL
) {
4143 old_datum
= &row
->old_datum
[idx
];
4145 old_datum
= ovsdb_datum_default(&column
->type
);
4148 del_set
= json_array_create_empty();
4149 ins_set
= json_array_create_empty();
4153 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
4154 set_op
= set_op_list_next(set_op_list
, set_op
)) {
4155 if (set_op_type(set_op
) == SET_OP_INSERT
) {
4156 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
4158 json_array_add(ins_set
, set
);
4160 } else { /* SETP_OP_DELETE */
4161 /* Verify that there is a key to delete. */
4163 pos
= ovsdb_datum_find_key(old_datum
,
4164 &set_op_datum(set_op
)->keys
[0],
4166 if (pos
== UINT_MAX
) {
4167 /* No key to delete. Move on to next update. */
4168 VLOG_WARN("Trying to delete a key that doesn't "
4169 "exist in the set.");
4172 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
4174 json_array_add(del_set
, set
);
4179 col_name
= json_string_create(column
->name
);
4180 mutator
= json_string_create("delete");
4181 set
= json_array_create_2(json_string_create("set"), del_set
);
4182 mutation
= json_array_create_3(col_name
, mutator
, set
);
4183 json_array_add(mutations
, mutation
);
4184 any_mutations
= true;
4186 json_destroy(del_set
);
4189 col_name
= json_string_create(column
->name
);
4190 mutator
= json_string_create("insert");
4191 set
= json_array_create_2(json_string_create("set"), ins_set
);
4192 mutation
= json_array_create_3(col_name
, mutator
, set
);
4193 json_array_add(mutations
, mutation
);
4194 any_mutations
= true;
4196 json_destroy(ins_set
);
4200 return any_mutations
;
4203 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
4204 * of the following TXN_* constants:
4208 * The transaction is in progress, but not yet complete. The caller
4209 * should call again later, after calling ovsdb_idl_run() to let the IDL
4210 * do OVSDB protocol processing.
4214 * The transaction is complete. (It didn't actually change the database,
4215 * so the IDL didn't send any request to the database server.)
4219 * The caller previously called ovsdb_idl_txn_abort().
4223 * The transaction was successful. The update made by the transaction
4224 * (and possibly other changes made by other database clients) should
4225 * already be visible in the IDL.
4229 * The transaction failed for some transient reason, e.g. because a
4230 * "verify" operation reported an inconsistency or due to a network
4231 * problem. The caller should wait for a change to the database, then
4232 * compose a new transaction, and commit the new transaction.
4234 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
4235 * the database. It is important to use its return value *before* the
4236 * initial call to ovsdb_idl_txn_commit() as the baseline for this
4237 * purpose, because the change that one should wait for can happen after
4238 * the initial call but before the call that returns TXN_TRY_AGAIN, and
4239 * using some other baseline value in that situation could cause an
4240 * indefinite wait if the database rarely changes.
4244 * The transaction failed because the IDL has been configured to require
4245 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
4246 * has already lost it.
4248 * Committing a transaction rolls back all of the changes that it made to the
4249 * IDL's copy of the database. If the transaction commits successfully, then
4250 * the database server will send an update and, thus, the IDL will be updated
4251 * with the committed changes. */
4252 enum ovsdb_idl_txn_status
4253 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
4255 struct ovsdb_idl_row
*row
;
4256 struct json
*operations
;
4259 if (txn
!= txn
->db
->txn
) {
4263 /* If we're still connecting or re-connecting, don't bother sending a
4265 if (txn
->db
->idl
->state
!= IDL_S_MONITORING
) {
4266 txn
->status
= TXN_TRY_AGAIN
;
4267 goto disassemble_out
;
4270 /* If we need a lock but don't have it, give up quickly. */
4271 if (txn
->db
->lock_name
&& !txn
->db
->has_lock
) {
4272 txn
->status
= TXN_NOT_LOCKED
;
4273 goto disassemble_out
;
4276 operations
= json_array_create_1(
4277 json_string_create(txn
->db
->class_
->database
));
4279 /* Assert that we have the required lock (avoiding a race). */
4280 if (txn
->db
->lock_name
) {
4281 struct json
*op
= json_object_create();
4282 json_array_add(operations
, op
);
4283 json_object_put_string(op
, "op", "assert");
4284 json_object_put_string(op
, "lock", txn
->db
->lock_name
);
4287 /* Add prerequisites and declarations of new rows. */
4288 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
4289 /* XXX check that deleted rows exist even if no prereqs? */
4291 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
4292 size_t n_columns
= class->n_columns
;
4293 struct json
*op
, *columns
, *row_json
;
4296 op
= json_object_create();
4297 json_array_add(operations
, op
);
4298 json_object_put_string(op
, "op", "wait");
4299 json_object_put_string(op
, "table", class->name
);
4300 json_object_put(op
, "timeout", json_integer_create(0));
4301 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
4302 json_object_put_string(op
, "until", "==");
4303 columns
= json_array_create_empty();
4304 json_object_put(op
, "columns", columns
);
4305 row_json
= json_object_create();
4306 json_object_put(op
, "rows", json_array_create_1(row_json
));
4308 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
4309 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
4310 json_array_add(columns
, json_string_create(column
->name
));
4311 json_object_put(row_json
, column
->name
,
4312 ovsdb_datum_to_json(&row
->old_datum
[idx
],
4319 any_updates
= false;
4321 /* For tables constrained to have only a single row (a fairly common OVSDB
4322 * pattern for storing global data), identify whether we're inserting a
4323 * row. If so, then verify that the table is empty before inserting the
4324 * row. This gives us a clear verification-related failure if there was an
4325 * insertion race with another client. */
4326 for (size_t i
= 0; i
< txn
->db
->class_
->n_tables
; i
++) {
4327 struct ovsdb_idl_table
*table
= &txn
->db
->tables
[i
];
4328 if (table
->class_
->is_singleton
) {
4329 /* Count the number of rows in the table before and after our
4330 * transaction commits. This is O(n) in the number of rows in the
4331 * table, but that's OK since we know that the table should only
4333 size_t initial_rows
= 0;
4334 size_t final_rows
= 0;
4335 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
4336 initial_rows
+= row
->old_datum
!= NULL
;
4337 final_rows
+= row
->new_datum
!= NULL
;
4340 if (initial_rows
== 0 && final_rows
== 1) {
4341 struct json
*op
= json_object_create();
4342 json_array_add(operations
, op
);
4343 json_object_put_string(op
, "op", "wait");
4344 json_object_put_string(op
, "table", table
->class_
->name
);
4345 json_object_put(op
, "where", json_array_create_empty());
4346 json_object_put(op
, "timeout", json_integer_create(0));
4347 json_object_put_string(op
, "until", "==");
4348 json_object_put(op
, "rows", json_array_create_empty());
4353 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
4354 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
4356 if (!row
->new_datum
) {
4357 if (class->is_root
) {
4358 struct json
*op
= json_object_create();
4359 json_object_put_string(op
, "op", "delete");
4360 json_object_put_string(op
, "table", class->name
);
4361 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
4362 json_array_add(operations
, op
);
4365 /* Let ovsdb-server decide whether to really delete it. */
4367 } else if (row
->old_datum
!= row
->new_datum
) {
4368 struct json
*row_json
;
4371 struct json
*op
= json_object_create();
4372 json_object_put_string(op
, "op",
4373 row
->old_datum
? "update" : "insert");
4374 json_object_put_string(op
, "table", class->name
);
4375 if (row
->old_datum
) {
4376 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
4378 struct ovsdb_idl_txn_insert
*insert
;
4382 json_object_put(op
, "uuid-name",
4383 json_string_create_nocopy(
4384 ovsdb_data_row_name(&row
->uuid
)));
4386 insert
= xmalloc(sizeof *insert
);
4387 insert
->dummy
= row
->uuid
;
4388 insert
->op_index
= operations
->array
.n
- 1;
4389 uuid_zero(&insert
->real
);
4390 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
4391 uuid_hash(&insert
->dummy
));
4393 row_json
= json_object_create();
4394 json_object_put(op
, "row", row_json
);
4397 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
4398 const struct ovsdb_idl_column
*column
=
4399 &class->columns
[idx
];
4402 || !ovsdb_datum_is_default(&row
->new_datum
[idx
],
4406 value
= ovsdb_datum_to_json(&row
->new_datum
[idx
],
4408 json_object_put(row_json
, column
->name
,
4409 substitute_uuids(value
, txn
));
4411 /* If anything really changed, consider it an update.
4412 * We can't suppress not-really-changed values earlier
4413 * or transactions would become nonatomic (see the big
4414 * comment inside ovsdb_idl_txn_write()). */
4415 if (!any_updates
&& row
->old_datum
&&
4416 !ovsdb_datum_equals(&row
->old_datum
[idx
],
4417 &row
->new_datum
[idx
],
4425 if (!row
->old_datum
|| !shash_is_empty(json_object(row_json
))) {
4426 json_array_add(operations
, op
);
4432 /* Add mutate operation, for partial map or partial set updates. */
4433 if (row
->map_op_written
|| row
->set_op_written
) {
4434 struct json
*op
, *mutations
;
4437 op
= json_object_create();
4438 json_object_put_string(op
, "op", "mutate");
4439 json_object_put_string(op
, "table", class->name
);
4440 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
4441 mutations
= json_array_create_empty();
4442 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
4443 json_object_put(op
, "mutations", mutations
);
4445 if (any_mutations
) {
4446 op
= substitute_uuids(op
, txn
);
4447 json_array_add(operations
, op
);
4455 /* Add increment. */
4456 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
4458 txn
->inc_index
= operations
->array
.n
- 1;
4460 struct json
*op
= json_object_create();
4461 json_object_put_string(op
, "op", "mutate");
4462 json_object_put_string(op
, "table", txn
->inc_table
);
4463 json_object_put(op
, "where",
4464 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
4466 json_object_put(op
, "mutations",
4467 json_array_create_1(
4468 json_array_create_3(
4469 json_string_create(txn
->inc_column
),
4470 json_string_create("+="),
4471 json_integer_create(1))));
4472 json_array_add(operations
, op
);
4474 op
= json_object_create();
4475 json_object_put_string(op
, "op", "select");
4476 json_object_put_string(op
, "table", txn
->inc_table
);
4477 json_object_put(op
, "where",
4478 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
4480 json_object_put(op
, "columns",
4481 json_array_create_1(json_string_create(
4483 json_array_add(operations
, op
);
4486 if (txn
->comment
.length
) {
4487 struct json
*op
= json_object_create();
4488 json_object_put_string(op
, "op", "comment");
4489 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
4490 json_array_add(operations
, op
);
4494 struct json
*op
= json_object_create();
4495 json_object_put_string(op
, "op", "abort");
4496 json_array_add(operations
, op
);
4500 txn
->status
= TXN_UNCHANGED
;
4501 json_destroy(operations
);
4502 } else if (!txn
->db
->idl
->session
) {
4503 txn
->status
= TXN_TRY_AGAIN
;
4504 json_destroy(operations
);
4505 } else if (!jsonrpc_session_send(
4506 txn
->db
->idl
->session
,
4507 jsonrpc_create_request(
4508 "transact", operations
, &txn
->request_id
))) {
4509 hmap_insert(&txn
->db
->outstanding_txns
, &txn
->hmap_node
,
4510 json_hash(txn
->request_id
, 0));
4511 txn
->status
= TXN_INCOMPLETE
;
4513 txn
->status
= TXN_TRY_AGAIN
;
4517 ovsdb_idl_txn_disassemble(txn
);
4519 switch (txn
->status
) {
4520 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
4521 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
4522 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
4523 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
4524 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
4525 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
4526 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
4527 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
4533 /* Attempts to commit 'txn', blocking until the commit either succeeds or
4534 * fails. Returns the final commit status, which may be any TXN_* value other
4535 * than TXN_INCOMPLETE.
4537 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
4538 * return value of ovsdb_idl_get_seqno() to change. */
4539 enum ovsdb_idl_txn_status
4540 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
4542 enum ovsdb_idl_txn_status status
;
4545 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
4546 ovsdb_idl_run(txn
->db
->idl
);
4547 ovsdb_idl_wait(txn
->db
->idl
);
4548 ovsdb_idl_txn_wait(txn
);
4554 /* Returns the final (incremented) value of the column in 'txn' that was set to
4555 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
4558 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
4560 ovs_assert(txn
->status
== TXN_SUCCESS
);
4561 return txn
->inc_new_value
;
4564 /* Aborts 'txn' without sending it to the database server. This is effective
4565 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
4566 * Otherwise, it has no effect.
4568 * Aborting a transaction doesn't free its memory. Use
4569 * ovsdb_idl_txn_destroy() to do that. */
4571 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
4573 ovsdb_idl_txn_disassemble(txn
);
4574 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
4575 txn
->status
= TXN_ABORTED
;
4579 /* Returns a string that reports the error status for 'txn'. The caller must
4580 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
4581 * for 'txn' may free the returned string.
4583 * The return value is ordinarily one of the strings that
4584 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
4585 * due to an error reported by the database server, the return value is that
4588 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
4590 if (txn
->status
!= TXN_ERROR
) {
4591 return ovsdb_idl_txn_status_to_string(txn
->status
);
4592 } else if (txn
->error
) {
4595 return "no error details available";
4600 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
4601 const struct json
*json
)
4603 if (json
&& txn
->error
== NULL
) {
4604 txn
->error
= json_to_string(json
, JSSF_SORT
);
4608 /* For transaction 'txn' that completed successfully, finds and returns the
4609 * permanent UUID that the database assigned to a newly inserted row, given the
4610 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
4612 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
4613 * if it was assigned by that function and then deleted by
4614 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
4615 * and then deleted within a single transaction are never sent to the database
4616 * server, so it never assigns them a permanent UUID.) */
4618 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
4619 const struct uuid
*uuid
)
4621 const struct ovsdb_idl_txn_insert
*insert
;
4623 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
4624 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
4625 uuid_hash(uuid
), &txn
->inserted_rows
) {
4626 if (uuid_equals(uuid
, &insert
->dummy
)) {
4627 return &insert
->real
;
4634 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
4635 enum ovsdb_idl_txn_status status
)
4637 txn
->status
= status
;
4638 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
4642 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
4643 const struct ovsdb_idl_column
*column
,
4644 struct ovsdb_datum
*datum
, bool owns_datum
)
4646 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4647 const struct ovsdb_idl_table_class
*class;
4651 ovs_assert(!column
->is_synthetic
);
4652 if (ovsdb_idl_row_is_synthetic(row
)) {
4656 class = row
->table
->class_
;
4657 column_idx
= column
- class->columns
;
4658 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
4660 ovs_assert(row
->new_datum
!= NULL
);
4661 ovs_assert(column_idx
< class->n_columns
);
4662 ovs_assert(row
->old_datum
== NULL
||
4663 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4665 if (row
->table
->db
->verify_write_only
&& !write_only
) {
4666 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
4667 " explicitly configured not to.", class->name
, column
->name
);
4671 /* If this is a write-only column and the datum being written is the same
4672 * as the one already there, just skip the update entirely. This is worth
4673 * optimizing because we have a lot of columns that get periodically
4674 * refreshed into the database but don't actually change that often.
4676 * We don't do this for read/write columns because that would break
4677 * atomicity of transactions--some other client might have written a
4678 * different value in that column since we read it. (But if a whole
4679 * transaction only does writes of existing values, without making any real
4680 * changes, we will drop the whole transaction later in
4681 * ovsdb_idl_txn_commit().) */
4682 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
4683 datum
, &column
->type
)) {
4687 bool index_row
= is_index_row(row
);
4689 ovsdb_idl_remove_from_indexes(row
);
4691 if (hmap_node_is_null(&row
->txn_node
)) {
4692 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4693 uuid_hash(&row
->uuid
));
4695 if (row
->old_datum
== row
->new_datum
) {
4696 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4698 if (!row
->written
) {
4699 row
->written
= bitmap_allocate(class->n_columns
);
4701 if (bitmap_is_set(row
->written
, column_idx
)) {
4702 ovsdb_datum_destroy(&row
->new_datum
[column_idx
], &column
->type
);
4704 bitmap_set1(row
->written
, column_idx
);
4707 row
->new_datum
[column_idx
] = *datum
;
4709 ovsdb_datum_clone(&row
->new_datum
[column_idx
], datum
, &column
->type
);
4711 (column
->unparse
)(row
);
4712 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
4715 ovsdb_idl_add_to_indexes(row
);
4721 ovsdb_datum_destroy(datum
, &column
->type
);
4725 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
4726 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
4729 * 'datum' must have the correct type for its column, but it needs not be
4730 * sorted or unique because this function will take care of that. The IDL does
4731 * not check that it meets schema constraints, but ovsdb-server will do so at
4732 * commit time so it had better be correct.
4734 * A transaction must be in progress. Replication of 'column' must not have
4735 * been disabled (by calling ovsdb_idl_omit()).
4737 * Usually this function is used indirectly through one of the "set" functions
4738 * generated by ovsdb-idlc.
4740 * Takes ownership of what 'datum' points to (and in some cases destroys that
4741 * data before returning) but makes a copy of 'datum' itself. (Commonly
4742 * 'datum' is on the caller's stack.) */
4744 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
4745 const struct ovsdb_idl_column
*column
,
4746 struct ovsdb_datum
*datum
)
4748 ovsdb_datum_sort_unique(datum
,
4749 column
->type
.key
.type
, column
->type
.value
.type
);
4750 ovsdb_idl_txn_write__(row
, column
, datum
, true);
4753 /* Similar to ovsdb_idl_txn_write(), except:
4755 * - The caller retains ownership of 'datum' and what it points to.
4757 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
4758 * ovsdb_datum_sort_unique().) */
4760 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
4761 const struct ovsdb_idl_column
*column
,
4762 const struct ovsdb_datum
*datum
)
4764 ovsdb_idl_txn_write__(row
, column
,
4765 CONST_CAST(struct ovsdb_datum
*, datum
), false);
4768 /* Causes the original contents of 'column' in 'row_' to be verified as a
4769 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
4770 * changed (or if 'row_' was deleted) between the time that the IDL originally
4771 * read its contents and the time that the transaction commits, then the
4772 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
4774 * The intention is that, to ensure that no transaction commits based on dirty
4775 * reads, an application should call ovsdb_idl_txn_verify() on each data item
4776 * read as part of a read-modify-write operation.
4778 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
4779 * value of 'column' is already known:
4781 * - If 'row_' is a row created by the current transaction (returned by
4782 * ovsdb_idl_txn_insert()).
4784 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
4785 * within the current transaction.
4787 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
4788 * ovsdb_idl_txn_write() for a given read-modify-write.
4790 * A transaction must be in progress.
4792 * Usually this function is used indirectly through one of the "verify"
4793 * functions generated by ovsdb-idlc. */
4795 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
4796 const struct ovsdb_idl_column
*column
)
4798 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4799 const struct ovsdb_idl_table_class
*class;
4802 if (ovsdb_idl_row_is_synthetic(row
)) {
4806 class = row
->table
->class_
;
4807 column_idx
= column
- class->columns
;
4809 ovs_assert(row
->new_datum
!= NULL
);
4810 ovs_assert(row
->old_datum
== NULL
||
4811 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4813 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
4817 if (hmap_node_is_null(&row
->txn_node
)) {
4818 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4819 uuid_hash(&row
->uuid
));
4821 if (!row
->prereqs
) {
4822 row
->prereqs
= bitmap_allocate(class->n_columns
);
4824 bitmap_set1(row
->prereqs
, column_idx
);
4827 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4828 * accessed afterward.
4830 * A transaction must be in progress.
4832 * Usually this function is used indirectly through one of the "delete"
4833 * functions generated by ovsdb-idlc. */
4835 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
4837 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4839 if (ovsdb_idl_row_is_synthetic(row
)) {
4843 ovs_assert(row
->new_datum
!= NULL
);
4844 ovs_assert(!is_index_row(row_
));
4845 ovsdb_idl_remove_from_indexes(row_
);
4846 if (!row
->old_datum
) {
4847 ovsdb_idl_row_unparse(row
);
4848 ovsdb_idl_row_clear_new(row
);
4849 ovs_assert(!row
->prereqs
);
4850 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
4851 hmap_remove(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
);
4855 if (hmap_node_is_null(&row
->txn_node
)) {
4856 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4857 uuid_hash(&row
->uuid
));
4859 ovsdb_idl_row_clear_new(row
);
4860 row
->new_datum
= NULL
;
4863 /* Inserts and returns a new row in the table with the specified 'class' in the
4864 * database with open transaction 'txn'.
4866 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4867 * randomly generated; otherwise 'uuid' should specify a randomly generated
4868 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4869 * 'txn' is committed, but the IDL will replace any uses of the provisional
4870 * UUID in the data to be to be committed by the UUID assigned by
4873 * Usually this function is used indirectly through one of the "insert"
4874 * functions generated by ovsdb-idlc. */
4875 const struct ovsdb_idl_row
*
4876 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
4877 const struct ovsdb_idl_table_class
*class,
4878 const struct uuid
*uuid
)
4880 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
4883 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
4886 uuid_generate(&row
->uuid
);
4889 row
->table
= ovsdb_idl_db_table_from_class(txn
->db
, class);
4890 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4891 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
4892 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
4893 ovsdb_idl_add_to_indexes(row
);
4899 ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db
*db
)
4901 struct ovsdb_idl_txn
*txn
;
4903 HMAP_FOR_EACH (txn
, hmap_node
, &db
->outstanding_txns
) {
4904 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
4909 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
4911 ovsdb_idl_db_txn_abort_all(&idl
->server
);
4912 ovsdb_idl_db_txn_abort_all(&idl
->data
);
4915 static struct ovsdb_idl_txn
*
4916 ovsdb_idl_db_txn_find(struct ovsdb_idl_db
*db
, const struct json
*id
)
4918 struct ovsdb_idl_txn
*txn
;
4920 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
4921 json_hash(id
, 0), &db
->outstanding_txns
) {
4922 if (json_equal(id
, txn
->request_id
)) {
4930 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
4933 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
4935 } else if (json
->type
!= type
) {
4936 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
4937 name
, json_type_to_string(json
->type
),
4938 json_type_to_string(type
));
4946 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
4947 const struct json_array
*results
)
4949 struct json
*count
, *rows
, *row
, *column
;
4950 struct shash
*mutate
, *select
;
4952 if (txn
->inc_index
+ 2 > results
->n
) {
4953 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4954 "for increment (has %"PRIuSIZE
", needs %u)",
4955 results
->n
, txn
->inc_index
+ 2);
4959 /* We know that this is a JSON object because the loop in
4960 * ovsdb_idl_db_txn_process_reply() checked. */
4961 mutate
= json_object(results
->elems
[txn
->inc_index
]);
4962 count
= shash_find_data(mutate
, "count");
4963 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
4966 if (count
->integer
!= 1) {
4967 VLOG_WARN_RL(&syntax_rl
,
4968 "\"mutate\" reply \"count\" is %lld instead of 1",
4973 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
4974 rows
= shash_find_data(select
, "rows");
4975 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
4978 if (rows
->array
.n
!= 1) {
4979 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
4984 row
= rows
->array
.elems
[0];
4985 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
4988 column
= shash_find_data(json_object(row
), txn
->inc_column
);
4989 if (!check_json_type(column
, JSON_INTEGER
,
4990 "\"select\" reply inc column")) {
4993 txn
->inc_new_value
= column
->integer
;
4998 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
4999 const struct json_array
*results
)
5001 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
5002 struct ovsdb_error
*error
;
5003 struct json
*json_uuid
;
5004 union ovsdb_atom uuid
;
5005 struct shash
*reply
;
5007 if (insert
->op_index
>= results
->n
) {
5008 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
5009 "for insert (has %"PRIuSIZE
", needs %u)",
5010 results
->n
, insert
->op_index
);
5014 /* We know that this is a JSON object because the loop in
5015 * ovsdb_idl_txn_process_reply() checked. */
5016 reply
= json_object(results
->elems
[insert
->op_index
]);
5017 json_uuid
= shash_find_data(reply
, "uuid");
5018 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
5022 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
5024 char *s
= ovsdb_error_to_string_free(error
);
5025 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
5031 insert
->real
= uuid
.uuid
;
5037 ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db
*db
,
5038 const struct jsonrpc_msg
*msg
)
5040 struct ovsdb_idl_txn
*txn
;
5041 enum ovsdb_idl_txn_status status
;
5043 txn
= ovsdb_idl_db_txn_find(db
, msg
->id
);
5048 if (msg
->type
== JSONRPC_ERROR
) {
5050 && msg
->error
->type
== JSON_STRING
5051 && !strcmp(json_string(msg
->error
), "canceled")) {
5052 /* ovsdb-server uses this error message to indicate that the
5053 * transaction was canceled because the database in question was
5054 * removed, converted, etc. */
5055 status
= TXN_TRY_AGAIN
;
5058 ovsdb_idl_txn_set_error_json(txn
, msg
->error
);
5060 } else if (msg
->result
->type
!= JSON_ARRAY
) {
5061 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
5063 ovsdb_idl_txn_set_error_json(txn
, msg
->result
);
5065 struct json_array
*ops
= &msg
->result
->array
;
5066 int hard_errors
= 0;
5067 int soft_errors
= 0;
5068 int lock_errors
= 0;
5071 for (i
= 0; i
< ops
->n
; i
++) {
5072 struct json
*op
= ops
->elems
[i
];
5074 if (op
->type
== JSON_NULL
) {
5075 /* This isn't an error in itself but indicates that some prior
5076 * operation failed, so make sure that we know about it. */
5078 } else if (op
->type
== JSON_OBJECT
) {
5081 error
= shash_find_data(json_object(op
), "error");
5083 if (error
->type
== JSON_STRING
) {
5084 if (!strcmp(error
->string
, "timed out")) {
5086 } else if (!strcmp(error
->string
,
5087 "unknown database")) {
5088 ovsdb_idl_retry(db
->idl
);
5090 } else if (!strcmp(error
->string
, "not owner")) {
5092 } else if (!strcmp(error
->string
, "not allowed")) {
5094 ovsdb_idl_txn_set_error_json(txn
, op
);
5095 } else if (strcmp(error
->string
, "aborted")) {
5097 ovsdb_idl_txn_set_error_json(txn
, op
);
5098 VLOG_WARN_RL(&other_rl
,
5099 "transaction error: %s", txn
->error
);
5103 ovsdb_idl_txn_set_error_json(txn
, op
);
5104 VLOG_WARN_RL(&syntax_rl
,
5105 "\"error\" in reply is not JSON string");
5110 ovsdb_idl_txn_set_error_json(txn
, op
);
5111 VLOG_WARN_RL(&syntax_rl
,
5112 "operation reply is not JSON null or object");
5116 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
5117 struct ovsdb_idl_txn_insert
*insert
;
5119 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
5123 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
5124 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
5130 status
= (hard_errors
? TXN_ERROR
5131 : lock_errors
? TXN_NOT_LOCKED
5132 : soft_errors
? TXN_TRY_AGAIN
5136 ovsdb_idl_txn_complete(txn
, status
);
5140 /* Returns the transaction currently active for 'row''s IDL. A transaction
5141 * must currently be active. */
5142 struct ovsdb_idl_txn
*
5143 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
5145 struct ovsdb_idl_txn
*txn
= row
->table
->db
->txn
;
5146 ovs_assert(txn
!= NULL
);
5150 /* Returns the IDL on which 'txn' acts. */
5152 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
5154 return txn
->db
->idl
;
5157 /* Blocks until 'idl' successfully connects to the remote database and
5158 * retrieves its contents. */
5160 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
5164 if (ovsdb_idl_has_ever_connected(idl
)) {
5167 ovsdb_idl_wait(idl
);
5172 static struct jsonrpc_msg
*
5173 ovsdb_idl_db_set_lock(struct ovsdb_idl_db
*db
, const char *lock_name
)
5175 ovs_assert(!db
->txn
);
5176 ovs_assert(hmap_is_empty(&db
->outstanding_txns
));
5179 && (!lock_name
|| strcmp(lock_name
, db
->lock_name
))) {
5180 /* Release previous lock. */
5181 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_unlock_request(db
);
5182 free(db
->lock_name
);
5183 db
->lock_name
= NULL
;
5184 db
->is_lock_contended
= false;
5188 if (lock_name
&& !db
->lock_name
) {
5189 /* Acquire new lock. */
5190 db
->lock_name
= xstrdup(lock_name
);
5191 return ovsdb_idl_db_compose_lock_request(db
);
5197 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
5198 * the database server and to avoid modifying the database when the lock cannot
5199 * be acquired (that is, when another client has the same lock).
5201 * If 'lock_name' is NULL, drops the locking requirement and releases the
5204 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
5207 struct jsonrpc_msg
*msg
= ovsdb_idl_db_set_lock(&idl
->data
, lock_name
);
5212 jsonrpc_session_send(idl
->session
, msg
);
5214 jsonrpc_msg_destroy(msg
);
5219 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
5221 * Locking and unlocking happens asynchronously from the database client's
5222 * point of view, so the information is only useful for optimization (e.g. if
5223 * the client doesn't have the lock then there's no point in trying to write to
5226 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
5228 return idl
->data
.has_lock
;
5231 /* Returns true if 'idl' is configured to obtain a lock but the database server
5232 * has indicated that some other client already owns the requested lock. */
5234 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
5236 return idl
->data
.is_lock_contended
;
5240 ovsdb_idl_db_update_has_lock(struct ovsdb_idl_db
*db
, bool new_has_lock
)
5242 if (new_has_lock
&& !db
->has_lock
) {
5243 if (db
->idl
->state
== IDL_S_MONITORING
) {
5246 /* We're setting up a session, so don't signal that the database
5247 * changed. Finalizing the session will increment change_seqno
5250 db
->is_lock_contended
= false;
5252 db
->has_lock
= new_has_lock
;
5256 ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db
*db
,
5257 const struct jsonrpc_msg
*msg
)
5259 if (msg
->type
== JSONRPC_REPLY
5260 && db
->lock_request_id
5261 && json_equal(db
->lock_request_id
, msg
->id
)) {
5262 /* Reply to our "lock" request. */
5263 ovsdb_idl_db_parse_lock_reply(db
, msg
->result
);
5267 if (msg
->type
== JSONRPC_NOTIFY
) {
5268 if (!strcmp(msg
->method
, "locked")) {
5269 /* We got our lock. */
5270 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, true);
5271 } else if (!strcmp(msg
->method
, "stolen")) {
5272 /* Someone else stole our lock. */
5273 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, false);
5280 static struct jsonrpc_msg
*
5281 ovsdb_idl_db_compose_lock_request__(struct ovsdb_idl_db
*db
,
5284 ovsdb_idl_db_update_has_lock(db
, false);
5286 json_destroy(db
->lock_request_id
);
5287 db
->lock_request_id
= NULL
;
5289 struct json
*params
= json_array_create_1(json_string_create(
5291 return jsonrpc_create_request(method
, params
, NULL
);
5294 static struct jsonrpc_msg
*
5295 ovsdb_idl_db_compose_lock_request(struct ovsdb_idl_db
*db
)
5297 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_lock_request__(db
, "lock");
5298 db
->lock_request_id
= json_clone(msg
->id
);
5302 static struct jsonrpc_msg
*
5303 ovsdb_idl_db_compose_unlock_request(struct ovsdb_idl_db
*db
)
5305 return ovsdb_idl_db_compose_lock_request__(db
, "unlock");
5309 ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db
*db
,
5310 const struct json
*result
)
5314 json_destroy(db
->lock_request_id
);
5315 db
->lock_request_id
= NULL
;
5317 if (result
->type
== JSON_OBJECT
) {
5318 const struct json
*locked
;
5320 locked
= shash_find_data(json_object(result
), "locked");
5321 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
5326 ovsdb_idl_db_update_has_lock(db
, got_lock
);
5328 db
->is_lock_contended
= true;
5333 ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db
*db
,
5334 const struct json
*params
,
5338 && params
->type
== JSON_ARRAY
5339 && json_array(params
)->n
> 0
5340 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
5341 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
5343 if (!strcmp(db
->lock_name
, lock_name
)) {
5344 ovsdb_idl_db_update_has_lock(db
, new_has_lock
);
5345 if (!new_has_lock
) {
5346 db
->is_lock_contended
= true;
5354 /* Inserts a new Map Operation into current transaction. */
5356 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
5357 const struct ovsdb_idl_column
*column
,
5358 struct ovsdb_datum
*datum
,
5359 enum map_op_type op_type
)
5361 const struct ovsdb_idl_table_class
*class;
5363 struct map_op
*map_op
;
5365 class = row
->table
->class_
;
5366 column_idx
= column
- class->columns
;
5368 /* Check if a map operation list exists for this column. */
5369 if (!row
->map_op_written
) {
5370 row
->map_op_written
= bitmap_allocate(class->n_columns
);
5371 row
->map_op_lists
= xzalloc(class->n_columns
*
5372 sizeof *row
->map_op_lists
);
5374 if (!row
->map_op_lists
[column_idx
]) {
5375 row
->map_op_lists
[column_idx
] = map_op_list_create();
5378 /* Add a map operation to the corresponding list. */
5379 map_op
= map_op_create(datum
, op_type
);
5380 bitmap_set1(row
->map_op_written
, column_idx
);
5381 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
5383 /* Add this row to transaction's list of rows. */
5384 if (hmap_node_is_null(&row
->txn_node
)) {
5385 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
5386 uuid_hash(&row
->uuid
));
5390 /* Inserts a new Set Operation into current transaction. */
5392 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
5393 const struct ovsdb_idl_column
*column
,
5394 struct ovsdb_datum
*datum
,
5395 enum set_op_type op_type
)
5397 const struct ovsdb_idl_table_class
*class;
5399 struct set_op
*set_op
;
5401 class = row
->table
->class_
;
5402 column_idx
= column
- class->columns
;
5404 /* Check if a set operation list exists for this column. */
5405 if (!row
->set_op_written
) {
5406 row
->set_op_written
= bitmap_allocate(class->n_columns
);
5407 row
->set_op_lists
= xzalloc(class->n_columns
*
5408 sizeof *row
->set_op_lists
);
5410 if (!row
->set_op_lists
[column_idx
]) {
5411 row
->set_op_lists
[column_idx
] = set_op_list_create();
5414 /* Add a set operation to the corresponding list. */
5415 set_op
= set_op_create(datum
, op_type
);
5416 bitmap_set1(row
->set_op_written
, column_idx
);
5417 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
5419 /* Add this row to the transactions's list of rows. */
5420 if (hmap_node_is_null(&row
->txn_node
)) {
5421 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
5422 uuid_hash(&row
->uuid
));
5427 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
5428 const struct ovsdb_idl_column
*column
,
5429 struct ovsdb_datum
*datum
)
5431 /* Verify that this column is being monitored. */
5432 unsigned int column_idx
= column
- row
->table
->class_
->columns
;
5433 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
5434 VLOG_WARN("cannot partially update non-monitored column");
5438 /* Verify that the update affects a single element. */
5439 if (datum
->n
!= 1) {
5440 VLOG_WARN("invalid datum for partial update");
5447 /* Inserts the value described in 'datum' into the map in 'column' in
5448 * 'row_'. If the value doesn't already exist in 'column' then it's value
5449 * is added. The value in 'datum' must be of the same type as the values
5450 * in 'column'. This function takes ownership of 'datum'.
5452 * Usually this function is used indirectly through one of the "update"
5453 * functions generated by vswitch-idl. */
5455 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
5456 const struct ovsdb_idl_column
*column
,
5457 struct ovsdb_datum
*datum
)
5459 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5460 enum set_op_type op_type
;
5462 if (!is_valid_partial_update(row
, column
, datum
)) {
5463 ovsdb_datum_destroy(datum
, &column
->type
);
5468 op_type
= SET_OP_INSERT
;
5470 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
5473 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
5474 * The value in 'datum' must be of the same type as the keys in 'column'.
5475 * This function takes ownership of 'datum'.
5477 * Usually this function is used indirectly through one of the "update"
5478 * functions generated by vswitch-idl. */
5480 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
5481 const struct ovsdb_idl_column
*column
,
5482 struct ovsdb_datum
*datum
)
5484 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5486 if (!is_valid_partial_update(row
, column
, datum
)) {
5487 struct ovsdb_type type_
= column
->type
;
5488 type_
.value
.type
= OVSDB_TYPE_VOID
;
5489 ovsdb_datum_destroy(datum
, &type_
);
5493 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
5496 /* Inserts the key-value specified in 'datum' into the map in 'column' in
5497 * 'row_'. If the key already exist in 'column', then it's value is updated
5498 * with the value in 'datum'. The key-value in 'datum' must be of the same type
5499 * as the keys-values in 'column'. This function takes ownership of 'datum'.
5501 * Usually this function is used indirectly through one of the "update"
5502 * functions generated by vswitch-idl. */
5504 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
5505 const struct ovsdb_idl_column
*column
,
5506 struct ovsdb_datum
*datum
)
5508 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5509 enum ovsdb_atomic_type key_type
;
5510 enum map_op_type op_type
;
5512 const struct ovsdb_datum
*old_datum
;
5514 if (!is_valid_partial_update(row
, column
, datum
)) {
5515 ovsdb_datum_destroy(datum
, &column
->type
);
5520 /* Find out if this is an insert or an update. */
5521 key_type
= column
->type
.key
.type
;
5522 old_datum
= ovsdb_idl_read(row
, column
);
5523 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
5524 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
5526 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
5529 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
5530 * The key in 'datum' must be of the same type as the keys in 'column'.
5531 * The value in 'datum' must be NULL. This function takes ownership of
5534 * Usually this function is used indirectly through one of the "update"
5535 * functions generated by vswitch-idl. */
5537 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
5538 const struct ovsdb_idl_column
*column
,
5539 struct ovsdb_datum
*datum
)
5541 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5543 if (!is_valid_partial_update(row
, column
, datum
)) {
5544 struct ovsdb_type type_
= column
->type
;
5545 type_
.value
.type
= OVSDB_TYPE_VOID
;
5546 ovsdb_datum_destroy(datum
, &type_
);
5550 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
5554 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
5557 ovsdb_idl_destroy(loop
->idl
);
5561 struct ovsdb_idl_txn
*
5562 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
5564 ovsdb_idl_run(loop
->idl
);
5566 /* See if we can commit the loop->committing_txn. */
5567 if (loop
->committing_txn
) {
5568 ovsdb_idl_try_commit_loop_txn(loop
, NULL
);
5571 loop
->open_txn
= (loop
->committing_txn
5572 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
5574 : ovsdb_idl_txn_create(loop
->idl
));
5575 if (loop
->open_txn
) {
5576 ovsdb_idl_txn_add_comment(loop
->open_txn
, "%s", program_name
);
5578 return loop
->open_txn
;
5581 /* Attempts to commit the current transaction, if one is open.
5583 * If a transaction was open, in this or a previous iteration of the main loop,
5584 * and had not before finished committing (successfully or unsuccessfully), the
5585 * return value is one of:
5587 * 1: The transaction committed successfully (or it did not change anything in
5589 * 0: The transaction failed.
5590 * -1: The commit is still in progress.
5592 * Thus, the return value is -1 if the transaction is in progress and otherwise
5593 * true for success, false for failure.
5595 * (In the corner case where the IDL sends a transaction to the database and
5596 * the database commits it, and the connection between the IDL and the database
5597 * drops before the IDL receives the message confirming the commit, this
5598 * function can return 0 even though the transaction succeeded.)
5601 ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop
*loop
,
5602 bool *may_need_wakeup
)
5604 if (!loop
->committing_txn
) {
5605 /* Not a meaningful return value: no transaction was in progress. */
5610 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
5612 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
5613 if (status
!= TXN_INCOMPLETE
) {
5616 /* We want to re-evaluate the database when it's changed from
5617 * the contents that it had when we started the commit. (That
5618 * might have already happened.) */
5619 loop
->skip_seqno
= loop
->precommit_seqno
;
5620 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
5621 && may_need_wakeup
) {
5622 *may_need_wakeup
= true;
5628 /* Possibly some work on the database was deferred because no
5629 * further transaction could proceed. Wake up again. */
5631 loop
->cur_cfg
= loop
->next_cfg
;
5632 if (may_need_wakeup
) {
5633 *may_need_wakeup
= true;
5639 loop
->cur_cfg
= loop
->next_cfg
;
5643 case TXN_NOT_LOCKED
:
5648 case TXN_UNCOMMITTED
:
5649 case TXN_INCOMPLETE
:
5653 ovsdb_idl_txn_destroy(txn
);
5654 loop
->committing_txn
= NULL
;
5662 /* Attempts to commit the current transaction, if one is open, and sets up the
5663 * poll loop to wake up when some more work might be needed.
5665 * If a transaction was open, in this or a previous iteration of the main loop,
5666 * and had not before finished committing (successfully or unsuccessfully), the
5667 * return value is one of:
5669 * 1: The transaction committed successfully (or it did not change anything in
5671 * 0: The transaction failed.
5672 * -1: The commit is still in progress.
5674 * Thus, the return value is -1 if the transaction is in progress and otherwise
5675 * true for success, false for failure.
5677 * (In the corner case where the IDL sends a transaction to the database and
5678 * the database commits it, and the connection between the IDL and the database
5679 * drops before the IDL receives the message confirming the commit, this
5680 * function can return 0 even though the transaction succeeded.)
5683 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
5685 if (loop
->open_txn
) {
5686 loop
->committing_txn
= loop
->open_txn
;
5687 loop
->open_txn
= NULL
;
5689 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
5692 bool may_need_wakeup
= false;
5693 int retval
= ovsdb_idl_try_commit_loop_txn(loop
, &may_need_wakeup
);
5694 if (may_need_wakeup
) {
5695 poll_immediate_wake();
5697 ovsdb_idl_wait(loop
->idl
);