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" 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_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" reply. If successful, replaces the \
129 * IDL contents by the data carried in the reply and transitions \
130 * to IDL_S_MONITORING. On failure, sends a "monitor" request \
131 * and transitions to IDL_S_DATA_MONITOR_REQUESTED. */ \
132 OVSDB_IDL_STATE(DATA_MONITOR_COND_REQUESTED) \
134 /* Waits for "monitor" reply. If successful, replaces the IDL \
135 * contents by the data carried in the reply and transitions to \
136 * IDL_S_MONITORING. On failure, transitions to IDL_S_ERROR. */ \
137 OVSDB_IDL_STATE(DATA_MONITOR_REQUESTED) \
139 /* State that processes "update" or "update2" notifications for \
140 * the main database (and the Database table in _Server if \
143 * If we're monitoring the Database table and we get notified \
144 * that the IDL database has been deleted, we close the \
145 * connection (which will restart the state machine). */ \
146 OVSDB_IDL_STATE(MONITORING) \
148 /* Terminal error state that indicates that nothing useful can be \
149 * done, for example because the database server doesn't actually \
150 * have the desired database. We maintain the session with the \
151 * database server anyway. If it starts serving the database \
152 * that we want, or if someone fixes and restarts the database, \
153 * then it will kill the session and we will automatically \
154 * reconnect and try again. */ \
155 OVSDB_IDL_STATE(ERROR) \
157 /* Terminal state that indicates we connected to a useless server \
158 * in a cluster, e.g. one that is partitioned from the rest of \
159 * the cluster. We're waiting to retry. */ \
160 OVSDB_IDL_STATE(RETRY)
162 enum ovsdb_idl_state
{
163 #define OVSDB_IDL_STATE(NAME) IDL_S_##NAME,
165 #undef OVSDB_IDL_STATE
168 static const char *ovsdb_idl_state_to_string(enum ovsdb_idl_state
);
170 enum ovsdb_idl_monitoring
{
171 OVSDB_IDL_NOT_MONITORING
, /* Database is not being monitored. */
172 OVSDB_IDL_MONITORING
, /* Database has "monitor" outstanding. */
173 OVSDB_IDL_MONITORING_COND
, /* Database has "monitor_cond" outstanding. */
176 struct ovsdb_idl_db
{
177 struct ovsdb_idl
*idl
;
180 const struct ovsdb_idl_class
*class_
;
181 struct shash table_by_name
; /* Contains "struct ovsdb_idl_table *"s.*/
182 struct ovsdb_idl_table
*tables
; /* Array of ->class_->n_tables elements. */
183 struct json
*monitor_id
;
184 unsigned int change_seqno
;
185 struct ovsdb_idl_txn
*txn
;
186 struct hmap outstanding_txns
;
187 bool verify_write_only
;
189 enum ovsdb_idl_monitoring monitoring
;
191 /* True if any of the tables' monitoring conditions has changed. */
194 unsigned int cond_seqno
; /* Keep track of condition clauses changes
195 over a single conditional monitoring session.
196 Reverts to zero when idl session
199 /* Database locking. */
200 char *lock_name
; /* Name of lock we need, NULL if none. */
201 bool has_lock
; /* Has db server told us we have the lock? */
202 bool is_lock_contended
; /* Has db server told us we can't get lock? */
203 struct json
*lock_request_id
; /* JSON-RPC ID of in-flight lock request. */
206 static void ovsdb_idl_db_track_clear(struct ovsdb_idl_db
*);
207 static void ovsdb_idl_db_add_column(struct ovsdb_idl_db
*,
208 const struct ovsdb_idl_column
*);
209 static void ovsdb_idl_db_omit(struct ovsdb_idl_db
*,
210 const struct ovsdb_idl_column
*);
211 static void ovsdb_idl_db_omit_alert(struct ovsdb_idl_db
*,
212 const struct ovsdb_idl_column
*);
213 static unsigned int ovsdb_idl_db_set_condition(
214 struct ovsdb_idl_db
*, const struct ovsdb_idl_table_class
*,
215 const struct ovsdb_idl_condition
*);
217 static void ovsdb_idl_send_schema_request(struct ovsdb_idl
*,
218 struct ovsdb_idl_db
*);
219 static void ovsdb_idl_send_db_change_aware(struct ovsdb_idl
*);
220 static bool ovsdb_idl_check_server_db(struct ovsdb_idl
*);
221 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl
*,
222 struct ovsdb_idl_db
*,
223 bool use_monitor_cond
);
226 struct ovsdb_idl_db server
;
227 struct ovsdb_idl_db data
;
231 *'state_seqno' is a snapshot of the session's sequence number as returned
232 * jsonrpc_session_get_seqno(session), so if it differs from the value that
233 * function currently returns then the session has reconnected and the
234 * state machine must restart. */
235 struct jsonrpc_session
*session
; /* Connection to the server. */
236 enum ovsdb_idl_state state
; /* Current session state. */
237 unsigned int state_seqno
; /* See above. */
238 struct json
*request_id
; /* JSON ID for request awaiting reply. */
246 static void ovsdb_idl_transition_at(struct ovsdb_idl
*, enum ovsdb_idl_state
,
248 #define ovsdb_idl_transition(IDL, STATE) \
249 ovsdb_idl_transition_at(IDL, STATE, OVS_SOURCE_LOCATOR)
251 static void ovsdb_idl_retry_at(struct ovsdb_idl
*, const char *where
);
252 #define ovsdb_idl_retry(IDL) ovsdb_idl_retry_at(IDL, OVS_SOURCE_LOCATOR)
254 struct ovsdb_idl_txn
{
255 struct hmap_node hmap_node
;
256 struct json
*request_id
;
257 struct ovsdb_idl_db
*db
;
258 struct hmap txn_rows
;
259 enum ovsdb_idl_txn_status status
;
265 const char *inc_table
;
266 const char *inc_column
;
269 unsigned int inc_index
;
270 int64_t inc_new_value
;
273 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
276 struct ovsdb_idl_txn_insert
{
277 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
278 struct uuid dummy
; /* Dummy UUID used locally. */
279 int op_index
; /* Index into transaction's operation array. */
280 struct uuid real
; /* Real UUID used by database server. */
283 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
284 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
285 static struct vlog_rate_limit other_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
287 static void ovsdb_idl_clear(struct ovsdb_idl
*);
288 static void ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db
*,
289 const struct json
*result
,
290 bool is_monitor_cond
);
291 static bool ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db
*,
292 const struct jsonrpc_msg
*);
293 static bool ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl
*,
294 struct ovsdb_idl_db
*,
295 const struct jsonrpc_msg
*);
296 static void ovsdb_idl_db_parse_update(struct ovsdb_idl_db
*,
297 const struct json
*table_updates
,
298 bool is_monitor_cond
);
299 static bool ovsdb_idl_process_update(struct ovsdb_idl_table
*,
301 const struct json
*old
,
302 const struct json
*new);
303 static bool ovsdb_idl_process_update2(struct ovsdb_idl_table
*,
305 const char *operation
,
306 const struct json
*row
);
307 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*, const struct json
*);
308 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
309 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*, const struct json
*);
310 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*,
311 const struct json
*);
313 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
314 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
315 const struct ovsdb_idl_table_class
*);
316 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
317 const struct uuid
*);
318 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
319 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db
*);
320 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
321 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*);
323 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
324 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
325 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
326 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
327 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
329 static void ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db
*);
330 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
331 static bool ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db
*,
332 const struct jsonrpc_msg
*msg
);
333 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
335 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
336 const struct ovsdb_idl_column
*,
337 struct ovsdb_datum
*,
339 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*,
340 const struct ovsdb_idl_column
*,
341 struct ovsdb_datum
*,
344 static bool ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db
*,
345 const struct jsonrpc_msg
*);
346 static struct jsonrpc_msg
*ovsdb_idl_db_compose_lock_request(
347 struct ovsdb_idl_db
*);
348 static struct jsonrpc_msg
*ovsdb_idl_db_compose_unlock_request(
349 struct ovsdb_idl_db
*);
350 static void ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db
*,
351 const struct json
*);
352 static bool ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db
*,
353 const struct json
*params
,
355 static struct ovsdb_idl_table
*
356 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db
*,
357 const struct ovsdb_idl_table_class
*);
358 static struct ovsdb_idl_table
*
359 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
360 const struct ovsdb_idl_table_class
*);
361 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
362 static void ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
);
364 static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*);
365 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*);
366 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*);
369 ovsdb_idl_open_session(struct ovsdb_idl
*idl
, const char *remote
, bool retry
)
371 ovs_assert(!idl
->data
.txn
);
372 jsonrpc_session_close(idl
->session
);
374 struct svec remotes
= SVEC_EMPTY_INITIALIZER
;
375 ovsdb_session_parse_remote(remote
, &remotes
, &idl
->cid
);
376 idl
->session
= jsonrpc_session_open_multiple(&remotes
, retry
);
377 svec_destroy(&remotes
);
381 ovsdb_idl_db_init(struct ovsdb_idl_db
*db
, const struct ovsdb_idl_class
*class,
382 struct ovsdb_idl
*parent
, bool monitor_everything_by_default
)
384 memset(db
, 0, sizeof *db
);
386 uint8_t default_mode
= (monitor_everything_by_default
387 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
392 shash_init(&db
->table_by_name
);
393 db
->tables
= xmalloc(class->n_tables
* sizeof *db
->tables
);
394 for (size_t i
= 0; i
< class->n_tables
; i
++) {
395 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
396 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
398 shash_add_assert(&db
->table_by_name
, tc
->name
, table
);
400 table
->modes
= xmalloc(tc
->n_columns
);
401 memset(table
->modes
, default_mode
, tc
->n_columns
);
402 table
->need_table
= false;
403 shash_init(&table
->columns
);
404 ovs_list_init(&table
->indexes
);
405 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
406 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
408 shash_add_assert(&table
->columns
, column
->name
, column
);
410 hmap_init(&table
->rows
);
411 ovs_list_init(&table
->track_list
);
412 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
413 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
414 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
416 ovsdb_idl_condition_init(&table
->condition
);
417 ovsdb_idl_condition_add_clause_true(&table
->condition
);
418 table
->cond_changed
= false;
420 db
->monitor_id
= json_array_create_2(json_string_create("monid"),
421 json_string_create(class->database
));
422 hmap_init(&db
->outstanding_txns
);
425 /* Creates and returns a connection to database 'remote', which should be in a
426 * form acceptable to jsonrpc_session_open(). The connection will maintain an
427 * in-memory replica of the remote database whose schema is described by
428 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
431 * Passes 'retry' to jsonrpc_session_open(). See that function for
434 * If 'monitor_everything_by_default' is true, then everything in the remote
435 * database will be replicated by default. ovsdb_idl_omit() and
436 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
439 * If 'monitor_everything_by_default' is false, then no columns or tables will
440 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
441 * must be used to choose some columns or tables to replicate.
444 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
445 bool monitor_everything_by_default
, bool retry
)
447 struct ovsdb_idl
*idl
;
449 idl
= xzalloc(sizeof *idl
);
450 ovsdb_idl_db_init(&idl
->server
, &serverrec_idl_class
, idl
, true);
451 ovsdb_idl_db_init(&idl
->data
, class, idl
, monitor_everything_by_default
);
452 ovsdb_idl_open_session(idl
, remote
, retry
);
453 idl
->state_seqno
= UINT_MAX
;
454 idl
->request_id
= NULL
;
455 idl
->leader_only
= true;
457 /* Monitor the Database table in the _Server database.
459 * We monitor only the row for 'class', or the row that has the
461 struct ovsdb_idl_condition cond
;
462 ovsdb_idl_condition_init(&cond
);
463 if (!uuid_is_zero(&idl
->cid
)) {
464 serverrec_database_add_clause_cid(&cond
, OVSDB_F_EQ
, &idl
->cid
, 1);
466 serverrec_database_add_clause_name(&cond
, OVSDB_F_EQ
, class->database
);
468 ovsdb_idl_db_set_condition(&idl
->server
, &serverrec_table_database
, &cond
);
469 ovsdb_idl_condition_destroy(&cond
);
474 /* Changes the remote and creates a new session. */
476 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
,
480 ovsdb_idl_open_session(idl
, remote
, retry
);
481 idl
->state_seqno
= UINT_MAX
;
486 ovsdb_idl_db_destroy(struct ovsdb_idl_db
*db
)
488 ovs_assert(!db
->txn
);
489 ovsdb_idl_db_txn_abort_all(db
);
490 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
491 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
492 ovsdb_idl_condition_destroy(&table
->condition
);
493 ovsdb_idl_destroy_indexes(table
);
494 shash_destroy(&table
->columns
);
495 hmap_destroy(&table
->rows
);
498 shash_destroy(&db
->table_by_name
);
500 json_destroy(db
->schema
);
501 hmap_destroy(&db
->outstanding_txns
);
503 json_destroy(db
->lock_request_id
);
504 json_destroy(db
->monitor_id
);
507 /* Destroys 'idl' and all of the data structures that it manages. */
509 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
512 ovsdb_idl_clear(idl
);
513 jsonrpc_session_close(idl
->session
);
515 ovsdb_idl_db_destroy(&idl
->server
);
516 ovsdb_idl_db_destroy(&idl
->data
);
517 json_destroy(idl
->request_id
);
523 ovsdb_idl_set_leader_only(struct ovsdb_idl
*idl
, bool leader_only
)
525 idl
->leader_only
= leader_only
;
526 if (leader_only
&& idl
->server
.monitoring
) {
527 ovsdb_idl_check_server_db(idl
);
532 ovsdb_idl_db_clear(struct ovsdb_idl_db
*db
)
534 bool changed
= false;
537 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
538 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
539 struct ovsdb_idl_row
*row
, *next_row
;
541 table
->cond_changed
= false;
542 if (hmap_is_empty(&table
->rows
)) {
547 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
548 struct ovsdb_idl_arc
*arc
, *next_arc
;
550 if (!ovsdb_idl_row_is_orphan(row
)) {
551 ovsdb_idl_remove_from_indexes(row
);
552 ovsdb_idl_row_unparse(row
);
554 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
557 /* No need to do anything with dst_arcs: some node has those arcs
558 * as forward arcs and will destroy them itself. */
560 if (!ovs_list_is_empty(&row
->track_node
)) {
561 ovs_list_remove(&row
->track_node
);
564 ovsdb_idl_row_destroy(row
);
568 db
->cond_changed
= false;
570 ovsdb_idl_db_track_clear(db
);
578 ovsdb_idl_state_to_string(enum ovsdb_idl_state state
)
581 #define OVSDB_IDL_STATE(NAME) case IDL_S_##NAME: return #NAME;
583 #undef OVSDB_IDL_STATE
584 default: return "<unknown>";
589 ovsdb_idl_retry_at(struct ovsdb_idl
*idl
, const char *where
)
591 if (jsonrpc_session_get_n_remotes(idl
->session
) > 1) {
592 ovsdb_idl_force_reconnect(idl
);
593 ovsdb_idl_transition_at(idl
, IDL_S_RETRY
, where
);
595 ovsdb_idl_transition_at(idl
, IDL_S_ERROR
, where
);
600 ovsdb_idl_transition_at(struct ovsdb_idl
*idl
, enum ovsdb_idl_state new_state
,
603 VLOG_DBG("%s: %s -> %s at %s",
604 jsonrpc_session_get_name(idl
->session
),
605 ovsdb_idl_state_to_string(idl
->state
),
606 ovsdb_idl_state_to_string(new_state
),
608 idl
->state
= new_state
;
612 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
614 ovsdb_idl_db_clear(&idl
->data
);
618 ovsdb_idl_send_request(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*request
)
620 json_destroy(idl
->request_id
);
621 idl
->request_id
= json_clone(request
->id
);
622 jsonrpc_session_send(idl
->session
, request
);
626 ovsdb_idl_restart_fsm(struct ovsdb_idl
*idl
)
628 ovsdb_idl_send_schema_request(idl
, &idl
->server
);
629 ovsdb_idl_transition(idl
, IDL_S_SERVER_SCHEMA_REQUESTED
);
630 idl
->data
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
631 idl
->server
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
635 ovsdb_idl_process_response(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
637 bool ok
= msg
->type
== JSONRPC_REPLY
;
639 && idl
->state
!= IDL_S_SERVER_SCHEMA_REQUESTED
640 && idl
->state
!= IDL_S_SERVER_MONITOR_COND_REQUESTED
641 && idl
->state
!= IDL_S_DATA_MONITOR_COND_REQUESTED
) {
642 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
643 char *s
= jsonrpc_msg_to_string(msg
);
644 VLOG_INFO_RL(&rl
, "%s: received unexpected %s response in "
645 "%s state: %s", jsonrpc_session_get_name(idl
->session
),
646 jsonrpc_msg_type_to_string(msg
->type
),
647 ovsdb_idl_state_to_string(idl
->state
),
650 ovsdb_idl_retry(idl
);
654 switch (idl
->state
) {
655 case IDL_S_SERVER_SCHEMA_REQUESTED
:
657 json_destroy(idl
->server
.schema
);
658 idl
->server
.schema
= json_clone(msg
->result
);
659 ovsdb_idl_send_monitor_request(idl
, &idl
->server
, true);
660 ovsdb_idl_transition(idl
, IDL_S_SERVER_MONITOR_COND_REQUESTED
);
662 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
663 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
667 case IDL_S_SERVER_MONITOR_COND_REQUESTED
:
669 idl
->server
.monitoring
= OVSDB_IDL_MONITORING_COND
;
670 ovsdb_idl_db_parse_monitor_reply(&idl
->server
, msg
->result
, true);
671 if (ovsdb_idl_check_server_db(idl
)) {
672 ovsdb_idl_send_db_change_aware(idl
);
675 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
676 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
680 case IDL_S_DATA_SCHEMA_REQUESTED
:
681 json_destroy(idl
->data
.schema
);
682 idl
->data
.schema
= json_clone(msg
->result
);
683 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, true);
684 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
687 case IDL_S_DATA_MONITOR_COND_REQUESTED
:
689 /* "monitor_cond" not supported. Try "monitor". */
690 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, false);
691 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_REQUESTED
);
693 idl
->data
.monitoring
= OVSDB_IDL_MONITORING_COND
;
694 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
695 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
, true);
699 case IDL_S_DATA_MONITOR_REQUESTED
:
700 idl
->data
.monitoring
= OVSDB_IDL_MONITORING
;
701 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
702 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
, false);
703 idl
->data
.change_seqno
++;
704 ovsdb_idl_clear(idl
);
705 ovsdb_idl_db_parse_update(&idl
->data
, msg
->result
, false);
708 case IDL_S_MONITORING
:
709 /* We don't normally have a request outstanding in this state. If we
710 * do, it's a "monitor_cond_change", which means that the conditional
711 * monitor clauses were updated.
713 * If further condition changes were pending, send them now. */
714 ovsdb_idl_send_cond_change(idl
);
715 idl
->data
.cond_seqno
++;
720 /* Nothing to do in this state. */
729 ovsdb_idl_process_msg(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
731 bool is_response
= (msg
->type
== JSONRPC_REPLY
||
732 msg
->type
== JSONRPC_ERROR
);
734 /* Process a reply to an outstanding request. */
736 && idl
->request_id
&& json_equal(idl
->request_id
, msg
->id
)) {
737 json_destroy(idl
->request_id
);
738 idl
->request_id
= NULL
;
739 ovsdb_idl_process_response(idl
, msg
);
743 /* Process database contents updates. */
744 if (ovsdb_idl_db_parse_update_rpc(&idl
->data
, msg
)) {
747 if (idl
->server
.monitoring
748 && ovsdb_idl_db_parse_update_rpc(&idl
->server
, msg
)) {
749 ovsdb_idl_check_server_db(idl
);
753 if (ovsdb_idl_handle_monitor_canceled(idl
, &idl
->data
, msg
)
754 || (idl
->server
.monitoring
755 && ovsdb_idl_handle_monitor_canceled(idl
, &idl
->server
, msg
))) {
759 /* Process "lock" replies and related notifications. */
760 if (ovsdb_idl_db_process_lock_replies(&idl
->data
, msg
)) {
764 /* Process response to a database transaction we submitted. */
765 if (is_response
&& ovsdb_idl_db_txn_process_reply(&idl
->data
, msg
)) {
769 /* Unknown message. Log at a low level because this can happen if
770 * ovsdb_idl_txn_destroy() is called to destroy a transaction
771 * before we receive the reply.
773 * (We could sort those out from other kinds of unknown messages by
774 * using distinctive IDs for transactions, if it seems valuable to
775 * do so, and then it would be possible to use different log
777 char *s
= jsonrpc_msg_to_string(msg
);
778 VLOG_DBG("%s: received unexpected %s message: %s",
779 jsonrpc_session_get_name(idl
->session
),
780 jsonrpc_msg_type_to_string(msg
->type
), s
);
784 /* Processes a batch of messages from the database server on 'idl'. This may
785 * cause the IDL's contents to change. The client may check for that with
786 * ovsdb_idl_get_seqno(). */
788 ovsdb_idl_run(struct ovsdb_idl
*idl
)
792 ovs_assert(!idl
->data
.txn
);
794 ovsdb_idl_send_cond_change(idl
);
796 jsonrpc_session_run(idl
->session
);
797 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
798 struct jsonrpc_msg
*msg
;
801 seqno
= jsonrpc_session_get_seqno(idl
->session
);
802 if (idl
->state_seqno
!= seqno
) {
803 idl
->state_seqno
= seqno
;
804 ovsdb_idl_txn_abort_all(idl
);
805 ovsdb_idl_restart_fsm(idl
);
807 if (idl
->data
.lock_name
) {
808 jsonrpc_session_send(
810 ovsdb_idl_db_compose_lock_request(&idl
->data
));
814 msg
= jsonrpc_session_recv(idl
->session
);
818 ovsdb_idl_process_msg(idl
, msg
);
819 jsonrpc_msg_destroy(msg
);
821 ovsdb_idl_row_destroy_postprocess(&idl
->data
);
824 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
825 * do or when activity occurs on a transaction on 'idl'. */
827 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
829 jsonrpc_session_wait(idl
->session
);
830 jsonrpc_session_recv_wait(idl
->session
);
833 /* Returns a "sequence number" that represents the state of 'idl'. When
834 * ovsdb_idl_run() changes the database, the sequence number changes. The
835 * initial fetch of the entire contents of the remote database is considered to
836 * be one kind of change. Successfully acquiring a lock, if one has been
837 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
839 * As long as the sequence number does not change, the client may continue to
840 * use any data structures it obtains from 'idl'. But when it changes, the
841 * client must not access any of these data structures again, because they
842 * could have freed or reused for other purposes.
844 * The sequence number can occasionally change even if the database does not.
845 * This happens if the connection to the database drops and reconnects, which
846 * causes the database contents to be reloaded even if they didn't change. (It
847 * could also happen if the database server sends out a "change" that reflects
848 * what the IDL already thought was in the database. The database server is
849 * not supposed to do that, but bugs could in theory cause it to do so.) */
851 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
853 return idl
->data
.change_seqno
;
856 /* Returns a "sequence number" that represents the number of conditional
857 * monitoring updates successfully received by the OVSDB server of an IDL
860 * ovsdb_idl_set_condition() sets a new condition that is different from
861 * the current condtion, the next expected "sequence number" is returned.
863 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
864 * the return value of ovsdb_idl_set_condition(), The client is
866 * - The ovsdb_idl_set_condition() changes has been acknowledged by
869 * - 'idl' now contains the content matches the new conditions. */
871 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl
*idl
)
873 return idl
->data
.cond_seqno
;
876 /* Returns true if 'idl' successfully connected to the remote database and
877 * retrieved its contents (even if the connection subsequently dropped and is
878 * in the process of reconnecting). If so, then 'idl' contains an atomic
879 * snapshot of the database's contents (but it might be arbitrarily old if the
880 * connection dropped).
882 * Returns false if 'idl' has never connected or retrieved the database's
883 * contents. If so, 'idl' is empty. */
885 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
887 return ovsdb_idl_get_seqno(idl
) != 0;
890 /* Reconfigures 'idl' so that it would reconnect to the database, if
891 * connection was dropped. */
893 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
895 jsonrpc_session_enable_reconnect(idl
->session
);
898 /* Forces 'idl' to drop its connection to the database and reconnect. In the
899 * meantime, the contents of 'idl' will not change. */
901 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
903 jsonrpc_session_force_reconnect(idl
->session
);
906 /* Some IDL users should only write to write-only columns. Furthermore,
907 * writing to a column which is not write-only can cause serious performance
908 * degradations for these users. This function causes 'idl' to reject writes
909 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
911 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
913 idl
->data
.verify_write_only
= true;
916 /* Returns true if 'idl' is currently connected or trying to connect
917 * and a negative response to a schema request has not been received */
919 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
921 return jsonrpc_session_is_alive(idl
->session
) &&
922 idl
->state
!= IDL_S_ERROR
;
926 ovsdb_idl_is_connected(const struct ovsdb_idl
*idl
)
928 return idl
->session
&& jsonrpc_session_is_connected(idl
->session
);
931 /* Returns the last error reported on a connection by 'idl'. The return value
932 * is 0 only if no connection made by 'idl' has ever encountered an error and
933 * a negative response to a schema request has never been received. See
934 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
937 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
941 err
= jsonrpc_session_get_last_error(idl
->session
);
945 } else if (idl
->state
== IDL_S_ERROR
) {
952 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
956 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
958 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
962 find_uuid_in_array(const struct uuid
*target
,
963 const struct uuid
*array
, size_t n
)
965 for (size_t i
= 0; i
< n
; i
++) {
966 if (uuid_equals(&array
[i
], target
)) {
974 array_contains_uuid(const struct uuid
*target
,
975 const struct uuid
*array
, size_t n
)
977 return find_uuid_in_array(target
, array
, n
) != SIZE_MAX
;
981 remove_uuid_from_array(const struct uuid
*target
,
982 struct uuid
*array
, size_t *n
)
984 size_t i
= find_uuid_in_array(target
, array
, *n
);
986 array
[i
] = array
[--*n
];
994 add_row_references(const struct ovsdb_base_type
*type
,
995 const union ovsdb_atom
*atoms
, size_t n_atoms
,
996 const struct uuid
*exclude_uuid
,
997 struct uuid
**dstsp
, size_t *n_dstsp
,
998 size_t *allocated_dstsp
)
1000 if (type
->type
!= OVSDB_TYPE_UUID
|| !type
->uuid
.refTableName
) {
1004 for (size_t i
= 0; i
< n_atoms
; i
++) {
1005 const struct uuid
*uuid
= &atoms
[i
].uuid
;
1006 if (!uuid_equals(uuid
, exclude_uuid
)
1007 && !array_contains_uuid(uuid
, *dstsp
, *n_dstsp
)) {
1008 if (*n_dstsp
>= *allocated_dstsp
) {
1009 *dstsp
= x2nrealloc(*dstsp
, allocated_dstsp
,
1013 (*dstsp
)[*n_dstsp
] = *uuid
;
1019 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
1020 * reference from one row to a different row should be reflected as a "struct
1021 * ovsdb_idl_arc" between those rows.
1023 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
1024 * thus it is only for use in test programs. */
1026 ovsdb_idl_check_consistency(const struct ovsdb_idl
*idl
)
1028 /* Consistency is broken while a transaction is in progress. */
1029 if (!idl
->data
.txn
) {
1035 struct uuid
*dsts
= NULL
;
1036 size_t allocated_dsts
= 0;
1038 for (size_t i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1039 const struct ovsdb_idl_table
*table
= &idl
->data
.tables
[i
];
1040 const struct ovsdb_idl_table_class
*class = table
->class_
;
1042 const struct ovsdb_idl_row
*row
;
1043 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
1045 if (row
->new_datum
) {
1046 size_t n_columns
= shash_count(&row
->table
->columns
);
1047 for (size_t j
= 0; j
< n_columns
; j
++) {
1048 const struct ovsdb_type
*type
= &class->columns
[j
].type
;
1049 const struct ovsdb_datum
*datum
= &row
->new_datum
[j
];
1050 add_row_references(&type
->key
,
1051 datum
->keys
, datum
->n
, &row
->uuid
,
1052 &dsts
, &n_dsts
, &allocated_dsts
);
1053 add_row_references(&type
->value
,
1054 datum
->values
, datum
->n
, &row
->uuid
,
1055 &dsts
, &n_dsts
, &allocated_dsts
);
1058 const struct ovsdb_idl_arc
*arc
;
1059 LIST_FOR_EACH (arc
, src_node
, &row
->src_arcs
) {
1060 if (!remove_uuid_from_array(&arc
->dst
->uuid
,
1062 VLOG_ERR("unexpected arc from %s row "UUID_FMT
" to %s "
1064 table
->class_
->name
,
1065 UUID_ARGS(&row
->uuid
),
1066 arc
->dst
->table
->class_
->name
,
1067 UUID_ARGS(&arc
->dst
->uuid
));
1071 for (size_t j
= 0; j
< n_dsts
; j
++) {
1072 VLOG_ERR("%s row "UUID_FMT
" missing arc to row "UUID_FMT
,
1073 table
->class_
->name
, UUID_ARGS(&row
->uuid
),
1074 UUID_ARGS(&dsts
[j
]));
1083 const struct ovsdb_idl_class
*
1084 ovsdb_idl_get_class(const struct ovsdb_idl
*idl
)
1086 return idl
->data
.class_
;
1089 /* Given 'column' in some table in 'class', returns the table's class. */
1090 const struct ovsdb_idl_table_class
*
1091 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class
*class,
1092 const struct ovsdb_idl_column
*column
)
1094 for (size_t i
= 0; i
< class->n_tables
; i
++) {
1095 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
1096 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
1104 /* Given 'column' in some table in 'db', returns the table. */
1105 static struct ovsdb_idl_table
*
1106 ovsdb_idl_table_from_column(struct ovsdb_idl_db
*db
,
1107 const struct ovsdb_idl_column
*column
)
1109 const struct ovsdb_idl_table_class
*tc
=
1110 ovsdb_idl_table_class_from_column(db
->class_
, column
);
1111 return &db
->tables
[tc
- db
->class_
->tables
];
1114 static unsigned char *
1115 ovsdb_idl_db_get_mode(struct ovsdb_idl_db
*db
,
1116 const struct ovsdb_idl_column
*column
)
1118 ovs_assert(!db
->change_seqno
);
1120 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1122 return &table
->modes
[column
- table
->class_
->columns
];
1126 ovsdb_idl_db_set_mode(struct ovsdb_idl_db
*db
,
1127 const struct ovsdb_idl_column
*column
,
1130 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1132 size_t column_idx
= column
- table
->class_
->columns
;
1134 if (table
->modes
[column_idx
] != mode
) {
1135 *ovsdb_idl_db_get_mode(db
, column
) = mode
;
1140 add_ref_table(struct ovsdb_idl_db
*db
, const struct ovsdb_base_type
*base
)
1142 if (base
->type
== OVSDB_TYPE_UUID
&& base
->uuid
.refTableName
) {
1143 struct ovsdb_idl_table
*table
;
1145 table
= shash_find_data(&db
->table_by_name
, base
->uuid
.refTableName
);
1147 table
->need_table
= true;
1149 VLOG_WARN("%s IDL class missing referenced table %s",
1150 db
->class_
->database
, base
->uuid
.refTableName
);
1156 ovsdb_idl_db_add_column(struct ovsdb_idl_db
*db
,
1157 const struct ovsdb_idl_column
*column
)
1159 ovsdb_idl_db_set_mode(db
, column
, OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
);
1160 add_ref_table(db
, &column
->type
.key
);
1161 add_ref_table(db
, &column
->type
.value
);
1164 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
1165 * ensures that any tables referenced by 'column' will be replicated, even if
1166 * no columns in that table are selected for replication (see
1167 * ovsdb_idl_add_table() for more information).
1169 * This function is only useful if 'monitor_everything_by_default' was false in
1170 * the call to ovsdb_idl_create(). This function should be called between
1171 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1174 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
1175 const struct ovsdb_idl_column
*column
)
1177 ovsdb_idl_db_add_column(&idl
->data
, column
);
1181 ovsdb_idl_db_add_table(struct ovsdb_idl_db
*db
,
1182 const struct ovsdb_idl_table_class
*tc
)
1186 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1187 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1189 if (table
->class_
== tc
) {
1190 table
->need_table
= true;
1198 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
1199 * no columns are selected for replication. Just the necessary data for table
1200 * references will be replicated (the UUID of the rows, for instance), any
1201 * columns not selected for replication will remain unreplicated.
1202 * This can be useful because it allows 'idl' to keep track of what rows in the
1203 * table actually exist, which in turn allows columns that reference the table
1204 * to have accurate contents. (The IDL presents the database with references to
1205 * rows that do not exist removed.)
1207 * This function is only useful if 'monitor_everything_by_default' was false in
1208 * the call to ovsdb_idl_create(). This function should be called between
1209 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1212 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
1213 const struct ovsdb_idl_table_class
*tc
)
1215 ovsdb_idl_db_add_table(&idl
->data
, tc
);
1218 /* A single clause within an ovsdb_idl_condition. */
1219 struct ovsdb_idl_clause
{
1220 struct hmap_node hmap_node
; /* In struct ovsdb_idl_condition. */
1221 enum ovsdb_function function
; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
1222 const struct ovsdb_idl_column
*column
; /* Must be nonnull. */
1223 struct ovsdb_datum arg
; /* Has ovsdb_type ->column->type. */
1227 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause
*clause
)
1229 uint32_t hash
= hash_pointer(clause
->column
, clause
->function
);
1230 return ovsdb_datum_hash(&clause
->arg
, &clause
->column
->type
, hash
);
1234 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause
*a
,
1235 const struct ovsdb_idl_clause
*b
)
1237 return (a
->function
== b
->function
1238 && a
->column
== b
->column
1239 && ovsdb_datum_equals(&a
->arg
, &b
->arg
, &a
->column
->type
));
1242 static struct json
*
1243 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
1245 const char *function
= ovsdb_function_to_string(clause
->function
);
1246 return json_array_create_3(json_string_create(clause
->column
->name
),
1247 json_string_create(function
),
1248 ovsdb_datum_to_json(&clause
->arg
,
1249 &clause
->column
->type
));
1253 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause
*clause
)
1256 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
1261 /* ovsdb_idl_condition. */
1264 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
)
1266 hmap_init(&cnd
->clauses
);
1267 cnd
->is_true
= false;
1271 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition
*cond
)
1274 ovsdb_idl_condition_clear(cond
);
1275 hmap_destroy(&cond
->clauses
);
1280 ovsdb_idl_condition_clear(struct ovsdb_idl_condition
*cond
)
1282 struct ovsdb_idl_clause
*clause
, *next
;
1283 HMAP_FOR_EACH_SAFE (clause
, next
, hmap_node
, &cond
->clauses
) {
1284 hmap_remove(&cond
->clauses
, &clause
->hmap_node
);
1285 ovsdb_idl_clause_destroy(clause
);
1287 cond
->is_true
= false;
1291 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition
*condition
)
1293 return condition
->is_true
;
1296 static struct ovsdb_idl_clause
*
1297 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition
*condition
,
1298 const struct ovsdb_idl_clause
*target
,
1301 struct ovsdb_idl_clause
*clause
;
1302 HMAP_FOR_EACH_WITH_HASH (clause
, hmap_node
, hash
, &condition
->clauses
) {
1303 if (ovsdb_idl_clause_equals(clause
, target
)) {
1311 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition
*condition
,
1312 const struct ovsdb_idl_clause
*src
,
1315 struct ovsdb_idl_clause
*clause
= xmalloc(sizeof *clause
);
1316 clause
->function
= src
->function
;
1317 clause
->column
= src
->column
;
1318 ovsdb_datum_clone(&clause
->arg
, &src
->arg
, &src
->column
->type
);
1319 hmap_insert(&condition
->clauses
, &clause
->hmap_node
, hash
);
1322 /* Adds a clause to the condition for replicating the table with class 'tc' in
1325 * The IDL replicates only rows in a table that satisfy at least one clause in
1326 * the table's condition. The default condition for a table has a single
1327 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1328 * the table. When the IDL client replaces the default condition by one of its
1329 * own, the condition can have any number of clauses. If it has no conditions,
1330 * then no rows are replicated.
1332 * Two distinct of clauses can usefully be added:
1334 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1335 * replicated, regardless of whether other clauses exist. 'column' and
1336 * 'arg' are ignored.
1338 * - Binary 'functions' add a clause of the form "<column> <function>
1339 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1340 * have a type that is compatible with 'column'.
1343 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition
*condition
,
1344 enum ovsdb_function function
,
1345 const struct ovsdb_idl_column
*column
,
1346 const struct ovsdb_datum
*arg
)
1348 if (condition
->is_true
) {
1349 /* Adding a clause to an always-true condition has no effect. */
1350 } else if (function
== OVSDB_F_TRUE
) {
1351 ovsdb_idl_condition_add_clause_true(condition
);
1352 } else if (function
== OVSDB_F_FALSE
) {
1353 /* Adding a "false" clause never has any effect. */
1355 struct ovsdb_idl_clause clause
= {
1356 .function
= function
,
1360 uint32_t hash
= ovsdb_idl_clause_hash(&clause
);
1361 if (!ovsdb_idl_condition_find_clause(condition
, &clause
, hash
)) {
1362 ovsdb_idl_condition_add_clause__(condition
, &clause
, hash
);
1368 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition
*condition
)
1370 if (!condition
->is_true
) {
1371 ovsdb_idl_condition_clear(condition
);
1372 condition
->is_true
= true;
1377 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition
*a
,
1378 const struct ovsdb_idl_condition
*b
)
1380 if (hmap_count(&a
->clauses
) != hmap_count(&b
->clauses
)) {
1383 if (a
->is_true
!= b
->is_true
) {
1387 const struct ovsdb_idl_clause
*clause
;
1388 HMAP_FOR_EACH (clause
, hmap_node
, &a
->clauses
) {
1389 if (!ovsdb_idl_condition_find_clause(b
, clause
,
1390 clause
->hmap_node
.hash
)) {
1398 ovsdb_idl_condition_clone(struct ovsdb_idl_condition
*dst
,
1399 const struct ovsdb_idl_condition
*src
)
1401 ovsdb_idl_condition_init(dst
);
1403 dst
->is_true
= src
->is_true
;
1405 const struct ovsdb_idl_clause
*clause
;
1406 HMAP_FOR_EACH (clause
, hmap_node
, &src
->clauses
) {
1407 ovsdb_idl_condition_add_clause__(dst
, clause
, clause
->hmap_node
.hash
);
1412 ovsdb_idl_db_set_condition(struct ovsdb_idl_db
*db
,
1413 const struct ovsdb_idl_table_class
*tc
,
1414 const struct ovsdb_idl_condition
*condition
)
1416 struct ovsdb_idl_table
*table
= ovsdb_idl_db_table_from_class(db
, tc
);
1417 unsigned int seqno
= db
->cond_seqno
;
1418 if (!ovsdb_idl_condition_equals(condition
, &table
->condition
)) {
1419 ovsdb_idl_condition_destroy(&table
->condition
);
1420 ovsdb_idl_condition_clone(&table
->condition
, condition
);
1421 db
->cond_changed
= table
->cond_changed
= true;
1422 poll_immediate_wake();
1429 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1430 * arranges to send the new condition to the database server.
1432 * Return the next conditional update sequence number. When this
1433 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1434 * contains rows that match the 'condition'. */
1436 ovsdb_idl_set_condition(struct ovsdb_idl
*idl
,
1437 const struct ovsdb_idl_table_class
*tc
,
1438 const struct ovsdb_idl_condition
*condition
)
1440 return ovsdb_idl_db_set_condition(&idl
->data
, tc
, condition
);
1443 static struct json
*
1444 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
1447 return json_array_create_empty();
1450 size_t n
= hmap_count(&cnd
->clauses
);
1452 return json_array_create_1(json_boolean_create(false));
1455 struct json
**clauses
= xmalloc(n
* sizeof *clauses
);
1456 const struct ovsdb_idl_clause
*clause
;
1458 HMAP_FOR_EACH (clause
, hmap_node
, &cnd
->clauses
) {
1459 clauses
[i
++] = ovsdb_idl_clause_to_json(clause
);
1462 return json_array_create(clauses
, n
);
1465 static struct json
*
1466 ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table
*table
)
1468 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
1469 struct json
*monitor_cond_change_request
= json_object_create();
1470 struct json
*cond_json
= ovsdb_idl_condition_to_json(cond
);
1472 json_object_put(monitor_cond_change_request
, "where", cond_json
);
1474 return monitor_cond_change_request
;
1477 static struct jsonrpc_msg
*
1478 ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db
*db
)
1480 if (!db
->cond_changed
) {
1484 struct json
*monitor_cond_change_requests
= NULL
;
1485 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1486 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1488 if (table
->cond_changed
) {
1489 struct json
*req
= ovsdb_idl_create_cond_change_req(table
);
1491 if (!monitor_cond_change_requests
) {
1492 monitor_cond_change_requests
= json_object_create();
1494 json_object_put(monitor_cond_change_requests
,
1495 table
->class_
->name
,
1496 json_array_create_1(req
));
1498 table
->cond_changed
= false;
1502 if (!monitor_cond_change_requests
) {
1506 db
->cond_changed
= false;
1507 struct json
*params
= json_array_create_3(json_clone(db
->monitor_id
),
1508 json_clone(db
->monitor_id
),
1509 monitor_cond_change_requests
);
1510 return jsonrpc_create_request("monitor_cond_change", params
, NULL
);
1514 ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
)
1516 /* When 'idl->request_id' is not NULL, there is an outstanding
1517 * conditional monitoring update request that we have not heard
1518 * from the server yet. Don't generate another request in this case. */
1519 if (!jsonrpc_session_is_connected(idl
->session
)
1520 || idl
->data
.monitoring
!= OVSDB_IDL_MONITORING_COND
1521 || idl
->request_id
) {
1525 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_cond_change(&idl
->data
);
1527 idl
->request_id
= json_clone(msg
->id
);
1528 jsonrpc_session_send(idl
->session
, msg
);
1532 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'db'.
1534 * This function should be called between ovsdb_idl_create() and the first call
1535 * to ovsdb_idl_run().
1538 ovsdb_idl_db_omit_alert(struct ovsdb_idl_db
*db
,
1539 const struct ovsdb_idl_column
*column
)
1541 *ovsdb_idl_db_get_mode(db
, column
) &= ~(OVSDB_IDL_ALERT
| OVSDB_IDL_TRACK
);
1544 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'idl'.
1546 * This function should be called between ovsdb_idl_create() and the first call
1547 * to ovsdb_idl_run().
1550 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
1551 const struct ovsdb_idl_column
*column
)
1553 ovsdb_idl_db_omit_alert(&idl
->data
, column
);
1557 ovsdb_idl_db_omit(struct ovsdb_idl_db
*db
,
1558 const struct ovsdb_idl_column
*column
)
1560 *ovsdb_idl_db_get_mode(db
, column
) = 0;
1563 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1564 * OVSDB_IDL_MONITOR for details.
1566 * This function should be called between ovsdb_idl_create() and the first call
1567 * to ovsdb_idl_run().
1570 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
1572 ovsdb_idl_db_omit(&idl
->data
, column
);
1575 /* Returns the most recent IDL change sequence number that caused a
1576 * insert, modify or delete update to the table with class 'table_class'.
1579 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
1580 const struct ovsdb_idl_table_class
*table_class
)
1582 struct ovsdb_idl_table
*table
1583 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1584 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
1586 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
1587 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
1589 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
1590 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
1595 /* For each row that contains tracked columns, IDL stores the most
1596 * recent IDL change sequence numbers associateed with insert, modify
1597 * and delete updates to the table.
1600 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
1601 enum ovsdb_idl_change change
)
1603 return row
->change_seqno
[change
];
1606 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1607 * all rows whose 'column' is modified are traced. Similarly, insert
1608 * or delete of rows having 'column' are tracked. Clients are able
1609 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1612 * This function should be called between ovsdb_idl_create() and
1613 * the first call to ovsdb_idl_run(). The column to be tracked
1614 * should have OVSDB_IDL_ALERT turned on.
1617 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1618 const struct ovsdb_idl_column
*column
)
1620 if (!(*ovsdb_idl_db_get_mode(&idl
->data
, column
) & OVSDB_IDL_ALERT
)) {
1621 ovsdb_idl_add_column(idl
, column
);
1623 *ovsdb_idl_db_get_mode(&idl
->data
, column
) |= OVSDB_IDL_TRACK
;
1627 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1631 for (i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1632 const struct ovsdb_idl_table_class
*tc
= &idl
->data
.class_
->tables
[i
];
1634 for (j
= 0; j
< tc
->n_columns
; j
++) {
1635 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1636 ovsdb_idl_track_add_column(idl
, column
);
1641 /* Returns true if 'table' has any tracked column. */
1643 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1647 for (i
= 0; i
< table
->class_
->n_columns
; i
++) {
1648 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1655 /* Returns the first tracked row in table with class 'table_class'
1656 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1657 const struct ovsdb_idl_row
*
1658 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1659 const struct ovsdb_idl_table_class
*table_class
)
1661 struct ovsdb_idl_table
*table
1662 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1664 if (!ovs_list_is_empty(&table
->track_list
)) {
1665 return CONTAINER_OF(ovs_list_front(&table
->track_list
), struct ovsdb_idl_row
, track_node
);
1670 /* Returns the next tracked row in table after the specified 'row'
1671 * (in no particular order). Returns NULL if there are no tracked rows */
1672 const struct ovsdb_idl_row
*
1673 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1675 if (row
->track_node
.next
!= &row
->table
->track_list
) {
1676 return CONTAINER_OF(row
->track_node
.next
, struct ovsdb_idl_row
, track_node
);
1682 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1683 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1685 * Function returns false if 'column' is not tracked (see
1686 * ovsdb_idl_track_add_column()).
1689 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1690 const struct ovsdb_idl_column
*column
)
1692 const struct ovsdb_idl_table_class
*class;
1695 class = row
->table
->class_
;
1696 column_idx
= column
- class->columns
;
1698 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1705 /* Flushes the tracked rows. Client calls this function after calling
1706 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1707 * functions. This is usually done at the end of the client's processing
1708 * loop when it is ready to do ovsdb_idl_run() again.
1711 ovsdb_idl_db_track_clear(struct ovsdb_idl_db
*db
)
1715 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1716 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1718 if (!ovs_list_is_empty(&table
->track_list
)) {
1719 struct ovsdb_idl_row
*row
, *next
;
1721 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1724 row
->updated
= NULL
;
1726 ovs_list_remove(&row
->track_node
);
1727 ovs_list_init(&row
->track_node
);
1728 if (ovsdb_idl_row_is_orphan(row
)) {
1736 /* Flushes the tracked rows. Client calls this function after calling
1737 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1738 * functions. This is usually done at the end of the client's processing
1739 * loop when it is ready to do ovsdb_idl_run() again.
1742 ovsdb_idl_track_clear(struct ovsdb_idl
*idl
)
1744 ovsdb_idl_db_track_clear(&idl
->data
);
1748 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
,
1749 struct ovsdb_idl_db
*db
)
1751 ovsdb_idl_send_request(idl
, jsonrpc_create_request(
1753 json_array_create_1(json_string_create(
1754 db
->class_
->database
)),
1759 ovsdb_idl_send_db_change_aware(struct ovsdb_idl
*idl
)
1761 struct jsonrpc_msg
*msg
= jsonrpc_create_request(
1762 "set_db_change_aware", json_array_create_1(json_boolean_create(true)),
1764 jsonrpc_session_send(idl
->session
, msg
);
1768 ovsdb_idl_check_server_db(struct ovsdb_idl
*idl
)
1770 const struct serverrec_database
*database
;
1771 SERVERREC_DATABASE_FOR_EACH (database
, idl
) {
1772 if (uuid_is_zero(&idl
->cid
)
1773 ? !strcmp(database
->name
, idl
->data
.class_
->database
)
1774 : database
->n_cid
&& uuid_equals(database
->cid
, &idl
->cid
)) {
1779 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
1780 const char *server_name
= jsonrpc_session_get_name(idl
->session
);
1783 VLOG_INFO_RL(&rl
, "%s: server does not have %s database",
1784 server_name
, idl
->data
.class_
->database
);
1785 } else if (!strcmp(database
->model
, "clustered")
1786 && jsonrpc_session_get_n_remotes(idl
->session
) > 1) {
1787 uint64_t index
= database
->n_index
? *database
->index
: 0;
1789 if (!database
->schema
) {
1790 VLOG_INFO("%s: clustered database server has not yet joined "
1791 "cluster; trying another server", server_name
);
1792 } else if (!database
->connected
) {
1793 VLOG_INFO("%s: clustered database server is disconnected "
1794 "from cluster; trying another server", server_name
);
1795 } else if (idl
->leader_only
&& !database
->leader
) {
1796 VLOG_INFO("%s: clustered database server is not cluster "
1797 "leader; trying another server", server_name
);
1798 } else if (index
< idl
->min_index
) {
1799 VLOG_WARN("%s: clustered database server has stale data; "
1800 "trying another server", server_name
);
1802 idl
->min_index
= MAX(idl
->min_index
, index
);
1809 ovsdb_idl_retry(idl
);
1813 if (idl
->state
== IDL_S_SERVER_MONITOR_COND_REQUESTED
) {
1814 json_destroy(idl
->data
.schema
);
1815 idl
->data
.schema
= json_from_string(database
->schema
);
1816 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, true);
1817 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
1823 log_error(struct ovsdb_error
*error
)
1825 char *s
= ovsdb_error_to_string_free(error
);
1826 VLOG_WARN("error parsing database schema: %s", s
);
1830 /* Frees 'schema', which is in the format returned by parse_schema(). */
1832 free_schema(struct shash
*schema
)
1835 struct shash_node
*node
, *next
;
1837 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
1838 struct sset
*sset
= node
->data
;
1841 shash_delete(schema
, node
);
1843 shash_destroy(schema
);
1848 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1849 * 7047, to obtain the names of its rows and columns. If successful, returns
1850 * an shash whose keys are table names and whose values are ssets, where each
1851 * sset contains the names of its table's columns. On failure (due to a parse
1852 * error), returns NULL.
1854 * It would also be possible to use the general-purpose OVSDB schema parser in
1855 * ovsdb-server, but that's overkill, possibly too strict for the current use
1856 * case, and would require restructuring ovsdb-server to separate the schema
1857 * code from the rest. */
1858 static struct shash
*
1859 parse_schema(const struct json
*schema_json
)
1861 struct ovsdb_parser parser
;
1862 const struct json
*tables_json
;
1863 struct ovsdb_error
*error
;
1864 struct shash_node
*node
;
1865 struct shash
*schema
;
1867 ovsdb_parser_init(&parser
, schema_json
, "database schema");
1868 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
1869 error
= ovsdb_parser_destroy(&parser
);
1875 schema
= xmalloc(sizeof *schema
);
1877 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
1878 const char *table_name
= node
->name
;
1879 const struct json
*json
= node
->data
;
1880 const struct json
*columns_json
;
1882 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
1884 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
1885 error
= ovsdb_parser_destroy(&parser
);
1888 free_schema(schema
);
1892 struct sset
*columns
= xmalloc(sizeof *columns
);
1895 struct shash_node
*node2
;
1896 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
1897 const char *column_name
= node2
->name
;
1898 sset_add(columns
, column_name
);
1900 shash_add(schema
, table_name
, columns
);
1906 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
, struct ovsdb_idl_db
*db
,
1907 bool use_monitor_cond
)
1909 struct shash
*schema
= parse_schema(db
->schema
);
1910 struct json
*monitor_requests
= json_object_create();
1912 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1913 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1914 const struct ovsdb_idl_table_class
*tc
= table
->class_
;
1915 struct json
*monitor_request
;
1916 const struct sset
*table_schema
1917 = schema
? shash_find_data(schema
, table
->class_
->name
) : NULL
;
1919 struct json
*columns
1920 = table
->need_table
? json_array_create_empty() : NULL
;
1921 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
1922 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1923 bool db_has_column
= (table_schema
&&
1924 sset_contains(table_schema
, column
->name
));
1925 if (column
->is_synthetic
) {
1926 if (db_has_column
) {
1927 VLOG_WARN("%s table in %s database has synthetic "
1928 "column %s", table
->class_
->name
,
1929 db
->class_
->database
, column
->name
);
1931 } else if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
1932 if (table_schema
&& !db_has_column
) {
1933 VLOG_WARN("%s table in %s database lacks %s column "
1934 "(database needs upgrade?)",
1935 table
->class_
->name
, db
->class_
->database
,
1940 columns
= json_array_create_empty();
1942 json_array_add(columns
, json_string_create(column
->name
));
1947 if (schema
&& !table_schema
) {
1948 VLOG_WARN("%s database lacks %s table "
1949 "(database needs upgrade?)",
1950 db
->class_
->database
, table
->class_
->name
);
1951 json_destroy(columns
);
1955 monitor_request
= json_object_create();
1956 json_object_put(monitor_request
, "columns", columns
);
1958 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
1959 if (use_monitor_cond
&& !ovsdb_idl_condition_is_true(cond
)) {
1960 json_object_put(monitor_request
, "where",
1961 ovsdb_idl_condition_to_json(cond
));
1962 table
->cond_changed
= false;
1964 json_object_put(monitor_requests
, tc
->name
,
1965 json_array_create_1(monitor_request
));
1968 free_schema(schema
);
1970 db
->cond_changed
= false;
1972 ovsdb_idl_send_request(
1974 jsonrpc_create_request(
1975 use_monitor_cond
? "monitor_cond" : "monitor",
1976 json_array_create_3(json_string_create(db
->class_
->database
),
1977 json_clone(db
->monitor_id
), monitor_requests
),
1982 log_parse_update_error(struct ovsdb_error
*error
)
1984 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1985 char *s
= ovsdb_error_to_string(error
);
1986 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1989 ovsdb_error_destroy(error
);
1993 ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db
*db
,
1994 const struct json
*result
,
1995 bool is_monitor_cond
)
1998 ovsdb_idl_db_clear(db
);
1999 ovsdb_idl_db_parse_update(db
, result
, is_monitor_cond
);
2003 ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db
*db
,
2004 const struct jsonrpc_msg
*msg
)
2006 if (msg
->type
== JSONRPC_NOTIFY
) {
2007 bool is_update
= !strcmp(msg
->method
, "update");
2008 bool is_update2
= !strcmp(msg
->method
, "update2");
2009 if ((is_update
|| is_update2
)
2010 && msg
->params
->type
== JSON_ARRAY
2011 && msg
->params
->array
.n
== 2
2012 && json_equal(msg
->params
->array
.elems
[0], db
->monitor_id
)) {
2013 ovsdb_idl_db_parse_update(db
, msg
->params
->array
.elems
[1],
2022 ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl
*idl
,
2023 struct ovsdb_idl_db
*db
,
2024 const struct jsonrpc_msg
*msg
)
2026 if (msg
->type
!= JSONRPC_NOTIFY
2027 || strcmp(msg
->method
, "monitor_canceled")
2028 || msg
->params
->type
!= JSON_ARRAY
2029 || msg
->params
->array
.n
!= 1
2030 || !json_equal(msg
->params
->array
.elems
[0], db
->monitor_id
)) {
2034 db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2036 /* Cancel the other monitor and restart the FSM from the top.
2038 * Maybe a more sophisticated response would be better in some cases, but
2039 * it doesn't seem worth optimizing yet. (Although this is already more
2040 * sophisticated than just dropping the connection and reconnecting.) */
2041 struct ovsdb_idl_db
*other_db
2042 = db
== &idl
->data
? &idl
->server
: &idl
->data
;
2043 if (other_db
->monitoring
) {
2044 jsonrpc_session_send(
2046 jsonrpc_create_request(
2048 json_array_create_1(json_clone(other_db
->monitor_id
)), NULL
));
2049 other_db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2051 ovsdb_idl_restart_fsm(idl
);
2056 static struct ovsdb_error
*
2057 ovsdb_idl_db_parse_update__(struct ovsdb_idl_db
*db
,
2058 const struct json
*table_updates
,
2059 bool is_monitor_cond
)
2061 const struct shash_node
*tables_node
;
2062 const char *version_suffix
= is_monitor_cond
? "2" : "";
2064 if (table_updates
->type
!= JSON_OBJECT
) {
2065 return ovsdb_syntax_error(table_updates
, NULL
,
2066 "<table_updates%s> is not an object",
2070 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
2071 const struct json
*table_update
= tables_node
->data
;
2072 const struct shash_node
*table_node
;
2073 struct ovsdb_idl_table
*table
;
2075 table
= shash_find_data(&db
->table_by_name
, tables_node
->name
);
2077 return ovsdb_syntax_error(
2078 table_updates
, NULL
,
2079 "<table_updates%s> includes unknown table \"%s\"",
2080 version_suffix
, tables_node
->name
);
2083 if (table_update
->type
!= JSON_OBJECT
) {
2084 return ovsdb_syntax_error(table_update
, NULL
,
2085 "<table_update%s> for table \"%s\" is "
2087 version_suffix
, table
->class_
->name
);
2089 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
2090 const struct json
*row_update
= table_node
->data
;
2093 if (!uuid_from_string(&uuid
, table_node
->name
)) {
2094 return ovsdb_syntax_error(table_update
, NULL
,
2095 "<table_update%s> for table \"%s\" "
2096 "contains bad UUID "
2097 "\"%s\" as member name",
2099 table
->class_
->name
,
2102 if (row_update
->type
!= JSON_OBJECT
) {
2103 return ovsdb_syntax_error(row_update
, NULL
,
2104 "<table_update%s> for table \"%s\" "
2105 "contains <row_update%s> for %s "
2106 "that is not an object",
2107 version_suffix
, table
->class_
->name
,
2108 version_suffix
, table_node
->name
);
2111 if (is_monitor_cond
) {
2112 const char *ops
[] = {"modify", "insert", "delete", "initial"};
2113 const char *operation
;
2114 const struct json
*row
;
2117 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
2119 row
= shash_find_data(json_object(row_update
), operation
);
2122 if (ovsdb_idl_process_update2(table
, &uuid
, operation
,
2130 /* row_update2 should contain one of the objects */
2131 if (i
== ARRAY_SIZE(ops
)) {
2132 return ovsdb_syntax_error(row_update
, NULL
,
2133 "<row_update2> includes unknown "
2137 const struct json
*old_json
, *new_json
;
2139 old_json
= shash_find_data(json_object(row_update
), "old");
2140 new_json
= shash_find_data(json_object(row_update
), "new");
2141 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
2142 return ovsdb_syntax_error(old_json
, NULL
,
2143 "\"old\" <row> is not object");
2144 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
2145 return ovsdb_syntax_error(new_json
, NULL
,
2146 "\"new\" <row> is not object");
2147 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
2148 != shash_count(json_object(row_update
))) {
2149 return ovsdb_syntax_error(row_update
, NULL
,
2150 "<row-update> contains "
2151 "unexpected member");
2152 } else if (!old_json
&& !new_json
) {
2153 return ovsdb_syntax_error(row_update
, NULL
,
2154 "<row-update> missing \"old\" "
2155 "and \"new\" members");
2158 if (ovsdb_idl_process_update(table
, &uuid
, old_json
,
2170 ovsdb_idl_db_parse_update(struct ovsdb_idl_db
*db
,
2171 const struct json
*table_updates
,
2172 bool is_monitor_cond
)
2174 struct ovsdb_error
*error
= ovsdb_idl_db_parse_update__(db
, table_updates
,
2177 log_parse_update_error(error
);
2181 static struct ovsdb_idl_row
*
2182 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2184 struct ovsdb_idl_row
*row
;
2186 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
2187 if (uuid_equals(&row
->uuid
, uuid
)) {
2194 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2197 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
2198 const struct uuid
*uuid
, const struct json
*old
,
2199 const struct json
*new)
2201 struct ovsdb_idl_row
*row
;
2203 row
= ovsdb_idl_get_row(table
, uuid
);
2206 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2207 /* XXX perhaps we should check the 'old' values? */
2208 ovsdb_idl_delete_row(row
);
2210 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2212 UUID_ARGS(uuid
), table
->class_
->name
);
2218 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
2219 } else if (ovsdb_idl_row_is_orphan(row
)) {
2220 ovsdb_idl_insert_row(row
, new);
2222 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2223 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2224 return ovsdb_idl_modify_row(row
, new);
2229 /* XXX perhaps we should check the 'old' values? */
2230 if (!ovsdb_idl_row_is_orphan(row
)) {
2231 return ovsdb_idl_modify_row(row
, new);
2233 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
2234 "referenced row "UUID_FMT
" in table %s",
2235 UUID_ARGS(uuid
), table
->class_
->name
);
2236 ovsdb_idl_insert_row(row
, new);
2239 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2240 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2241 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
2248 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2251 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
2252 const struct uuid
*uuid
,
2253 const char *operation
,
2254 const struct json
*json_row
)
2256 struct ovsdb_idl_row
*row
;
2258 row
= ovsdb_idl_get_row(table
, uuid
);
2259 if (!strcmp(operation
, "delete")) {
2261 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2262 ovsdb_idl_delete_row(row
);
2264 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2266 UUID_ARGS(uuid
), table
->class_
->name
);
2269 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
2272 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
2273 } else if (ovsdb_idl_row_is_orphan(row
)) {
2274 ovsdb_idl_insert_row(row
, json_row
);
2276 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2277 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2278 ovsdb_idl_delete_row(row
);
2279 ovsdb_idl_insert_row(row
, json_row
);
2281 } else if (!strcmp(operation
, "modify")) {
2284 if (!ovsdb_idl_row_is_orphan(row
)) {
2285 return ovsdb_idl_modify_row_by_diff(row
, json_row
);
2287 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
2288 "referenced row "UUID_FMT
" in table %s",
2289 UUID_ARGS(uuid
), table
->class_
->name
);
2293 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2294 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2298 VLOG_WARN_RL(&semantic_rl
, "unknown operation %s to "
2299 "table %s", operation
, table
->class_
->name
);
2306 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2309 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
2310 * Caller needs to provide either valid 'row_json' or 'diff', but not
2313 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2314 const struct json
*diff_json
,
2315 enum ovsdb_idl_change change
)
2317 struct ovsdb_idl_table
*table
= row
->table
;
2318 const struct ovsdb_idl_table_class
*class = table
->class_
;
2319 struct shash_node
*node
;
2320 bool changed
= false;
2321 bool apply_diff
= diff_json
!= NULL
;
2322 const struct json
*json
= apply_diff
? diff_json
: row_json
;
2324 SHASH_FOR_EACH (node
, json_object(json
)) {
2325 const char *column_name
= node
->name
;
2326 const struct ovsdb_idl_column
*column
;
2327 struct ovsdb_datum datum
;
2328 struct ovsdb_error
*error
;
2329 unsigned int column_idx
;
2330 struct ovsdb_datum
*old
;
2332 column
= shash_find_data(&table
->columns
, column_name
);
2334 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
2335 column_name
, UUID_ARGS(&row
->uuid
));
2339 column_idx
= column
- table
->class_
->columns
;
2340 old
= &row
->old_datum
[column_idx
];
2344 struct ovsdb_datum diff
;
2346 ovs_assert(!row_json
);
2347 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
2350 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
2352 ovsdb_datum_destroy(&diff
, &column
->type
);
2355 ovs_assert(!diff_json
);
2356 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
2361 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
2362 ovsdb_datum_swap(old
, &datum
);
2363 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
2365 row
->change_seqno
[change
]
2366 = row
->table
->change_seqno
[change
]
2367 = row
->table
->db
->change_seqno
+ 1;
2368 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
2369 if (!ovs_list_is_empty(&row
->track_node
)) {
2370 ovs_list_remove(&row
->track_node
);
2372 ovs_list_push_back(&row
->table
->track_list
,
2374 if (!row
->updated
) {
2375 row
->updated
= bitmap_allocate(class->n_columns
);
2377 bitmap_set1(row
->updated
, column_idx
);
2381 /* Didn't really change but the OVSDB monitor protocol always
2382 * includes every value in a row. */
2385 ovsdb_datum_destroy(&datum
, &column
->type
);
2387 char *s
= ovsdb_error_to_string_free(error
);
2388 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
2389 " in table %s: %s", column_name
,
2390 UUID_ARGS(&row
->uuid
), table
->class_
->name
, s
);
2398 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2399 enum ovsdb_idl_change change
)
2401 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
2405 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
2406 const struct json
*diff_json
,
2407 enum ovsdb_idl_change change
)
2409 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
2412 /* When a row A refers to row B through a column with a "refTable" constraint,
2413 * but row B does not exist, row B is called an "orphan row". Orphan rows
2414 * should not persist, because the database enforces referential integrity, but
2415 * they can appear transiently as changes from the database are received (the
2416 * database doesn't try to topologically sort them and circular references mean
2417 * it isn't always possible anyhow).
2419 * This function returns true if 'row' is an orphan row, otherwise false.
2422 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
2424 return !row
->old_datum
&& !row
->new_datum
;
2427 /* Returns true if 'row' is conceptually part of the database as modified by
2428 * the current transaction (if any), false otherwise.
2430 * This function will return true if 'row' is not an orphan (see the comment on
2431 * ovsdb_idl_row_is_orphan()) and:
2433 * - 'row' exists in the database and has not been deleted within the
2434 * current transaction (if any).
2436 * - 'row' was inserted within the current transaction and has not been
2437 * deleted. (In the latter case you should not have passed 'row' in at
2438 * all, because ovsdb_idl_txn_delete() freed it.)
2440 * This function will return false if 'row' is an orphan or if 'row' was
2441 * deleted within the current transaction.
2444 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
2446 return row
->new_datum
!= NULL
;
2450 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
2452 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2455 for (i
= 0; i
< class->n_columns
; i
++) {
2456 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2457 (c
->parse
)(row
, &row
->old_datum
[i
]);
2462 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
2464 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2467 for (i
= 0; i
< class->n_columns
; i
++) {
2468 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2473 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2474 * table indexes over one or more columns in the IDL. These indexes provide
2475 * the ability to retrieve rows matching a particular search criteria and to
2476 * iterate over a subset of rows in a defined order.
2479 /* Generic comparator that can compare each index, using the custom
2480 * configuration (an struct ovsdb_idl_index) passed to it.
2481 * Not intended for direct usage.
2484 ovsdb_idl_index_generic_comparer(const void *a
,
2485 const void *b
, const void *conf
)
2487 const struct ovsdb_idl_column
*column
;
2488 const struct ovsdb_idl_index
*index
;
2491 index
= CONST_CAST(struct ovsdb_idl_index
*, conf
);
2497 for (i
= 0; i
< index
->n_columns
; i
++) {
2499 if (index
->columns
[i
].comparer
) {
2500 val
= index
->columns
[i
].comparer(a
, b
);
2502 column
= index
->columns
[i
].column
;
2503 const struct ovsdb_idl_row
*row_a
, *row_b
;
2504 row_a
= CONST_CAST(struct ovsdb_idl_row
*, a
);
2505 row_b
= CONST_CAST(struct ovsdb_idl_row
*, b
);
2506 const struct ovsdb_datum
*datum_a
, *datum_b
;
2507 datum_a
= ovsdb_idl_read(row_a
, column
);
2508 datum_b
= ovsdb_idl_read(row_b
, column
);
2509 val
= ovsdb_datum_compare_3way(datum_a
, datum_b
, &column
->type
);
2513 return index
->columns
[i
].order
== OVSDB_INDEX_ASC
? val
: -val
;
2517 /* If ins_del is true then a row is being inserted into or deleted from
2518 * the index list. In this case, we augment the search key with
2519 * additional values (row UUID and memory address) to create a unique
2520 * search key in order to locate the correct entry efficiently and to
2521 * ensure that the correct entry is deleted in the case of a "delete"
2524 if (index
->ins_del
) {
2525 const struct ovsdb_idl_row
*row_a
, *row_b
;
2527 row_a
= (const struct ovsdb_idl_row
*) a
;
2528 row_b
= (const struct ovsdb_idl_row
*) b
;
2529 int value
= uuid_compare_3way(&row_a
->uuid
, &row_b
->uuid
);
2531 return value
? value
: (a
< b
) - (a
> b
);
2537 static struct ovsdb_idl_index
*
2538 ovsdb_idl_db_index_create(struct ovsdb_idl_db
*db
,
2539 const struct ovsdb_idl_index_column
*columns
,
2544 struct ovsdb_idl_index
*index
= xzalloc(sizeof *index
);
2546 index
->table
= ovsdb_idl_table_from_column(db
, columns
[0].column
);
2547 for (size_t i
= 0; i
< n
; i
++) {
2548 const struct ovsdb_idl_index_column
*c
= &columns
[i
];
2549 ovs_assert(ovsdb_idl_table_from_column(db
, c
->column
) == index
->table
);
2550 ovs_assert(*ovsdb_idl_db_get_mode(db
, c
->column
) & OVSDB_IDL_MONITOR
);
2553 index
->columns
= xmemdup(columns
, n
* sizeof *columns
);
2554 index
->n_columns
= n
;
2555 index
->skiplist
= skiplist_create(ovsdb_idl_index_generic_comparer
, index
);
2557 ovs_list_push_back(&index
->table
->indexes
, &index
->node
);
2562 /* Creates a new index for the given 'idl' and with the 'n' specified
2565 * All indexes must be created before the first call to ovsdb_idl_run(). */
2566 struct ovsdb_idl_index
*
2567 ovsdb_idl_index_create(struct ovsdb_idl
*idl
,
2568 const struct ovsdb_idl_index_column
*columns
,
2571 return ovsdb_idl_db_index_create(&idl
->data
, columns
, n
);
2574 struct ovsdb_idl_index
*
2575 ovsdb_idl_index_create1(struct ovsdb_idl
*idl
,
2576 const struct ovsdb_idl_column
*column1
)
2578 const struct ovsdb_idl_index_column columns
[] = {
2579 { .column
= column1
},
2581 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
2584 struct ovsdb_idl_index
*
2585 ovsdb_idl_index_create2(struct ovsdb_idl
*idl
,
2586 const struct ovsdb_idl_column
*column1
,
2587 const struct ovsdb_idl_column
*column2
)
2589 const struct ovsdb_idl_index_column columns
[] = {
2590 { .column
= column1
},
2591 { .column
= column2
},
2593 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
2597 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
)
2599 struct ovsdb_idl_index
*index
, *next
;
2600 LIST_FOR_EACH_SAFE (index
, next
, node
, &table
->indexes
) {
2601 skiplist_destroy(index
->skiplist
, NULL
);
2602 free(index
->columns
);
2608 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*row
)
2610 struct ovsdb_idl_table
*table
= row
->table
;
2611 struct ovsdb_idl_index
*index
;
2612 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
2613 index
->ins_del
= true;
2614 skiplist_insert(index
->skiplist
, row
);
2615 index
->ins_del
= false;
2620 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*row
)
2622 struct ovsdb_idl_table
*table
= row
->table
;
2623 struct ovsdb_idl_index
*index
;
2624 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
2625 index
->ins_del
= true;
2626 skiplist_delete(index
->skiplist
, row
);
2627 index
->ins_del
= false;
2631 /* Writes a datum in an ovsdb_idl_row, and updates the corresponding field in
2632 * the table record. Not intended for direct usage. */
2634 ovsdb_idl_index_write(struct ovsdb_idl_row
*const_row
,
2635 const struct ovsdb_idl_column
*column
,
2636 struct ovsdb_datum
*datum
,
2637 const struct ovsdb_idl_table_class
*class)
2639 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, const_row
);
2640 size_t column_idx
= column
- class->columns
;
2642 if (bitmap_is_set(row
->written
, column_idx
)) {
2643 free(row
->new_datum
[column_idx
].values
);
2644 free(row
->new_datum
[column_idx
].keys
);
2646 bitmap_set1(row
->written
, column_idx
);
2648 row
->new_datum
[column_idx
] = *datum
;
2649 (column
->unparse
)(row
);
2650 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
2653 /* Magic UUID for index rows */
2654 static const struct uuid index_row_uuid
= {
2655 .parts
= {0xdeadbeef,
2660 /* Check if a row is an index row */
2662 is_index_row(const struct ovsdb_idl_row
*row
)
2664 return uuid_equals(&row
->uuid
, &index_row_uuid
);
2667 /* Initializes a row for use in an indexed query.
2668 * Not intended for direct usage.
2670 struct ovsdb_idl_row
*
2671 ovsdb_idl_index_init_row(struct ovsdb_idl_index
*index
)
2673 const struct ovsdb_idl_table_class
*class = index
->table
->class_
;
2674 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2675 class->row_init(row
);
2676 row
->uuid
= index_row_uuid
;
2677 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
2678 row
->written
= bitmap_allocate(class->n_columns
);
2679 row
->table
= index
->table
;
2680 /* arcs are not used for index row, but it doesn't harm to initialize */
2681 ovs_list_init(&row
->src_arcs
);
2682 ovs_list_init(&row
->dst_arcs
);
2686 /* Destroys 'row_' and frees all associated memory. This function is intended
2687 * to be used indirectly through one of the "index_destroy_row" functions
2688 * generated by ovsdb-idlc.
2691 ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row
*row_
)
2693 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2694 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2695 const struct ovsdb_idl_column
*c
;
2698 ovs_assert(is_index_row(row_
));
2699 ovs_assert(ovs_list_is_empty(&row_
->src_arcs
));
2700 ovs_assert(ovs_list_is_empty(&row_
->dst_arcs
));
2701 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2702 c
= &class->columns
[i
];
2704 free(row
->new_datum
[i
].values
);
2705 free(row
->new_datum
[i
].keys
);
2707 free(row
->new_datum
);
2712 struct ovsdb_idl_row
*
2713 ovsdb_idl_index_find(struct ovsdb_idl_index
*index
,
2714 const struct ovsdb_idl_row
*target
)
2716 return skiplist_get_data(skiplist_find(index
->skiplist
, target
));
2719 struct ovsdb_idl_cursor
2720 ovsdb_idl_cursor_first(struct ovsdb_idl_index
*index
)
2722 struct skiplist_node
*node
= skiplist_first(index
->skiplist
);
2723 return (struct ovsdb_idl_cursor
) { index
, node
};
2726 struct ovsdb_idl_cursor
2727 ovsdb_idl_cursor_first_eq(struct ovsdb_idl_index
*index
,
2728 const struct ovsdb_idl_row
*target
)
2730 struct skiplist_node
*node
= skiplist_find(index
->skiplist
, target
);
2731 return (struct ovsdb_idl_cursor
) { index
, node
};
2734 struct ovsdb_idl_cursor
2735 ovsdb_idl_cursor_first_ge(struct ovsdb_idl_index
*index
,
2736 const struct ovsdb_idl_row
*target
)
2738 struct skiplist_node
*node
= (target
2739 ? skiplist_forward_to(index
->skiplist
,
2741 : skiplist_first(index
->skiplist
));
2742 return (struct ovsdb_idl_cursor
) { index
, node
};
2746 ovsdb_idl_cursor_next(struct ovsdb_idl_cursor
*cursor
)
2748 cursor
->position
= skiplist_next(cursor
->position
);
2752 ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor
*cursor
)
2754 struct ovsdb_idl_row
*data
= skiplist_get_data(cursor
->position
);
2755 struct skiplist_node
*next_position
= skiplist_next(cursor
->position
);
2756 struct ovsdb_idl_row
*next_data
= skiplist_get_data(next_position
);
2757 cursor
->position
= (!ovsdb_idl_index_compare(cursor
->index
,
2759 ? next_position
: NULL
);
2762 struct ovsdb_idl_row
*
2763 ovsdb_idl_cursor_data(struct ovsdb_idl_cursor
*cursor
)
2765 return skiplist_get_data(cursor
->position
);
2768 /* Returns the result of comparing two rows using the comparison function
2774 * When the pointer to either row is NULL, this function considers NULL to be
2775 * greater than any other value, and NULL == NULL.
2778 ovsdb_idl_index_compare(struct ovsdb_idl_index
*index
,
2779 const struct ovsdb_idl_row
*a
,
2780 const struct ovsdb_idl_row
*b
)
2783 return ovsdb_idl_index_generic_comparer(a
, b
, index
);
2784 } else if (!a
&& !b
) {
2794 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
2796 ovs_assert(row
->old_datum
== row
->new_datum
);
2797 if (!ovsdb_idl_row_is_orphan(row
)) {
2798 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2801 for (i
= 0; i
< class->n_columns
; i
++) {
2802 ovsdb_datum_destroy(&row
->old_datum
[i
], &class->columns
[i
].type
);
2804 free(row
->old_datum
);
2805 row
->old_datum
= row
->new_datum
= NULL
;
2810 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
2812 if (row
->old_datum
!= row
->new_datum
) {
2813 if (row
->new_datum
) {
2814 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2818 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2819 ovsdb_datum_destroy(&row
->new_datum
[i
],
2820 &class->columns
[i
].type
);
2823 free(row
->new_datum
);
2825 row
->written
= NULL
;
2827 row
->new_datum
= row
->old_datum
;
2832 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
2834 struct ovsdb_idl_arc
*arc
, *next
;
2836 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
2837 * that this causes to be unreferenced, if tracking is not enabled.
2838 * If tracking is enabled, orphaned nodes are removed from hmap but not
2841 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
2842 ovs_list_remove(&arc
->dst_node
);
2844 && ovsdb_idl_row_is_orphan(arc
->dst
)
2845 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
2846 ovsdb_idl_row_destroy(arc
->dst
);
2850 ovs_list_init(&row
->src_arcs
);
2853 /* Force nodes that reference 'row' to reparse. */
2855 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
2857 struct ovsdb_idl_arc
*arc
, *next
;
2859 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2860 * 'arc', so we need to use the "safe" variant of list traversal. However,
2861 * calling an ovsdb_idl_column's 'parse' function will add an arc
2862 * equivalent to 'arc' to row->arcs. That could be a problem for
2863 * traversal, but it adds it at the beginning of the list to prevent us
2864 * from stumbling upon it again.
2866 * (If duplicate arcs were possible then we would need to make sure that
2867 * 'next' didn't also point into 'arc''s destination, but we forbid
2868 * duplicate arcs.) */
2869 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
2870 struct ovsdb_idl_row
*ref
= arc
->src
;
2872 ovsdb_idl_row_unparse(ref
);
2873 ovsdb_idl_row_clear_arcs(ref
, false);
2874 ovsdb_idl_row_parse(ref
);
2878 static struct ovsdb_idl_row
*
2879 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
2881 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2882 class->row_init(row
);
2883 ovs_list_init(&row
->src_arcs
);
2884 ovs_list_init(&row
->dst_arcs
);
2885 hmap_node_nullify(&row
->txn_node
);
2886 ovs_list_init(&row
->track_node
);
2890 static struct ovsdb_idl_row
*
2891 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2893 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class_
);
2894 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
2897 row
->map_op_written
= NULL
;
2898 row
->map_op_lists
= NULL
;
2899 row
->set_op_written
= NULL
;
2900 row
->set_op_lists
= NULL
;
2905 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
2908 ovsdb_idl_row_clear_old(row
);
2909 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2910 ovsdb_idl_destroy_all_map_op_lists(row
);
2911 ovsdb_idl_destroy_all_set_op_lists(row
);
2912 if (ovsdb_idl_track_is_set(row
->table
)) {
2913 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2914 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2915 = row
->table
->db
->change_seqno
+ 1;
2917 if (!ovs_list_is_empty(&row
->track_node
)) {
2918 ovs_list_remove(&row
->track_node
);
2920 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
2925 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
2927 if (row
->map_op_written
) {
2928 /* Clear Map Operation Lists */
2929 size_t idx
, n_columns
;
2930 const struct ovsdb_idl_column
*columns
;
2931 const struct ovsdb_type
*type
;
2932 n_columns
= row
->table
->class_
->n_columns
;
2933 columns
= row
->table
->class_
->columns
;
2934 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
2935 type
= &columns
[idx
].type
;
2936 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
2938 free(row
->map_op_lists
);
2939 bitmap_free(row
->map_op_written
);
2940 row
->map_op_lists
= NULL
;
2941 row
->map_op_written
= NULL
;
2946 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
2948 if (row
->set_op_written
) {
2949 /* Clear Set Operation Lists */
2950 size_t idx
, n_columns
;
2951 const struct ovsdb_idl_column
*columns
;
2952 const struct ovsdb_type
*type
;
2953 n_columns
= row
->table
->class_
->n_columns
;
2954 columns
= row
->table
->class_
->columns
;
2955 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
2956 type
= &columns
[idx
].type
;
2957 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
2959 free(row
->set_op_lists
);
2960 bitmap_free(row
->set_op_written
);
2961 row
->set_op_lists
= NULL
;
2962 row
->set_op_written
= NULL
;
2967 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db
*db
)
2971 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
2972 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
2974 if (!ovs_list_is_empty(&table
->track_list
)) {
2975 struct ovsdb_idl_row
*row
, *next
;
2977 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
2978 if (!ovsdb_idl_track_is_set(row
->table
)) {
2979 ovs_list_remove(&row
->track_node
);
2988 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
2990 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2991 size_t i
, datum_size
;
2993 ovs_assert(!row
->old_datum
&& !row
->new_datum
);
2994 datum_size
= class->n_columns
* sizeof *row
->old_datum
;
2995 row
->old_datum
= row
->new_datum
= xmalloc(datum_size
);
2996 for (i
= 0; i
< class->n_columns
; i
++) {
2997 ovsdb_datum_init_default(&row
->old_datum
[i
], &class->columns
[i
].type
);
2999 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
3000 ovsdb_idl_row_parse(row
);
3002 ovsdb_idl_row_reparse_backrefs(row
);
3003 ovsdb_idl_add_to_indexes(row
);
3007 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
3009 ovsdb_idl_remove_from_indexes(row
);
3010 ovsdb_idl_row_unparse(row
);
3011 ovsdb_idl_row_clear_arcs(row
, true);
3012 ovsdb_idl_row_clear_old(row
);
3013 if (ovs_list_is_empty(&row
->dst_arcs
)) {
3014 ovsdb_idl_row_destroy(row
);
3016 ovsdb_idl_row_reparse_backrefs(row
);
3020 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
3023 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
3027 ovsdb_idl_remove_from_indexes(row
);
3028 ovsdb_idl_row_unparse(row
);
3029 ovsdb_idl_row_clear_arcs(row
, true);
3030 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
3031 ovsdb_idl_row_parse(row
);
3032 ovsdb_idl_add_to_indexes(row
);
3038 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
3039 const struct json
*diff_json
)
3043 ovsdb_idl_row_unparse(row
);
3044 ovsdb_idl_row_clear_arcs(row
, true);
3045 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
3046 OVSDB_IDL_CHANGE_MODIFY
);
3047 ovsdb_idl_row_parse(row
);
3053 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
3055 const struct ovsdb_idl_arc
*arc
;
3062 /* No duplicate arcs.
3064 * We only need to test whether the first arc in dst->dst_arcs originates
3065 * at 'src', since we add all of the arcs from a given source in a clump
3066 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
3067 * added at the front of the dst_arcs list. */
3068 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
3071 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
3072 return arc
->src
!= src
;
3075 static struct ovsdb_idl_table
*
3076 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db
*db
,
3077 const struct ovsdb_idl_table_class
*table_class
)
3079 ptrdiff_t idx
= table_class
- db
->class_
->tables
;
3080 return idx
>= 0 && idx
< db
->class_
->n_tables
? &db
->tables
[idx
] : NULL
;
3083 static struct ovsdb_idl_table
*
3084 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
3085 const struct ovsdb_idl_table_class
*table_class
)
3087 struct ovsdb_idl_table
*table
;
3089 table
= ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
3091 table
= ovsdb_idl_db_table_from_class(&idl
->server
, table_class
);
3097 /* Called by ovsdb-idlc generated code. */
3098 struct ovsdb_idl_row
*
3099 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
3100 const struct ovsdb_idl_table_class
*dst_table_class
,
3101 const struct uuid
*dst_uuid
)
3103 struct ovsdb_idl_db
*db
= src
->table
->db
;
3104 struct ovsdb_idl_table
*dst_table
;
3105 struct ovsdb_idl_arc
*arc
;
3106 struct ovsdb_idl_row
*dst
;
3108 dst_table
= ovsdb_idl_db_table_from_class(db
, dst_table_class
);
3109 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
3110 if (db
->txn
|| is_index_row(src
)) {
3111 /* There are two cases we should not update any arcs:
3113 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
3114 * any arcs, because the transaction will be backed out at commit or
3115 * abort time and we don't want our graph screwed up.
3117 * 2. The row is used as an index for querying purpose only.
3119 * In these cases, just return the destination row, if there is one and
3120 * it has not been deleted. */
3121 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new_datum
)) {
3126 /* We're being called from some other context. Update the graph. */
3128 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
3131 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
3132 if (may_add_arc(src
, dst
)) {
3133 /* The arc *must* be added at the front of the dst_arcs list. See
3134 * ovsdb_idl_row_reparse_backrefs() for details. */
3135 arc
= xmalloc(sizeof *arc
);
3136 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
3137 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
3142 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
3146 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
3147 * pointer to the row if there is one, otherwise a null pointer. */
3148 const struct ovsdb_idl_row
*
3149 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
3150 const struct ovsdb_idl_table_class
*tc
,
3151 const struct uuid
*uuid
)
3153 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
3156 static struct ovsdb_idl_row
*
3157 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
3159 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
3160 struct ovsdb_idl_row
*row
;
3162 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
3163 if (ovsdb_idl_row_exists(row
)) {
3170 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
3173 * Database tables are internally maintained as hash tables, so adding or
3174 * removing rows while traversing the same table can cause some rows to be
3175 * visited twice or not at apply. */
3176 const struct ovsdb_idl_row
*
3177 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
3178 const struct ovsdb_idl_table_class
*table_class
)
3180 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
,
3182 return next_real_row(table
, hmap_first(&table
->rows
));
3185 /* Returns a row following 'row' within its table, or a null pointer if 'row'
3186 * is the last row in its table. */
3187 const struct ovsdb_idl_row
*
3188 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
3190 struct ovsdb_idl_table
*table
= row
->table
;
3192 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
3195 /* Reads and returns the value of 'column' within 'row'. If an ongoing
3196 * transaction has changed 'column''s value, the modified value is returned.
3198 * The caller must not modify or free the returned value.
3200 * Various kinds of changes can invalidate the returned value: writing to the
3201 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
3202 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
3203 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
3204 * returned value is needed for a long time, it is best to make a copy of it
3205 * with ovsdb_datum_clone(). */
3206 const struct ovsdb_datum
*
3207 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
3208 const struct ovsdb_idl_column
*column
)
3210 const struct ovsdb_idl_table_class
*class;
3213 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
3215 class = row
->table
->class_
;
3216 column_idx
= column
- class->columns
;
3218 ovs_assert(row
->new_datum
!= NULL
);
3219 ovs_assert(column_idx
< class->n_columns
);
3221 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
3222 return &row
->new_datum
[column_idx
];
3223 } else if (row
->old_datum
) {
3224 return &row
->old_datum
[column_idx
];
3226 return ovsdb_datum_default(&column
->type
);
3230 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
3231 * type 'key_type' and value type 'value_type'. (Scalar and set types will
3232 * have a value type of OVSDB_TYPE_VOID.)
3234 * This is useful in code that "knows" that a particular column has a given
3235 * type, so that it will abort if someone changes the column's type without
3236 * updating the code that uses it. */
3237 const struct ovsdb_datum
*
3238 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
3239 const struct ovsdb_idl_column
*column
,
3240 enum ovsdb_atomic_type key_type OVS_UNUSED
,
3241 enum ovsdb_atomic_type value_type OVS_UNUSED
)
3243 ovs_assert(column
->type
.key
.type
== key_type
);
3244 ovs_assert(column
->type
.value
.type
== value_type
);
3246 return ovsdb_idl_read(row
, column
);
3249 /* Returns true if the field represented by 'column' in 'row' may be modified,
3250 * false if it is immutable.
3252 * Normally, whether a field is mutable is controlled by its column's schema.
3253 * However, an immutable column can be set to any initial value at the time of
3254 * insertion, so if 'row' is a new row (one that is being added as part of the
3255 * current transaction, supposing that a transaction is in progress) then even
3256 * its "immutable" fields are actually mutable. */
3258 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
3259 const struct ovsdb_idl_column
*column
)
3261 return column
->is_mutable
|| (row
->new_datum
&& !row
->old_datum
);
3264 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
3265 * to all-zero-bits by some other entity. If 'row' was set up some other way
3266 * then the return value is indeterminate. */
3268 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
3270 return row
->table
== NULL
;
3275 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3276 enum ovsdb_idl_txn_status
);
3278 /* Returns a string representation of 'status'. The caller must not modify or
3279 * free the returned string.
3281 * The return value is probably useful only for debug log messages and unit
3284 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
3287 case TXN_UNCOMMITTED
:
3288 return "uncommitted";
3291 case TXN_INCOMPLETE
:
3292 return "incomplete";
3299 case TXN_NOT_LOCKED
:
3300 return "not locked";
3307 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
3308 * active transaction at a time. See the large comment in ovsdb-idl.h for
3309 * general information on transactions. */
3310 struct ovsdb_idl_txn
*
3311 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
3313 struct ovsdb_idl_txn
*txn
;
3315 ovs_assert(!idl
->data
.txn
);
3316 idl
->data
.txn
= txn
= xmalloc(sizeof *txn
);
3317 txn
->request_id
= NULL
;
3318 txn
->db
= &idl
->data
;
3319 hmap_init(&txn
->txn_rows
);
3320 txn
->status
= TXN_UNCOMMITTED
;
3322 txn
->dry_run
= false;
3323 ds_init(&txn
->comment
);
3325 txn
->inc_table
= NULL
;
3326 txn
->inc_column
= NULL
;
3328 hmap_init(&txn
->inserted_rows
);
3333 /* Appends 's', which is treated as a printf()-type format string, to the
3334 * comments that will be passed to the OVSDB server when 'txn' is committed.
3335 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
3336 * show-log" can print in a relatively human-readable form.) */
3338 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
3342 if (txn
->comment
.length
) {
3343 ds_put_char(&txn
->comment
, '\n');
3347 ds_put_format_valist(&txn
->comment
, s
, args
);
3351 /* Marks 'txn' as a transaction that will not actually modify the database. In
3352 * almost every way, the transaction is treated like other transactions. It
3353 * must be committed or aborted like other transactions, it will be sent to the
3354 * database server like other transactions, and so on. The only difference is
3355 * that the operations sent to the database server will include, as the last
3356 * step, an "abort" operation, so that any changes made by the transaction will
3357 * not actually take effect. */
3359 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
3361 txn
->dry_run
= true;
3364 /* Causes 'txn', when committed, to increment the value of 'column' within
3365 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3366 * successfully, the client may retrieve the final (incremented) value of
3367 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3369 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3370 * change the database, then 'force' is important. If 'force' is false in this
3371 * case, the IDL suppresses the increment and skips a round trip to the
3372 * database server. If 'force' is true, the IDL will still increment the
3375 * The client could accomplish something similar with ovsdb_idl_read(),
3376 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3377 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3378 * will never (by itself) fail because of a verify error.
3380 * The intended use is for incrementing the "next_cfg" column in the
3381 * Open_vSwitch table. */
3383 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
3384 const struct ovsdb_idl_row
*row
,
3385 const struct ovsdb_idl_column
*column
,
3388 ovs_assert(!txn
->inc_table
);
3389 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
3390 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
3392 txn
->inc_table
= row
->table
->class_
->name
;
3393 txn
->inc_column
= column
->name
;
3394 txn
->inc_row
= row
->uuid
;
3395 txn
->inc_force
= force
;
3398 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3399 * has been called for 'txn' but the commit is still incomplete (that is, the
3400 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3401 * end up committing at the database server, but the client will not be able to
3402 * get any further status information back. */
3404 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
3406 struct ovsdb_idl_txn_insert
*insert
, *next
;
3408 json_destroy(txn
->request_id
);
3409 if (txn
->status
== TXN_INCOMPLETE
) {
3410 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
3412 ovsdb_idl_txn_abort(txn
);
3413 ds_destroy(&txn
->comment
);
3415 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
3418 hmap_destroy(&txn
->inserted_rows
);
3422 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3424 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
3426 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
3427 poll_immediate_wake();
3431 static struct json
*
3432 where_uuid_equals(const struct uuid
*uuid
)
3435 json_array_create_1(
3436 json_array_create_3(
3437 json_string_create("_uuid"),
3438 json_string_create("=="),
3439 json_array_create_2(
3440 json_string_create("uuid"),
3441 json_string_create_nocopy(
3442 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
3445 static const struct ovsdb_idl_row
*
3446 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
3448 const struct ovsdb_idl_row
*row
;
3450 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
3451 if (uuid_equals(&row
->uuid
, uuid
)) {
3458 /* XXX there must be a cleaner way to do this */
3459 static struct json
*
3460 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
3462 if (json
->type
== JSON_ARRAY
) {
3466 if (json
->array
.n
== 2
3467 && json
->array
.elems
[0]->type
== JSON_STRING
3468 && json
->array
.elems
[1]->type
== JSON_STRING
3469 && !strcmp(json
->array
.elems
[0]->string
, "uuid")
3470 && uuid_from_string(&uuid
, json
->array
.elems
[1]->string
)) {
3471 const struct ovsdb_idl_row
*row
;
3473 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
3474 if (row
&& !row
->old_datum
&& row
->new_datum
) {
3477 return json_array_create_2(
3478 json_string_create("named-uuid"),
3479 json_string_create_nocopy(ovsdb_data_row_name(&uuid
)));
3483 for (i
= 0; i
< json
->array
.n
; i
++) {
3484 json
->array
.elems
[i
] = substitute_uuids(json
->array
.elems
[i
],
3487 } else if (json
->type
== JSON_OBJECT
) {
3488 struct shash_node
*node
;
3490 SHASH_FOR_EACH (node
, json_object(json
)) {
3491 node
->data
= substitute_uuids(node
->data
, txn
);
3498 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
3500 struct ovsdb_idl_row
*row
, *next
;
3502 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3503 * ovsdb_idl_column's 'parse' function, which will call
3504 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3505 * transaction and fail to update the graph. */
3506 txn
->db
->txn
= NULL
;
3508 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
3509 ovsdb_idl_destroy_all_map_op_lists(row
);
3510 ovsdb_idl_destroy_all_set_op_lists(row
);
3511 if (row
->old_datum
) {
3513 ovsdb_idl_row_unparse(row
);
3514 ovsdb_idl_row_clear_arcs(row
, false);
3515 ovsdb_idl_row_parse(row
);
3518 ovsdb_idl_row_unparse(row
);
3520 ovsdb_idl_row_clear_new(row
);
3523 row
->prereqs
= NULL
;
3526 row
->written
= NULL
;
3528 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
3529 hmap_node_nullify(&row
->txn_node
);
3530 if (!row
->old_datum
) {
3531 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3535 hmap_destroy(&txn
->txn_rows
);
3536 hmap_init(&txn
->txn_rows
);
3540 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
3541 struct json
*mutations
)
3543 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3545 bool any_mutations
= false;
3547 if (row
->map_op_written
) {
3548 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
3549 struct map_op_list
*map_op_list
;
3550 const struct ovsdb_idl_column
*column
;
3551 const struct ovsdb_datum
*old_datum
;
3552 enum ovsdb_atomic_type key_type
, value_type
;
3553 struct json
*mutation
, *map
, *col_name
, *mutator
;
3554 struct json
*del_set
, *ins_map
;
3555 bool any_del
, any_ins
;
3557 map_op_list
= row
->map_op_lists
[idx
];
3558 column
= &class->columns
[idx
];
3559 key_type
= column
->type
.key
.type
;
3560 value_type
= column
->type
.value
.type
;
3562 /* Get the value to be changed */
3563 if (row
->new_datum
&& row
->written
3564 && bitmap_is_set(row
->written
,idx
)) {
3565 old_datum
= &row
->new_datum
[idx
];
3566 } else if (row
->old_datum
!= NULL
) {
3567 old_datum
= &row
->old_datum
[idx
];
3569 old_datum
= ovsdb_datum_default(&column
->type
);
3572 del_set
= json_array_create_empty();
3573 ins_map
= json_array_create_empty();
3577 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
3578 map_op
= map_op_list_next(map_op_list
, map_op
)) {
3580 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3581 /* Find out if value really changed. */
3582 struct ovsdb_datum
*new_datum
;
3584 new_datum
= map_op_datum(map_op
);
3585 pos
= ovsdb_datum_find_key(old_datum
,
3586 &new_datum
->keys
[0],
3588 if (ovsdb_atom_equals(&new_datum
->values
[0],
3589 &old_datum
->values
[pos
],
3591 /* No change in value. Move on to next update. */
3594 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
3595 /* Verify that there is a key to delete. */
3597 pos
= ovsdb_datum_find_key(old_datum
,
3598 &map_op_datum(map_op
)->keys
[0],
3600 if (pos
== UINT_MAX
) {
3601 /* No key to delete. Move on to next update. */
3602 VLOG_WARN("Trying to delete a key that doesn't "
3603 "exist in the map.");
3608 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
3609 map
= json_array_create_2(
3610 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3612 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3614 json_array_add(ins_map
, map
);
3616 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
3617 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3619 json_array_add(del_set
, map
);
3623 /* Generate an additional insert mutate for updates. */
3624 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3625 map
= json_array_create_2(
3626 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3628 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3630 json_array_add(ins_map
, map
);
3636 col_name
= json_string_create(column
->name
);
3637 mutator
= json_string_create("delete");
3638 map
= json_array_create_2(json_string_create("set"), del_set
);
3639 mutation
= json_array_create_3(col_name
, mutator
, map
);
3640 json_array_add(mutations
, mutation
);
3641 any_mutations
= true;
3643 json_destroy(del_set
);
3646 col_name
= json_string_create(column
->name
);
3647 mutator
= json_string_create("insert");
3648 map
= json_array_create_2(json_string_create("map"), ins_map
);
3649 mutation
= json_array_create_3(col_name
, mutator
, map
);
3650 json_array_add(mutations
, mutation
);
3651 any_mutations
= true;
3653 json_destroy(ins_map
);
3657 if (row
->set_op_written
) {
3658 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
3659 struct set_op_list
*set_op_list
;
3660 const struct ovsdb_idl_column
*column
;
3661 const struct ovsdb_datum
*old_datum
;
3662 enum ovsdb_atomic_type key_type
;
3663 struct json
*mutation
, *set
, *col_name
, *mutator
;
3664 struct json
*del_set
, *ins_set
;
3665 bool any_del
, any_ins
;
3667 set_op_list
= row
->set_op_lists
[idx
];
3668 column
= &class->columns
[idx
];
3669 key_type
= column
->type
.key
.type
;
3671 /* Get the value to be changed */
3672 if (row
->new_datum
&& row
->written
3673 && bitmap_is_set(row
->written
,idx
)) {
3674 old_datum
= &row
->new_datum
[idx
];
3675 } else if (row
->old_datum
!= NULL
) {
3676 old_datum
= &row
->old_datum
[idx
];
3678 old_datum
= ovsdb_datum_default(&column
->type
);
3681 del_set
= json_array_create_empty();
3682 ins_set
= json_array_create_empty();
3686 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
3687 set_op
= set_op_list_next(set_op_list
, set_op
)) {
3688 if (set_op_type(set_op
) == SET_OP_INSERT
) {
3689 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3691 json_array_add(ins_set
, set
);
3693 } else { /* SETP_OP_DELETE */
3694 /* Verify that there is a key to delete. */
3696 pos
= ovsdb_datum_find_key(old_datum
,
3697 &set_op_datum(set_op
)->keys
[0],
3699 if (pos
== UINT_MAX
) {
3700 /* No key to delete. Move on to next update. */
3701 VLOG_WARN("Trying to delete a key that doesn't "
3702 "exist in the set.");
3705 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3707 json_array_add(del_set
, set
);
3712 col_name
= json_string_create(column
->name
);
3713 mutator
= json_string_create("delete");
3714 set
= json_array_create_2(json_string_create("set"), del_set
);
3715 mutation
= json_array_create_3(col_name
, mutator
, set
);
3716 json_array_add(mutations
, mutation
);
3717 any_mutations
= true;
3719 json_destroy(del_set
);
3722 col_name
= json_string_create(column
->name
);
3723 mutator
= json_string_create("insert");
3724 set
= json_array_create_2(json_string_create("set"), ins_set
);
3725 mutation
= json_array_create_3(col_name
, mutator
, set
);
3726 json_array_add(mutations
, mutation
);
3727 any_mutations
= true;
3729 json_destroy(ins_set
);
3733 return any_mutations
;
3736 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
3737 * of the following TXN_* constants:
3741 * The transaction is in progress, but not yet complete. The caller
3742 * should call again later, after calling ovsdb_idl_run() to let the IDL
3743 * do OVSDB protocol processing.
3747 * The transaction is complete. (It didn't actually change the database,
3748 * so the IDL didn't send any request to the database server.)
3752 * The caller previously called ovsdb_idl_txn_abort().
3756 * The transaction was successful. The update made by the transaction
3757 * (and possibly other changes made by other database clients) should
3758 * already be visible in the IDL.
3762 * The transaction failed for some transient reason, e.g. because a
3763 * "verify" operation reported an inconsistency or due to a network
3764 * problem. The caller should wait for a change to the database, then
3765 * compose a new transaction, and commit the new transaction.
3767 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
3768 * the database. It is important to use its return value *before* the
3769 * initial call to ovsdb_idl_txn_commit() as the baseline for this
3770 * purpose, because the change that one should wait for can happen after
3771 * the initial call but before the call that returns TXN_TRY_AGAIN, and
3772 * using some other baseline value in that situation could cause an
3773 * indefinite wait if the database rarely changes.
3777 * The transaction failed because the IDL has been configured to require
3778 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
3779 * has already lost it.
3781 * Committing a transaction rolls back all of the changes that it made to the
3782 * IDL's copy of the database. If the transaction commits successfully, then
3783 * the database server will send an update and, thus, the IDL will be updated
3784 * with the committed changes. */
3785 enum ovsdb_idl_txn_status
3786 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
3788 struct ovsdb_idl_row
*row
;
3789 struct json
*operations
;
3792 if (txn
!= txn
->db
->txn
) {
3796 /* If we need a lock but don't have it, give up quickly. */
3797 if (txn
->db
->lock_name
&& !txn
->db
->has_lock
) {
3798 txn
->status
= TXN_NOT_LOCKED
;
3799 goto disassemble_out
;
3802 operations
= json_array_create_1(
3803 json_string_create(txn
->db
->class_
->database
));
3805 /* Assert that we have the required lock (avoiding a race). */
3806 if (txn
->db
->lock_name
) {
3807 struct json
*op
= json_object_create();
3808 json_array_add(operations
, op
);
3809 json_object_put_string(op
, "op", "assert");
3810 json_object_put_string(op
, "lock", txn
->db
->lock_name
);
3813 /* Add prerequisites and declarations of new rows. */
3814 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3815 /* XXX check that deleted rows exist even if no prereqs? */
3817 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3818 size_t n_columns
= class->n_columns
;
3819 struct json
*op
, *columns
, *row_json
;
3822 op
= json_object_create();
3823 json_array_add(operations
, op
);
3824 json_object_put_string(op
, "op", "wait");
3825 json_object_put_string(op
, "table", class->name
);
3826 json_object_put(op
, "timeout", json_integer_create(0));
3827 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3828 json_object_put_string(op
, "until", "==");
3829 columns
= json_array_create_empty();
3830 json_object_put(op
, "columns", columns
);
3831 row_json
= json_object_create();
3832 json_object_put(op
, "rows", json_array_create_1(row_json
));
3834 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
3835 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
3836 json_array_add(columns
, json_string_create(column
->name
));
3837 json_object_put(row_json
, column
->name
,
3838 ovsdb_datum_to_json(&row
->old_datum
[idx
],
3845 any_updates
= false;
3847 /* For tables constrained to have only a single row (a fairly common OVSDB
3848 * pattern for storing global data), identify whether we're inserting a
3849 * row. If so, then verify that the table is empty before inserting the
3850 * row. This gives us a clear verification-related failure if there was an
3851 * insertion race with another client. */
3852 for (size_t i
= 0; i
< txn
->db
->class_
->n_tables
; i
++) {
3853 struct ovsdb_idl_table
*table
= &txn
->db
->tables
[i
];
3854 if (table
->class_
->is_singleton
) {
3855 /* Count the number of rows in the table before and after our
3856 * transaction commits. This is O(n) in the number of rows in the
3857 * table, but that's OK since we know that the table should only
3859 size_t initial_rows
= 0;
3860 size_t final_rows
= 0;
3861 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
3862 initial_rows
+= row
->old_datum
!= NULL
;
3863 final_rows
+= row
->new_datum
!= NULL
;
3866 if (initial_rows
== 0 && final_rows
== 1) {
3867 struct json
*op
= json_object_create();
3868 json_array_add(operations
, op
);
3869 json_object_put_string(op
, "op", "wait");
3870 json_object_put_string(op
, "table", table
->class_
->name
);
3871 json_object_put(op
, "where", json_array_create_empty());
3872 json_object_put(op
, "timeout", json_integer_create(0));
3873 json_object_put_string(op
, "until", "==");
3874 json_object_put(op
, "rows", json_array_create_empty());
3879 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3880 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3882 if (!row
->new_datum
) {
3883 if (class->is_root
) {
3884 struct json
*op
= json_object_create();
3885 json_object_put_string(op
, "op", "delete");
3886 json_object_put_string(op
, "table", class->name
);
3887 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3888 json_array_add(operations
, op
);
3891 /* Let ovsdb-server decide whether to really delete it. */
3893 } else if (row
->old_datum
!= row
->new_datum
) {
3894 struct json
*row_json
;
3897 struct json
*op
= json_object_create();
3898 json_object_put_string(op
, "op",
3899 row
->old_datum
? "update" : "insert");
3900 json_object_put_string(op
, "table", class->name
);
3901 if (row
->old_datum
) {
3902 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3904 struct ovsdb_idl_txn_insert
*insert
;
3908 json_object_put(op
, "uuid-name",
3909 json_string_create_nocopy(
3910 ovsdb_data_row_name(&row
->uuid
)));
3912 insert
= xmalloc(sizeof *insert
);
3913 insert
->dummy
= row
->uuid
;
3914 insert
->op_index
= operations
->array
.n
- 1;
3915 uuid_zero(&insert
->real
);
3916 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
3917 uuid_hash(&insert
->dummy
));
3919 row_json
= json_object_create();
3920 json_object_put(op
, "row", row_json
);
3923 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
3924 const struct ovsdb_idl_column
*column
=
3925 &class->columns
[idx
];
3928 || !ovsdb_datum_is_default(&row
->new_datum
[idx
],
3932 value
= ovsdb_datum_to_json(&row
->new_datum
[idx
],
3934 json_object_put(row_json
, column
->name
,
3935 substitute_uuids(value
, txn
));
3937 /* If anything really changed, consider it an update.
3938 * We can't suppress not-really-changed values earlier
3939 * or transactions would become nonatomic (see the big
3940 * comment inside ovsdb_idl_txn_write()). */
3941 if (!any_updates
&& row
->old_datum
&&
3942 !ovsdb_datum_equals(&row
->old_datum
[idx
],
3943 &row
->new_datum
[idx
],
3951 if (!row
->old_datum
|| !shash_is_empty(json_object(row_json
))) {
3952 json_array_add(operations
, op
);
3958 /* Add mutate operation, for partial map or partial set updates. */
3959 if (row
->map_op_written
|| row
->set_op_written
) {
3960 struct json
*op
, *mutations
;
3963 op
= json_object_create();
3964 json_object_put_string(op
, "op", "mutate");
3965 json_object_put_string(op
, "table", class->name
);
3966 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3967 mutations
= json_array_create_empty();
3968 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
3969 json_object_put(op
, "mutations", mutations
);
3971 if (any_mutations
) {
3972 op
= substitute_uuids(op
, txn
);
3973 json_array_add(operations
, op
);
3981 /* Add increment. */
3982 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
3984 txn
->inc_index
= operations
->array
.n
- 1;
3986 struct json
*op
= json_object_create();
3987 json_object_put_string(op
, "op", "mutate");
3988 json_object_put_string(op
, "table", txn
->inc_table
);
3989 json_object_put(op
, "where",
3990 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
3992 json_object_put(op
, "mutations",
3993 json_array_create_1(
3994 json_array_create_3(
3995 json_string_create(txn
->inc_column
),
3996 json_string_create("+="),
3997 json_integer_create(1))));
3998 json_array_add(operations
, op
);
4000 op
= json_object_create();
4001 json_object_put_string(op
, "op", "select");
4002 json_object_put_string(op
, "table", txn
->inc_table
);
4003 json_object_put(op
, "where",
4004 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
4006 json_object_put(op
, "columns",
4007 json_array_create_1(json_string_create(
4009 json_array_add(operations
, op
);
4012 if (txn
->comment
.length
) {
4013 struct json
*op
= json_object_create();
4014 json_object_put_string(op
, "op", "comment");
4015 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
4016 json_array_add(operations
, op
);
4020 struct json
*op
= json_object_create();
4021 json_object_put_string(op
, "op", "abort");
4022 json_array_add(operations
, op
);
4026 txn
->status
= TXN_UNCHANGED
;
4027 json_destroy(operations
);
4028 } else if (!jsonrpc_session_send(
4029 txn
->db
->idl
->session
,
4030 jsonrpc_create_request(
4031 "transact", operations
, &txn
->request_id
))) {
4032 hmap_insert(&txn
->db
->outstanding_txns
, &txn
->hmap_node
,
4033 json_hash(txn
->request_id
, 0));
4034 txn
->status
= TXN_INCOMPLETE
;
4036 txn
->status
= TXN_TRY_AGAIN
;
4040 ovsdb_idl_txn_disassemble(txn
);
4042 switch (txn
->status
) {
4043 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
4044 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
4045 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
4046 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
4047 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
4048 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
4049 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
4050 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
4056 /* Attempts to commit 'txn', blocking until the commit either succeeds or
4057 * fails. Returns the final commit status, which may be any TXN_* value other
4058 * than TXN_INCOMPLETE.
4060 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
4061 * return value of ovsdb_idl_get_seqno() to change. */
4062 enum ovsdb_idl_txn_status
4063 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
4065 enum ovsdb_idl_txn_status status
;
4068 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
4069 ovsdb_idl_run(txn
->db
->idl
);
4070 ovsdb_idl_wait(txn
->db
->idl
);
4071 ovsdb_idl_txn_wait(txn
);
4077 /* Returns the final (incremented) value of the column in 'txn' that was set to
4078 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
4081 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
4083 ovs_assert(txn
->status
== TXN_SUCCESS
);
4084 return txn
->inc_new_value
;
4087 /* Aborts 'txn' without sending it to the database server. This is effective
4088 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
4089 * Otherwise, it has no effect.
4091 * Aborting a transaction doesn't free its memory. Use
4092 * ovsdb_idl_txn_destroy() to do that. */
4094 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
4096 ovsdb_idl_txn_disassemble(txn
);
4097 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
4098 txn
->status
= TXN_ABORTED
;
4102 /* Returns a string that reports the error status for 'txn'. The caller must
4103 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
4104 * for 'txn' may free the returned string.
4106 * The return value is ordinarily one of the strings that
4107 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
4108 * due to an error reported by the database server, the return value is that
4111 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
4113 if (txn
->status
!= TXN_ERROR
) {
4114 return ovsdb_idl_txn_status_to_string(txn
->status
);
4115 } else if (txn
->error
) {
4118 return "no error details available";
4123 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
4124 const struct json
*json
)
4126 if (json
&& txn
->error
== NULL
) {
4127 txn
->error
= json_to_string(json
, JSSF_SORT
);
4131 /* For transaction 'txn' that completed successfully, finds and returns the
4132 * permanent UUID that the database assigned to a newly inserted row, given the
4133 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
4135 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
4136 * if it was assigned by that function and then deleted by
4137 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
4138 * and then deleted within a single transaction are never sent to the database
4139 * server, so it never assigns them a permanent UUID.) */
4141 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
4142 const struct uuid
*uuid
)
4144 const struct ovsdb_idl_txn_insert
*insert
;
4146 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
4147 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
4148 uuid_hash(uuid
), &txn
->inserted_rows
) {
4149 if (uuid_equals(uuid
, &insert
->dummy
)) {
4150 return &insert
->real
;
4157 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
4158 enum ovsdb_idl_txn_status status
)
4160 txn
->status
= status
;
4161 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
4165 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
4166 const struct ovsdb_idl_column
*column
,
4167 struct ovsdb_datum
*datum
, bool owns_datum
)
4169 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4170 const struct ovsdb_idl_table_class
*class;
4174 ovs_assert(!column
->is_synthetic
);
4175 if (ovsdb_idl_row_is_synthetic(row
)) {
4179 class = row
->table
->class_
;
4180 column_idx
= column
- class->columns
;
4181 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
4183 ovs_assert(row
->new_datum
!= NULL
);
4184 ovs_assert(column_idx
< class->n_columns
);
4185 ovs_assert(row
->old_datum
== NULL
||
4186 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4188 if (row
->table
->db
->verify_write_only
&& !write_only
) {
4189 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
4190 " explicitly configured not to.", class->name
, column
->name
);
4194 /* If this is a write-only column and the datum being written is the same
4195 * as the one already there, just skip the update entirely. This is worth
4196 * optimizing because we have a lot of columns that get periodically
4197 * refreshed into the database but don't actually change that often.
4199 * We don't do this for read/write columns because that would break
4200 * atomicity of transactions--some other client might have written a
4201 * different value in that column since we read it. (But if a whole
4202 * transaction only does writes of existing values, without making any real
4203 * changes, we will drop the whole transaction later in
4204 * ovsdb_idl_txn_commit().) */
4205 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
4206 datum
, &column
->type
)) {
4210 if (hmap_node_is_null(&row
->txn_node
)) {
4211 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4212 uuid_hash(&row
->uuid
));
4214 if (row
->old_datum
== row
->new_datum
) {
4215 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4217 if (!row
->written
) {
4218 row
->written
= bitmap_allocate(class->n_columns
);
4220 if (bitmap_is_set(row
->written
, column_idx
)) {
4221 ovsdb_datum_destroy(&row
->new_datum
[column_idx
], &column
->type
);
4223 bitmap_set1(row
->written
, column_idx
);
4226 row
->new_datum
[column_idx
] = *datum
;
4228 ovsdb_datum_clone(&row
->new_datum
[column_idx
], datum
, &column
->type
);
4230 (column
->unparse
)(row
);
4231 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
4236 ovsdb_datum_destroy(datum
, &column
->type
);
4240 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
4241 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
4244 * 'datum' must have the correct type for its column, but it needs not be
4245 * sorted or unique because this function will take care of that. The IDL does
4246 * not check that it meets schema constraints, but ovsdb-server will do so at
4247 * commit time so it had better be correct.
4249 * A transaction must be in progress. Replication of 'column' must not have
4250 * been disabled (by calling ovsdb_idl_omit()).
4252 * Usually this function is used indirectly through one of the "set" functions
4253 * generated by ovsdb-idlc.
4255 * Takes ownership of what 'datum' points to (and in some cases destroys that
4256 * data before returning) but makes a copy of 'datum' itself. (Commonly
4257 * 'datum' is on the caller's stack.) */
4259 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
4260 const struct ovsdb_idl_column
*column
,
4261 struct ovsdb_datum
*datum
)
4263 ovsdb_datum_sort_unique(datum
,
4264 column
->type
.key
.type
, column
->type
.value
.type
);
4265 ovsdb_idl_txn_write__(row
, column
, datum
, true);
4268 /* Similar to ovsdb_idl_txn_write(), except:
4270 * - The caller retains ownership of 'datum' and what it points to.
4272 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
4273 * ovsdb_datum_sort_unique().) */
4275 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
4276 const struct ovsdb_idl_column
*column
,
4277 const struct ovsdb_datum
*datum
)
4279 ovsdb_idl_txn_write__(row
, column
,
4280 CONST_CAST(struct ovsdb_datum
*, datum
), false);
4283 /* Causes the original contents of 'column' in 'row_' to be verified as a
4284 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
4285 * changed (or if 'row_' was deleted) between the time that the IDL originally
4286 * read its contents and the time that the transaction commits, then the
4287 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
4289 * The intention is that, to ensure that no transaction commits based on dirty
4290 * reads, an application should call ovsdb_idl_txn_verify() on each data item
4291 * read as part of a read-modify-write operation.
4293 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
4294 * value of 'column' is already known:
4296 * - If 'row_' is a row created by the current transaction (returned by
4297 * ovsdb_idl_txn_insert()).
4299 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
4300 * within the current transaction.
4302 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
4303 * ovsdb_idl_txn_write() for a given read-modify-write.
4305 * A transaction must be in progress.
4307 * Usually this function is used indirectly through one of the "verify"
4308 * functions generated by ovsdb-idlc. */
4310 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
4311 const struct ovsdb_idl_column
*column
)
4313 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4314 const struct ovsdb_idl_table_class
*class;
4317 if (ovsdb_idl_row_is_synthetic(row
)) {
4321 class = row
->table
->class_
;
4322 column_idx
= column
- class->columns
;
4324 ovs_assert(row
->new_datum
!= NULL
);
4325 ovs_assert(row
->old_datum
== NULL
||
4326 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4328 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
4332 if (hmap_node_is_null(&row
->txn_node
)) {
4333 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4334 uuid_hash(&row
->uuid
));
4336 if (!row
->prereqs
) {
4337 row
->prereqs
= bitmap_allocate(class->n_columns
);
4339 bitmap_set1(row
->prereqs
, column_idx
);
4342 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4343 * accessed afterward.
4345 * A transaction must be in progress.
4347 * Usually this function is used indirectly through one of the "delete"
4348 * functions generated by ovsdb-idlc. */
4350 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
4352 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4354 if (ovsdb_idl_row_is_synthetic(row
)) {
4358 ovs_assert(row
->new_datum
!= NULL
);
4359 if (!row
->old_datum
) {
4360 ovsdb_idl_row_unparse(row
);
4361 ovsdb_idl_row_clear_new(row
);
4362 ovs_assert(!row
->prereqs
);
4363 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
4364 hmap_remove(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
);
4368 if (hmap_node_is_null(&row
->txn_node
)) {
4369 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4370 uuid_hash(&row
->uuid
));
4372 ovsdb_idl_row_clear_new(row
);
4373 row
->new_datum
= NULL
;
4376 /* Inserts and returns a new row in the table with the specified 'class' in the
4377 * database with open transaction 'txn'.
4379 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4380 * randomly generated; otherwise 'uuid' should specify a randomly generated
4381 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4382 * 'txn' is committed, but the IDL will replace any uses of the provisional
4383 * UUID in the data to be to be committed by the UUID assigned by
4386 * Usually this function is used indirectly through one of the "insert"
4387 * functions generated by ovsdb-idlc. */
4388 const struct ovsdb_idl_row
*
4389 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
4390 const struct ovsdb_idl_table_class
*class,
4391 const struct uuid
*uuid
)
4393 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
4396 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
4399 uuid_generate(&row
->uuid
);
4402 row
->table
= ovsdb_idl_db_table_from_class(txn
->db
, class);
4403 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4404 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
4405 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
4410 ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db
*db
)
4412 struct ovsdb_idl_txn
*txn
;
4414 HMAP_FOR_EACH (txn
, hmap_node
, &db
->outstanding_txns
) {
4415 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
4420 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
4422 ovsdb_idl_db_txn_abort_all(&idl
->server
);
4423 ovsdb_idl_db_txn_abort_all(&idl
->data
);
4426 static struct ovsdb_idl_txn
*
4427 ovsdb_idl_db_txn_find(struct ovsdb_idl_db
*db
, const struct json
*id
)
4429 struct ovsdb_idl_txn
*txn
;
4431 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
4432 json_hash(id
, 0), &db
->outstanding_txns
) {
4433 if (json_equal(id
, txn
->request_id
)) {
4441 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
4444 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
4446 } else if (json
->type
!= type
) {
4447 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
4448 name
, json_type_to_string(json
->type
),
4449 json_type_to_string(type
));
4457 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
4458 const struct json_array
*results
)
4460 struct json
*count
, *rows
, *row
, *column
;
4461 struct shash
*mutate
, *select
;
4463 if (txn
->inc_index
+ 2 > results
->n
) {
4464 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4465 "for increment (has %"PRIuSIZE
", needs %u)",
4466 results
->n
, txn
->inc_index
+ 2);
4470 /* We know that this is a JSON object because the loop in
4471 * ovsdb_idl_db_txn_process_reply() checked. */
4472 mutate
= json_object(results
->elems
[txn
->inc_index
]);
4473 count
= shash_find_data(mutate
, "count");
4474 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
4477 if (count
->integer
!= 1) {
4478 VLOG_WARN_RL(&syntax_rl
,
4479 "\"mutate\" reply \"count\" is %lld instead of 1",
4484 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
4485 rows
= shash_find_data(select
, "rows");
4486 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
4489 if (rows
->array
.n
!= 1) {
4490 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
4495 row
= rows
->array
.elems
[0];
4496 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
4499 column
= shash_find_data(json_object(row
), txn
->inc_column
);
4500 if (!check_json_type(column
, JSON_INTEGER
,
4501 "\"select\" reply inc column")) {
4504 txn
->inc_new_value
= column
->integer
;
4509 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
4510 const struct json_array
*results
)
4512 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
4513 struct ovsdb_error
*error
;
4514 struct json
*json_uuid
;
4515 union ovsdb_atom uuid
;
4516 struct shash
*reply
;
4518 if (insert
->op_index
>= results
->n
) {
4519 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4520 "for insert (has %"PRIuSIZE
", needs %u)",
4521 results
->n
, insert
->op_index
);
4525 /* We know that this is a JSON object because the loop in
4526 * ovsdb_idl_txn_process_reply() checked. */
4527 reply
= json_object(results
->elems
[insert
->op_index
]);
4528 json_uuid
= shash_find_data(reply
, "uuid");
4529 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
4533 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
4535 char *s
= ovsdb_error_to_string_free(error
);
4536 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
4542 insert
->real
= uuid
.uuid
;
4548 ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db
*db
,
4549 const struct jsonrpc_msg
*msg
)
4551 struct ovsdb_idl_txn
*txn
;
4552 enum ovsdb_idl_txn_status status
;
4554 txn
= ovsdb_idl_db_txn_find(db
, msg
->id
);
4559 if (msg
->type
== JSONRPC_ERROR
) {
4561 && msg
->error
->type
== JSON_STRING
4562 && !strcmp(json_string(msg
->error
), "canceled")) {
4563 /* ovsdb-server uses this error message to indicate that the
4564 * transaction was canceled because the database in question was
4565 * removed, converted, etc. */
4566 status
= TXN_TRY_AGAIN
;
4569 ovsdb_idl_txn_set_error_json(txn
, msg
->error
);
4571 } else if (msg
->result
->type
!= JSON_ARRAY
) {
4572 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
4574 ovsdb_idl_txn_set_error_json(txn
, msg
->result
);
4576 struct json_array
*ops
= &msg
->result
->array
;
4577 int hard_errors
= 0;
4578 int soft_errors
= 0;
4579 int lock_errors
= 0;
4582 for (i
= 0; i
< ops
->n
; i
++) {
4583 struct json
*op
= ops
->elems
[i
];
4585 if (op
->type
== JSON_NULL
) {
4586 /* This isn't an error in itself but indicates that some prior
4587 * operation failed, so make sure that we know about it. */
4589 } else if (op
->type
== JSON_OBJECT
) {
4592 error
= shash_find_data(json_object(op
), "error");
4594 if (error
->type
== JSON_STRING
) {
4595 if (!strcmp(error
->string
, "timed out")) {
4597 } else if (!strcmp(error
->string
, "not owner")) {
4599 } else if (!strcmp(error
->string
, "not allowed")) {
4601 ovsdb_idl_txn_set_error_json(txn
, op
);
4602 } else if (strcmp(error
->string
, "aborted")) {
4604 ovsdb_idl_txn_set_error_json(txn
, op
);
4605 VLOG_WARN_RL(&other_rl
,
4606 "transaction error: %s", txn
->error
);
4610 ovsdb_idl_txn_set_error_json(txn
, op
);
4611 VLOG_WARN_RL(&syntax_rl
,
4612 "\"error\" in reply is not JSON string");
4617 ovsdb_idl_txn_set_error_json(txn
, op
);
4618 VLOG_WARN_RL(&syntax_rl
,
4619 "operation reply is not JSON null or object");
4623 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
4624 struct ovsdb_idl_txn_insert
*insert
;
4626 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
4630 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
4631 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
4637 status
= (hard_errors
? TXN_ERROR
4638 : lock_errors
? TXN_NOT_LOCKED
4639 : soft_errors
? TXN_TRY_AGAIN
4643 ovsdb_idl_txn_complete(txn
, status
);
4647 /* Returns the transaction currently active for 'row''s IDL. A transaction
4648 * must currently be active. */
4649 struct ovsdb_idl_txn
*
4650 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
4652 struct ovsdb_idl_txn
*txn
= row
->table
->db
->txn
;
4653 ovs_assert(txn
!= NULL
);
4657 /* Returns the IDL on which 'txn' acts. */
4659 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
4661 return txn
->db
->idl
;
4664 /* Blocks until 'idl' successfully connects to the remote database and
4665 * retrieves its contents. */
4667 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
4671 if (ovsdb_idl_has_ever_connected(idl
)) {
4674 ovsdb_idl_wait(idl
);
4679 static struct jsonrpc_msg
*
4680 ovsdb_idl_db_set_lock(struct ovsdb_idl_db
*db
, const char *lock_name
)
4682 ovs_assert(!db
->txn
);
4683 ovs_assert(hmap_is_empty(&db
->outstanding_txns
));
4686 && (!lock_name
|| strcmp(lock_name
, db
->lock_name
))) {
4687 /* Release previous lock. */
4688 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_unlock_request(db
);
4689 free(db
->lock_name
);
4690 db
->lock_name
= NULL
;
4691 db
->is_lock_contended
= false;
4695 if (lock_name
&& !db
->lock_name
) {
4696 /* Acquire new lock. */
4697 db
->lock_name
= xstrdup(lock_name
);
4698 return ovsdb_idl_db_compose_lock_request(db
);
4704 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
4705 * the database server and to avoid modifying the database when the lock cannot
4706 * be acquired (that is, when another client has the same lock).
4708 * If 'lock_name' is NULL, drops the locking requirement and releases the
4711 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
4714 struct jsonrpc_msg
*msg
= ovsdb_idl_db_set_lock(&idl
->data
, lock_name
);
4718 jsonrpc_session_send(idl
->session
, msg
);
4722 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
4724 * Locking and unlocking happens asynchronously from the database client's
4725 * point of view, so the information is only useful for optimization (e.g. if
4726 * the client doesn't have the lock then there's no point in trying to write to
4729 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
4731 return idl
->data
.has_lock
;
4734 /* Returns true if 'idl' is configured to obtain a lock but the database server
4735 * has indicated that some other client already owns the requested lock. */
4737 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
4739 return idl
->data
.is_lock_contended
;
4743 ovsdb_idl_db_update_has_lock(struct ovsdb_idl_db
*db
, bool new_has_lock
)
4745 if (new_has_lock
&& !db
->has_lock
) {
4746 if (db
->idl
->state
== IDL_S_MONITORING
) {
4749 /* We're setting up a session, so don't signal that the database
4750 * changed. Finalizing the session will increment change_seqno
4753 db
->is_lock_contended
= false;
4755 db
->has_lock
= new_has_lock
;
4759 ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db
*db
,
4760 const struct jsonrpc_msg
*msg
)
4762 if (msg
->type
== JSONRPC_REPLY
4763 && db
->lock_request_id
4764 && json_equal(db
->lock_request_id
, msg
->id
)) {
4765 /* Reply to our "lock" request. */
4766 ovsdb_idl_db_parse_lock_reply(db
, msg
->result
);
4770 if (msg
->type
== JSONRPC_NOTIFY
) {
4771 if (!strcmp(msg
->method
, "locked")) {
4772 /* We got our lock. */
4773 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, true);
4774 } else if (!strcmp(msg
->method
, "stolen")) {
4775 /* Someone else stole our lock. */
4776 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, false);
4783 static struct jsonrpc_msg
*
4784 ovsdb_idl_db_compose_lock_request__(struct ovsdb_idl_db
*db
,
4787 ovsdb_idl_db_update_has_lock(db
, false);
4789 json_destroy(db
->lock_request_id
);
4790 db
->lock_request_id
= NULL
;
4792 struct json
*params
= json_array_create_1(json_string_create(
4794 return jsonrpc_create_request(method
, params
, NULL
);
4797 static struct jsonrpc_msg
*
4798 ovsdb_idl_db_compose_lock_request(struct ovsdb_idl_db
*db
)
4800 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_lock_request__(db
, "lock");
4801 db
->lock_request_id
= json_clone(msg
->id
);
4805 static struct jsonrpc_msg
*
4806 ovsdb_idl_db_compose_unlock_request(struct ovsdb_idl_db
*db
)
4808 return ovsdb_idl_db_compose_lock_request__(db
, "unlock");
4812 ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db
*db
,
4813 const struct json
*result
)
4817 json_destroy(db
->lock_request_id
);
4818 db
->lock_request_id
= NULL
;
4820 if (result
->type
== JSON_OBJECT
) {
4821 const struct json
*locked
;
4823 locked
= shash_find_data(json_object(result
), "locked");
4824 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
4829 ovsdb_idl_db_update_has_lock(db
, got_lock
);
4831 db
->is_lock_contended
= true;
4836 ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db
*db
,
4837 const struct json
*params
,
4841 && params
->type
== JSON_ARRAY
4842 && json_array(params
)->n
> 0
4843 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
4844 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
4846 if (!strcmp(db
->lock_name
, lock_name
)) {
4847 ovsdb_idl_db_update_has_lock(db
, new_has_lock
);
4848 if (!new_has_lock
) {
4849 db
->is_lock_contended
= true;
4857 /* Inserts a new Map Operation into current transaction. */
4859 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
4860 const struct ovsdb_idl_column
*column
,
4861 struct ovsdb_datum
*datum
,
4862 enum map_op_type op_type
)
4864 const struct ovsdb_idl_table_class
*class;
4866 struct map_op
*map_op
;
4868 class = row
->table
->class_
;
4869 column_idx
= column
- class->columns
;
4871 /* Check if a map operation list exists for this column. */
4872 if (!row
->map_op_written
) {
4873 row
->map_op_written
= bitmap_allocate(class->n_columns
);
4874 row
->map_op_lists
= xzalloc(class->n_columns
*
4875 sizeof *row
->map_op_lists
);
4877 if (!row
->map_op_lists
[column_idx
]) {
4878 row
->map_op_lists
[column_idx
] = map_op_list_create();
4881 /* Add a map operation to the corresponding list. */
4882 map_op
= map_op_create(datum
, op_type
);
4883 bitmap_set1(row
->map_op_written
, column_idx
);
4884 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
4886 /* Add this row to transaction's list of rows. */
4887 if (hmap_node_is_null(&row
->txn_node
)) {
4888 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4889 uuid_hash(&row
->uuid
));
4893 /* Inserts a new Set Operation into current transaction. */
4895 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
4896 const struct ovsdb_idl_column
*column
,
4897 struct ovsdb_datum
*datum
,
4898 enum set_op_type op_type
)
4900 const struct ovsdb_idl_table_class
*class;
4902 struct set_op
*set_op
;
4904 class = row
->table
->class_
;
4905 column_idx
= column
- class->columns
;
4907 /* Check if a set operation list exists for this column. */
4908 if (!row
->set_op_written
) {
4909 row
->set_op_written
= bitmap_allocate(class->n_columns
);
4910 row
->set_op_lists
= xzalloc(class->n_columns
*
4911 sizeof *row
->set_op_lists
);
4913 if (!row
->set_op_lists
[column_idx
]) {
4914 row
->set_op_lists
[column_idx
] = set_op_list_create();
4917 /* Add a set operation to the corresponding list. */
4918 set_op
= set_op_create(datum
, op_type
);
4919 bitmap_set1(row
->set_op_written
, column_idx
);
4920 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
4922 /* Add this row to the transactions's list of rows. */
4923 if (hmap_node_is_null(&row
->txn_node
)) {
4924 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4925 uuid_hash(&row
->uuid
));
4930 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
4931 const struct ovsdb_idl_column
*column
,
4932 struct ovsdb_datum
*datum
)
4934 /* Verify that this column is being monitored. */
4935 unsigned int column_idx
= column
- row
->table
->class_
->columns
;
4936 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
4937 VLOG_WARN("cannot partially update non-monitored column");
4941 /* Verify that the update affects a single element. */
4942 if (datum
->n
!= 1) {
4943 VLOG_WARN("invalid datum for partial update");
4950 /* Inserts the value described in 'datum' into the map in 'column' in
4951 * 'row_'. If the value doesn't already exist in 'column' then it's value
4952 * is added. The value in 'datum' must be of the same type as the values
4953 * in 'column'. This function takes ownership of 'datum'.
4955 * Usually this function is used indirectly through one of the "update"
4956 * functions generated by vswitch-idl. */
4958 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
4959 const struct ovsdb_idl_column
*column
,
4960 struct ovsdb_datum
*datum
)
4962 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4963 enum set_op_type op_type
;
4965 if (!is_valid_partial_update(row
, column
, datum
)) {
4966 ovsdb_datum_destroy(datum
, &column
->type
);
4971 op_type
= SET_OP_INSERT
;
4973 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
4976 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
4977 * The value in 'datum' must be of the same type as the keys in 'column'.
4978 * This function takes ownership of 'datum'.
4980 * Usually this function is used indirectly through one of the "update"
4981 * functions generated by vswitch-idl. */
4983 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
4984 const struct ovsdb_idl_column
*column
,
4985 struct ovsdb_datum
*datum
)
4987 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4989 if (!is_valid_partial_update(row
, column
, datum
)) {
4990 struct ovsdb_type type_
= column
->type
;
4991 type_
.value
.type
= OVSDB_TYPE_VOID
;
4992 ovsdb_datum_destroy(datum
, &type_
);
4996 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
4999 /* Inserts the key-value specified in 'datum' into the map in 'column' in
5000 * 'row_'. If the key already exist in 'column', then it's value is updated
5001 * with the value in 'datum'. The key-value in 'datum' must be of the same type
5002 * as the keys-values in 'column'. This function takes ownership of 'datum'.
5004 * Usually this function is used indirectly through one of the "update"
5005 * functions generated by vswitch-idl. */
5007 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
5008 const struct ovsdb_idl_column
*column
,
5009 struct ovsdb_datum
*datum
)
5011 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5012 enum ovsdb_atomic_type key_type
;
5013 enum map_op_type op_type
;
5015 const struct ovsdb_datum
*old_datum
;
5017 if (!is_valid_partial_update(row
, column
, datum
)) {
5018 ovsdb_datum_destroy(datum
, &column
->type
);
5023 /* Find out if this is an insert or an update. */
5024 key_type
= column
->type
.key
.type
;
5025 old_datum
= ovsdb_idl_read(row
, column
);
5026 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
5027 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
5029 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
5032 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
5033 * The key in 'datum' must be of the same type as the keys in 'column'.
5034 * The value in 'datum' must be NULL. This function takes ownership of
5037 * Usually this function is used indirectly through one of the "update"
5038 * functions generated by vswitch-idl. */
5040 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
5041 const struct ovsdb_idl_column
*column
,
5042 struct ovsdb_datum
*datum
)
5044 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5046 if (!is_valid_partial_update(row
, column
, datum
)) {
5047 struct ovsdb_type type_
= column
->type
;
5048 type_
.value
.type
= OVSDB_TYPE_VOID
;
5049 ovsdb_datum_destroy(datum
, &type_
);
5053 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
5057 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
5060 ovsdb_idl_destroy(loop
->idl
);
5064 struct ovsdb_idl_txn
*
5065 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
5067 ovsdb_idl_run(loop
->idl
);
5068 loop
->open_txn
= (loop
->committing_txn
5069 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
5071 : ovsdb_idl_txn_create(loop
->idl
));
5072 return loop
->open_txn
;
5075 /* Attempts to commit the current transaction, if one is open, and sets up the
5076 * poll loop to wake up when some more work might be needed.
5078 * If a transaction was open, in this or a previous iteration of the main loop,
5079 * and had not before finished committing (successfully or unsuccessfully), the
5080 * return value is one of:
5082 * 1: The transaction committed successfully (or it did not change anything in
5084 * 0: The transaction failed.
5085 * -1: The commit is still in progress.
5087 * Thus, the return value is -1 if the transaction is in progress and otherwise
5088 * true for success, false for failure.
5090 * (In the corner case where the IDL sends a transaction to the database and
5091 * the database commits it, and the connection between the IDL and the database
5092 * drops before the IDL receives the message confirming the commit, this
5093 * function can return 0 even though the transaction succeeded.)
5096 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
5098 if (loop
->open_txn
) {
5099 loop
->committing_txn
= loop
->open_txn
;
5100 loop
->open_txn
= NULL
;
5102 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
5105 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
5108 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
5109 if (status
!= TXN_INCOMPLETE
) {
5112 /* We want to re-evaluate the database when it's changed from
5113 * the contents that it had when we started the commit. (That
5114 * might have already happened.) */
5115 loop
->skip_seqno
= loop
->precommit_seqno
;
5116 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
5117 poll_immediate_wake();
5123 /* Possibly some work on the database was deferred because no
5124 * further transaction could proceed. Wake up again. */
5126 loop
->cur_cfg
= loop
->next_cfg
;
5127 poll_immediate_wake();
5132 loop
->cur_cfg
= loop
->next_cfg
;
5136 case TXN_NOT_LOCKED
:
5141 case TXN_UNCOMMITTED
:
5142 case TXN_INCOMPLETE
:
5146 ovsdb_idl_txn_destroy(txn
);
5147 loop
->committing_txn
= NULL
;
5152 /* Not a meaningful return value: no transaction was in progress. */
5156 ovsdb_idl_wait(loop
->idl
);