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 ovsdb_idl_row_destroy(row
);
564 db
->cond_changed
= false;
566 ovsdb_idl_db_track_clear(db
);
574 ovsdb_idl_state_to_string(enum ovsdb_idl_state state
)
577 #define OVSDB_IDL_STATE(NAME) case IDL_S_##NAME: return #NAME;
579 #undef OVSDB_IDL_STATE
580 default: return "<unknown>";
585 ovsdb_idl_retry_at(struct ovsdb_idl
*idl
, const char *where
)
587 if (jsonrpc_session_get_n_remotes(idl
->session
) > 1) {
588 ovsdb_idl_force_reconnect(idl
);
589 ovsdb_idl_transition_at(idl
, IDL_S_RETRY
, where
);
591 ovsdb_idl_transition_at(idl
, IDL_S_ERROR
, where
);
596 ovsdb_idl_transition_at(struct ovsdb_idl
*idl
, enum ovsdb_idl_state new_state
,
599 VLOG_DBG("%s: %s -> %s at %s",
600 jsonrpc_session_get_name(idl
->session
),
601 ovsdb_idl_state_to_string(idl
->state
),
602 ovsdb_idl_state_to_string(new_state
),
604 idl
->state
= new_state
;
608 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
610 ovsdb_idl_db_clear(&idl
->data
);
614 ovsdb_idl_send_request(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*request
)
616 json_destroy(idl
->request_id
);
617 idl
->request_id
= json_clone(request
->id
);
618 jsonrpc_session_send(idl
->session
, request
);
622 ovsdb_idl_restart_fsm(struct ovsdb_idl
*idl
)
624 ovsdb_idl_send_schema_request(idl
, &idl
->server
);
625 ovsdb_idl_transition(idl
, IDL_S_SERVER_SCHEMA_REQUESTED
);
626 idl
->data
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
627 idl
->server
.monitoring
= OVSDB_IDL_NOT_MONITORING
;
631 ovsdb_idl_process_response(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
633 bool ok
= msg
->type
== JSONRPC_REPLY
;
635 && idl
->state
!= IDL_S_SERVER_SCHEMA_REQUESTED
636 && idl
->state
!= IDL_S_SERVER_MONITOR_COND_REQUESTED
637 && idl
->state
!= IDL_S_DATA_MONITOR_COND_REQUESTED
) {
638 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
639 char *s
= jsonrpc_msg_to_string(msg
);
640 VLOG_INFO_RL(&rl
, "%s: received unexpected %s response in "
641 "%s state: %s", jsonrpc_session_get_name(idl
->session
),
642 jsonrpc_msg_type_to_string(msg
->type
),
643 ovsdb_idl_state_to_string(idl
->state
),
646 ovsdb_idl_retry(idl
);
650 switch (idl
->state
) {
651 case IDL_S_SERVER_SCHEMA_REQUESTED
:
653 json_destroy(idl
->server
.schema
);
654 idl
->server
.schema
= json_clone(msg
->result
);
655 ovsdb_idl_send_monitor_request(idl
, &idl
->server
, true);
656 ovsdb_idl_transition(idl
, IDL_S_SERVER_MONITOR_COND_REQUESTED
);
658 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
659 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
663 case IDL_S_SERVER_MONITOR_COND_REQUESTED
:
665 idl
->server
.monitoring
= OVSDB_IDL_MONITORING_COND
;
666 ovsdb_idl_db_parse_monitor_reply(&idl
->server
, msg
->result
, true);
667 if (ovsdb_idl_check_server_db(idl
)) {
668 ovsdb_idl_send_db_change_aware(idl
);
671 ovsdb_idl_send_schema_request(idl
, &idl
->data
);
672 ovsdb_idl_transition(idl
, IDL_S_DATA_SCHEMA_REQUESTED
);
676 case IDL_S_DATA_SCHEMA_REQUESTED
:
677 json_destroy(idl
->data
.schema
);
678 idl
->data
.schema
= json_clone(msg
->result
);
679 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, true);
680 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
683 case IDL_S_DATA_MONITOR_COND_REQUESTED
:
685 /* "monitor_cond" not supported. Try "monitor". */
686 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, false);
687 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_REQUESTED
);
689 idl
->data
.monitoring
= OVSDB_IDL_MONITORING_COND
;
690 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
691 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
, true);
695 case IDL_S_DATA_MONITOR_REQUESTED
:
696 idl
->data
.monitoring
= OVSDB_IDL_MONITORING
;
697 ovsdb_idl_transition(idl
, IDL_S_MONITORING
);
698 ovsdb_idl_db_parse_monitor_reply(&idl
->data
, msg
->result
, false);
699 idl
->data
.change_seqno
++;
700 ovsdb_idl_clear(idl
);
701 ovsdb_idl_db_parse_update(&idl
->data
, msg
->result
, false);
704 case IDL_S_MONITORING
:
705 /* We don't normally have a request outstanding in this state. If we
706 * do, it's a "monitor_cond_change", which means that the conditional
707 * monitor clauses were updated.
709 * If further condition changes were pending, send them now. */
710 ovsdb_idl_send_cond_change(idl
);
711 idl
->data
.cond_seqno
++;
716 /* Nothing to do in this state. */
725 ovsdb_idl_process_msg(struct ovsdb_idl
*idl
, struct jsonrpc_msg
*msg
)
727 bool is_response
= (msg
->type
== JSONRPC_REPLY
||
728 msg
->type
== JSONRPC_ERROR
);
730 /* Process a reply to an outstanding request. */
732 && idl
->request_id
&& json_equal(idl
->request_id
, msg
->id
)) {
733 json_destroy(idl
->request_id
);
734 idl
->request_id
= NULL
;
735 ovsdb_idl_process_response(idl
, msg
);
739 /* Process database contents updates. */
740 if (ovsdb_idl_db_parse_update_rpc(&idl
->data
, msg
)) {
743 if (idl
->server
.monitoring
744 && ovsdb_idl_db_parse_update_rpc(&idl
->server
, msg
)) {
745 ovsdb_idl_check_server_db(idl
);
749 if (ovsdb_idl_handle_monitor_canceled(idl
, &idl
->data
, msg
)
750 || (idl
->server
.monitoring
751 && ovsdb_idl_handle_monitor_canceled(idl
, &idl
->server
, msg
))) {
755 /* Process "lock" replies and related notifications. */
756 if (ovsdb_idl_db_process_lock_replies(&idl
->data
, msg
)) {
760 /* Process response to a database transaction we submitted. */
761 if (is_response
&& ovsdb_idl_db_txn_process_reply(&idl
->data
, msg
)) {
765 /* Unknown message. Log at a low level because this can happen if
766 * ovsdb_idl_txn_destroy() is called to destroy a transaction
767 * before we receive the reply.
769 * (We could sort those out from other kinds of unknown messages by
770 * using distinctive IDs for transactions, if it seems valuable to
771 * do so, and then it would be possible to use different log
773 char *s
= jsonrpc_msg_to_string(msg
);
774 VLOG_DBG("%s: received unexpected %s message: %s",
775 jsonrpc_session_get_name(idl
->session
),
776 jsonrpc_msg_type_to_string(msg
->type
), s
);
780 /* Processes a batch of messages from the database server on 'idl'. This may
781 * cause the IDL's contents to change. The client may check for that with
782 * ovsdb_idl_get_seqno(). */
784 ovsdb_idl_run(struct ovsdb_idl
*idl
)
788 ovs_assert(!idl
->data
.txn
);
790 ovsdb_idl_send_cond_change(idl
);
792 jsonrpc_session_run(idl
->session
);
793 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
794 struct jsonrpc_msg
*msg
;
797 seqno
= jsonrpc_session_get_seqno(idl
->session
);
798 if (idl
->state_seqno
!= seqno
) {
799 idl
->state_seqno
= seqno
;
800 ovsdb_idl_txn_abort_all(idl
);
801 ovsdb_idl_restart_fsm(idl
);
803 if (idl
->data
.lock_name
) {
804 jsonrpc_session_send(
806 ovsdb_idl_db_compose_lock_request(&idl
->data
));
810 msg
= jsonrpc_session_recv(idl
->session
);
814 ovsdb_idl_process_msg(idl
, msg
);
815 jsonrpc_msg_destroy(msg
);
817 ovsdb_idl_row_destroy_postprocess(&idl
->data
);
820 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
821 * do or when activity occurs on a transaction on 'idl'. */
823 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
825 jsonrpc_session_wait(idl
->session
);
826 jsonrpc_session_recv_wait(idl
->session
);
829 /* Returns a "sequence number" that represents the state of 'idl'. When
830 * ovsdb_idl_run() changes the database, the sequence number changes. The
831 * initial fetch of the entire contents of the remote database is considered to
832 * be one kind of change. Successfully acquiring a lock, if one has been
833 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
835 * As long as the sequence number does not change, the client may continue to
836 * use any data structures it obtains from 'idl'. But when it changes, the
837 * client must not access any of these data structures again, because they
838 * could have freed or reused for other purposes.
840 * The sequence number can occasionally change even if the database does not.
841 * This happens if the connection to the database drops and reconnects, which
842 * causes the database contents to be reloaded even if they didn't change. (It
843 * could also happen if the database server sends out a "change" that reflects
844 * what the IDL already thought was in the database. The database server is
845 * not supposed to do that, but bugs could in theory cause it to do so.) */
847 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
849 return idl
->data
.change_seqno
;
852 /* Returns a "sequence number" that represents the number of conditional
853 * monitoring updates successfully received by the OVSDB server of an IDL
856 * ovsdb_idl_set_condition() sets a new condition that is different from
857 * the current condtion, the next expected "sequence number" is returned.
859 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
860 * the return value of ovsdb_idl_set_condition(), The client is
862 * - The ovsdb_idl_set_condition() changes has been acknowledged by
865 * - 'idl' now contains the content matches the new conditions. */
867 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl
*idl
)
869 return idl
->data
.cond_seqno
;
872 /* Returns true if 'idl' successfully connected to the remote database and
873 * retrieved its contents (even if the connection subsequently dropped and is
874 * in the process of reconnecting). If so, then 'idl' contains an atomic
875 * snapshot of the database's contents (but it might be arbitrarily old if the
876 * connection dropped).
878 * Returns false if 'idl' has never connected or retrieved the database's
879 * contents. If so, 'idl' is empty. */
881 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
883 return ovsdb_idl_get_seqno(idl
) != 0;
886 /* Reconfigures 'idl' so that it would reconnect to the database, if
887 * connection was dropped. */
889 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
891 jsonrpc_session_enable_reconnect(idl
->session
);
894 /* Forces 'idl' to drop its connection to the database and reconnect. In the
895 * meantime, the contents of 'idl' will not change. */
897 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
899 jsonrpc_session_force_reconnect(idl
->session
);
902 /* Some IDL users should only write to write-only columns. Furthermore,
903 * writing to a column which is not write-only can cause serious performance
904 * degradations for these users. This function causes 'idl' to reject writes
905 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
907 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
909 idl
->data
.verify_write_only
= true;
912 /* Returns true if 'idl' is currently connected or trying to connect
913 * and a negative response to a schema request has not been received */
915 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
917 return jsonrpc_session_is_alive(idl
->session
) &&
918 idl
->state
!= IDL_S_ERROR
;
922 ovsdb_idl_is_connected(const struct ovsdb_idl
*idl
)
924 return idl
->session
&& jsonrpc_session_is_connected(idl
->session
);
927 /* Returns the last error reported on a connection by 'idl'. The return value
928 * is 0 only if no connection made by 'idl' has ever encountered an error and
929 * a negative response to a schema request has never been received. See
930 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
933 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
937 err
= jsonrpc_session_get_last_error(idl
->session
);
941 } else if (idl
->state
== IDL_S_ERROR
) {
948 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
952 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
954 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
958 find_uuid_in_array(const struct uuid
*target
,
959 const struct uuid
*array
, size_t n
)
961 for (size_t i
= 0; i
< n
; i
++) {
962 if (uuid_equals(&array
[i
], target
)) {
970 array_contains_uuid(const struct uuid
*target
,
971 const struct uuid
*array
, size_t n
)
973 return find_uuid_in_array(target
, array
, n
) != SIZE_MAX
;
977 remove_uuid_from_array(const struct uuid
*target
,
978 struct uuid
*array
, size_t *n
)
980 size_t i
= find_uuid_in_array(target
, array
, *n
);
982 array
[i
] = array
[--*n
];
990 add_row_references(const struct ovsdb_base_type
*type
,
991 const union ovsdb_atom
*atoms
, size_t n_atoms
,
992 const struct uuid
*exclude_uuid
,
993 struct uuid
**dstsp
, size_t *n_dstsp
,
994 size_t *allocated_dstsp
)
996 if (type
->type
!= OVSDB_TYPE_UUID
|| !type
->uuid
.refTableName
) {
1000 for (size_t i
= 0; i
< n_atoms
; i
++) {
1001 const struct uuid
*uuid
= &atoms
[i
].uuid
;
1002 if (!uuid_equals(uuid
, exclude_uuid
)
1003 && !array_contains_uuid(uuid
, *dstsp
, *n_dstsp
)) {
1004 if (*n_dstsp
>= *allocated_dstsp
) {
1005 *dstsp
= x2nrealloc(*dstsp
, allocated_dstsp
,
1009 (*dstsp
)[*n_dstsp
] = *uuid
;
1015 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
1016 * reference from one row to a different row should be reflected as a "struct
1017 * ovsdb_idl_arc" between those rows.
1019 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
1020 * thus it is only for use in test programs. */
1022 ovsdb_idl_check_consistency(const struct ovsdb_idl
*idl
)
1024 /* Consistency is broken while a transaction is in progress. */
1025 if (!idl
->data
.txn
) {
1031 struct uuid
*dsts
= NULL
;
1032 size_t allocated_dsts
= 0;
1034 for (size_t i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1035 const struct ovsdb_idl_table
*table
= &idl
->data
.tables
[i
];
1036 const struct ovsdb_idl_table_class
*class = table
->class_
;
1038 const struct ovsdb_idl_row
*row
;
1039 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
1041 if (row
->new_datum
) {
1042 size_t n_columns
= shash_count(&row
->table
->columns
);
1043 for (size_t j
= 0; j
< n_columns
; j
++) {
1044 const struct ovsdb_type
*type
= &class->columns
[j
].type
;
1045 const struct ovsdb_datum
*datum
= &row
->new_datum
[j
];
1046 add_row_references(&type
->key
,
1047 datum
->keys
, datum
->n
, &row
->uuid
,
1048 &dsts
, &n_dsts
, &allocated_dsts
);
1049 add_row_references(&type
->value
,
1050 datum
->values
, datum
->n
, &row
->uuid
,
1051 &dsts
, &n_dsts
, &allocated_dsts
);
1054 const struct ovsdb_idl_arc
*arc
;
1055 LIST_FOR_EACH (arc
, src_node
, &row
->src_arcs
) {
1056 if (!remove_uuid_from_array(&arc
->dst
->uuid
,
1058 VLOG_ERR("unexpected arc from %s row "UUID_FMT
" to %s "
1060 table
->class_
->name
,
1061 UUID_ARGS(&row
->uuid
),
1062 arc
->dst
->table
->class_
->name
,
1063 UUID_ARGS(&arc
->dst
->uuid
));
1067 for (size_t j
= 0; j
< n_dsts
; j
++) {
1068 VLOG_ERR("%s row "UUID_FMT
" missing arc to row "UUID_FMT
,
1069 table
->class_
->name
, UUID_ARGS(&row
->uuid
),
1070 UUID_ARGS(&dsts
[j
]));
1079 const struct ovsdb_idl_class
*
1080 ovsdb_idl_get_class(const struct ovsdb_idl
*idl
)
1082 return idl
->data
.class_
;
1085 /* Given 'column' in some table in 'class', returns the table's class. */
1086 const struct ovsdb_idl_table_class
*
1087 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class
*class,
1088 const struct ovsdb_idl_column
*column
)
1090 for (size_t i
= 0; i
< class->n_tables
; i
++) {
1091 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
1092 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
1100 /* Given 'column' in some table in 'db', returns the table. */
1101 static struct ovsdb_idl_table
*
1102 ovsdb_idl_table_from_column(struct ovsdb_idl_db
*db
,
1103 const struct ovsdb_idl_column
*column
)
1105 const struct ovsdb_idl_table_class
*tc
=
1106 ovsdb_idl_table_class_from_column(db
->class_
, column
);
1107 return &db
->tables
[tc
- db
->class_
->tables
];
1110 static unsigned char *
1111 ovsdb_idl_db_get_mode(struct ovsdb_idl_db
*db
,
1112 const struct ovsdb_idl_column
*column
)
1114 ovs_assert(!db
->change_seqno
);
1116 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1118 return &table
->modes
[column
- table
->class_
->columns
];
1122 ovsdb_idl_db_set_mode(struct ovsdb_idl_db
*db
,
1123 const struct ovsdb_idl_column
*column
,
1126 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(db
,
1128 size_t column_idx
= column
- table
->class_
->columns
;
1130 if (table
->modes
[column_idx
] != mode
) {
1131 *ovsdb_idl_db_get_mode(db
, column
) = mode
;
1136 add_ref_table(struct ovsdb_idl_db
*db
, const struct ovsdb_base_type
*base
)
1138 if (base
->type
== OVSDB_TYPE_UUID
&& base
->uuid
.refTableName
) {
1139 struct ovsdb_idl_table
*table
;
1141 table
= shash_find_data(&db
->table_by_name
, base
->uuid
.refTableName
);
1143 table
->need_table
= true;
1145 VLOG_WARN("%s IDL class missing referenced table %s",
1146 db
->class_
->database
, base
->uuid
.refTableName
);
1152 ovsdb_idl_db_add_column(struct ovsdb_idl_db
*db
,
1153 const struct ovsdb_idl_column
*column
)
1155 ovsdb_idl_db_set_mode(db
, column
, OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
);
1156 add_ref_table(db
, &column
->type
.key
);
1157 add_ref_table(db
, &column
->type
.value
);
1160 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
1161 * ensures that any tables referenced by 'column' will be replicated, even if
1162 * no columns in that table are selected for replication (see
1163 * ovsdb_idl_add_table() for more information).
1165 * This function is only useful if 'monitor_everything_by_default' was false in
1166 * the call to ovsdb_idl_create(). This function should be called between
1167 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1170 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
1171 const struct ovsdb_idl_column
*column
)
1173 ovsdb_idl_db_add_column(&idl
->data
, column
);
1177 ovsdb_idl_db_add_table(struct ovsdb_idl_db
*db
,
1178 const struct ovsdb_idl_table_class
*tc
)
1182 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1183 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1185 if (table
->class_
== tc
) {
1186 table
->need_table
= true;
1194 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
1195 * no columns are selected for replication. Just the necessary data for table
1196 * references will be replicated (the UUID of the rows, for instance), any
1197 * columns not selected for replication will remain unreplicated.
1198 * This can be useful because it allows 'idl' to keep track of what rows in the
1199 * table actually exist, which in turn allows columns that reference the table
1200 * to have accurate contents. (The IDL presents the database with references to
1201 * rows that do not exist removed.)
1203 * This function is only useful if 'monitor_everything_by_default' was false in
1204 * the call to ovsdb_idl_create(). This function should be called between
1205 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1208 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
1209 const struct ovsdb_idl_table_class
*tc
)
1211 ovsdb_idl_db_add_table(&idl
->data
, tc
);
1214 /* A single clause within an ovsdb_idl_condition. */
1215 struct ovsdb_idl_clause
{
1216 struct hmap_node hmap_node
; /* In struct ovsdb_idl_condition. */
1217 enum ovsdb_function function
; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
1218 const struct ovsdb_idl_column
*column
; /* Must be nonnull. */
1219 struct ovsdb_datum arg
; /* Has ovsdb_type ->column->type. */
1223 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause
*clause
)
1225 uint32_t hash
= hash_pointer(clause
->column
, clause
->function
);
1226 return ovsdb_datum_hash(&clause
->arg
, &clause
->column
->type
, hash
);
1230 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause
*a
,
1231 const struct ovsdb_idl_clause
*b
)
1233 return (a
->function
== b
->function
1234 && a
->column
== b
->column
1235 && ovsdb_datum_equals(&a
->arg
, &b
->arg
, &a
->column
->type
));
1238 static struct json
*
1239 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
1241 const char *function
= ovsdb_function_to_string(clause
->function
);
1242 return json_array_create_3(json_string_create(clause
->column
->name
),
1243 json_string_create(function
),
1244 ovsdb_datum_to_json(&clause
->arg
,
1245 &clause
->column
->type
));
1249 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause
*clause
)
1252 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
1257 /* ovsdb_idl_condition. */
1260 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
)
1262 hmap_init(&cnd
->clauses
);
1263 cnd
->is_true
= false;
1267 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition
*cond
)
1270 ovsdb_idl_condition_clear(cond
);
1271 hmap_destroy(&cond
->clauses
);
1276 ovsdb_idl_condition_clear(struct ovsdb_idl_condition
*cond
)
1278 struct ovsdb_idl_clause
*clause
, *next
;
1279 HMAP_FOR_EACH_SAFE (clause
, next
, hmap_node
, &cond
->clauses
) {
1280 hmap_remove(&cond
->clauses
, &clause
->hmap_node
);
1281 ovsdb_idl_clause_destroy(clause
);
1283 cond
->is_true
= false;
1287 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition
*condition
)
1289 return condition
->is_true
;
1292 static struct ovsdb_idl_clause
*
1293 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition
*condition
,
1294 const struct ovsdb_idl_clause
*target
,
1297 struct ovsdb_idl_clause
*clause
;
1298 HMAP_FOR_EACH_WITH_HASH (clause
, hmap_node
, hash
, &condition
->clauses
) {
1299 if (ovsdb_idl_clause_equals(clause
, target
)) {
1307 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition
*condition
,
1308 const struct ovsdb_idl_clause
*src
,
1311 struct ovsdb_idl_clause
*clause
= xmalloc(sizeof *clause
);
1312 clause
->function
= src
->function
;
1313 clause
->column
= src
->column
;
1314 ovsdb_datum_clone(&clause
->arg
, &src
->arg
, &src
->column
->type
);
1315 hmap_insert(&condition
->clauses
, &clause
->hmap_node
, hash
);
1318 /* Adds a clause to the condition for replicating the table with class 'tc' in
1321 * The IDL replicates only rows in a table that satisfy at least one clause in
1322 * the table's condition. The default condition for a table has a single
1323 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1324 * the table. When the IDL client replaces the default condition by one of its
1325 * own, the condition can have any number of clauses. If it has no conditions,
1326 * then no rows are replicated.
1328 * Two distinct of clauses can usefully be added:
1330 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1331 * replicated, regardless of whether other clauses exist. 'column' and
1332 * 'arg' are ignored.
1334 * - Binary 'functions' add a clause of the form "<column> <function>
1335 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1336 * have a type that is compatible with 'column'.
1339 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition
*condition
,
1340 enum ovsdb_function function
,
1341 const struct ovsdb_idl_column
*column
,
1342 const struct ovsdb_datum
*arg
)
1344 if (condition
->is_true
) {
1345 /* Adding a clause to an always-true condition has no effect. */
1346 } else if (function
== OVSDB_F_TRUE
) {
1347 ovsdb_idl_condition_add_clause_true(condition
);
1348 } else if (function
== OVSDB_F_FALSE
) {
1349 /* Adding a "false" clause never has any effect. */
1351 struct ovsdb_idl_clause clause
= {
1352 .function
= function
,
1356 uint32_t hash
= ovsdb_idl_clause_hash(&clause
);
1357 if (!ovsdb_idl_condition_find_clause(condition
, &clause
, hash
)) {
1358 ovsdb_idl_condition_add_clause__(condition
, &clause
, hash
);
1364 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition
*condition
)
1366 if (!condition
->is_true
) {
1367 ovsdb_idl_condition_clear(condition
);
1368 condition
->is_true
= true;
1373 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition
*a
,
1374 const struct ovsdb_idl_condition
*b
)
1376 if (hmap_count(&a
->clauses
) != hmap_count(&b
->clauses
)) {
1379 if (a
->is_true
!= b
->is_true
) {
1383 const struct ovsdb_idl_clause
*clause
;
1384 HMAP_FOR_EACH (clause
, hmap_node
, &a
->clauses
) {
1385 if (!ovsdb_idl_condition_find_clause(b
, clause
,
1386 clause
->hmap_node
.hash
)) {
1394 ovsdb_idl_condition_clone(struct ovsdb_idl_condition
*dst
,
1395 const struct ovsdb_idl_condition
*src
)
1397 ovsdb_idl_condition_init(dst
);
1399 dst
->is_true
= src
->is_true
;
1401 const struct ovsdb_idl_clause
*clause
;
1402 HMAP_FOR_EACH (clause
, hmap_node
, &src
->clauses
) {
1403 ovsdb_idl_condition_add_clause__(dst
, clause
, clause
->hmap_node
.hash
);
1408 ovsdb_idl_db_set_condition(struct ovsdb_idl_db
*db
,
1409 const struct ovsdb_idl_table_class
*tc
,
1410 const struct ovsdb_idl_condition
*condition
)
1412 struct ovsdb_idl_table
*table
= ovsdb_idl_db_table_from_class(db
, tc
);
1413 unsigned int seqno
= db
->cond_seqno
;
1414 if (!ovsdb_idl_condition_equals(condition
, &table
->condition
)) {
1415 ovsdb_idl_condition_destroy(&table
->condition
);
1416 ovsdb_idl_condition_clone(&table
->condition
, condition
);
1417 db
->cond_changed
= table
->cond_changed
= true;
1418 poll_immediate_wake();
1425 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1426 * arranges to send the new condition to the database server.
1428 * Return the next conditional update sequence number. When this
1429 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1430 * contains rows that match the 'condition'. */
1432 ovsdb_idl_set_condition(struct ovsdb_idl
*idl
,
1433 const struct ovsdb_idl_table_class
*tc
,
1434 const struct ovsdb_idl_condition
*condition
)
1436 return ovsdb_idl_db_set_condition(&idl
->data
, tc
, condition
);
1439 static struct json
*
1440 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
1443 return json_array_create_empty();
1446 size_t n
= hmap_count(&cnd
->clauses
);
1448 return json_array_create_1(json_boolean_create(false));
1451 struct json
**clauses
= xmalloc(n
* sizeof *clauses
);
1452 const struct ovsdb_idl_clause
*clause
;
1454 HMAP_FOR_EACH (clause
, hmap_node
, &cnd
->clauses
) {
1455 clauses
[i
++] = ovsdb_idl_clause_to_json(clause
);
1458 return json_array_create(clauses
, n
);
1461 static struct json
*
1462 ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table
*table
)
1464 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
1465 struct json
*monitor_cond_change_request
= json_object_create();
1466 struct json
*cond_json
= ovsdb_idl_condition_to_json(cond
);
1468 json_object_put(monitor_cond_change_request
, "where", cond_json
);
1470 return monitor_cond_change_request
;
1473 static struct jsonrpc_msg
*
1474 ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db
*db
)
1476 if (!db
->cond_changed
) {
1480 struct json
*monitor_cond_change_requests
= NULL
;
1481 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1482 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1484 if (table
->cond_changed
) {
1485 struct json
*req
= ovsdb_idl_create_cond_change_req(table
);
1487 if (!monitor_cond_change_requests
) {
1488 monitor_cond_change_requests
= json_object_create();
1490 json_object_put(monitor_cond_change_requests
,
1491 table
->class_
->name
,
1492 json_array_create_1(req
));
1494 table
->cond_changed
= false;
1498 if (!monitor_cond_change_requests
) {
1502 db
->cond_changed
= false;
1503 struct json
*params
= json_array_create_3(json_clone(db
->monitor_id
),
1504 json_clone(db
->monitor_id
),
1505 monitor_cond_change_requests
);
1506 return jsonrpc_create_request("monitor_cond_change", params
, NULL
);
1510 ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
)
1512 /* When 'idl->request_id' is not NULL, there is an outstanding
1513 * conditional monitoring update request that we have not heard
1514 * from the server yet. Don't generate another request in this case. */
1515 if (!jsonrpc_session_is_connected(idl
->session
)
1516 || idl
->data
.monitoring
!= OVSDB_IDL_MONITORING_COND
1517 || idl
->request_id
) {
1521 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_cond_change(&idl
->data
);
1523 idl
->request_id
= json_clone(msg
->id
);
1524 jsonrpc_session_send(idl
->session
, msg
);
1528 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'db'.
1530 * This function should be called between ovsdb_idl_create() and the first call
1531 * to ovsdb_idl_run().
1534 ovsdb_idl_db_omit_alert(struct ovsdb_idl_db
*db
,
1535 const struct ovsdb_idl_column
*column
)
1537 *ovsdb_idl_db_get_mode(db
, column
) &= ~(OVSDB_IDL_ALERT
| OVSDB_IDL_TRACK
);
1540 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'idl'.
1542 * This function should be called between ovsdb_idl_create() and the first call
1543 * to ovsdb_idl_run().
1546 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
1547 const struct ovsdb_idl_column
*column
)
1549 ovsdb_idl_db_omit_alert(&idl
->data
, column
);
1553 ovsdb_idl_db_omit(struct ovsdb_idl_db
*db
,
1554 const struct ovsdb_idl_column
*column
)
1556 *ovsdb_idl_db_get_mode(db
, column
) = 0;
1559 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1560 * OVSDB_IDL_MONITOR for details.
1562 * This function should be called between ovsdb_idl_create() and the first call
1563 * to ovsdb_idl_run().
1566 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
1568 ovsdb_idl_db_omit(&idl
->data
, column
);
1571 /* Returns the most recent IDL change sequence number that caused a
1572 * insert, modify or delete update to the table with class 'table_class'.
1575 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
1576 const struct ovsdb_idl_table_class
*table_class
)
1578 struct ovsdb_idl_table
*table
1579 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1580 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
1582 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
1583 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
1585 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
1586 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
1591 /* For each row that contains tracked columns, IDL stores the most
1592 * recent IDL change sequence numbers associateed with insert, modify
1593 * and delete updates to the table.
1596 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
1597 enum ovsdb_idl_change change
)
1599 return row
->change_seqno
[change
];
1602 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1603 * all rows whose 'column' is modified are traced. Similarly, insert
1604 * or delete of rows having 'column' are tracked. Clients are able
1605 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1608 * This function should be called between ovsdb_idl_create() and
1609 * the first call to ovsdb_idl_run(). The column to be tracked
1610 * should have OVSDB_IDL_ALERT turned on.
1613 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1614 const struct ovsdb_idl_column
*column
)
1616 if (!(*ovsdb_idl_db_get_mode(&idl
->data
, column
) & OVSDB_IDL_ALERT
)) {
1617 ovsdb_idl_add_column(idl
, column
);
1619 *ovsdb_idl_db_get_mode(&idl
->data
, column
) |= OVSDB_IDL_TRACK
;
1623 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1627 for (i
= 0; i
< idl
->data
.class_
->n_tables
; i
++) {
1628 const struct ovsdb_idl_table_class
*tc
= &idl
->data
.class_
->tables
[i
];
1630 for (j
= 0; j
< tc
->n_columns
; j
++) {
1631 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1632 ovsdb_idl_track_add_column(idl
, column
);
1637 /* Returns true if 'table' has any tracked column. */
1639 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1643 for (i
= 0; i
< table
->class_
->n_columns
; i
++) {
1644 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1651 /* Returns the first tracked row in table with class 'table_class'
1652 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1653 const struct ovsdb_idl_row
*
1654 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1655 const struct ovsdb_idl_table_class
*table_class
)
1657 struct ovsdb_idl_table
*table
1658 = ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
1660 if (!ovs_list_is_empty(&table
->track_list
)) {
1661 return CONTAINER_OF(ovs_list_front(&table
->track_list
), struct ovsdb_idl_row
, track_node
);
1666 /* Returns the next tracked row in table after the specified 'row'
1667 * (in no particular order). Returns NULL if there are no tracked rows */
1668 const struct ovsdb_idl_row
*
1669 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1671 if (row
->track_node
.next
!= &row
->table
->track_list
) {
1672 return CONTAINER_OF(row
->track_node
.next
, struct ovsdb_idl_row
, track_node
);
1678 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1679 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1681 * Function returns false if 'column' is not tracked (see
1682 * ovsdb_idl_track_add_column()).
1685 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1686 const struct ovsdb_idl_column
*column
)
1688 const struct ovsdb_idl_table_class
*class;
1691 class = row
->table
->class_
;
1692 column_idx
= column
- class->columns
;
1694 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1701 /* Flushes the tracked rows. Client calls this function after calling
1702 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1703 * functions. This is usually done at the end of the client's processing
1704 * loop when it is ready to do ovsdb_idl_run() again.
1707 ovsdb_idl_db_track_clear(struct ovsdb_idl_db
*db
)
1711 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
1712 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1714 if (!ovs_list_is_empty(&table
->track_list
)) {
1715 struct ovsdb_idl_row
*row
, *next
;
1717 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1720 row
->updated
= NULL
;
1722 ovs_list_remove(&row
->track_node
);
1723 ovs_list_init(&row
->track_node
);
1724 if (ovsdb_idl_row_is_orphan(row
)) {
1732 /* Flushes the tracked rows. Client calls this function after calling
1733 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1734 * functions. This is usually done at the end of the client's processing
1735 * loop when it is ready to do ovsdb_idl_run() again.
1738 ovsdb_idl_track_clear(struct ovsdb_idl
*idl
)
1740 ovsdb_idl_db_track_clear(&idl
->data
);
1744 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
,
1745 struct ovsdb_idl_db
*db
)
1747 ovsdb_idl_send_request(idl
, jsonrpc_create_request(
1749 json_array_create_1(json_string_create(
1750 db
->class_
->database
)),
1755 ovsdb_idl_send_db_change_aware(struct ovsdb_idl
*idl
)
1757 struct jsonrpc_msg
*msg
= jsonrpc_create_request(
1758 "set_db_change_aware", json_array_create_1(json_boolean_create(true)),
1760 jsonrpc_session_send(idl
->session
, msg
);
1764 ovsdb_idl_check_server_db(struct ovsdb_idl
*idl
)
1766 const struct serverrec_database
*database
;
1767 SERVERREC_DATABASE_FOR_EACH (database
, idl
) {
1768 if (uuid_is_zero(&idl
->cid
)
1769 ? !strcmp(database
->name
, idl
->data
.class_
->database
)
1770 : database
->n_cid
&& uuid_equals(database
->cid
, &idl
->cid
)) {
1775 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
1776 const char *server_name
= jsonrpc_session_get_name(idl
->session
);
1779 VLOG_INFO_RL(&rl
, "%s: server does not have %s database",
1780 server_name
, idl
->data
.class_
->database
);
1781 } else if (!strcmp(database
->model
, "clustered")
1782 && jsonrpc_session_get_n_remotes(idl
->session
) > 1) {
1783 uint64_t index
= database
->n_index
? *database
->index
: 0;
1785 if (!database
->schema
) {
1786 VLOG_INFO("%s: clustered database server has not yet joined "
1787 "cluster; trying another server", server_name
);
1788 } else if (!database
->connected
) {
1789 VLOG_INFO("%s: clustered database server is disconnected "
1790 "from cluster; trying another server", server_name
);
1791 } else if (idl
->leader_only
&& !database
->leader
) {
1792 VLOG_INFO("%s: clustered database server is not cluster "
1793 "leader; trying another server", server_name
);
1794 } else if (index
< idl
->min_index
) {
1795 VLOG_WARN("%s: clustered database server has stale data; "
1796 "trying another server", server_name
);
1798 idl
->min_index
= MAX(idl
->min_index
, index
);
1805 ovsdb_idl_retry(idl
);
1809 if (idl
->state
== IDL_S_SERVER_MONITOR_COND_REQUESTED
) {
1810 json_destroy(idl
->data
.schema
);
1811 idl
->data
.schema
= json_from_string(database
->schema
);
1812 ovsdb_idl_send_monitor_request(idl
, &idl
->data
, true);
1813 ovsdb_idl_transition(idl
, IDL_S_DATA_MONITOR_COND_REQUESTED
);
1819 log_error(struct ovsdb_error
*error
)
1821 char *s
= ovsdb_error_to_string_free(error
);
1822 VLOG_WARN("error parsing database schema: %s", s
);
1826 /* Frees 'schema', which is in the format returned by parse_schema(). */
1828 free_schema(struct shash
*schema
)
1831 struct shash_node
*node
, *next
;
1833 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
1834 struct sset
*sset
= node
->data
;
1837 shash_delete(schema
, node
);
1839 shash_destroy(schema
);
1844 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1845 * 7047, to obtain the names of its rows and columns. If successful, returns
1846 * an shash whose keys are table names and whose values are ssets, where each
1847 * sset contains the names of its table's columns. On failure (due to a parse
1848 * error), returns NULL.
1850 * It would also be possible to use the general-purpose OVSDB schema parser in
1851 * ovsdb-server, but that's overkill, possibly too strict for the current use
1852 * case, and would require restructuring ovsdb-server to separate the schema
1853 * code from the rest. */
1854 static struct shash
*
1855 parse_schema(const struct json
*schema_json
)
1857 struct ovsdb_parser parser
;
1858 const struct json
*tables_json
;
1859 struct ovsdb_error
*error
;
1860 struct shash_node
*node
;
1861 struct shash
*schema
;
1863 ovsdb_parser_init(&parser
, schema_json
, "database schema");
1864 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
1865 error
= ovsdb_parser_destroy(&parser
);
1871 schema
= xmalloc(sizeof *schema
);
1873 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
1874 const char *table_name
= node
->name
;
1875 const struct json
*json
= node
->data
;
1876 const struct json
*columns_json
;
1878 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
1880 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
1881 error
= ovsdb_parser_destroy(&parser
);
1884 free_schema(schema
);
1888 struct sset
*columns
= xmalloc(sizeof *columns
);
1891 struct shash_node
*node2
;
1892 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
1893 const char *column_name
= node2
->name
;
1894 sset_add(columns
, column_name
);
1896 shash_add(schema
, table_name
, columns
);
1902 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
, struct ovsdb_idl_db
*db
,
1903 bool use_monitor_cond
)
1905 struct shash
*schema
= parse_schema(db
->schema
);
1906 struct json
*monitor_requests
= json_object_create();
1908 for (size_t i
= 0; i
< db
->class_
->n_tables
; i
++) {
1909 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
1910 const struct ovsdb_idl_table_class
*tc
= table
->class_
;
1911 struct json
*monitor_request
;
1912 const struct sset
*table_schema
1913 = schema
? shash_find_data(schema
, table
->class_
->name
) : NULL
;
1915 struct json
*columns
1916 = table
->need_table
? json_array_create_empty() : NULL
;
1917 for (size_t j
= 0; j
< tc
->n_columns
; j
++) {
1918 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1919 bool db_has_column
= (table_schema
&&
1920 sset_contains(table_schema
, column
->name
));
1921 if (column
->is_synthetic
) {
1922 if (db_has_column
) {
1923 VLOG_WARN("%s table in %s database has synthetic "
1924 "column %s", table
->class_
->name
,
1925 db
->class_
->database
, column
->name
);
1927 } else if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
1928 if (table_schema
&& !db_has_column
) {
1929 VLOG_WARN("%s table in %s database lacks %s column "
1930 "(database needs upgrade?)",
1931 table
->class_
->name
, db
->class_
->database
,
1936 columns
= json_array_create_empty();
1938 json_array_add(columns
, json_string_create(column
->name
));
1943 if (schema
&& !table_schema
) {
1944 VLOG_WARN("%s database lacks %s table "
1945 "(database needs upgrade?)",
1946 db
->class_
->database
, table
->class_
->name
);
1947 json_destroy(columns
);
1951 monitor_request
= json_object_create();
1952 json_object_put(monitor_request
, "columns", columns
);
1954 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
1955 if (use_monitor_cond
&& !ovsdb_idl_condition_is_true(cond
)) {
1956 json_object_put(monitor_request
, "where",
1957 ovsdb_idl_condition_to_json(cond
));
1958 table
->cond_changed
= false;
1960 json_object_put(monitor_requests
, tc
->name
,
1961 json_array_create_1(monitor_request
));
1964 free_schema(schema
);
1966 db
->cond_changed
= false;
1968 ovsdb_idl_send_request(
1970 jsonrpc_create_request(
1971 use_monitor_cond
? "monitor_cond" : "monitor",
1972 json_array_create_3(json_string_create(db
->class_
->database
),
1973 json_clone(db
->monitor_id
), monitor_requests
),
1978 log_parse_update_error(struct ovsdb_error
*error
)
1980 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1981 char *s
= ovsdb_error_to_string(error
);
1982 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1985 ovsdb_error_destroy(error
);
1989 ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db
*db
,
1990 const struct json
*result
,
1991 bool is_monitor_cond
)
1994 ovsdb_idl_db_clear(db
);
1995 ovsdb_idl_db_parse_update(db
, result
, is_monitor_cond
);
1999 ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db
*db
,
2000 const struct jsonrpc_msg
*msg
)
2002 if (msg
->type
== JSONRPC_NOTIFY
) {
2003 bool is_update
= !strcmp(msg
->method
, "update");
2004 bool is_update2
= !strcmp(msg
->method
, "update2");
2005 if ((is_update
|| is_update2
)
2006 && msg
->params
->type
== JSON_ARRAY
2007 && msg
->params
->array
.n
== 2
2008 && json_equal(msg
->params
->array
.elems
[0], db
->monitor_id
)) {
2009 ovsdb_idl_db_parse_update(db
, msg
->params
->array
.elems
[1],
2018 ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl
*idl
,
2019 struct ovsdb_idl_db
*db
,
2020 const struct jsonrpc_msg
*msg
)
2022 if (msg
->type
!= JSONRPC_NOTIFY
2023 || strcmp(msg
->method
, "monitor_canceled")
2024 || msg
->params
->type
!= JSON_ARRAY
2025 || msg
->params
->array
.n
!= 1
2026 || !json_equal(msg
->params
->array
.elems
[0], db
->monitor_id
)) {
2030 db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2032 /* Cancel the other monitor and restart the FSM from the top.
2034 * Maybe a more sophisticated response would be better in some cases, but
2035 * it doesn't seem worth optimizing yet. (Although this is already more
2036 * sophisticated than just dropping the connection and reconnecting.) */
2037 struct ovsdb_idl_db
*other_db
2038 = db
== &idl
->data
? &idl
->server
: &idl
->data
;
2039 if (other_db
->monitoring
) {
2040 jsonrpc_session_send(
2042 jsonrpc_create_request(
2044 json_array_create_1(json_clone(other_db
->monitor_id
)), NULL
));
2045 other_db
->monitoring
= OVSDB_IDL_NOT_MONITORING
;
2047 ovsdb_idl_restart_fsm(idl
);
2052 static struct ovsdb_error
*
2053 ovsdb_idl_db_parse_update__(struct ovsdb_idl_db
*db
,
2054 const struct json
*table_updates
,
2055 bool is_monitor_cond
)
2057 const struct shash_node
*tables_node
;
2058 const char *version_suffix
= is_monitor_cond
? "2" : "";
2060 if (table_updates
->type
!= JSON_OBJECT
) {
2061 return ovsdb_syntax_error(table_updates
, NULL
,
2062 "<table_updates%s> is not an object",
2066 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
2067 const struct json
*table_update
= tables_node
->data
;
2068 const struct shash_node
*table_node
;
2069 struct ovsdb_idl_table
*table
;
2071 table
= shash_find_data(&db
->table_by_name
, tables_node
->name
);
2073 return ovsdb_syntax_error(
2074 table_updates
, NULL
,
2075 "<table_updates%s> includes unknown table \"%s\"",
2076 version_suffix
, tables_node
->name
);
2079 if (table_update
->type
!= JSON_OBJECT
) {
2080 return ovsdb_syntax_error(table_update
, NULL
,
2081 "<table_update%s> for table \"%s\" is "
2083 version_suffix
, table
->class_
->name
);
2085 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
2086 const struct json
*row_update
= table_node
->data
;
2089 if (!uuid_from_string(&uuid
, table_node
->name
)) {
2090 return ovsdb_syntax_error(table_update
, NULL
,
2091 "<table_update%s> for table \"%s\" "
2092 "contains bad UUID "
2093 "\"%s\" as member name",
2095 table
->class_
->name
,
2098 if (row_update
->type
!= JSON_OBJECT
) {
2099 return ovsdb_syntax_error(row_update
, NULL
,
2100 "<table_update%s> for table \"%s\" "
2101 "contains <row_update%s> for %s "
2102 "that is not an object",
2103 version_suffix
, table
->class_
->name
,
2104 version_suffix
, table_node
->name
);
2107 if (is_monitor_cond
) {
2108 const char *ops
[] = {"modify", "insert", "delete", "initial"};
2109 const char *operation
;
2110 const struct json
*row
;
2113 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
2115 row
= shash_find_data(json_object(row_update
), operation
);
2118 if (ovsdb_idl_process_update2(table
, &uuid
, operation
,
2126 /* row_update2 should contain one of the objects */
2127 if (i
== ARRAY_SIZE(ops
)) {
2128 return ovsdb_syntax_error(row_update
, NULL
,
2129 "<row_update2> includes unknown "
2133 const struct json
*old_json
, *new_json
;
2135 old_json
= shash_find_data(json_object(row_update
), "old");
2136 new_json
= shash_find_data(json_object(row_update
), "new");
2137 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
2138 return ovsdb_syntax_error(old_json
, NULL
,
2139 "\"old\" <row> is not object");
2140 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
2141 return ovsdb_syntax_error(new_json
, NULL
,
2142 "\"new\" <row> is not object");
2143 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
2144 != shash_count(json_object(row_update
))) {
2145 return ovsdb_syntax_error(row_update
, NULL
,
2146 "<row-update> contains "
2147 "unexpected member");
2148 } else if (!old_json
&& !new_json
) {
2149 return ovsdb_syntax_error(row_update
, NULL
,
2150 "<row-update> missing \"old\" "
2151 "and \"new\" members");
2154 if (ovsdb_idl_process_update(table
, &uuid
, old_json
,
2166 ovsdb_idl_db_parse_update(struct ovsdb_idl_db
*db
,
2167 const struct json
*table_updates
,
2168 bool is_monitor_cond
)
2170 struct ovsdb_error
*error
= ovsdb_idl_db_parse_update__(db
, table_updates
,
2173 log_parse_update_error(error
);
2177 static struct ovsdb_idl_row
*
2178 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2180 struct ovsdb_idl_row
*row
;
2182 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
2183 if (uuid_equals(&row
->uuid
, uuid
)) {
2190 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2193 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
2194 const struct uuid
*uuid
, const struct json
*old
,
2195 const struct json
*new)
2197 struct ovsdb_idl_row
*row
;
2199 row
= ovsdb_idl_get_row(table
, uuid
);
2202 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2203 /* XXX perhaps we should check the 'old' values? */
2204 ovsdb_idl_delete_row(row
);
2206 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2208 UUID_ARGS(uuid
), table
->class_
->name
);
2214 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
2215 } else if (ovsdb_idl_row_is_orphan(row
)) {
2216 ovsdb_idl_insert_row(row
, new);
2218 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2219 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2220 return ovsdb_idl_modify_row(row
, new);
2225 /* XXX perhaps we should check the 'old' values? */
2226 if (!ovsdb_idl_row_is_orphan(row
)) {
2227 return ovsdb_idl_modify_row(row
, new);
2229 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
2230 "referenced row "UUID_FMT
" in table %s",
2231 UUID_ARGS(uuid
), table
->class_
->name
);
2232 ovsdb_idl_insert_row(row
, new);
2235 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2236 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2237 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
2244 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2247 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
2248 const struct uuid
*uuid
,
2249 const char *operation
,
2250 const struct json
*json_row
)
2252 struct ovsdb_idl_row
*row
;
2254 row
= ovsdb_idl_get_row(table
, uuid
);
2255 if (!strcmp(operation
, "delete")) {
2257 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
2258 ovsdb_idl_delete_row(row
);
2260 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
2262 UUID_ARGS(uuid
), table
->class_
->name
);
2265 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
2268 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
2269 } else if (ovsdb_idl_row_is_orphan(row
)) {
2270 ovsdb_idl_insert_row(row
, json_row
);
2272 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
2273 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2274 ovsdb_idl_delete_row(row
);
2275 ovsdb_idl_insert_row(row
, json_row
);
2277 } else if (!strcmp(operation
, "modify")) {
2280 if (!ovsdb_idl_row_is_orphan(row
)) {
2281 return ovsdb_idl_modify_row_by_diff(row
, json_row
);
2283 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
2284 "referenced row "UUID_FMT
" in table %s",
2285 UUID_ARGS(uuid
), table
->class_
->name
);
2289 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
2290 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
2294 VLOG_WARN_RL(&semantic_rl
, "unknown operation %s to "
2295 "table %s", operation
, table
->class_
->name
);
2302 /* Recursively add rows to tracked change lists for current row
2303 * and the rows that reference this row. */
2305 add_tracked_change_for_references(struct ovsdb_idl_row
*row
)
2307 if (ovs_list_is_empty(&row
->track_node
) &&
2308 ovsdb_idl_track_is_set(row
->table
)) {
2309 ovs_list_push_back(&row
->table
->track_list
,
2312 const struct ovsdb_idl_arc
*arc
;
2313 LIST_FOR_EACH (arc
, dst_node
, &row
->dst_arcs
) {
2314 add_tracked_change_for_references(arc
->src
);
2320 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2323 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
2324 * Caller needs to provide either valid 'row_json' or 'diff', but not
2327 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2328 const struct json
*diff_json
,
2329 enum ovsdb_idl_change change
)
2331 struct ovsdb_idl_table
*table
= row
->table
;
2332 const struct ovsdb_idl_table_class
*class = table
->class_
;
2333 struct shash_node
*node
;
2334 bool changed
= false;
2335 bool apply_diff
= diff_json
!= NULL
;
2336 const struct json
*json
= apply_diff
? diff_json
: row_json
;
2338 SHASH_FOR_EACH (node
, json_object(json
)) {
2339 const char *column_name
= node
->name
;
2340 const struct ovsdb_idl_column
*column
;
2341 struct ovsdb_datum datum
;
2342 struct ovsdb_error
*error
;
2343 unsigned int column_idx
;
2344 struct ovsdb_datum
*old
;
2346 column
= shash_find_data(&table
->columns
, column_name
);
2348 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
2349 column_name
, UUID_ARGS(&row
->uuid
));
2353 column_idx
= column
- table
->class_
->columns
;
2354 old
= &row
->old_datum
[column_idx
];
2358 struct ovsdb_datum diff
;
2360 ovs_assert(!row_json
);
2361 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
2364 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
2366 ovsdb_datum_destroy(&diff
, &column
->type
);
2369 ovs_assert(!diff_json
);
2370 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
2375 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
2376 ovsdb_datum_swap(old
, &datum
);
2377 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
2379 row
->change_seqno
[change
]
2380 = row
->table
->change_seqno
[change
]
2381 = row
->table
->db
->change_seqno
+ 1;
2382 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
2383 add_tracked_change_for_references(row
);
2384 if (!row
->updated
) {
2385 row
->updated
= bitmap_allocate(class->n_columns
);
2387 bitmap_set1(row
->updated
, column_idx
);
2391 /* Didn't really change but the OVSDB monitor protocol always
2392 * includes every value in a row. */
2395 ovsdb_datum_destroy(&datum
, &column
->type
);
2397 char *s
= ovsdb_error_to_string_free(error
);
2398 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
2399 " in table %s: %s", column_name
,
2400 UUID_ARGS(&row
->uuid
), table
->class_
->name
, s
);
2408 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
2409 enum ovsdb_idl_change change
)
2411 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
2415 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
2416 const struct json
*diff_json
,
2417 enum ovsdb_idl_change change
)
2419 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
2422 /* When a row A refers to row B through a column with a "refTable" constraint,
2423 * but row B does not exist, row B is called an "orphan row". Orphan rows
2424 * should not persist, because the database enforces referential integrity, but
2425 * they can appear transiently as changes from the database are received (the
2426 * database doesn't try to topologically sort them and circular references mean
2427 * it isn't always possible anyhow).
2429 * This function returns true if 'row' is an orphan row, otherwise false.
2432 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
2434 return !row
->old_datum
&& !row
->new_datum
;
2437 /* Returns true if 'row' is conceptually part of the database as modified by
2438 * the current transaction (if any), false otherwise.
2440 * This function will return true if 'row' is not an orphan (see the comment on
2441 * ovsdb_idl_row_is_orphan()) and:
2443 * - 'row' exists in the database and has not been deleted within the
2444 * current transaction (if any).
2446 * - 'row' was inserted within the current transaction and has not been
2447 * deleted. (In the latter case you should not have passed 'row' in at
2448 * all, because ovsdb_idl_txn_delete() freed it.)
2450 * This function will return false if 'row' is an orphan or if 'row' was
2451 * deleted within the current transaction.
2454 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
2456 return row
->new_datum
!= NULL
;
2460 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
2462 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2465 for (i
= 0; i
< class->n_columns
; i
++) {
2466 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2467 (c
->parse
)(row
, &row
->old_datum
[i
]);
2472 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
2474 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2477 for (i
= 0; i
< class->n_columns
; i
++) {
2478 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2483 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2484 * table indexes over one or more columns in the IDL. These indexes provide
2485 * the ability to retrieve rows matching a particular search criteria and to
2486 * iterate over a subset of rows in a defined order.
2489 /* Generic comparator that can compare each index, using the custom
2490 * configuration (an struct ovsdb_idl_index) passed to it.
2491 * Not intended for direct usage.
2494 ovsdb_idl_index_generic_comparer(const void *a
,
2495 const void *b
, const void *conf
)
2497 const struct ovsdb_idl_column
*column
;
2498 const struct ovsdb_idl_index
*index
;
2501 index
= CONST_CAST(struct ovsdb_idl_index
*, conf
);
2507 for (i
= 0; i
< index
->n_columns
; i
++) {
2509 if (index
->columns
[i
].comparer
) {
2510 val
= index
->columns
[i
].comparer(a
, b
);
2512 column
= index
->columns
[i
].column
;
2513 const struct ovsdb_idl_row
*row_a
, *row_b
;
2514 row_a
= CONST_CAST(struct ovsdb_idl_row
*, a
);
2515 row_b
= CONST_CAST(struct ovsdb_idl_row
*, b
);
2516 const struct ovsdb_datum
*datum_a
, *datum_b
;
2517 datum_a
= ovsdb_idl_read(row_a
, column
);
2518 datum_b
= ovsdb_idl_read(row_b
, column
);
2519 val
= ovsdb_datum_compare_3way(datum_a
, datum_b
, &column
->type
);
2523 return index
->columns
[i
].order
== OVSDB_INDEX_ASC
? val
: -val
;
2527 /* If ins_del is true then a row is being inserted into or deleted from
2528 * the index list. In this case, we augment the search key with
2529 * additional values (row UUID and memory address) to create a unique
2530 * search key in order to locate the correct entry efficiently and to
2531 * ensure that the correct entry is deleted in the case of a "delete"
2534 if (index
->ins_del
) {
2535 const struct ovsdb_idl_row
*row_a
, *row_b
;
2537 row_a
= (const struct ovsdb_idl_row
*) a
;
2538 row_b
= (const struct ovsdb_idl_row
*) b
;
2539 int value
= uuid_compare_3way(&row_a
->uuid
, &row_b
->uuid
);
2541 return value
? value
: (a
< b
) - (a
> b
);
2547 static struct ovsdb_idl_index
*
2548 ovsdb_idl_db_index_create(struct ovsdb_idl_db
*db
,
2549 const struct ovsdb_idl_index_column
*columns
,
2554 struct ovsdb_idl_index
*index
= xzalloc(sizeof *index
);
2556 index
->table
= ovsdb_idl_table_from_column(db
, columns
[0].column
);
2557 for (size_t i
= 0; i
< n
; i
++) {
2558 const struct ovsdb_idl_index_column
*c
= &columns
[i
];
2559 ovs_assert(ovsdb_idl_table_from_column(db
, c
->column
) == index
->table
);
2560 ovs_assert(*ovsdb_idl_db_get_mode(db
, c
->column
) & OVSDB_IDL_MONITOR
);
2563 index
->columns
= xmemdup(columns
, n
* sizeof *columns
);
2564 index
->n_columns
= n
;
2565 index
->skiplist
= skiplist_create(ovsdb_idl_index_generic_comparer
, index
);
2567 ovs_list_push_back(&index
->table
->indexes
, &index
->node
);
2572 /* Creates a new index for the given 'idl' and with the 'n' specified
2575 * All indexes must be created before the first call to ovsdb_idl_run(). */
2576 struct ovsdb_idl_index
*
2577 ovsdb_idl_index_create(struct ovsdb_idl
*idl
,
2578 const struct ovsdb_idl_index_column
*columns
,
2581 return ovsdb_idl_db_index_create(&idl
->data
, columns
, n
);
2584 struct ovsdb_idl_index
*
2585 ovsdb_idl_index_create1(struct ovsdb_idl
*idl
,
2586 const struct ovsdb_idl_column
*column1
)
2588 const struct ovsdb_idl_index_column columns
[] = {
2589 { .column
= column1
},
2591 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
2594 struct ovsdb_idl_index
*
2595 ovsdb_idl_index_create2(struct ovsdb_idl
*idl
,
2596 const struct ovsdb_idl_column
*column1
,
2597 const struct ovsdb_idl_column
*column2
)
2599 const struct ovsdb_idl_index_column columns
[] = {
2600 { .column
= column1
},
2601 { .column
= column2
},
2603 return ovsdb_idl_index_create(idl
, columns
, ARRAY_SIZE(columns
));
2607 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
)
2609 struct ovsdb_idl_index
*index
, *next
;
2610 LIST_FOR_EACH_SAFE (index
, next
, node
, &table
->indexes
) {
2611 skiplist_destroy(index
->skiplist
, NULL
);
2612 free(index
->columns
);
2618 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*row
)
2620 struct ovsdb_idl_table
*table
= row
->table
;
2621 struct ovsdb_idl_index
*index
;
2622 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
2623 index
->ins_del
= true;
2624 skiplist_insert(index
->skiplist
, row
);
2625 index
->ins_del
= false;
2630 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*row
)
2632 struct ovsdb_idl_table
*table
= row
->table
;
2633 struct ovsdb_idl_index
*index
;
2634 LIST_FOR_EACH (index
, node
, &table
->indexes
) {
2635 index
->ins_del
= true;
2636 skiplist_delete(index
->skiplist
, row
);
2637 index
->ins_del
= false;
2641 /* Writes a datum in an ovsdb_idl_row, and updates the corresponding field in
2642 * the table record. Not intended for direct usage. */
2644 ovsdb_idl_index_write(struct ovsdb_idl_row
*const_row
,
2645 const struct ovsdb_idl_column
*column
,
2646 struct ovsdb_datum
*datum
,
2647 const struct ovsdb_idl_table_class
*class)
2649 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, const_row
);
2650 size_t column_idx
= column
- class->columns
;
2652 if (bitmap_is_set(row
->written
, column_idx
)) {
2653 free(row
->new_datum
[column_idx
].values
);
2654 free(row
->new_datum
[column_idx
].keys
);
2656 bitmap_set1(row
->written
, column_idx
);
2658 row
->new_datum
[column_idx
] = *datum
;
2659 (column
->unparse
)(row
);
2660 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
2663 /* Magic UUID for index rows */
2664 static const struct uuid index_row_uuid
= {
2665 .parts
= {0xdeadbeef,
2670 /* Check if a row is an index row */
2672 is_index_row(const struct ovsdb_idl_row
*row
)
2674 return uuid_equals(&row
->uuid
, &index_row_uuid
);
2677 /* Initializes a row for use in an indexed query.
2678 * Not intended for direct usage.
2680 struct ovsdb_idl_row
*
2681 ovsdb_idl_index_init_row(struct ovsdb_idl_index
*index
)
2683 const struct ovsdb_idl_table_class
*class = index
->table
->class_
;
2684 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2685 class->row_init(row
);
2686 row
->uuid
= index_row_uuid
;
2687 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
2688 row
->written
= bitmap_allocate(class->n_columns
);
2689 row
->table
= index
->table
;
2690 /* arcs are not used for index row, but it doesn't harm to initialize */
2691 ovs_list_init(&row
->src_arcs
);
2692 ovs_list_init(&row
->dst_arcs
);
2696 /* Destroys 'row_' and frees all associated memory. This function is intended
2697 * to be used indirectly through one of the "index_destroy_row" functions
2698 * generated by ovsdb-idlc.
2701 ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row
*row_
)
2703 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2704 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2705 const struct ovsdb_idl_column
*c
;
2708 ovs_assert(is_index_row(row_
));
2709 ovs_assert(ovs_list_is_empty(&row_
->src_arcs
));
2710 ovs_assert(ovs_list_is_empty(&row_
->dst_arcs
));
2711 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2712 c
= &class->columns
[i
];
2714 free(row
->new_datum
[i
].values
);
2715 free(row
->new_datum
[i
].keys
);
2717 free(row
->new_datum
);
2722 struct ovsdb_idl_row
*
2723 ovsdb_idl_index_find(struct ovsdb_idl_index
*index
,
2724 const struct ovsdb_idl_row
*target
)
2726 return skiplist_get_data(skiplist_find(index
->skiplist
, target
));
2729 struct ovsdb_idl_cursor
2730 ovsdb_idl_cursor_first(struct ovsdb_idl_index
*index
)
2732 struct skiplist_node
*node
= skiplist_first(index
->skiplist
);
2733 return (struct ovsdb_idl_cursor
) { index
, node
};
2736 struct ovsdb_idl_cursor
2737 ovsdb_idl_cursor_first_eq(struct ovsdb_idl_index
*index
,
2738 const struct ovsdb_idl_row
*target
)
2740 struct skiplist_node
*node
= skiplist_find(index
->skiplist
, target
);
2741 return (struct ovsdb_idl_cursor
) { index
, node
};
2744 struct ovsdb_idl_cursor
2745 ovsdb_idl_cursor_first_ge(struct ovsdb_idl_index
*index
,
2746 const struct ovsdb_idl_row
*target
)
2748 struct skiplist_node
*node
= (target
2749 ? skiplist_forward_to(index
->skiplist
,
2751 : skiplist_first(index
->skiplist
));
2752 return (struct ovsdb_idl_cursor
) { index
, node
};
2756 ovsdb_idl_cursor_next(struct ovsdb_idl_cursor
*cursor
)
2758 cursor
->position
= skiplist_next(cursor
->position
);
2762 ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor
*cursor
)
2764 struct ovsdb_idl_row
*data
= skiplist_get_data(cursor
->position
);
2765 struct skiplist_node
*next_position
= skiplist_next(cursor
->position
);
2766 struct ovsdb_idl_row
*next_data
= skiplist_get_data(next_position
);
2767 cursor
->position
= (!ovsdb_idl_index_compare(cursor
->index
,
2769 ? next_position
: NULL
);
2772 struct ovsdb_idl_row
*
2773 ovsdb_idl_cursor_data(struct ovsdb_idl_cursor
*cursor
)
2775 return skiplist_get_data(cursor
->position
);
2778 /* Returns the result of comparing two rows using the comparison function
2784 * When the pointer to either row is NULL, this function considers NULL to be
2785 * greater than any other value, and NULL == NULL.
2788 ovsdb_idl_index_compare(struct ovsdb_idl_index
*index
,
2789 const struct ovsdb_idl_row
*a
,
2790 const struct ovsdb_idl_row
*b
)
2793 return ovsdb_idl_index_generic_comparer(a
, b
, index
);
2794 } else if (!a
&& !b
) {
2804 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
2806 ovs_assert(row
->old_datum
== row
->new_datum
);
2807 if (!ovsdb_idl_row_is_orphan(row
)) {
2808 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2811 for (i
= 0; i
< class->n_columns
; i
++) {
2812 ovsdb_datum_destroy(&row
->old_datum
[i
], &class->columns
[i
].type
);
2814 free(row
->old_datum
);
2815 row
->old_datum
= row
->new_datum
= NULL
;
2820 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
2822 if (row
->old_datum
!= row
->new_datum
) {
2823 if (row
->new_datum
) {
2824 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2828 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2829 ovsdb_datum_destroy(&row
->new_datum
[i
],
2830 &class->columns
[i
].type
);
2833 free(row
->new_datum
);
2835 row
->written
= NULL
;
2837 row
->new_datum
= row
->old_datum
;
2842 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
2844 struct ovsdb_idl_arc
*arc
, *next
;
2846 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
2847 * that this causes to be unreferenced.
2849 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
2850 ovs_list_remove(&arc
->dst_node
);
2852 && ovsdb_idl_row_is_orphan(arc
->dst
)
2853 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
2854 ovsdb_idl_row_destroy(arc
->dst
);
2858 ovs_list_init(&row
->src_arcs
);
2861 /* Force nodes that reference 'row' to reparse. */
2863 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
2865 struct ovsdb_idl_arc
*arc
, *next
;
2867 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2868 * 'arc', so we need to use the "safe" variant of list traversal. However,
2869 * calling an ovsdb_idl_column's 'parse' function will add an arc
2870 * equivalent to 'arc' to row->arcs. That could be a problem for
2871 * traversal, but it adds it at the beginning of the list to prevent us
2872 * from stumbling upon it again.
2874 * (If duplicate arcs were possible then we would need to make sure that
2875 * 'next' didn't also point into 'arc''s destination, but we forbid
2876 * duplicate arcs.) */
2877 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
2878 struct ovsdb_idl_row
*ref
= arc
->src
;
2880 ovsdb_idl_row_unparse(ref
);
2881 ovsdb_idl_row_clear_arcs(ref
, false);
2882 ovsdb_idl_row_parse(ref
);
2886 static struct ovsdb_idl_row
*
2887 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
2889 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2890 class->row_init(row
);
2891 ovs_list_init(&row
->src_arcs
);
2892 ovs_list_init(&row
->dst_arcs
);
2893 hmap_node_nullify(&row
->txn_node
);
2894 ovs_list_init(&row
->track_node
);
2898 static struct ovsdb_idl_row
*
2899 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2901 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class_
);
2902 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
2905 row
->map_op_written
= NULL
;
2906 row
->map_op_lists
= NULL
;
2907 row
->set_op_written
= NULL
;
2908 row
->set_op_lists
= NULL
;
2913 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
2916 ovsdb_idl_row_clear_old(row
);
2917 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2918 ovsdb_idl_destroy_all_map_op_lists(row
);
2919 ovsdb_idl_destroy_all_set_op_lists(row
);
2920 if (ovsdb_idl_track_is_set(row
->table
)) {
2921 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2922 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2923 = row
->table
->db
->change_seqno
+ 1;
2925 if (ovs_list_is_empty(&row
->track_node
)) {
2926 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
2932 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
2934 if (row
->map_op_written
) {
2935 /* Clear Map Operation Lists */
2936 size_t idx
, n_columns
;
2937 const struct ovsdb_idl_column
*columns
;
2938 const struct ovsdb_type
*type
;
2939 n_columns
= row
->table
->class_
->n_columns
;
2940 columns
= row
->table
->class_
->columns
;
2941 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
2942 type
= &columns
[idx
].type
;
2943 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
2945 free(row
->map_op_lists
);
2946 bitmap_free(row
->map_op_written
);
2947 row
->map_op_lists
= NULL
;
2948 row
->map_op_written
= NULL
;
2953 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
2955 if (row
->set_op_written
) {
2956 /* Clear Set Operation Lists */
2957 size_t idx
, n_columns
;
2958 const struct ovsdb_idl_column
*columns
;
2959 const struct ovsdb_type
*type
;
2960 n_columns
= row
->table
->class_
->n_columns
;
2961 columns
= row
->table
->class_
->columns
;
2962 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
2963 type
= &columns
[idx
].type
;
2964 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
2966 free(row
->set_op_lists
);
2967 bitmap_free(row
->set_op_written
);
2968 row
->set_op_lists
= NULL
;
2969 row
->set_op_written
= NULL
;
2974 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db
*db
)
2978 for (i
= 0; i
< db
->class_
->n_tables
; i
++) {
2979 struct ovsdb_idl_table
*table
= &db
->tables
[i
];
2981 if (!ovs_list_is_empty(&table
->track_list
)) {
2982 struct ovsdb_idl_row
*row
, *next
;
2984 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
2985 if (!ovsdb_idl_track_is_set(row
->table
)) {
2986 ovs_list_remove(&row
->track_node
);
2995 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
2997 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2998 size_t i
, datum_size
;
3000 ovs_assert(!row
->old_datum
&& !row
->new_datum
);
3001 datum_size
= class->n_columns
* sizeof *row
->old_datum
;
3002 row
->old_datum
= row
->new_datum
= xmalloc(datum_size
);
3003 for (i
= 0; i
< class->n_columns
; i
++) {
3004 ovsdb_datum_init_default(&row
->old_datum
[i
], &class->columns
[i
].type
);
3006 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
3007 ovsdb_idl_row_parse(row
);
3009 ovsdb_idl_row_reparse_backrefs(row
);
3010 ovsdb_idl_add_to_indexes(row
);
3014 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
3016 ovsdb_idl_remove_from_indexes(row
);
3017 ovsdb_idl_row_unparse(row
);
3018 ovsdb_idl_row_clear_arcs(row
, true);
3019 ovsdb_idl_row_clear_old(row
);
3020 if (ovs_list_is_empty(&row
->dst_arcs
)) {
3021 ovsdb_idl_row_destroy(row
);
3023 ovsdb_idl_row_reparse_backrefs(row
);
3027 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
3030 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
3034 ovsdb_idl_remove_from_indexes(row
);
3035 ovsdb_idl_row_unparse(row
);
3036 ovsdb_idl_row_clear_arcs(row
, true);
3037 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
3038 ovsdb_idl_row_parse(row
);
3039 ovsdb_idl_add_to_indexes(row
);
3045 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
3046 const struct json
*diff_json
)
3050 ovsdb_idl_remove_from_indexes(row
);
3051 ovsdb_idl_row_unparse(row
);
3052 ovsdb_idl_row_clear_arcs(row
, true);
3053 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
3054 OVSDB_IDL_CHANGE_MODIFY
);
3055 ovsdb_idl_row_parse(row
);
3056 ovsdb_idl_add_to_indexes(row
);
3062 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
3064 const struct ovsdb_idl_arc
*arc
;
3071 /* No duplicate arcs.
3073 * We only need to test whether the first arc in dst->dst_arcs originates
3074 * at 'src', since we add all of the arcs from a given source in a clump
3075 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
3076 * added at the front of the dst_arcs list. */
3077 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
3080 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
3081 return arc
->src
!= src
;
3084 static struct ovsdb_idl_table
*
3085 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db
*db
,
3086 const struct ovsdb_idl_table_class
*table_class
)
3088 ptrdiff_t idx
= table_class
- db
->class_
->tables
;
3089 return idx
>= 0 && idx
< db
->class_
->n_tables
? &db
->tables
[idx
] : NULL
;
3092 static struct ovsdb_idl_table
*
3093 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
3094 const struct ovsdb_idl_table_class
*table_class
)
3096 struct ovsdb_idl_table
*table
;
3098 table
= ovsdb_idl_db_table_from_class(&idl
->data
, table_class
);
3100 table
= ovsdb_idl_db_table_from_class(&idl
->server
, table_class
);
3106 /* Called by ovsdb-idlc generated code. */
3107 struct ovsdb_idl_row
*
3108 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
3109 const struct ovsdb_idl_table_class
*dst_table_class
,
3110 const struct uuid
*dst_uuid
)
3112 struct ovsdb_idl_db
*db
= src
->table
->db
;
3113 struct ovsdb_idl_table
*dst_table
;
3114 struct ovsdb_idl_arc
*arc
;
3115 struct ovsdb_idl_row
*dst
;
3117 dst_table
= ovsdb_idl_db_table_from_class(db
, dst_table_class
);
3118 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
3119 if (db
->txn
|| is_index_row(src
)) {
3120 /* There are two cases we should not update any arcs:
3122 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
3123 * any arcs, because the transaction will be backed out at commit or
3124 * abort time and we don't want our graph screwed up.
3126 * 2. The row is used as an index for querying purpose only.
3128 * In these cases, just return the destination row, if there is one and
3129 * it has not been deleted. */
3130 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new_datum
)) {
3135 /* We're being called from some other context. Update the graph. */
3137 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
3140 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
3141 if (may_add_arc(src
, dst
)) {
3142 /* The arc *must* be added at the front of the dst_arcs list. See
3143 * ovsdb_idl_row_reparse_backrefs() for details. */
3144 arc
= xmalloc(sizeof *arc
);
3145 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
3146 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
3151 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
3155 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
3156 * pointer to the row if there is one, otherwise a null pointer. */
3157 const struct ovsdb_idl_row
*
3158 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
3159 const struct ovsdb_idl_table_class
*tc
,
3160 const struct uuid
*uuid
)
3162 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
3165 static struct ovsdb_idl_row
*
3166 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
3168 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
3169 struct ovsdb_idl_row
*row
;
3171 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
3172 if (ovsdb_idl_row_exists(row
)) {
3179 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
3182 * Database tables are internally maintained as hash tables, so adding or
3183 * removing rows while traversing the same table can cause some rows to be
3184 * visited twice or not at apply. */
3185 const struct ovsdb_idl_row
*
3186 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
3187 const struct ovsdb_idl_table_class
*table_class
)
3189 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
,
3191 return next_real_row(table
, hmap_first(&table
->rows
));
3194 /* Returns a row following 'row' within its table, or a null pointer if 'row'
3195 * is the last row in its table. */
3196 const struct ovsdb_idl_row
*
3197 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
3199 struct ovsdb_idl_table
*table
= row
->table
;
3201 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
3204 /* Reads and returns the value of 'column' within 'row'. If an ongoing
3205 * transaction has changed 'column''s value, the modified value is returned.
3207 * The caller must not modify or free the returned value.
3209 * Various kinds of changes can invalidate the returned value: writing to the
3210 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
3211 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
3212 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
3213 * returned value is needed for a long time, it is best to make a copy of it
3214 * with ovsdb_datum_clone(). */
3215 const struct ovsdb_datum
*
3216 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
3217 const struct ovsdb_idl_column
*column
)
3219 const struct ovsdb_idl_table_class
*class;
3222 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
3224 class = row
->table
->class_
;
3225 column_idx
= column
- class->columns
;
3227 ovs_assert(row
->new_datum
!= NULL
);
3228 ovs_assert(column_idx
< class->n_columns
);
3230 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
3231 return &row
->new_datum
[column_idx
];
3232 } else if (row
->old_datum
) {
3233 return &row
->old_datum
[column_idx
];
3235 return ovsdb_datum_default(&column
->type
);
3239 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
3240 * type 'key_type' and value type 'value_type'. (Scalar and set types will
3241 * have a value type of OVSDB_TYPE_VOID.)
3243 * This is useful in code that "knows" that a particular column has a given
3244 * type, so that it will abort if someone changes the column's type without
3245 * updating the code that uses it. */
3246 const struct ovsdb_datum
*
3247 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
3248 const struct ovsdb_idl_column
*column
,
3249 enum ovsdb_atomic_type key_type OVS_UNUSED
,
3250 enum ovsdb_atomic_type value_type OVS_UNUSED
)
3252 ovs_assert(column
->type
.key
.type
== key_type
);
3253 ovs_assert(column
->type
.value
.type
== value_type
);
3255 return ovsdb_idl_read(row
, column
);
3258 /* Returns true if the field represented by 'column' in 'row' may be modified,
3259 * false if it is immutable.
3261 * Normally, whether a field is mutable is controlled by its column's schema.
3262 * However, an immutable column can be set to any initial value at the time of
3263 * insertion, so if 'row' is a new row (one that is being added as part of the
3264 * current transaction, supposing that a transaction is in progress) then even
3265 * its "immutable" fields are actually mutable. */
3267 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
3268 const struct ovsdb_idl_column
*column
)
3270 return column
->is_mutable
|| (row
->new_datum
&& !row
->old_datum
);
3273 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
3274 * to all-zero-bits by some other entity. If 'row' was set up some other way
3275 * then the return value is indeterminate. */
3277 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
3279 return row
->table
== NULL
;
3284 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3285 enum ovsdb_idl_txn_status
);
3287 /* Returns a string representation of 'status'. The caller must not modify or
3288 * free the returned string.
3290 * The return value is probably useful only for debug log messages and unit
3293 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
3296 case TXN_UNCOMMITTED
:
3297 return "uncommitted";
3300 case TXN_INCOMPLETE
:
3301 return "incomplete";
3308 case TXN_NOT_LOCKED
:
3309 return "not locked";
3316 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
3317 * active transaction at a time. See the large comment in ovsdb-idl.h for
3318 * general information on transactions. */
3319 struct ovsdb_idl_txn
*
3320 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
3322 struct ovsdb_idl_txn
*txn
;
3324 ovs_assert(!idl
->data
.txn
);
3325 idl
->data
.txn
= txn
= xmalloc(sizeof *txn
);
3326 txn
->request_id
= NULL
;
3327 txn
->db
= &idl
->data
;
3328 hmap_init(&txn
->txn_rows
);
3329 txn
->status
= TXN_UNCOMMITTED
;
3331 txn
->dry_run
= false;
3332 ds_init(&txn
->comment
);
3334 txn
->inc_table
= NULL
;
3335 txn
->inc_column
= NULL
;
3337 hmap_init(&txn
->inserted_rows
);
3342 /* Appends 's', which is treated as a printf()-type format string, to the
3343 * comments that will be passed to the OVSDB server when 'txn' is committed.
3344 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
3345 * show-log" can print in a relatively human-readable form.) */
3347 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
3351 if (txn
->comment
.length
) {
3352 ds_put_char(&txn
->comment
, '\n');
3356 ds_put_format_valist(&txn
->comment
, s
, args
);
3360 /* Marks 'txn' as a transaction that will not actually modify the database. In
3361 * almost every way, the transaction is treated like other transactions. It
3362 * must be committed or aborted like other transactions, it will be sent to the
3363 * database server like other transactions, and so on. The only difference is
3364 * that the operations sent to the database server will include, as the last
3365 * step, an "abort" operation, so that any changes made by the transaction will
3366 * not actually take effect. */
3368 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
3370 txn
->dry_run
= true;
3373 /* Causes 'txn', when committed, to increment the value of 'column' within
3374 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3375 * successfully, the client may retrieve the final (incremented) value of
3376 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3378 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3379 * change the database, then 'force' is important. If 'force' is false in this
3380 * case, the IDL suppresses the increment and skips a round trip to the
3381 * database server. If 'force' is true, the IDL will still increment the
3384 * The client could accomplish something similar with ovsdb_idl_read(),
3385 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3386 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3387 * will never (by itself) fail because of a verify error.
3389 * The intended use is for incrementing the "next_cfg" column in the
3390 * Open_vSwitch table. */
3392 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
3393 const struct ovsdb_idl_row
*row
,
3394 const struct ovsdb_idl_column
*column
,
3397 ovs_assert(!txn
->inc_table
);
3398 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
3399 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
3401 txn
->inc_table
= row
->table
->class_
->name
;
3402 txn
->inc_column
= column
->name
;
3403 txn
->inc_row
= row
->uuid
;
3404 txn
->inc_force
= force
;
3407 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3408 * has been called for 'txn' but the commit is still incomplete (that is, the
3409 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3410 * end up committing at the database server, but the client will not be able to
3411 * get any further status information back. */
3413 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
3415 struct ovsdb_idl_txn_insert
*insert
, *next
;
3417 json_destroy(txn
->request_id
);
3418 if (txn
->status
== TXN_INCOMPLETE
) {
3419 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
3421 ovsdb_idl_txn_abort(txn
);
3422 ds_destroy(&txn
->comment
);
3424 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
3427 hmap_destroy(&txn
->inserted_rows
);
3431 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3433 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
3435 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
3436 poll_immediate_wake();
3440 static struct json
*
3441 where_uuid_equals(const struct uuid
*uuid
)
3444 json_array_create_1(
3445 json_array_create_3(
3446 json_string_create("_uuid"),
3447 json_string_create("=="),
3448 json_array_create_2(
3449 json_string_create("uuid"),
3450 json_string_create_nocopy(
3451 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
3454 static const struct ovsdb_idl_row
*
3455 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
3457 const struct ovsdb_idl_row
*row
;
3459 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
3460 if (uuid_equals(&row
->uuid
, uuid
)) {
3467 /* XXX there must be a cleaner way to do this */
3468 static struct json
*
3469 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
3471 if (json
->type
== JSON_ARRAY
) {
3475 if (json
->array
.n
== 2
3476 && json
->array
.elems
[0]->type
== JSON_STRING
3477 && json
->array
.elems
[1]->type
== JSON_STRING
3478 && !strcmp(json
->array
.elems
[0]->string
, "uuid")
3479 && uuid_from_string(&uuid
, json
->array
.elems
[1]->string
)) {
3480 const struct ovsdb_idl_row
*row
;
3482 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
3483 if (row
&& !row
->old_datum
&& row
->new_datum
) {
3486 return json_array_create_2(
3487 json_string_create("named-uuid"),
3488 json_string_create_nocopy(ovsdb_data_row_name(&uuid
)));
3492 for (i
= 0; i
< json
->array
.n
; i
++) {
3493 json
->array
.elems
[i
] = substitute_uuids(json
->array
.elems
[i
],
3496 } else if (json
->type
== JSON_OBJECT
) {
3497 struct shash_node
*node
;
3499 SHASH_FOR_EACH (node
, json_object(json
)) {
3500 node
->data
= substitute_uuids(node
->data
, txn
);
3507 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
3509 struct ovsdb_idl_row
*row
, *next
;
3511 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3512 * ovsdb_idl_column's 'parse' function, which will call
3513 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3514 * transaction and fail to update the graph. */
3515 txn
->db
->txn
= NULL
;
3517 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
3518 enum { INSERTED
, MODIFIED
, DELETED
} op
3519 = (!row
->new_datum
? DELETED
3520 : !row
->old_datum
? INSERTED
3523 if (op
!= DELETED
) {
3524 ovsdb_idl_remove_from_indexes(row
);
3527 ovsdb_idl_destroy_all_map_op_lists(row
);
3528 ovsdb_idl_destroy_all_set_op_lists(row
);
3529 if (op
!= INSERTED
) {
3531 ovsdb_idl_row_unparse(row
);
3532 ovsdb_idl_row_clear_arcs(row
, false);
3533 ovsdb_idl_row_parse(row
);
3536 ovsdb_idl_row_unparse(row
);
3538 ovsdb_idl_row_clear_new(row
);
3541 row
->prereqs
= NULL
;
3544 row
->written
= NULL
;
3546 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
3547 hmap_node_nullify(&row
->txn_node
);
3548 if (op
!= INSERTED
) {
3549 ovsdb_idl_add_to_indexes(row
);
3551 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3555 hmap_destroy(&txn
->txn_rows
);
3556 hmap_init(&txn
->txn_rows
);
3560 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
3561 struct json
*mutations
)
3563 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3565 bool any_mutations
= false;
3567 if (row
->map_op_written
) {
3568 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
3569 struct map_op_list
*map_op_list
;
3570 const struct ovsdb_idl_column
*column
;
3571 const struct ovsdb_datum
*old_datum
;
3572 enum ovsdb_atomic_type key_type
, value_type
;
3573 struct json
*mutation
, *map
, *col_name
, *mutator
;
3574 struct json
*del_set
, *ins_map
;
3575 bool any_del
, any_ins
;
3577 map_op_list
= row
->map_op_lists
[idx
];
3578 column
= &class->columns
[idx
];
3579 key_type
= column
->type
.key
.type
;
3580 value_type
= column
->type
.value
.type
;
3582 /* Get the value to be changed */
3583 if (row
->new_datum
&& row
->written
3584 && bitmap_is_set(row
->written
,idx
)) {
3585 old_datum
= &row
->new_datum
[idx
];
3586 } else if (row
->old_datum
!= NULL
) {
3587 old_datum
= &row
->old_datum
[idx
];
3589 old_datum
= ovsdb_datum_default(&column
->type
);
3592 del_set
= json_array_create_empty();
3593 ins_map
= json_array_create_empty();
3597 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
3598 map_op
= map_op_list_next(map_op_list
, map_op
)) {
3600 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3601 /* Find out if value really changed. */
3602 struct ovsdb_datum
*new_datum
;
3604 new_datum
= map_op_datum(map_op
);
3605 pos
= ovsdb_datum_find_key(old_datum
,
3606 &new_datum
->keys
[0],
3608 if (ovsdb_atom_equals(&new_datum
->values
[0],
3609 &old_datum
->values
[pos
],
3611 /* No change in value. Move on to next update. */
3614 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
3615 /* Verify that there is a key to delete. */
3617 pos
= ovsdb_datum_find_key(old_datum
,
3618 &map_op_datum(map_op
)->keys
[0],
3620 if (pos
== UINT_MAX
) {
3621 /* No key to delete. Move on to next update. */
3622 VLOG_WARN("Trying to delete a key that doesn't "
3623 "exist in the map.");
3628 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
3629 map
= json_array_create_2(
3630 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3632 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3634 json_array_add(ins_map
, map
);
3636 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
3637 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3639 json_array_add(del_set
, map
);
3643 /* Generate an additional insert mutate for updates. */
3644 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3645 map
= json_array_create_2(
3646 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3648 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3650 json_array_add(ins_map
, map
);
3656 col_name
= json_string_create(column
->name
);
3657 mutator
= json_string_create("delete");
3658 map
= json_array_create_2(json_string_create("set"), del_set
);
3659 mutation
= json_array_create_3(col_name
, mutator
, map
);
3660 json_array_add(mutations
, mutation
);
3661 any_mutations
= true;
3663 json_destroy(del_set
);
3666 col_name
= json_string_create(column
->name
);
3667 mutator
= json_string_create("insert");
3668 map
= json_array_create_2(json_string_create("map"), ins_map
);
3669 mutation
= json_array_create_3(col_name
, mutator
, map
);
3670 json_array_add(mutations
, mutation
);
3671 any_mutations
= true;
3673 json_destroy(ins_map
);
3677 if (row
->set_op_written
) {
3678 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
3679 struct set_op_list
*set_op_list
;
3680 const struct ovsdb_idl_column
*column
;
3681 const struct ovsdb_datum
*old_datum
;
3682 enum ovsdb_atomic_type key_type
;
3683 struct json
*mutation
, *set
, *col_name
, *mutator
;
3684 struct json
*del_set
, *ins_set
;
3685 bool any_del
, any_ins
;
3687 set_op_list
= row
->set_op_lists
[idx
];
3688 column
= &class->columns
[idx
];
3689 key_type
= column
->type
.key
.type
;
3691 /* Get the value to be changed */
3692 if (row
->new_datum
&& row
->written
3693 && bitmap_is_set(row
->written
,idx
)) {
3694 old_datum
= &row
->new_datum
[idx
];
3695 } else if (row
->old_datum
!= NULL
) {
3696 old_datum
= &row
->old_datum
[idx
];
3698 old_datum
= ovsdb_datum_default(&column
->type
);
3701 del_set
= json_array_create_empty();
3702 ins_set
= json_array_create_empty();
3706 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
3707 set_op
= set_op_list_next(set_op_list
, set_op
)) {
3708 if (set_op_type(set_op
) == SET_OP_INSERT
) {
3709 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3711 json_array_add(ins_set
, set
);
3713 } else { /* SETP_OP_DELETE */
3714 /* Verify that there is a key to delete. */
3716 pos
= ovsdb_datum_find_key(old_datum
,
3717 &set_op_datum(set_op
)->keys
[0],
3719 if (pos
== UINT_MAX
) {
3720 /* No key to delete. Move on to next update. */
3721 VLOG_WARN("Trying to delete a key that doesn't "
3722 "exist in the set.");
3725 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3727 json_array_add(del_set
, set
);
3732 col_name
= json_string_create(column
->name
);
3733 mutator
= json_string_create("delete");
3734 set
= json_array_create_2(json_string_create("set"), del_set
);
3735 mutation
= json_array_create_3(col_name
, mutator
, set
);
3736 json_array_add(mutations
, mutation
);
3737 any_mutations
= true;
3739 json_destroy(del_set
);
3742 col_name
= json_string_create(column
->name
);
3743 mutator
= json_string_create("insert");
3744 set
= json_array_create_2(json_string_create("set"), ins_set
);
3745 mutation
= json_array_create_3(col_name
, mutator
, set
);
3746 json_array_add(mutations
, mutation
);
3747 any_mutations
= true;
3749 json_destroy(ins_set
);
3753 return any_mutations
;
3756 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
3757 * of the following TXN_* constants:
3761 * The transaction is in progress, but not yet complete. The caller
3762 * should call again later, after calling ovsdb_idl_run() to let the IDL
3763 * do OVSDB protocol processing.
3767 * The transaction is complete. (It didn't actually change the database,
3768 * so the IDL didn't send any request to the database server.)
3772 * The caller previously called ovsdb_idl_txn_abort().
3776 * The transaction was successful. The update made by the transaction
3777 * (and possibly other changes made by other database clients) should
3778 * already be visible in the IDL.
3782 * The transaction failed for some transient reason, e.g. because a
3783 * "verify" operation reported an inconsistency or due to a network
3784 * problem. The caller should wait for a change to the database, then
3785 * compose a new transaction, and commit the new transaction.
3787 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
3788 * the database. It is important to use its return value *before* the
3789 * initial call to ovsdb_idl_txn_commit() as the baseline for this
3790 * purpose, because the change that one should wait for can happen after
3791 * the initial call but before the call that returns TXN_TRY_AGAIN, and
3792 * using some other baseline value in that situation could cause an
3793 * indefinite wait if the database rarely changes.
3797 * The transaction failed because the IDL has been configured to require
3798 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
3799 * has already lost it.
3801 * Committing a transaction rolls back all of the changes that it made to the
3802 * IDL's copy of the database. If the transaction commits successfully, then
3803 * the database server will send an update and, thus, the IDL will be updated
3804 * with the committed changes. */
3805 enum ovsdb_idl_txn_status
3806 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
3808 struct ovsdb_idl_row
*row
;
3809 struct json
*operations
;
3812 if (txn
!= txn
->db
->txn
) {
3816 /* If we need a lock but don't have it, give up quickly. */
3817 if (txn
->db
->lock_name
&& !txn
->db
->has_lock
) {
3818 txn
->status
= TXN_NOT_LOCKED
;
3819 goto disassemble_out
;
3822 operations
= json_array_create_1(
3823 json_string_create(txn
->db
->class_
->database
));
3825 /* Assert that we have the required lock (avoiding a race). */
3826 if (txn
->db
->lock_name
) {
3827 struct json
*op
= json_object_create();
3828 json_array_add(operations
, op
);
3829 json_object_put_string(op
, "op", "assert");
3830 json_object_put_string(op
, "lock", txn
->db
->lock_name
);
3833 /* Add prerequisites and declarations of new rows. */
3834 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3835 /* XXX check that deleted rows exist even if no prereqs? */
3837 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3838 size_t n_columns
= class->n_columns
;
3839 struct json
*op
, *columns
, *row_json
;
3842 op
= json_object_create();
3843 json_array_add(operations
, op
);
3844 json_object_put_string(op
, "op", "wait");
3845 json_object_put_string(op
, "table", class->name
);
3846 json_object_put(op
, "timeout", json_integer_create(0));
3847 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3848 json_object_put_string(op
, "until", "==");
3849 columns
= json_array_create_empty();
3850 json_object_put(op
, "columns", columns
);
3851 row_json
= json_object_create();
3852 json_object_put(op
, "rows", json_array_create_1(row_json
));
3854 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
3855 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
3856 json_array_add(columns
, json_string_create(column
->name
));
3857 json_object_put(row_json
, column
->name
,
3858 ovsdb_datum_to_json(&row
->old_datum
[idx
],
3865 any_updates
= false;
3867 /* For tables constrained to have only a single row (a fairly common OVSDB
3868 * pattern for storing global data), identify whether we're inserting a
3869 * row. If so, then verify that the table is empty before inserting the
3870 * row. This gives us a clear verification-related failure if there was an
3871 * insertion race with another client. */
3872 for (size_t i
= 0; i
< txn
->db
->class_
->n_tables
; i
++) {
3873 struct ovsdb_idl_table
*table
= &txn
->db
->tables
[i
];
3874 if (table
->class_
->is_singleton
) {
3875 /* Count the number of rows in the table before and after our
3876 * transaction commits. This is O(n) in the number of rows in the
3877 * table, but that's OK since we know that the table should only
3879 size_t initial_rows
= 0;
3880 size_t final_rows
= 0;
3881 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
3882 initial_rows
+= row
->old_datum
!= NULL
;
3883 final_rows
+= row
->new_datum
!= NULL
;
3886 if (initial_rows
== 0 && final_rows
== 1) {
3887 struct json
*op
= json_object_create();
3888 json_array_add(operations
, op
);
3889 json_object_put_string(op
, "op", "wait");
3890 json_object_put_string(op
, "table", table
->class_
->name
);
3891 json_object_put(op
, "where", json_array_create_empty());
3892 json_object_put(op
, "timeout", json_integer_create(0));
3893 json_object_put_string(op
, "until", "==");
3894 json_object_put(op
, "rows", json_array_create_empty());
3899 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3900 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3902 if (!row
->new_datum
) {
3903 if (class->is_root
) {
3904 struct json
*op
= json_object_create();
3905 json_object_put_string(op
, "op", "delete");
3906 json_object_put_string(op
, "table", class->name
);
3907 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3908 json_array_add(operations
, op
);
3911 /* Let ovsdb-server decide whether to really delete it. */
3913 } else if (row
->old_datum
!= row
->new_datum
) {
3914 struct json
*row_json
;
3917 struct json
*op
= json_object_create();
3918 json_object_put_string(op
, "op",
3919 row
->old_datum
? "update" : "insert");
3920 json_object_put_string(op
, "table", class->name
);
3921 if (row
->old_datum
) {
3922 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3924 struct ovsdb_idl_txn_insert
*insert
;
3928 json_object_put(op
, "uuid-name",
3929 json_string_create_nocopy(
3930 ovsdb_data_row_name(&row
->uuid
)));
3932 insert
= xmalloc(sizeof *insert
);
3933 insert
->dummy
= row
->uuid
;
3934 insert
->op_index
= operations
->array
.n
- 1;
3935 uuid_zero(&insert
->real
);
3936 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
3937 uuid_hash(&insert
->dummy
));
3939 row_json
= json_object_create();
3940 json_object_put(op
, "row", row_json
);
3943 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
3944 const struct ovsdb_idl_column
*column
=
3945 &class->columns
[idx
];
3948 || !ovsdb_datum_is_default(&row
->new_datum
[idx
],
3952 value
= ovsdb_datum_to_json(&row
->new_datum
[idx
],
3954 json_object_put(row_json
, column
->name
,
3955 substitute_uuids(value
, txn
));
3957 /* If anything really changed, consider it an update.
3958 * We can't suppress not-really-changed values earlier
3959 * or transactions would become nonatomic (see the big
3960 * comment inside ovsdb_idl_txn_write()). */
3961 if (!any_updates
&& row
->old_datum
&&
3962 !ovsdb_datum_equals(&row
->old_datum
[idx
],
3963 &row
->new_datum
[idx
],
3971 if (!row
->old_datum
|| !shash_is_empty(json_object(row_json
))) {
3972 json_array_add(operations
, op
);
3978 /* Add mutate operation, for partial map or partial set updates. */
3979 if (row
->map_op_written
|| row
->set_op_written
) {
3980 struct json
*op
, *mutations
;
3983 op
= json_object_create();
3984 json_object_put_string(op
, "op", "mutate");
3985 json_object_put_string(op
, "table", class->name
);
3986 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3987 mutations
= json_array_create_empty();
3988 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
3989 json_object_put(op
, "mutations", mutations
);
3991 if (any_mutations
) {
3992 op
= substitute_uuids(op
, txn
);
3993 json_array_add(operations
, op
);
4001 /* Add increment. */
4002 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
4004 txn
->inc_index
= operations
->array
.n
- 1;
4006 struct json
*op
= json_object_create();
4007 json_object_put_string(op
, "op", "mutate");
4008 json_object_put_string(op
, "table", txn
->inc_table
);
4009 json_object_put(op
, "where",
4010 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
4012 json_object_put(op
, "mutations",
4013 json_array_create_1(
4014 json_array_create_3(
4015 json_string_create(txn
->inc_column
),
4016 json_string_create("+="),
4017 json_integer_create(1))));
4018 json_array_add(operations
, op
);
4020 op
= json_object_create();
4021 json_object_put_string(op
, "op", "select");
4022 json_object_put_string(op
, "table", txn
->inc_table
);
4023 json_object_put(op
, "where",
4024 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
4026 json_object_put(op
, "columns",
4027 json_array_create_1(json_string_create(
4029 json_array_add(operations
, op
);
4032 if (txn
->comment
.length
) {
4033 struct json
*op
= json_object_create();
4034 json_object_put_string(op
, "op", "comment");
4035 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
4036 json_array_add(operations
, op
);
4040 struct json
*op
= json_object_create();
4041 json_object_put_string(op
, "op", "abort");
4042 json_array_add(operations
, op
);
4046 txn
->status
= TXN_UNCHANGED
;
4047 json_destroy(operations
);
4048 } else if (!jsonrpc_session_send(
4049 txn
->db
->idl
->session
,
4050 jsonrpc_create_request(
4051 "transact", operations
, &txn
->request_id
))) {
4052 hmap_insert(&txn
->db
->outstanding_txns
, &txn
->hmap_node
,
4053 json_hash(txn
->request_id
, 0));
4054 txn
->status
= TXN_INCOMPLETE
;
4056 txn
->status
= TXN_TRY_AGAIN
;
4060 ovsdb_idl_txn_disassemble(txn
);
4062 switch (txn
->status
) {
4063 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
4064 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
4065 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
4066 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
4067 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
4068 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
4069 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
4070 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
4076 /* Attempts to commit 'txn', blocking until the commit either succeeds or
4077 * fails. Returns the final commit status, which may be any TXN_* value other
4078 * than TXN_INCOMPLETE.
4080 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
4081 * return value of ovsdb_idl_get_seqno() to change. */
4082 enum ovsdb_idl_txn_status
4083 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
4085 enum ovsdb_idl_txn_status status
;
4088 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
4089 ovsdb_idl_run(txn
->db
->idl
);
4090 ovsdb_idl_wait(txn
->db
->idl
);
4091 ovsdb_idl_txn_wait(txn
);
4097 /* Returns the final (incremented) value of the column in 'txn' that was set to
4098 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
4101 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
4103 ovs_assert(txn
->status
== TXN_SUCCESS
);
4104 return txn
->inc_new_value
;
4107 /* Aborts 'txn' without sending it to the database server. This is effective
4108 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
4109 * Otherwise, it has no effect.
4111 * Aborting a transaction doesn't free its memory. Use
4112 * ovsdb_idl_txn_destroy() to do that. */
4114 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
4116 ovsdb_idl_txn_disassemble(txn
);
4117 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
4118 txn
->status
= TXN_ABORTED
;
4122 /* Returns a string that reports the error status for 'txn'. The caller must
4123 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
4124 * for 'txn' may free the returned string.
4126 * The return value is ordinarily one of the strings that
4127 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
4128 * due to an error reported by the database server, the return value is that
4131 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
4133 if (txn
->status
!= TXN_ERROR
) {
4134 return ovsdb_idl_txn_status_to_string(txn
->status
);
4135 } else if (txn
->error
) {
4138 return "no error details available";
4143 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
4144 const struct json
*json
)
4146 if (json
&& txn
->error
== NULL
) {
4147 txn
->error
= json_to_string(json
, JSSF_SORT
);
4151 /* For transaction 'txn' that completed successfully, finds and returns the
4152 * permanent UUID that the database assigned to a newly inserted row, given the
4153 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
4155 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
4156 * if it was assigned by that function and then deleted by
4157 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
4158 * and then deleted within a single transaction are never sent to the database
4159 * server, so it never assigns them a permanent UUID.) */
4161 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
4162 const struct uuid
*uuid
)
4164 const struct ovsdb_idl_txn_insert
*insert
;
4166 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
4167 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
4168 uuid_hash(uuid
), &txn
->inserted_rows
) {
4169 if (uuid_equals(uuid
, &insert
->dummy
)) {
4170 return &insert
->real
;
4177 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
4178 enum ovsdb_idl_txn_status status
)
4180 txn
->status
= status
;
4181 hmap_remove(&txn
->db
->outstanding_txns
, &txn
->hmap_node
);
4185 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
4186 const struct ovsdb_idl_column
*column
,
4187 struct ovsdb_datum
*datum
, bool owns_datum
)
4189 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4190 const struct ovsdb_idl_table_class
*class;
4194 ovs_assert(!column
->is_synthetic
);
4195 if (ovsdb_idl_row_is_synthetic(row
)) {
4199 class = row
->table
->class_
;
4200 column_idx
= column
- class->columns
;
4201 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
4203 ovs_assert(row
->new_datum
!= NULL
);
4204 ovs_assert(column_idx
< class->n_columns
);
4205 ovs_assert(row
->old_datum
== NULL
||
4206 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4208 if (row
->table
->db
->verify_write_only
&& !write_only
) {
4209 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
4210 " explicitly configured not to.", class->name
, column
->name
);
4214 /* If this is a write-only column and the datum being written is the same
4215 * as the one already there, just skip the update entirely. This is worth
4216 * optimizing because we have a lot of columns that get periodically
4217 * refreshed into the database but don't actually change that often.
4219 * We don't do this for read/write columns because that would break
4220 * atomicity of transactions--some other client might have written a
4221 * different value in that column since we read it. (But if a whole
4222 * transaction only does writes of existing values, without making any real
4223 * changes, we will drop the whole transaction later in
4224 * ovsdb_idl_txn_commit().) */
4225 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
4226 datum
, &column
->type
)) {
4230 bool index_row
= is_index_row(row
);
4232 ovsdb_idl_remove_from_indexes(row
);
4234 if (hmap_node_is_null(&row
->txn_node
)) {
4235 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4236 uuid_hash(&row
->uuid
));
4238 if (row
->old_datum
== row
->new_datum
) {
4239 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4241 if (!row
->written
) {
4242 row
->written
= bitmap_allocate(class->n_columns
);
4244 if (bitmap_is_set(row
->written
, column_idx
)) {
4245 ovsdb_datum_destroy(&row
->new_datum
[column_idx
], &column
->type
);
4247 bitmap_set1(row
->written
, column_idx
);
4250 row
->new_datum
[column_idx
] = *datum
;
4252 ovsdb_datum_clone(&row
->new_datum
[column_idx
], datum
, &column
->type
);
4254 (column
->unparse
)(row
);
4255 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
4257 ovsdb_idl_add_to_indexes(row
);
4263 ovsdb_datum_destroy(datum
, &column
->type
);
4267 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
4268 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
4271 * 'datum' must have the correct type for its column, but it needs not be
4272 * sorted or unique because this function will take care of that. The IDL does
4273 * not check that it meets schema constraints, but ovsdb-server will do so at
4274 * commit time so it had better be correct.
4276 * A transaction must be in progress. Replication of 'column' must not have
4277 * been disabled (by calling ovsdb_idl_omit()).
4279 * Usually this function is used indirectly through one of the "set" functions
4280 * generated by ovsdb-idlc.
4282 * Takes ownership of what 'datum' points to (and in some cases destroys that
4283 * data before returning) but makes a copy of 'datum' itself. (Commonly
4284 * 'datum' is on the caller's stack.) */
4286 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
4287 const struct ovsdb_idl_column
*column
,
4288 struct ovsdb_datum
*datum
)
4290 ovsdb_datum_sort_unique(datum
,
4291 column
->type
.key
.type
, column
->type
.value
.type
);
4292 ovsdb_idl_txn_write__(row
, column
, datum
, true);
4295 /* Similar to ovsdb_idl_txn_write(), except:
4297 * - The caller retains ownership of 'datum' and what it points to.
4299 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
4300 * ovsdb_datum_sort_unique().) */
4302 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
4303 const struct ovsdb_idl_column
*column
,
4304 const struct ovsdb_datum
*datum
)
4306 ovsdb_idl_txn_write__(row
, column
,
4307 CONST_CAST(struct ovsdb_datum
*, datum
), false);
4310 /* Causes the original contents of 'column' in 'row_' to be verified as a
4311 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
4312 * changed (or if 'row_' was deleted) between the time that the IDL originally
4313 * read its contents and the time that the transaction commits, then the
4314 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
4316 * The intention is that, to ensure that no transaction commits based on dirty
4317 * reads, an application should call ovsdb_idl_txn_verify() on each data item
4318 * read as part of a read-modify-write operation.
4320 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
4321 * value of 'column' is already known:
4323 * - If 'row_' is a row created by the current transaction (returned by
4324 * ovsdb_idl_txn_insert()).
4326 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
4327 * within the current transaction.
4329 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
4330 * ovsdb_idl_txn_write() for a given read-modify-write.
4332 * A transaction must be in progress.
4334 * Usually this function is used indirectly through one of the "verify"
4335 * functions generated by ovsdb-idlc. */
4337 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
4338 const struct ovsdb_idl_column
*column
)
4340 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4341 const struct ovsdb_idl_table_class
*class;
4344 if (ovsdb_idl_row_is_synthetic(row
)) {
4348 class = row
->table
->class_
;
4349 column_idx
= column
- class->columns
;
4351 ovs_assert(row
->new_datum
!= NULL
);
4352 ovs_assert(row
->old_datum
== NULL
||
4353 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
4355 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
4359 if (hmap_node_is_null(&row
->txn_node
)) {
4360 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4361 uuid_hash(&row
->uuid
));
4363 if (!row
->prereqs
) {
4364 row
->prereqs
= bitmap_allocate(class->n_columns
);
4366 bitmap_set1(row
->prereqs
, column_idx
);
4369 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4370 * accessed afterward.
4372 * A transaction must be in progress.
4374 * Usually this function is used indirectly through one of the "delete"
4375 * functions generated by ovsdb-idlc. */
4377 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
4379 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4381 if (ovsdb_idl_row_is_synthetic(row
)) {
4385 ovs_assert(row
->new_datum
!= NULL
);
4386 ovs_assert(!is_index_row(row_
));
4387 ovsdb_idl_remove_from_indexes(row_
);
4388 if (!row
->old_datum
) {
4389 ovsdb_idl_row_unparse(row
);
4390 ovsdb_idl_row_clear_new(row
);
4391 ovs_assert(!row
->prereqs
);
4392 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
4393 hmap_remove(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
);
4397 if (hmap_node_is_null(&row
->txn_node
)) {
4398 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4399 uuid_hash(&row
->uuid
));
4401 ovsdb_idl_row_clear_new(row
);
4402 row
->new_datum
= NULL
;
4405 /* Inserts and returns a new row in the table with the specified 'class' in the
4406 * database with open transaction 'txn'.
4408 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4409 * randomly generated; otherwise 'uuid' should specify a randomly generated
4410 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4411 * 'txn' is committed, but the IDL will replace any uses of the provisional
4412 * UUID in the data to be to be committed by the UUID assigned by
4415 * Usually this function is used indirectly through one of the "insert"
4416 * functions generated by ovsdb-idlc. */
4417 const struct ovsdb_idl_row
*
4418 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
4419 const struct ovsdb_idl_table_class
*class,
4420 const struct uuid
*uuid
)
4422 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
4425 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
4428 uuid_generate(&row
->uuid
);
4431 row
->table
= ovsdb_idl_db_table_from_class(txn
->db
, class);
4432 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4433 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
4434 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
4435 ovsdb_idl_add_to_indexes(row
);
4440 ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db
*db
)
4442 struct ovsdb_idl_txn
*txn
;
4444 HMAP_FOR_EACH (txn
, hmap_node
, &db
->outstanding_txns
) {
4445 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
4450 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
4452 ovsdb_idl_db_txn_abort_all(&idl
->server
);
4453 ovsdb_idl_db_txn_abort_all(&idl
->data
);
4456 static struct ovsdb_idl_txn
*
4457 ovsdb_idl_db_txn_find(struct ovsdb_idl_db
*db
, const struct json
*id
)
4459 struct ovsdb_idl_txn
*txn
;
4461 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
4462 json_hash(id
, 0), &db
->outstanding_txns
) {
4463 if (json_equal(id
, txn
->request_id
)) {
4471 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
4474 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
4476 } else if (json
->type
!= type
) {
4477 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
4478 name
, json_type_to_string(json
->type
),
4479 json_type_to_string(type
));
4487 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
4488 const struct json_array
*results
)
4490 struct json
*count
, *rows
, *row
, *column
;
4491 struct shash
*mutate
, *select
;
4493 if (txn
->inc_index
+ 2 > results
->n
) {
4494 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4495 "for increment (has %"PRIuSIZE
", needs %u)",
4496 results
->n
, txn
->inc_index
+ 2);
4500 /* We know that this is a JSON object because the loop in
4501 * ovsdb_idl_db_txn_process_reply() checked. */
4502 mutate
= json_object(results
->elems
[txn
->inc_index
]);
4503 count
= shash_find_data(mutate
, "count");
4504 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
4507 if (count
->integer
!= 1) {
4508 VLOG_WARN_RL(&syntax_rl
,
4509 "\"mutate\" reply \"count\" is %lld instead of 1",
4514 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
4515 rows
= shash_find_data(select
, "rows");
4516 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
4519 if (rows
->array
.n
!= 1) {
4520 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
4525 row
= rows
->array
.elems
[0];
4526 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
4529 column
= shash_find_data(json_object(row
), txn
->inc_column
);
4530 if (!check_json_type(column
, JSON_INTEGER
,
4531 "\"select\" reply inc column")) {
4534 txn
->inc_new_value
= column
->integer
;
4539 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
4540 const struct json_array
*results
)
4542 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
4543 struct ovsdb_error
*error
;
4544 struct json
*json_uuid
;
4545 union ovsdb_atom uuid
;
4546 struct shash
*reply
;
4548 if (insert
->op_index
>= results
->n
) {
4549 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4550 "for insert (has %"PRIuSIZE
", needs %u)",
4551 results
->n
, insert
->op_index
);
4555 /* We know that this is a JSON object because the loop in
4556 * ovsdb_idl_txn_process_reply() checked. */
4557 reply
= json_object(results
->elems
[insert
->op_index
]);
4558 json_uuid
= shash_find_data(reply
, "uuid");
4559 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
4563 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
4565 char *s
= ovsdb_error_to_string_free(error
);
4566 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
4572 insert
->real
= uuid
.uuid
;
4578 ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db
*db
,
4579 const struct jsonrpc_msg
*msg
)
4581 struct ovsdb_idl_txn
*txn
;
4582 enum ovsdb_idl_txn_status status
;
4584 txn
= ovsdb_idl_db_txn_find(db
, msg
->id
);
4589 if (msg
->type
== JSONRPC_ERROR
) {
4591 && msg
->error
->type
== JSON_STRING
4592 && !strcmp(json_string(msg
->error
), "canceled")) {
4593 /* ovsdb-server uses this error message to indicate that the
4594 * transaction was canceled because the database in question was
4595 * removed, converted, etc. */
4596 status
= TXN_TRY_AGAIN
;
4599 ovsdb_idl_txn_set_error_json(txn
, msg
->error
);
4601 } else if (msg
->result
->type
!= JSON_ARRAY
) {
4602 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
4604 ovsdb_idl_txn_set_error_json(txn
, msg
->result
);
4606 struct json_array
*ops
= &msg
->result
->array
;
4607 int hard_errors
= 0;
4608 int soft_errors
= 0;
4609 int lock_errors
= 0;
4612 for (i
= 0; i
< ops
->n
; i
++) {
4613 struct json
*op
= ops
->elems
[i
];
4615 if (op
->type
== JSON_NULL
) {
4616 /* This isn't an error in itself but indicates that some prior
4617 * operation failed, so make sure that we know about it. */
4619 } else if (op
->type
== JSON_OBJECT
) {
4622 error
= shash_find_data(json_object(op
), "error");
4624 if (error
->type
== JSON_STRING
) {
4625 if (!strcmp(error
->string
, "timed out")) {
4627 } else if (!strcmp(error
->string
, "not owner")) {
4629 } else if (!strcmp(error
->string
, "not allowed")) {
4631 ovsdb_idl_txn_set_error_json(txn
, op
);
4632 } else if (strcmp(error
->string
, "aborted")) {
4634 ovsdb_idl_txn_set_error_json(txn
, op
);
4635 VLOG_WARN_RL(&other_rl
,
4636 "transaction error: %s", txn
->error
);
4640 ovsdb_idl_txn_set_error_json(txn
, op
);
4641 VLOG_WARN_RL(&syntax_rl
,
4642 "\"error\" in reply is not JSON string");
4647 ovsdb_idl_txn_set_error_json(txn
, op
);
4648 VLOG_WARN_RL(&syntax_rl
,
4649 "operation reply is not JSON null or object");
4653 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
4654 struct ovsdb_idl_txn_insert
*insert
;
4656 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
4660 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
4661 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
4667 status
= (hard_errors
? TXN_ERROR
4668 : lock_errors
? TXN_NOT_LOCKED
4669 : soft_errors
? TXN_TRY_AGAIN
4673 ovsdb_idl_txn_complete(txn
, status
);
4677 /* Returns the transaction currently active for 'row''s IDL. A transaction
4678 * must currently be active. */
4679 struct ovsdb_idl_txn
*
4680 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
4682 struct ovsdb_idl_txn
*txn
= row
->table
->db
->txn
;
4683 ovs_assert(txn
!= NULL
);
4687 /* Returns the IDL on which 'txn' acts. */
4689 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
4691 return txn
->db
->idl
;
4694 /* Blocks until 'idl' successfully connects to the remote database and
4695 * retrieves its contents. */
4697 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
4701 if (ovsdb_idl_has_ever_connected(idl
)) {
4704 ovsdb_idl_wait(idl
);
4709 static struct jsonrpc_msg
*
4710 ovsdb_idl_db_set_lock(struct ovsdb_idl_db
*db
, const char *lock_name
)
4712 ovs_assert(!db
->txn
);
4713 ovs_assert(hmap_is_empty(&db
->outstanding_txns
));
4716 && (!lock_name
|| strcmp(lock_name
, db
->lock_name
))) {
4717 /* Release previous lock. */
4718 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_unlock_request(db
);
4719 free(db
->lock_name
);
4720 db
->lock_name
= NULL
;
4721 db
->is_lock_contended
= false;
4725 if (lock_name
&& !db
->lock_name
) {
4726 /* Acquire new lock. */
4727 db
->lock_name
= xstrdup(lock_name
);
4728 return ovsdb_idl_db_compose_lock_request(db
);
4734 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
4735 * the database server and to avoid modifying the database when the lock cannot
4736 * be acquired (that is, when another client has the same lock).
4738 * If 'lock_name' is NULL, drops the locking requirement and releases the
4741 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
4744 struct jsonrpc_msg
*msg
= ovsdb_idl_db_set_lock(&idl
->data
, lock_name
);
4748 jsonrpc_session_send(idl
->session
, msg
);
4752 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
4754 * Locking and unlocking happens asynchronously from the database client's
4755 * point of view, so the information is only useful for optimization (e.g. if
4756 * the client doesn't have the lock then there's no point in trying to write to
4759 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
4761 return idl
->data
.has_lock
;
4764 /* Returns true if 'idl' is configured to obtain a lock but the database server
4765 * has indicated that some other client already owns the requested lock. */
4767 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
4769 return idl
->data
.is_lock_contended
;
4773 ovsdb_idl_db_update_has_lock(struct ovsdb_idl_db
*db
, bool new_has_lock
)
4775 if (new_has_lock
&& !db
->has_lock
) {
4776 if (db
->idl
->state
== IDL_S_MONITORING
) {
4779 /* We're setting up a session, so don't signal that the database
4780 * changed. Finalizing the session will increment change_seqno
4783 db
->is_lock_contended
= false;
4785 db
->has_lock
= new_has_lock
;
4789 ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db
*db
,
4790 const struct jsonrpc_msg
*msg
)
4792 if (msg
->type
== JSONRPC_REPLY
4793 && db
->lock_request_id
4794 && json_equal(db
->lock_request_id
, msg
->id
)) {
4795 /* Reply to our "lock" request. */
4796 ovsdb_idl_db_parse_lock_reply(db
, msg
->result
);
4800 if (msg
->type
== JSONRPC_NOTIFY
) {
4801 if (!strcmp(msg
->method
, "locked")) {
4802 /* We got our lock. */
4803 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, true);
4804 } else if (!strcmp(msg
->method
, "stolen")) {
4805 /* Someone else stole our lock. */
4806 return ovsdb_idl_db_parse_lock_notify(db
, msg
->params
, false);
4813 static struct jsonrpc_msg
*
4814 ovsdb_idl_db_compose_lock_request__(struct ovsdb_idl_db
*db
,
4817 ovsdb_idl_db_update_has_lock(db
, false);
4819 json_destroy(db
->lock_request_id
);
4820 db
->lock_request_id
= NULL
;
4822 struct json
*params
= json_array_create_1(json_string_create(
4824 return jsonrpc_create_request(method
, params
, NULL
);
4827 static struct jsonrpc_msg
*
4828 ovsdb_idl_db_compose_lock_request(struct ovsdb_idl_db
*db
)
4830 struct jsonrpc_msg
*msg
= ovsdb_idl_db_compose_lock_request__(db
, "lock");
4831 db
->lock_request_id
= json_clone(msg
->id
);
4835 static struct jsonrpc_msg
*
4836 ovsdb_idl_db_compose_unlock_request(struct ovsdb_idl_db
*db
)
4838 return ovsdb_idl_db_compose_lock_request__(db
, "unlock");
4842 ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db
*db
,
4843 const struct json
*result
)
4847 json_destroy(db
->lock_request_id
);
4848 db
->lock_request_id
= NULL
;
4850 if (result
->type
== JSON_OBJECT
) {
4851 const struct json
*locked
;
4853 locked
= shash_find_data(json_object(result
), "locked");
4854 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
4859 ovsdb_idl_db_update_has_lock(db
, got_lock
);
4861 db
->is_lock_contended
= true;
4866 ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db
*db
,
4867 const struct json
*params
,
4871 && params
->type
== JSON_ARRAY
4872 && json_array(params
)->n
> 0
4873 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
4874 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
4876 if (!strcmp(db
->lock_name
, lock_name
)) {
4877 ovsdb_idl_db_update_has_lock(db
, new_has_lock
);
4878 if (!new_has_lock
) {
4879 db
->is_lock_contended
= true;
4887 /* Inserts a new Map Operation into current transaction. */
4889 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
4890 const struct ovsdb_idl_column
*column
,
4891 struct ovsdb_datum
*datum
,
4892 enum map_op_type op_type
)
4894 const struct ovsdb_idl_table_class
*class;
4896 struct map_op
*map_op
;
4898 class = row
->table
->class_
;
4899 column_idx
= column
- class->columns
;
4901 /* Check if a map operation list exists for this column. */
4902 if (!row
->map_op_written
) {
4903 row
->map_op_written
= bitmap_allocate(class->n_columns
);
4904 row
->map_op_lists
= xzalloc(class->n_columns
*
4905 sizeof *row
->map_op_lists
);
4907 if (!row
->map_op_lists
[column_idx
]) {
4908 row
->map_op_lists
[column_idx
] = map_op_list_create();
4911 /* Add a map operation to the corresponding list. */
4912 map_op
= map_op_create(datum
, op_type
);
4913 bitmap_set1(row
->map_op_written
, column_idx
);
4914 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
4916 /* Add this row to transaction's list of rows. */
4917 if (hmap_node_is_null(&row
->txn_node
)) {
4918 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4919 uuid_hash(&row
->uuid
));
4923 /* Inserts a new Set Operation into current transaction. */
4925 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
4926 const struct ovsdb_idl_column
*column
,
4927 struct ovsdb_datum
*datum
,
4928 enum set_op_type op_type
)
4930 const struct ovsdb_idl_table_class
*class;
4932 struct set_op
*set_op
;
4934 class = row
->table
->class_
;
4935 column_idx
= column
- class->columns
;
4937 /* Check if a set operation list exists for this column. */
4938 if (!row
->set_op_written
) {
4939 row
->set_op_written
= bitmap_allocate(class->n_columns
);
4940 row
->set_op_lists
= xzalloc(class->n_columns
*
4941 sizeof *row
->set_op_lists
);
4943 if (!row
->set_op_lists
[column_idx
]) {
4944 row
->set_op_lists
[column_idx
] = set_op_list_create();
4947 /* Add a set operation to the corresponding list. */
4948 set_op
= set_op_create(datum
, op_type
);
4949 bitmap_set1(row
->set_op_written
, column_idx
);
4950 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
4952 /* Add this row to the transactions's list of rows. */
4953 if (hmap_node_is_null(&row
->txn_node
)) {
4954 hmap_insert(&row
->table
->db
->txn
->txn_rows
, &row
->txn_node
,
4955 uuid_hash(&row
->uuid
));
4960 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
4961 const struct ovsdb_idl_column
*column
,
4962 struct ovsdb_datum
*datum
)
4964 /* Verify that this column is being monitored. */
4965 unsigned int column_idx
= column
- row
->table
->class_
->columns
;
4966 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
4967 VLOG_WARN("cannot partially update non-monitored column");
4971 /* Verify that the update affects a single element. */
4972 if (datum
->n
!= 1) {
4973 VLOG_WARN("invalid datum for partial update");
4980 /* Inserts the value described in 'datum' into the map in 'column' in
4981 * 'row_'. If the value doesn't already exist in 'column' then it's value
4982 * is added. The value in 'datum' must be of the same type as the values
4983 * in 'column'. This function takes ownership of 'datum'.
4985 * Usually this function is used indirectly through one of the "update"
4986 * functions generated by vswitch-idl. */
4988 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
4989 const struct ovsdb_idl_column
*column
,
4990 struct ovsdb_datum
*datum
)
4992 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4993 enum set_op_type op_type
;
4995 if (!is_valid_partial_update(row
, column
, datum
)) {
4996 ovsdb_datum_destroy(datum
, &column
->type
);
5001 op_type
= SET_OP_INSERT
;
5003 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
5006 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
5007 * The value in 'datum' must be of the same type as the keys in 'column'.
5008 * This function takes ownership of 'datum'.
5010 * Usually this function is used indirectly through one of the "update"
5011 * functions generated by vswitch-idl. */
5013 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
5014 const struct ovsdb_idl_column
*column
,
5015 struct ovsdb_datum
*datum
)
5017 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5019 if (!is_valid_partial_update(row
, column
, datum
)) {
5020 struct ovsdb_type type_
= column
->type
;
5021 type_
.value
.type
= OVSDB_TYPE_VOID
;
5022 ovsdb_datum_destroy(datum
, &type_
);
5026 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
5029 /* Inserts the key-value specified in 'datum' into the map in 'column' in
5030 * 'row_'. If the key already exist in 'column', then it's value is updated
5031 * with the value in 'datum'. The key-value in 'datum' must be of the same type
5032 * as the keys-values in 'column'. This function takes ownership of 'datum'.
5034 * Usually this function is used indirectly through one of the "update"
5035 * functions generated by vswitch-idl. */
5037 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
5038 const struct ovsdb_idl_column
*column
,
5039 struct ovsdb_datum
*datum
)
5041 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5042 enum ovsdb_atomic_type key_type
;
5043 enum map_op_type op_type
;
5045 const struct ovsdb_datum
*old_datum
;
5047 if (!is_valid_partial_update(row
, column
, datum
)) {
5048 ovsdb_datum_destroy(datum
, &column
->type
);
5053 /* Find out if this is an insert or an update. */
5054 key_type
= column
->type
.key
.type
;
5055 old_datum
= ovsdb_idl_read(row
, column
);
5056 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
5057 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
5059 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
5062 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
5063 * The key in 'datum' must be of the same type as the keys in 'column'.
5064 * The value in 'datum' must be NULL. This function takes ownership of
5067 * Usually this function is used indirectly through one of the "update"
5068 * functions generated by vswitch-idl. */
5070 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
5071 const struct ovsdb_idl_column
*column
,
5072 struct ovsdb_datum
*datum
)
5074 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
5076 if (!is_valid_partial_update(row
, column
, datum
)) {
5077 struct ovsdb_type type_
= column
->type
;
5078 type_
.value
.type
= OVSDB_TYPE_VOID
;
5079 ovsdb_datum_destroy(datum
, &type_
);
5083 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
5087 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
5090 ovsdb_idl_destroy(loop
->idl
);
5094 struct ovsdb_idl_txn
*
5095 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
5097 ovsdb_idl_run(loop
->idl
);
5098 loop
->open_txn
= (loop
->committing_txn
5099 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
5101 : ovsdb_idl_txn_create(loop
->idl
));
5102 return loop
->open_txn
;
5105 /* Attempts to commit the current transaction, if one is open, and sets up the
5106 * poll loop to wake up when some more work might be needed.
5108 * If a transaction was open, in this or a previous iteration of the main loop,
5109 * and had not before finished committing (successfully or unsuccessfully), the
5110 * return value is one of:
5112 * 1: The transaction committed successfully (or it did not change anything in
5114 * 0: The transaction failed.
5115 * -1: The commit is still in progress.
5117 * Thus, the return value is -1 if the transaction is in progress and otherwise
5118 * true for success, false for failure.
5120 * (In the corner case where the IDL sends a transaction to the database and
5121 * the database commits it, and the connection between the IDL and the database
5122 * drops before the IDL receives the message confirming the commit, this
5123 * function can return 0 even though the transaction succeeded.)
5126 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
5128 if (loop
->open_txn
) {
5129 loop
->committing_txn
= loop
->open_txn
;
5130 loop
->open_txn
= NULL
;
5132 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
5135 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
5138 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
5139 if (status
!= TXN_INCOMPLETE
) {
5142 /* We want to re-evaluate the database when it's changed from
5143 * the contents that it had when we started the commit. (That
5144 * might have already happened.) */
5145 loop
->skip_seqno
= loop
->precommit_seqno
;
5146 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
5147 poll_immediate_wake();
5153 /* Possibly some work on the database was deferred because no
5154 * further transaction could proceed. Wake up again. */
5156 loop
->cur_cfg
= loop
->next_cfg
;
5157 poll_immediate_wake();
5162 loop
->cur_cfg
= loop
->next_cfg
;
5166 case TXN_NOT_LOCKED
:
5171 case TXN_UNCOMMITTED
:
5172 case TXN_INCOMPLETE
:
5176 ovsdb_idl_txn_destroy(txn
);
5177 loop
->committing_txn
= NULL
;
5182 /* Not a meaningful return value: no transaction was in progress. */
5186 ovsdb_idl_wait(loop
->idl
);