]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ovsdb-idl.c
dpctl: Add the option 'pmd' for dump-flows.
[mirror_ovs.git] / lib / ovsdb-idl.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
2 * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
3 *
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include <config.h>
18
19 #include "ovsdb-idl.h"
20
21 #include <errno.h>
22 #include <inttypes.h>
23 #include <limits.h>
24 #include <stdlib.h>
25
26 #include "bitmap.h"
27 #include "coverage.h"
28 #include "hash.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "openvswitch/json.h"
32 #include "jsonrpc.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"
43 #include "skiplist.h"
44 #include "sset.h"
45 #include "svec.h"
46 #include "util.h"
47 #include "uuid.h"
48 #include "openvswitch/vlog.h"
49
50 VLOG_DEFINE_THIS_MODULE(ovsdb_idl);
51
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);
60
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
63 * (the destination).
64 *
65 * Arcs from a row to itself are omitted, that is, src and dst are always
66 * different.
67 *
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.
70 *
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.
74 *
75 * The source and destination row may be in the same table or in different
76 * tables.
77 */
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. */
83 };
84
85 /* Connection state machine.
86 *
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) \
98 \
99 /* Waits for "monitor_cond" reply for the Database table: \
100 * \
101 * - If the reply indicates success, and the Database table has a \
102 * row for the IDL database: \
103 * \
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. \
108 * \
109 * * Otherwise, sends a "monitor_cond_since" request for the IDL \
110 * database whose details are informed by the schema \
111 * (obtained from the row), and transitions to \
112 * IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED. \
113 * \
114 * - If the reply indicates success, but the Database table does \
115 * not have a row for the IDL database, transitions to \
116 * IDL_S_ERROR. \
117 * \
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) \
122 \
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) \
127 \
128 /* Waits for "monitor_cond_since" reply. If successful, replaces \
129 * the IDL contents by the data carried in the reply and \
130 * transitions to IDL_S_MONITORING. On failure, sends a \
131 * "monitor_cond" request and transitions to \
132 * IDL_S_DATA_MONITOR_COND_REQUESTED. */ \
133 OVSDB_IDL_STATE(DATA_MONITOR_COND_SINCE_REQUESTED) \
134 \
135 /* Waits for "monitor_cond" reply. If successful, replaces the \
136 * IDL contents by the data carried in the reply and transitions \
137 * to IDL_S_MONITORING. On failure, sends a "monitor" request \
138 * and transitions to IDL_S_DATA_MONITOR_REQUESTED. */ \
139 OVSDB_IDL_STATE(DATA_MONITOR_COND_REQUESTED) \
140 \
141 /* Waits for "monitor" reply. If successful, replaces the IDL \
142 * contents by the data carried in the reply and transitions to \
143 * IDL_S_MONITORING. On failure, transitions to IDL_S_ERROR. */ \
144 OVSDB_IDL_STATE(DATA_MONITOR_REQUESTED) \
145 \
146 /* State that processes "update", "update2" or "update3" \
147 * notifications for the main database (and the Database table \
148 * in _Server if available). \
149 * \
150 * If we're monitoring the Database table and we get notified \
151 * that the IDL database has been deleted, we close the \
152 * connection (which will restart the state machine). */ \
153 OVSDB_IDL_STATE(MONITORING) \
154 \
155 /* Terminal error state that indicates that nothing useful can be \
156 * done, for example because the database server doesn't actually \
157 * have the desired database. We maintain the session with the \
158 * database server anyway. If it starts serving the database \
159 * that we want, or if someone fixes and restarts the database, \
160 * then it will kill the session and we will automatically \
161 * reconnect and try again. */ \
162 OVSDB_IDL_STATE(ERROR) \
163 \
164 /* Terminal state that indicates we connected to a useless server \
165 * in a cluster, e.g. one that is partitioned from the rest of \
166 * the cluster. We're waiting to retry. */ \
167 OVSDB_IDL_STATE(RETRY)
168
169 enum ovsdb_idl_state {
170 #define OVSDB_IDL_STATE(NAME) IDL_S_##NAME,
171 OVSDB_IDL_STATES
172 #undef OVSDB_IDL_STATE
173 };
174
175 static const char *ovsdb_idl_state_to_string(enum ovsdb_idl_state);
176
177 enum ovsdb_idl_monitor_method {
178 OVSDB_IDL_MM_MONITOR,
179 OVSDB_IDL_MM_MONITOR_COND,
180 OVSDB_IDL_MM_MONITOR_COND_SINCE
181 };
182
183 enum ovsdb_idl_monitoring {
184 OVSDB_IDL_NOT_MONITORING, /* Database is not being monitored. */
185 OVSDB_IDL_MONITORING, /* Database has "monitor" outstanding. */
186 OVSDB_IDL_MONITORING_COND, /* Database has "monitor_cond" outstanding. */
187 OVSDB_IDL_MONITORING_COND_SINCE, /* Database has "monitor_cond_since"
188 outstanding. */
189 };
190
191 struct ovsdb_idl_db {
192 struct ovsdb_idl *idl;
193
194 /* Data. */
195 const struct ovsdb_idl_class *class_;
196 struct shash table_by_name; /* Contains "struct ovsdb_idl_table *"s.*/
197 struct ovsdb_idl_table *tables; /* Array of ->class_->n_tables elements. */
198 struct json *monitor_id;
199 unsigned int change_seqno;
200 struct ovsdb_idl_txn *txn;
201 struct hmap outstanding_txns;
202 bool verify_write_only;
203 struct json *schema;
204 enum ovsdb_idl_monitoring monitoring;
205
206 /* True if any of the tables' monitoring conditions has changed. */
207 bool cond_changed;
208
209 unsigned int cond_seqno; /* Keep track of condition clauses changes
210 over a single conditional monitoring session.
211 Reverts to zero when idl session
212 reconnects. */
213
214 /* Database locking. */
215 char *lock_name; /* Name of lock we need, NULL if none. */
216 bool has_lock; /* Has db server told us we have the lock? */
217 bool is_lock_contended; /* Has db server told us we can't get lock? */
218 struct json *lock_request_id; /* JSON-RPC ID of in-flight lock request. */
219
220 /* Last db txn id, used for fast resync through monitor_cond_since */
221 struct uuid last_id;
222 };
223
224 static void ovsdb_idl_db_track_clear(struct ovsdb_idl_db *);
225 static void ovsdb_idl_db_add_column(struct ovsdb_idl_db *,
226 const struct ovsdb_idl_column *);
227 static void ovsdb_idl_db_omit(struct ovsdb_idl_db *,
228 const struct ovsdb_idl_column *);
229 static void ovsdb_idl_db_omit_alert(struct ovsdb_idl_db *,
230 const struct ovsdb_idl_column *);
231 static unsigned int ovsdb_idl_db_set_condition(
232 struct ovsdb_idl_db *, const struct ovsdb_idl_table_class *,
233 const struct ovsdb_idl_condition *);
234
235 static void ovsdb_idl_send_schema_request(struct ovsdb_idl *,
236 struct ovsdb_idl_db *);
237 static void ovsdb_idl_send_db_change_aware(struct ovsdb_idl *);
238 static bool ovsdb_idl_check_server_db(struct ovsdb_idl *);
239 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *,
240 struct ovsdb_idl_db *,
241 enum ovsdb_idl_monitor_method);
242 static void ovsdb_idl_db_clear(struct ovsdb_idl_db *db);
243 static void ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db);
244 static void ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db);
245 static void ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst,
246 struct ovsdb_idl_condition **src);
247
248 struct ovsdb_idl {
249 struct ovsdb_idl_db server;
250 struct ovsdb_idl_db data;
251
252 /* Session state.
253 *
254 *'state_seqno' is a snapshot of the session's sequence number as returned
255 * jsonrpc_session_get_seqno(session), so if it differs from the value that
256 * function currently returns then the session has reconnected and the
257 * state machine must restart. */
258 struct jsonrpc_session *session; /* Connection to the server. */
259 char *remote; /* 'session' remote name. */
260 enum ovsdb_idl_state state; /* Current session state. */
261 unsigned int state_seqno; /* See above. */
262 struct json *request_id; /* JSON ID for request awaiting reply. */
263
264 struct uuid cid;
265
266 uint64_t min_index;
267 bool leader_only;
268 bool shuffle_remotes;
269 };
270
271 static void ovsdb_idl_transition_at(struct ovsdb_idl *, enum ovsdb_idl_state,
272 const char *where);
273 #define ovsdb_idl_transition(IDL, STATE) \
274 ovsdb_idl_transition_at(IDL, STATE, OVS_SOURCE_LOCATOR)
275
276 static void ovsdb_idl_retry_at(struct ovsdb_idl *, const char *where);
277 #define ovsdb_idl_retry(IDL) ovsdb_idl_retry_at(IDL, OVS_SOURCE_LOCATOR)
278
279 struct ovsdb_idl_txn {
280 struct hmap_node hmap_node;
281 struct json *request_id;
282 struct ovsdb_idl_db *db;
283 struct hmap txn_rows;
284 enum ovsdb_idl_txn_status status;
285 char *error;
286 bool dry_run;
287 struct ds comment;
288
289 /* Increments. */
290 const char *inc_table;
291 const char *inc_column;
292 struct uuid inc_row;
293 bool inc_force;
294 unsigned int inc_index;
295 int64_t inc_new_value;
296
297 /* Inserted rows. */
298 struct hmap inserted_rows; /* Contains "struct ovsdb_idl_txn_insert"s. */
299 };
300
301 struct ovsdb_idl_txn_insert {
302 struct hmap_node hmap_node; /* In struct ovsdb_idl_txn's inserted_rows. */
303 struct uuid dummy; /* Dummy UUID used locally. */
304 int op_index; /* Index into transaction's operation array. */
305 struct uuid real; /* Real UUID used by database server. */
306 };
307
308 static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
309 static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5);
310 static struct vlog_rate_limit other_rl = VLOG_RATE_LIMIT_INIT(1, 5);
311
312 static void ovsdb_idl_clear(struct ovsdb_idl *);
313 static void ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db *,
314 const struct json *result,
315 enum ovsdb_idl_monitor_method method);
316 static bool ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db *,
317 const struct jsonrpc_msg *);
318 static bool ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl *,
319 struct ovsdb_idl_db *,
320 const struct jsonrpc_msg *);
321 static void ovsdb_idl_db_parse_update(struct ovsdb_idl_db *,
322 const struct json *table_updates,
323 enum ovsdb_idl_monitor_method method);
324 enum update_result {
325 OVSDB_IDL_UPDATE_DB_CHANGED,
326 OVSDB_IDL_UPDATE_NO_CHANGES,
327 OVSDB_IDL_UPDATE_INCONSISTENT,
328 };
329 static enum update_result ovsdb_idl_process_update(struct ovsdb_idl_table *,
330 const struct uuid *,
331 const struct json *old,
332 const struct json *new);
333 static enum update_result ovsdb_idl_process_update2(struct ovsdb_idl_table *,
334 const struct uuid *,
335 const char *operation,
336 const struct json *row);
337 static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct json *);
338 static void ovsdb_idl_delete_row(struct ovsdb_idl_row *);
339 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct json *);
340 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *,
341 const struct json *);
342
343 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *);
344 static struct ovsdb_idl_row *ovsdb_idl_row_create__(
345 const struct ovsdb_idl_table_class *);
346 static struct ovsdb_idl_row *ovsdb_idl_row_create(struct ovsdb_idl_table *,
347 const struct uuid *);
348 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row *);
349 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db *);
350 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *);
351 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *);
352
353 static void ovsdb_idl_row_parse(struct ovsdb_idl_row *);
354 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row *);
355 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row *);
356 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row *);
357 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *, bool destroy_dsts);
358
359 static void ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db *);
360 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl *);
361 static bool ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db *,
362 const struct jsonrpc_msg *msg);
363 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *,
364 struct json *);
365 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *,
366 const struct ovsdb_idl_column *,
367 struct ovsdb_datum *,
368 enum map_op_type);
369 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *,
370 const struct ovsdb_idl_column *,
371 struct ovsdb_datum *,
372 enum set_op_type);
373
374 static bool ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db *,
375 const struct jsonrpc_msg *);
376 static struct jsonrpc_msg *ovsdb_idl_db_compose_lock_request(
377 struct ovsdb_idl_db *);
378 static struct jsonrpc_msg *ovsdb_idl_db_compose_unlock_request(
379 struct ovsdb_idl_db *);
380 static void ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db *,
381 const struct json *);
382 static bool ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db *,
383 const struct json *params,
384 bool new_has_lock);
385 static struct ovsdb_idl_table *
386 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db *,
387 const struct ovsdb_idl_table_class *);
388 static struct ovsdb_idl_table *
389 ovsdb_idl_table_from_class(const struct ovsdb_idl *,
390 const struct ovsdb_idl_table_class *);
391 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table);
392 static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
393
394 static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
395 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
396 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
397 static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop,
398 bool *may_need_wakeup);
399
400 static void
401 ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
402 struct ovsdb_idl *parent, bool monitor_everything_by_default)
403 {
404 memset(db, 0, sizeof *db);
405
406 uint8_t default_mode = (monitor_everything_by_default
407 ? OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT
408 : 0);
409
410 db->idl = parent;
411 db->class_ = class;
412 shash_init(&db->table_by_name);
413 db->tables = xmalloc(class->n_tables * sizeof *db->tables);
414 for (size_t i = 0; i < class->n_tables; i++) {
415 const struct ovsdb_idl_table_class *tc = &class->tables[i];
416 struct ovsdb_idl_table *table = &db->tables[i];
417
418 shash_add_assert(&db->table_by_name, tc->name, table);
419 table->class_ = tc;
420 table->modes = xmalloc(tc->n_columns);
421 memset(table->modes, default_mode, tc->n_columns);
422 table->need_table = false;
423 shash_init(&table->columns);
424 ovs_list_init(&table->indexes);
425 for (size_t j = 0; j < tc->n_columns; j++) {
426 const struct ovsdb_idl_column *column = &tc->columns[j];
427
428 shash_add_assert(&table->columns, column->name, column);
429 }
430 hmap_init(&table->rows);
431 ovs_list_init(&table->track_list);
432 table->change_seqno[OVSDB_IDL_CHANGE_INSERT]
433 = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
434 = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
435 table->db = db;
436 table->ack_cond = NULL;
437 table->req_cond = NULL;
438 table->new_cond = xmalloc(sizeof *table->new_cond);
439 ovsdb_idl_condition_init(table->new_cond);
440 ovsdb_idl_condition_add_clause_true(table->new_cond);
441 }
442 db->monitor_id = json_array_create_2(json_string_create("monid"),
443 json_string_create(class->database));
444 hmap_init(&db->outstanding_txns);
445 }
446
447 /* Creates and returns a connection to database 'remote', which should be in a
448 * form acceptable to jsonrpc_session_open(). The connection will maintain an
449 * in-memory replica of the remote database whose schema is described by
450 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
451 * by ovsdb-idlc.)
452 *
453 * Passes 'retry' to jsonrpc_session_open(). See that function for
454 * documentation.
455 *
456 * If 'monitor_everything_by_default' is true, then everything in the remote
457 * database will be replicated by default. ovsdb_idl_omit() and
458 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
459 * monitoring.
460 *
461 * If 'monitor_everything_by_default' is false, then no columns or tables will
462 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
463 * must be used to choose some columns or tables to replicate.
464 */
465 struct ovsdb_idl *
466 ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
467 bool monitor_everything_by_default, bool retry)
468 {
469 struct ovsdb_idl *idl = ovsdb_idl_create_unconnected(
470 class, monitor_everything_by_default);
471 ovsdb_idl_set_remote(idl, remote, retry);
472 return idl;
473 }
474
475 /* Creates and returns a connection to an in-memory replica of the remote
476 * database whose schema is described by 'class'. (Ordinarily 'class' is
477 * compiled from an OVSDB schema automatically by ovsdb-idlc.)
478 *
479 * Use ovsdb_idl_set_remote() to configure the database to which to connect.
480 * Until a remote is configured, no data can be retrieved.
481 *
482 * If 'monitor_everything_by_default' is true, then everything in the remote
483 * database will be replicated by default. ovsdb_idl_omit() and
484 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
485 * monitoring.
486 *
487 * If 'monitor_everything_by_default' is false, then no columns or tables will
488 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
489 * must be used to choose some columns or tables to replicate.
490 */
491 struct ovsdb_idl *
492 ovsdb_idl_create_unconnected(const struct ovsdb_idl_class *class,
493 bool monitor_everything_by_default)
494 {
495 struct ovsdb_idl *idl;
496
497 idl = xzalloc(sizeof *idl);
498 ovsdb_idl_db_init(&idl->server, &serverrec_idl_class, idl, true);
499 ovsdb_idl_db_init(&idl->data, class, idl, monitor_everything_by_default);
500 idl->state_seqno = UINT_MAX;
501 idl->request_id = NULL;
502 idl->leader_only = true;
503 idl->shuffle_remotes = true;
504
505 /* Monitor the Database table in the _Server database.
506 *
507 * We monitor only the row for 'class', or the row that has the
508 * desired 'cid'. */
509 struct ovsdb_idl_condition cond;
510 ovsdb_idl_condition_init(&cond);
511 if (!uuid_is_zero(&idl->cid)) {
512 serverrec_database_add_clause_cid(&cond, OVSDB_F_EQ, &idl->cid, 1);
513 } else {
514 serverrec_database_add_clause_name(&cond, OVSDB_F_EQ, class->database);
515 }
516 ovsdb_idl_db_set_condition(&idl->server, &serverrec_table_database, &cond);
517 ovsdb_idl_condition_destroy(&cond);
518
519 return idl;
520 }
521
522 /* Changes the remote and creates a new session.
523 *
524 * If 'retry' is true, the connection to the remote will automatically retry
525 * when it fails. If 'retry' is false, the connection is one-time. */
526 void
527 ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote, bool retry)
528 {
529 if (idl
530 && ((remote != NULL) != (idl->remote != NULL)
531 || (remote && idl->remote && strcmp(remote, idl->remote)))) {
532 ovs_assert(!idl->data.txn);
533
534 /* Close the old session, if any. */
535 if (idl->session) {
536 jsonrpc_session_close(idl->session);
537 idl->session = NULL;
538
539 free(idl->remote);
540 idl->remote = NULL;
541 }
542
543 /* Open new session, if any. */
544 if (remote) {
545 struct svec remotes = SVEC_EMPTY_INITIALIZER;
546 ovsdb_session_parse_remote(remote, &remotes, &idl->cid);
547 if (idl->shuffle_remotes) {
548 svec_shuffle(&remotes);
549 }
550 idl->session = jsonrpc_session_open_multiple(&remotes, retry);
551 svec_destroy(&remotes);
552
553 idl->state_seqno = UINT_MAX;
554
555 idl->remote = xstrdup(remote);
556 }
557 }
558 }
559
560 /* Set whether the order of remotes should be shuffled, when there
561 * are more than one remotes. The setting doesn't take effect
562 * until the next time when ovsdb_idl_set_remote() is called. */
563 void
564 ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *idl, bool shuffle)
565 {
566 idl->shuffle_remotes = shuffle;
567 }
568
569 /* Reset min_index to 0. This prevents a situation where the client
570 * thinks all databases have stale data, when they actually have all
571 * been destroyed and rebuilt from scratch.
572 */
573 void
574 ovsdb_idl_reset_min_index(struct ovsdb_idl *idl)
575 {
576 idl->min_index = 0;
577 }
578
579 static void
580 ovsdb_idl_db_destroy(struct ovsdb_idl_db *db)
581 {
582 struct ovsdb_idl_condition *null_cond = NULL;
583 ovs_assert(!db->txn);
584 ovsdb_idl_db_txn_abort_all(db);
585 ovsdb_idl_db_clear(db);
586 for (size_t i = 0; i < db->class_->n_tables; i++) {
587 struct ovsdb_idl_table *table = &db->tables[i];
588 ovsdb_idl_condition_move(&table->ack_cond, &null_cond);
589 ovsdb_idl_condition_move(&table->req_cond, &null_cond);
590 ovsdb_idl_condition_move(&table->new_cond, &null_cond);
591 ovsdb_idl_destroy_indexes(table);
592 shash_destroy(&table->columns);
593 hmap_destroy(&table->rows);
594 free(table->modes);
595 }
596 shash_destroy(&db->table_by_name);
597 free(db->tables);
598 json_destroy(db->schema);
599 hmap_destroy(&db->outstanding_txns);
600 free(db->lock_name);
601 json_destroy(db->lock_request_id);
602 json_destroy(db->monitor_id);
603 }
604
605 /* Destroys 'idl' and all of the data structures that it manages. */
606 void
607 ovsdb_idl_destroy(struct ovsdb_idl *idl)
608 {
609 if (idl) {
610 ovsdb_idl_clear(idl);
611 jsonrpc_session_close(idl->session);
612 ovsdb_idl_db_destroy(&idl->server);
613 ovsdb_idl_db_destroy(&idl->data);
614 json_destroy(idl->request_id);
615 free(idl->remote);
616 free(idl);
617 }
618 }
619
620 void
621 ovsdb_idl_set_leader_only(struct ovsdb_idl *idl, bool leader_only)
622 {
623 idl->leader_only = leader_only;
624 if (leader_only && idl->server.monitoring) {
625 ovsdb_idl_check_server_db(idl);
626 }
627 }
628
629 static void
630 ovsdb_idl_db_clear(struct ovsdb_idl_db *db)
631 {
632 bool changed = false;
633 size_t i;
634
635 for (i = 0; i < db->class_->n_tables; i++) {
636 struct ovsdb_idl_table *table = &db->tables[i];
637 struct ovsdb_idl_row *row, *next_row;
638
639 if (hmap_is_empty(&table->rows)) {
640 continue;
641 }
642
643 changed = true;
644 HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &table->rows) {
645 struct ovsdb_idl_arc *arc, *next_arc;
646
647 if (!ovsdb_idl_row_is_orphan(row)) {
648 ovsdb_idl_remove_from_indexes(row);
649 ovsdb_idl_row_unparse(row);
650 }
651 LIST_FOR_EACH_SAFE (arc, next_arc, src_node, &row->src_arcs) {
652 free(arc);
653 }
654 /* No need to do anything with dst_arcs: some node has those arcs
655 * as forward arcs and will destroy them itself. */
656
657 ovsdb_idl_row_destroy(row);
658 }
659 }
660 ovsdb_idl_row_destroy_postprocess(db);
661
662 db->cond_seqno = 0;
663 ovsdb_idl_db_track_clear(db);
664
665 if (changed) {
666 db->change_seqno++;
667 }
668 }
669
670 static const char *
671 ovsdb_idl_state_to_string(enum ovsdb_idl_state state)
672 {
673 switch (state) {
674 #define OVSDB_IDL_STATE(NAME) case IDL_S_##NAME: return #NAME;
675 OVSDB_IDL_STATES
676 #undef OVSDB_IDL_STATE
677 default: return "<unknown>";
678 }
679 }
680
681 static void
682 ovsdb_idl_retry_at(struct ovsdb_idl *idl, const char *where)
683 {
684 ovsdb_idl_force_reconnect(idl);
685 ovsdb_idl_transition_at(idl, IDL_S_RETRY, where);
686 }
687
688 static void
689 ovsdb_idl_transition_at(struct ovsdb_idl *idl, enum ovsdb_idl_state new_state,
690 const char *where)
691 {
692 VLOG_DBG("%s: %s -> %s at %s",
693 idl->session ? jsonrpc_session_get_name(idl->session) : "void",
694 ovsdb_idl_state_to_string(idl->state),
695 ovsdb_idl_state_to_string(new_state),
696 where);
697 idl->state = new_state;
698 }
699
700 static void
701 ovsdb_idl_clear(struct ovsdb_idl *idl)
702 {
703 ovsdb_idl_db_clear(&idl->data);
704 }
705
706 static void
707 ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request)
708 {
709 json_destroy(idl->request_id);
710 idl->request_id = json_clone(request->id);
711 if (idl->session) {
712 jsonrpc_session_send(idl->session, request);
713 }
714 }
715
716 static void
717 ovsdb_idl_restart_fsm(struct ovsdb_idl *idl)
718 {
719 /* Resync data DB table conditions to avoid missing updates due to
720 * conditions that were in flight or changed locally while the connection
721 * was down.
722 */
723 ovsdb_idl_db_sync_condition(&idl->data);
724
725 ovsdb_idl_send_schema_request(idl, &idl->server);
726 ovsdb_idl_transition(idl, IDL_S_SERVER_SCHEMA_REQUESTED);
727 idl->data.monitoring = OVSDB_IDL_NOT_MONITORING;
728 idl->server.monitoring = OVSDB_IDL_NOT_MONITORING;
729 }
730
731 static void
732 ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
733 {
734 bool ok = msg->type == JSONRPC_REPLY;
735 if (!ok
736 && idl->state != IDL_S_SERVER_SCHEMA_REQUESTED
737 && idl->state != IDL_S_SERVER_MONITOR_COND_REQUESTED
738 && idl->state != IDL_S_DATA_MONITOR_COND_REQUESTED
739 && idl->state != IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED) {
740 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
741 char *s = jsonrpc_msg_to_string(msg);
742 VLOG_INFO_RL(&rl, "%s: received unexpected %s response in "
743 "%s state: %s", jsonrpc_session_get_name(idl->session),
744 jsonrpc_msg_type_to_string(msg->type),
745 ovsdb_idl_state_to_string(idl->state),
746 s);
747 free(s);
748 ovsdb_idl_retry(idl);
749 return;
750 }
751
752 switch (idl->state) {
753 case IDL_S_SERVER_SCHEMA_REQUESTED:
754 if (ok) {
755 json_destroy(idl->server.schema);
756 idl->server.schema = json_clone(msg->result);
757 ovsdb_idl_send_monitor_request(idl, &idl->server,
758 OVSDB_IDL_MM_MONITOR_COND);
759 ovsdb_idl_transition(idl, IDL_S_SERVER_MONITOR_COND_REQUESTED);
760 } else {
761 ovsdb_idl_send_schema_request(idl, &idl->data);
762 ovsdb_idl_transition(idl, IDL_S_DATA_SCHEMA_REQUESTED);
763 }
764 break;
765
766 case IDL_S_SERVER_MONITOR_COND_REQUESTED:
767 if (ok) {
768 idl->server.monitoring = OVSDB_IDL_MONITORING_COND;
769 ovsdb_idl_db_parse_monitor_reply(&idl->server, msg->result,
770 OVSDB_IDL_MM_MONITOR_COND);
771 if (ovsdb_idl_check_server_db(idl)) {
772 ovsdb_idl_send_db_change_aware(idl);
773 }
774 } else {
775 ovsdb_idl_send_schema_request(idl, &idl->data);
776 ovsdb_idl_transition(idl, IDL_S_DATA_SCHEMA_REQUESTED);
777 }
778 break;
779
780 case IDL_S_DATA_SCHEMA_REQUESTED:
781 json_destroy(idl->data.schema);
782 idl->data.schema = json_clone(msg->result);
783 ovsdb_idl_send_monitor_request(idl, &idl->data,
784 OVSDB_IDL_MM_MONITOR_COND);
785 ovsdb_idl_transition(idl, IDL_S_DATA_MONITOR_COND_REQUESTED);
786 break;
787
788 case IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED:
789 if (!ok) {
790 /* "monitor_cond_since" not supported. Try "monitor_cond". */
791 ovsdb_idl_send_monitor_request(idl, &idl->data,
792 OVSDB_IDL_MM_MONITOR_COND);
793 ovsdb_idl_transition(idl, IDL_S_DATA_MONITOR_COND_REQUESTED);
794 } else {
795 idl->data.monitoring = OVSDB_IDL_MONITORING_COND_SINCE;
796 ovsdb_idl_transition(idl, IDL_S_MONITORING);
797 ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
798 OVSDB_IDL_MM_MONITOR_COND_SINCE);
799 }
800 break;
801
802 case IDL_S_DATA_MONITOR_COND_REQUESTED:
803 if (!ok) {
804 /* "monitor_cond" not supported. Try "monitor". */
805 ovsdb_idl_send_monitor_request(idl, &idl->data,
806 OVSDB_IDL_MM_MONITOR);
807 ovsdb_idl_transition(idl, IDL_S_DATA_MONITOR_REQUESTED);
808 } else {
809 idl->data.monitoring = OVSDB_IDL_MONITORING_COND;
810 ovsdb_idl_transition(idl, IDL_S_MONITORING);
811 ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
812 OVSDB_IDL_MM_MONITOR_COND);
813 }
814 break;
815
816 case IDL_S_DATA_MONITOR_REQUESTED:
817 idl->data.monitoring = OVSDB_IDL_MONITORING;
818 ovsdb_idl_transition(idl, IDL_S_MONITORING);
819 ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
820 OVSDB_IDL_MM_MONITOR);
821 idl->data.change_seqno++;
822 ovsdb_idl_clear(idl);
823 ovsdb_idl_db_parse_update(&idl->data, msg->result,
824 OVSDB_IDL_MM_MONITOR);
825 break;
826
827 case IDL_S_MONITORING:
828 /* We don't normally have a request outstanding in this state. If we
829 * do, it's a "monitor_cond_change", which means that the conditional
830 * monitor clauses were updated.
831 *
832 * Mark the last requested conditions as acked and if further
833 * condition changes were pending, send them now. */
834 ovsdb_idl_db_ack_condition(&idl->data);
835 ovsdb_idl_send_cond_change(idl);
836 idl->data.cond_seqno++;
837 break;
838
839 case IDL_S_ERROR:
840 case IDL_S_RETRY:
841 /* Nothing to do in this state. */
842 break;
843
844 default:
845 OVS_NOT_REACHED();
846 }
847 }
848
849 static void
850 ovsdb_idl_process_msg(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
851 {
852 bool is_response = (msg->type == JSONRPC_REPLY ||
853 msg->type == JSONRPC_ERROR);
854
855 /* Process a reply to an outstanding request. */
856 if (is_response
857 && idl->request_id && json_equal(idl->request_id, msg->id)) {
858 json_destroy(idl->request_id);
859 idl->request_id = NULL;
860 ovsdb_idl_process_response(idl, msg);
861 return;
862 }
863
864 /* Process database contents updates. */
865 if (ovsdb_idl_db_parse_update_rpc(&idl->data, msg)) {
866 return;
867 }
868 if (idl->server.monitoring
869 && ovsdb_idl_db_parse_update_rpc(&idl->server, msg)) {
870 ovsdb_idl_check_server_db(idl);
871 return;
872 }
873
874 if (ovsdb_idl_handle_monitor_canceled(idl, &idl->data, msg)
875 || (idl->server.monitoring
876 && ovsdb_idl_handle_monitor_canceled(idl, &idl->server, msg))) {
877 return;
878 }
879
880 /* Process "lock" replies and related notifications. */
881 if (ovsdb_idl_db_process_lock_replies(&idl->data, msg)) {
882 return;
883 }
884
885 /* Process response to a database transaction we submitted. */
886 if (is_response && ovsdb_idl_db_txn_process_reply(&idl->data, msg)) {
887 return;
888 }
889
890 /* Unknown message. Log at a low level because this can happen if
891 * ovsdb_idl_txn_destroy() is called to destroy a transaction
892 * before we receive the reply.
893 *
894 * (We could sort those out from other kinds of unknown messages by
895 * using distinctive IDs for transactions, if it seems valuable to
896 * do so, and then it would be possible to use different log
897 * levels. XXX?) */
898 char *s = jsonrpc_msg_to_string(msg);
899 VLOG_DBG("%s: received unexpected %s message: %s",
900 jsonrpc_session_get_name(idl->session),
901 jsonrpc_msg_type_to_string(msg->type), s);
902 free(s);
903 }
904
905 /* Processes a batch of messages from the database server on 'idl'. This may
906 * cause the IDL's contents to change. The client may check for that with
907 * ovsdb_idl_get_seqno(). */
908 void
909 ovsdb_idl_run(struct ovsdb_idl *idl)
910 {
911 if (!idl->session) {
912 ovsdb_idl_txn_abort_all(idl);
913 return;
914 }
915
916 int i;
917
918 ovs_assert(!idl->data.txn);
919
920 ovsdb_idl_send_cond_change(idl);
921
922 jsonrpc_session_run(idl->session);
923 for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
924 struct jsonrpc_msg *msg;
925 unsigned int seqno;
926
927 seqno = jsonrpc_session_get_seqno(idl->session);
928 if (idl->state_seqno != seqno) {
929 idl->state_seqno = seqno;
930 ovsdb_idl_txn_abort_all(idl);
931 ovsdb_idl_restart_fsm(idl);
932
933 if (idl->data.lock_name) {
934 jsonrpc_session_send(
935 idl->session,
936 ovsdb_idl_db_compose_lock_request(&idl->data));
937 }
938 }
939
940 msg = jsonrpc_session_recv(idl->session);
941 if (!msg) {
942 break;
943 }
944 ovsdb_idl_process_msg(idl, msg);
945 jsonrpc_msg_destroy(msg);
946 }
947 ovsdb_idl_row_destroy_postprocess(&idl->data);
948 }
949
950 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
951 * do or when activity occurs on a transaction on 'idl'. */
952 void
953 ovsdb_idl_wait(struct ovsdb_idl *idl)
954 {
955 if (!idl->session) {
956 return;
957 }
958 jsonrpc_session_wait(idl->session);
959 jsonrpc_session_recv_wait(idl->session);
960 }
961
962 /* Returns a "sequence number" that represents the state of 'idl'. When
963 * ovsdb_idl_run() changes the database, the sequence number changes. The
964 * initial fetch of the entire contents of the remote database is considered to
965 * be one kind of change. Successfully acquiring a lock, if one has been
966 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
967 *
968 * As long as the sequence number does not change, the client may continue to
969 * use any data structures it obtains from 'idl'. But when it changes, the
970 * client must not access any of these data structures again, because they
971 * could have freed or reused for other purposes.
972 *
973 * The sequence number can occasionally change even if the database does not.
974 * This happens if the connection to the database drops and reconnects, which
975 * causes the database contents to be reloaded even if they didn't change. (It
976 * could also happen if the database server sends out a "change" that reflects
977 * what the IDL already thought was in the database. The database server is
978 * not supposed to do that, but bugs could in theory cause it to do so.) */
979 unsigned int
980 ovsdb_idl_get_seqno(const struct ovsdb_idl *idl)
981 {
982 return idl->data.change_seqno;
983 }
984
985 /* Returns a "sequence number" that represents the number of conditional
986 * monitoring updates successfully received by the OVSDB server of an IDL
987 * connection.
988 *
989 * ovsdb_idl_set_condition() sets a new condition that is different from
990 * the current condtion, the next expected "sequence number" is returned.
991 *
992 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
993 * the return value of ovsdb_idl_set_condition(), The client is
994 * assured that:
995 * - The ovsdb_idl_set_condition() changes has been acknowledged by
996 * the OVSDB sever.
997 *
998 * - 'idl' now contains the content matches the new conditions. */
999 unsigned int
1000 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl *idl)
1001 {
1002 return idl->data.cond_seqno;
1003 }
1004
1005 /* Returns true if 'idl' successfully connected to the remote database and
1006 * retrieved its contents (even if the connection subsequently dropped and is
1007 * in the process of reconnecting). If so, then 'idl' contains an atomic
1008 * snapshot of the database's contents (but it might be arbitrarily old if the
1009 * connection dropped).
1010 *
1011 * Returns false if 'idl' has never connected or retrieved the database's
1012 * contents. If so, 'idl' is empty. */
1013 bool
1014 ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
1015 {
1016 return ovsdb_idl_get_seqno(idl) != 0;
1017 }
1018
1019 /* Reconfigures 'idl' so that it would reconnect to the database, if
1020 * connection was dropped. */
1021 void
1022 ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
1023 {
1024 if (idl->session) {
1025 jsonrpc_session_enable_reconnect(idl->session);
1026 }
1027 }
1028
1029 /* Forces 'idl' to drop its connection to the database and reconnect. In the
1030 * meantime, the contents of 'idl' will not change. */
1031 void
1032 ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
1033 {
1034 if (idl->session) {
1035 jsonrpc_session_force_reconnect(idl->session);
1036 }
1037 }
1038
1039 /* Some IDL users should only write to write-only columns. Furthermore,
1040 * writing to a column which is not write-only can cause serious performance
1041 * degradations for these users. This function causes 'idl' to reject writes
1042 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
1043 void
1044 ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
1045 {
1046 idl->data.verify_write_only = true;
1047 }
1048
1049 /* Returns true if 'idl' is currently connected or trying to connect
1050 * and a negative response to a schema request has not been received */
1051 bool
1052 ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
1053 {
1054 return idl->session && jsonrpc_session_is_alive(idl->session) &&
1055 idl->state != IDL_S_ERROR;
1056 }
1057
1058 bool
1059 ovsdb_idl_is_connected(const struct ovsdb_idl *idl)
1060 {
1061 return idl->session && jsonrpc_session_is_connected(idl->session);
1062 }
1063
1064 /* Returns the last error reported on a connection by 'idl'. The return value
1065 * is 0 only if no connection made by 'idl' has ever encountered an error and
1066 * a negative response to a schema request has never been received. See
1067 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
1068 * interpretation. */
1069 int
1070 ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
1071 {
1072 int err = idl->session ? jsonrpc_session_get_last_error(idl->session) : 0;
1073 if (err) {
1074 return err;
1075 } else if (idl->state == IDL_S_ERROR) {
1076 return ENOENT;
1077 } else {
1078 return 0;
1079 }
1080 }
1081
1082 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
1083 * milliseconds.
1084 */
1085 void
1086 ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
1087 {
1088 if (idl->session) {
1089 jsonrpc_session_set_probe_interval(idl->session, probe_interval);
1090 }
1091 }
1092
1093 static size_t
1094 find_uuid_in_array(const struct uuid *target,
1095 const struct uuid *array, size_t n)
1096 {
1097 for (size_t i = 0; i < n; i++) {
1098 if (uuid_equals(&array[i], target)) {
1099 return i;
1100 }
1101 }
1102 return SIZE_MAX;
1103 }
1104
1105 static size_t
1106 array_contains_uuid(const struct uuid *target,
1107 const struct uuid *array, size_t n)
1108 {
1109 return find_uuid_in_array(target, array, n) != SIZE_MAX;
1110 }
1111
1112 static bool
1113 remove_uuid_from_array(const struct uuid *target,
1114 struct uuid *array, size_t *n)
1115 {
1116 size_t i = find_uuid_in_array(target, array, *n);
1117 if (i != SIZE_MAX) {
1118 array[i] = array[--*n];
1119 return true;
1120 } else {
1121 return false;
1122 }
1123 }
1124
1125 static void
1126 add_row_references(const struct ovsdb_base_type *type,
1127 const union ovsdb_atom *atoms, size_t n_atoms,
1128 const struct uuid *exclude_uuid,
1129 struct uuid **dstsp, size_t *n_dstsp,
1130 size_t *allocated_dstsp)
1131 {
1132 if (type->type != OVSDB_TYPE_UUID || !type->uuid.refTableName) {
1133 return;
1134 }
1135
1136 for (size_t i = 0; i < n_atoms; i++) {
1137 const struct uuid *uuid = &atoms[i].uuid;
1138 if (!uuid_equals(uuid, exclude_uuid)
1139 && !array_contains_uuid(uuid, *dstsp, *n_dstsp)) {
1140 if (*n_dstsp >= *allocated_dstsp) {
1141 *dstsp = x2nrealloc(*dstsp, allocated_dstsp,
1142 sizeof **dstsp);
1143
1144 }
1145 (*dstsp)[*n_dstsp] = *uuid;
1146 ++*n_dstsp;
1147 }
1148 }
1149 }
1150
1151 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
1152 * reference from one row to a different row should be reflected as a "struct
1153 * ovsdb_idl_arc" between those rows.
1154 *
1155 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
1156 * thus it is only for use in test programs. */
1157 void
1158 ovsdb_idl_check_consistency(const struct ovsdb_idl *idl)
1159 {
1160 /* Consistency is broken while a transaction is in progress. */
1161 if (!idl->data.txn) {
1162 return;
1163 }
1164
1165 bool ok = true;
1166
1167 struct uuid *dsts = NULL;
1168 size_t allocated_dsts = 0;
1169
1170 for (size_t i = 0; i < idl->data.class_->n_tables; i++) {
1171 const struct ovsdb_idl_table *table = &idl->data.tables[i];
1172 const struct ovsdb_idl_table_class *class = table->class_;
1173
1174 const struct ovsdb_idl_row *row;
1175 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
1176 size_t n_dsts = 0;
1177 if (row->new_datum) {
1178 size_t n_columns = shash_count(&row->table->columns);
1179 for (size_t j = 0; j < n_columns; j++) {
1180 const struct ovsdb_type *type = &class->columns[j].type;
1181 const struct ovsdb_datum *datum = &row->new_datum[j];
1182 add_row_references(&type->key,
1183 datum->keys, datum->n, &row->uuid,
1184 &dsts, &n_dsts, &allocated_dsts);
1185 add_row_references(&type->value,
1186 datum->values, datum->n, &row->uuid,
1187 &dsts, &n_dsts, &allocated_dsts);
1188 }
1189 }
1190 const struct ovsdb_idl_arc *arc;
1191 LIST_FOR_EACH (arc, src_node, &row->src_arcs) {
1192 if (!remove_uuid_from_array(&arc->dst->uuid,
1193 dsts, &n_dsts)) {
1194 VLOG_ERR("unexpected arc from %s row "UUID_FMT" to %s "
1195 "row "UUID_FMT,
1196 table->class_->name,
1197 UUID_ARGS(&row->uuid),
1198 arc->dst->table->class_->name,
1199 UUID_ARGS(&arc->dst->uuid));
1200 ok = false;
1201 }
1202 }
1203 for (size_t j = 0; j < n_dsts; j++) {
1204 VLOG_ERR("%s row "UUID_FMT" missing arc to row "UUID_FMT,
1205 table->class_->name, UUID_ARGS(&row->uuid),
1206 UUID_ARGS(&dsts[j]));
1207 ok = false;
1208 }
1209 }
1210 }
1211 free(dsts);
1212 ovs_assert(ok);
1213 }
1214 \f
1215 const struct ovsdb_idl_class *
1216 ovsdb_idl_get_class(const struct ovsdb_idl *idl)
1217 {
1218 return idl->data.class_;
1219 }
1220
1221 /* Given 'column' in some table in 'class', returns the table's class. */
1222 const struct ovsdb_idl_table_class *
1223 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class *class,
1224 const struct ovsdb_idl_column *column)
1225 {
1226 for (size_t i = 0; i < class->n_tables; i++) {
1227 const struct ovsdb_idl_table_class *tc = &class->tables[i];
1228 if (column >= tc->columns && column < &tc->columns[tc->n_columns]) {
1229 return tc;
1230 }
1231 }
1232
1233 OVS_NOT_REACHED();
1234 }
1235
1236 /* Given 'column' in some table in 'db', returns the table. */
1237 static struct ovsdb_idl_table *
1238 ovsdb_idl_table_from_column(struct ovsdb_idl_db *db,
1239 const struct ovsdb_idl_column *column)
1240 {
1241 const struct ovsdb_idl_table_class *tc =
1242 ovsdb_idl_table_class_from_column(db->class_, column);
1243 return &db->tables[tc - db->class_->tables];
1244 }
1245
1246 static unsigned char *
1247 ovsdb_idl_db_get_mode(struct ovsdb_idl_db *db,
1248 const struct ovsdb_idl_column *column)
1249 {
1250 ovs_assert(!db->change_seqno);
1251
1252 const struct ovsdb_idl_table *table = ovsdb_idl_table_from_column(db,
1253 column);
1254 return &table->modes[column - table->class_->columns];
1255 }
1256
1257 static void
1258 ovsdb_idl_db_set_mode(struct ovsdb_idl_db *db,
1259 const struct ovsdb_idl_column *column,
1260 unsigned char mode)
1261 {
1262 const struct ovsdb_idl_table *table = ovsdb_idl_table_from_column(db,
1263 column);
1264 size_t column_idx = column - table->class_->columns;
1265
1266 if (table->modes[column_idx] != mode) {
1267 *ovsdb_idl_db_get_mode(db, column) = mode;
1268 }
1269 }
1270
1271 static void
1272 add_ref_table(struct ovsdb_idl_db *db, const struct ovsdb_base_type *base)
1273 {
1274 if (base->type == OVSDB_TYPE_UUID && base->uuid.refTableName) {
1275 struct ovsdb_idl_table *table;
1276
1277 table = shash_find_data(&db->table_by_name, base->uuid.refTableName);
1278 if (table) {
1279 table->need_table = true;
1280 } else {
1281 VLOG_WARN("%s IDL class missing referenced table %s",
1282 db->class_->database, base->uuid.refTableName);
1283 }
1284 }
1285 }
1286
1287 static void
1288 ovsdb_idl_db_add_column(struct ovsdb_idl_db *db,
1289 const struct ovsdb_idl_column *column)
1290 {
1291 ovsdb_idl_db_set_mode(db, column, OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT);
1292 add_ref_table(db, &column->type.key);
1293 add_ref_table(db, &column->type.value);
1294 }
1295
1296 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
1297 * ensures that any tables referenced by 'column' will be replicated, even if
1298 * no columns in that table are selected for replication (see
1299 * ovsdb_idl_add_table() for more information).
1300 *
1301 * This function is only useful if 'monitor_everything_by_default' was false in
1302 * the call to ovsdb_idl_create(). This function should be called between
1303 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1304 */
1305 void
1306 ovsdb_idl_add_column(struct ovsdb_idl *idl,
1307 const struct ovsdb_idl_column *column)
1308 {
1309 ovsdb_idl_db_add_column(&idl->data, column);
1310 }
1311
1312 static void
1313 ovsdb_idl_db_add_table(struct ovsdb_idl_db *db,
1314 const struct ovsdb_idl_table_class *tc)
1315 {
1316 size_t i;
1317
1318 for (i = 0; i < db->class_->n_tables; i++) {
1319 struct ovsdb_idl_table *table = &db->tables[i];
1320
1321 if (table->class_ == tc) {
1322 table->need_table = true;
1323 return;
1324 }
1325 }
1326
1327 OVS_NOT_REACHED();
1328 }
1329
1330 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
1331 * no columns are selected for replication. Just the necessary data for table
1332 * references will be replicated (the UUID of the rows, for instance), any
1333 * columns not selected for replication will remain unreplicated.
1334 * This can be useful because it allows 'idl' to keep track of what rows in the
1335 * table actually exist, which in turn allows columns that reference the table
1336 * to have accurate contents. (The IDL presents the database with references to
1337 * rows that do not exist removed.)
1338 *
1339 * This function is only useful if 'monitor_everything_by_default' was false in
1340 * the call to ovsdb_idl_create(). This function should be called between
1341 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
1342 */
1343 void
1344 ovsdb_idl_add_table(struct ovsdb_idl *idl,
1345 const struct ovsdb_idl_table_class *tc)
1346 {
1347 ovsdb_idl_db_add_table(&idl->data, tc);
1348 }
1349 \f
1350 /* A single clause within an ovsdb_idl_condition. */
1351 struct ovsdb_idl_clause {
1352 struct hmap_node hmap_node; /* In struct ovsdb_idl_condition. */
1353 enum ovsdb_function function; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
1354 const struct ovsdb_idl_column *column; /* Must be nonnull. */
1355 struct ovsdb_datum arg; /* Has ovsdb_type ->column->type. */
1356 };
1357
1358 static uint32_t
1359 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause *clause)
1360 {
1361 uint32_t hash = hash_pointer(clause->column, clause->function);
1362 return ovsdb_datum_hash(&clause->arg, &clause->column->type, hash);
1363 }
1364
1365 static int
1366 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause *a,
1367 const struct ovsdb_idl_clause *b)
1368 {
1369 return (a->function == b->function
1370 && a->column == b->column
1371 && ovsdb_datum_equals(&a->arg, &b->arg, &a->column->type));
1372 }
1373
1374 static struct json *
1375 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
1376 {
1377 const char *function = ovsdb_function_to_string(clause->function);
1378 return json_array_create_3(json_string_create(clause->column->name),
1379 json_string_create(function),
1380 ovsdb_datum_to_json(&clause->arg,
1381 &clause->column->type));
1382 }
1383
1384 static void
1385 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause *clause)
1386 {
1387 if (clause) {
1388 ovsdb_datum_destroy(&clause->arg, &clause->column->type);
1389 free(clause);
1390 }
1391 }
1392 \f
1393 /* ovsdb_idl_condition. */
1394
1395 void
1396 ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd)
1397 {
1398 hmap_init(&cnd->clauses);
1399 cnd->is_true = false;
1400 }
1401
1402 void
1403 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cond)
1404 {
1405 if (cond) {
1406 ovsdb_idl_condition_clear(cond);
1407 hmap_destroy(&cond->clauses);
1408 }
1409 }
1410
1411 void
1412 ovsdb_idl_condition_clear(struct ovsdb_idl_condition *cond)
1413 {
1414 struct ovsdb_idl_clause *clause, *next;
1415 HMAP_FOR_EACH_SAFE (clause, next, hmap_node, &cond->clauses) {
1416 hmap_remove(&cond->clauses, &clause->hmap_node);
1417 ovsdb_idl_clause_destroy(clause);
1418 }
1419 cond->is_true = false;
1420 }
1421
1422 bool
1423 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition *condition)
1424 {
1425 return condition->is_true;
1426 }
1427
1428 static struct ovsdb_idl_clause *
1429 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition *condition,
1430 const struct ovsdb_idl_clause *target,
1431 uint32_t hash)
1432 {
1433 struct ovsdb_idl_clause *clause;
1434 HMAP_FOR_EACH_WITH_HASH (clause, hmap_node, hash, &condition->clauses) {
1435 if (ovsdb_idl_clause_equals(clause, target)) {
1436 return clause;
1437 }
1438 }
1439 return NULL;
1440 }
1441
1442 static void
1443 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition *condition,
1444 const struct ovsdb_idl_clause *src,
1445 uint32_t hash)
1446 {
1447 struct ovsdb_idl_clause *clause = xmalloc(sizeof *clause);
1448 clause->function = src->function;
1449 clause->column = src->column;
1450 ovsdb_datum_clone(&clause->arg, &src->arg, &src->column->type);
1451 hmap_insert(&condition->clauses, &clause->hmap_node, hash);
1452 }
1453
1454 /* Adds a clause to the condition for replicating the table with class 'tc' in
1455 * 'idl'.
1456 *
1457 * The IDL replicates only rows in a table that satisfy at least one clause in
1458 * the table's condition. The default condition for a table has a single
1459 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1460 * the table. When the IDL client replaces the default condition by one of its
1461 * own, the condition can have any number of clauses. If it has no conditions,
1462 * then no rows are replicated.
1463 *
1464 * Two distinct of clauses can usefully be added:
1465 *
1466 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1467 * replicated, regardless of whether other clauses exist. 'column' and
1468 * 'arg' are ignored.
1469 *
1470 * - Binary 'functions' add a clause of the form "<column> <function>
1471 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1472 * have a type that is compatible with 'column'.
1473 */
1474 void
1475 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *condition,
1476 enum ovsdb_function function,
1477 const struct ovsdb_idl_column *column,
1478 const struct ovsdb_datum *arg)
1479 {
1480 if (condition->is_true) {
1481 /* Adding a clause to an always-true condition has no effect. */
1482 } else if (function == OVSDB_F_TRUE) {
1483 ovsdb_idl_condition_add_clause_true(condition);
1484 } else if (function == OVSDB_F_FALSE) {
1485 /* Adding a "false" clause never has any effect. */
1486 } else {
1487 struct ovsdb_idl_clause clause = {
1488 .function = function,
1489 .column = column,
1490 .arg = *arg,
1491 };
1492 uint32_t hash = ovsdb_idl_clause_hash(&clause);
1493 if (!ovsdb_idl_condition_find_clause(condition, &clause, hash)) {
1494 ovsdb_idl_condition_add_clause__(condition, &clause, hash);
1495 }
1496 }
1497 }
1498
1499 void
1500 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition *condition)
1501 {
1502 if (!condition->is_true) {
1503 ovsdb_idl_condition_clear(condition);
1504 condition->is_true = true;
1505 }
1506 }
1507
1508 static bool
1509 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a,
1510 const struct ovsdb_idl_condition *b)
1511 {
1512 if (hmap_count(&a->clauses) != hmap_count(&b->clauses)) {
1513 return false;
1514 }
1515 if (a->is_true != b->is_true) {
1516 return false;
1517 }
1518
1519 const struct ovsdb_idl_clause *clause;
1520 HMAP_FOR_EACH (clause, hmap_node, &a->clauses) {
1521 if (!ovsdb_idl_condition_find_clause(b, clause,
1522 clause->hmap_node.hash)) {
1523 return false;
1524 }
1525 }
1526 return true;
1527 }
1528
1529 static void
1530 ovsdb_idl_condition_clone(struct ovsdb_idl_condition **dst,
1531 const struct ovsdb_idl_condition *src)
1532 {
1533 if (*dst) {
1534 ovsdb_idl_condition_destroy(*dst);
1535 } else {
1536 *dst = xmalloc(sizeof **dst);
1537 }
1538 ovsdb_idl_condition_init(*dst);
1539
1540 (*dst)->is_true = src->is_true;
1541
1542 const struct ovsdb_idl_clause *clause;
1543 HMAP_FOR_EACH (clause, hmap_node, &src->clauses) {
1544 ovsdb_idl_condition_add_clause__(*dst, clause, clause->hmap_node.hash);
1545 }
1546 }
1547
1548 static void
1549 ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst,
1550 struct ovsdb_idl_condition **src)
1551 {
1552 if (*dst) {
1553 ovsdb_idl_condition_destroy(*dst);
1554 free(*dst);
1555 }
1556 *dst = *src;
1557 *src = NULL;
1558 }
1559
1560 static unsigned int
1561 ovsdb_idl_db_set_condition(struct ovsdb_idl_db *db,
1562 const struct ovsdb_idl_table_class *tc,
1563 const struct ovsdb_idl_condition *condition)
1564 {
1565 struct ovsdb_idl_condition *table_cond;
1566 struct ovsdb_idl_table *table = ovsdb_idl_db_table_from_class(db, tc);
1567 unsigned int seqno = db->cond_seqno;
1568
1569 /* Compare the new condition to the last known condition which can be
1570 * either "new" (not sent yet), "requested" or "acked", in this order.
1571 */
1572 if (table->new_cond) {
1573 table_cond = table->new_cond;
1574 } else if (table->req_cond) {
1575 table_cond = table->req_cond;
1576 } else {
1577 table_cond = table->ack_cond;
1578 }
1579 ovs_assert(table_cond);
1580
1581 if (!ovsdb_idl_condition_equals(condition, table_cond)) {
1582 ovsdb_idl_condition_clone(&table->new_cond, condition);
1583 db->cond_changed = true;
1584 poll_immediate_wake();
1585 return seqno + 1;
1586 }
1587
1588 return seqno;
1589 }
1590
1591 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1592 * arranges to send the new condition to the database server.
1593 *
1594 * Return the next conditional update sequence number. When this
1595 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1596 * contains rows that match the 'condition'. */
1597 unsigned int
1598 ovsdb_idl_set_condition(struct ovsdb_idl *idl,
1599 const struct ovsdb_idl_table_class *tc,
1600 const struct ovsdb_idl_condition *condition)
1601 {
1602 return ovsdb_idl_db_set_condition(&idl->data, tc, condition);
1603 }
1604
1605 static struct json *
1606 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
1607 {
1608 if (cnd->is_true) {
1609 return json_array_create_empty();
1610 }
1611
1612 size_t n = hmap_count(&cnd->clauses);
1613 if (!n) {
1614 return json_array_create_1(json_boolean_create(false));
1615 }
1616
1617 struct json **clauses = xmalloc(n * sizeof *clauses);
1618 const struct ovsdb_idl_clause *clause;
1619 size_t i = 0;
1620 HMAP_FOR_EACH (clause, hmap_node, &cnd->clauses) {
1621 clauses[i++] = ovsdb_idl_clause_to_json(clause);
1622 }
1623 ovs_assert(i == n);
1624 return json_array_create(clauses, n);
1625 }
1626 \f
1627 static struct json *
1628 ovsdb_idl_create_cond_change_req(const struct ovsdb_idl_condition *cond)
1629 {
1630 struct json *monitor_cond_change_request = json_object_create();
1631 struct json *cond_json = ovsdb_idl_condition_to_json(cond);
1632
1633 json_object_put(monitor_cond_change_request, "where", cond_json);
1634
1635 return monitor_cond_change_request;
1636 }
1637
1638 static struct jsonrpc_msg *
1639 ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db)
1640 {
1641 if (!db->cond_changed) {
1642 return NULL;
1643 }
1644
1645 struct json *monitor_cond_change_requests = NULL;
1646 for (size_t i = 0; i < db->class_->n_tables; i++) {
1647 struct ovsdb_idl_table *table = &db->tables[i];
1648
1649 /* Always use the most recent conditions set by the IDL client when
1650 * requesting monitor_cond_change, i.e., table->new_cond.
1651 */
1652 if (table->new_cond) {
1653 struct json *req =
1654 ovsdb_idl_create_cond_change_req(table->new_cond);
1655 if (req) {
1656 if (!monitor_cond_change_requests) {
1657 monitor_cond_change_requests = json_object_create();
1658 }
1659 json_object_put(monitor_cond_change_requests,
1660 table->class_->name,
1661 json_array_create_1(req));
1662 }
1663 /* Mark the new condition as requested by moving it to req_cond.
1664 * If there's already requested condition that's a bug.
1665 */
1666 ovs_assert(table->req_cond == NULL);
1667 ovsdb_idl_condition_move(&table->req_cond, &table->new_cond);
1668 }
1669 }
1670
1671 if (!monitor_cond_change_requests) {
1672 return NULL;
1673 }
1674
1675 db->cond_changed = false;
1676 struct json *params = json_array_create_3(json_clone(db->monitor_id),
1677 json_clone(db->monitor_id),
1678 monitor_cond_change_requests);
1679 return jsonrpc_create_request("monitor_cond_change", params, NULL);
1680 }
1681
1682 /* Marks all requested table conditions in 'db' as acked by the server.
1683 * It should be called when the server replies to monitor_cond_change
1684 * requests.
1685 */
1686 static void
1687 ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db)
1688 {
1689 for (size_t i = 0; i < db->class_->n_tables; i++) {
1690 struct ovsdb_idl_table *table = &db->tables[i];
1691
1692 if (table->req_cond) {
1693 ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond);
1694 }
1695 }
1696 }
1697
1698 /* Should be called when the IDL fsm is restarted and resyncs table conditions
1699 * based on the state the DB is in:
1700 * - if a non-zero last_id is available for the DB then upon reconnect
1701 * the IDL should first request acked conditions to avoid missing updates
1702 * about records that were added before the transaction with
1703 * txn-id == last_id. If there were requested condition changes in flight
1704 * (i.e., req_cond not NULL) and the IDL client didn't set new conditions
1705 * (i.e., new_cond is NULL) then move req_cond to new_cond to trigger a
1706 * follow up monitor_cond_change request.
1707 * - if there's no last_id available for the DB then it's safe to use the
1708 * latest conditions set by the IDL client even if they weren't acked yet.
1709 */
1710 static void
1711 ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db)
1712 {
1713 bool ack_all = uuid_is_zero(&db->last_id);
1714
1715 db->cond_changed = false;
1716 for (size_t i = 0; i < db->class_->n_tables; i++) {
1717 struct ovsdb_idl_table *table = &db->tables[i];
1718
1719 /* When monitor_cond_since requests will be issued, the
1720 * table->ack_cond condition will be added to the "where" clause".
1721 * Follow up monitor_cond_change requests will use table->new_cond.
1722 */
1723 if (ack_all) {
1724 if (table->new_cond) {
1725 ovsdb_idl_condition_move(&table->req_cond, &table->new_cond);
1726 }
1727
1728 if (table->req_cond) {
1729 ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond);
1730 }
1731 } else {
1732 /* If there was no "unsent" condition but instead a
1733 * monitor_cond_change request was in flight, move table->req_cond
1734 * to table->new_cond and set db->cond_changed to trigger a new
1735 * monitor_cond_change request.
1736 *
1737 * However, if a new condition has been set by the IDL client,
1738 * monitor_cond_change will be sent anyway and will use the most
1739 * recent table->new_cond so there's no need to update it here.
1740 */
1741 if (table->req_cond && !table->new_cond) {
1742 ovsdb_idl_condition_move(&table->new_cond, &table->req_cond);
1743 db->cond_changed = true;
1744 }
1745 }
1746 }
1747 }
1748
1749 static void
1750 ovsdb_idl_send_cond_change(struct ovsdb_idl *idl)
1751 {
1752 /* When 'idl->request_id' is not NULL, there is an outstanding
1753 * conditional monitoring update request that we have not heard
1754 * from the server yet. Don't generate another request in this case. */
1755 if (!jsonrpc_session_is_connected(idl->session)
1756 || idl->data.monitoring == OVSDB_IDL_MONITORING
1757 || idl->request_id) {
1758 return;
1759 }
1760
1761 struct jsonrpc_msg *msg = ovsdb_idl_db_compose_cond_change(&idl->data);
1762 if (msg) {
1763 idl->request_id = json_clone(msg->id);
1764 jsonrpc_session_send(idl->session, msg);
1765 }
1766 }
1767
1768 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'db'.
1769 *
1770 * This function should be called between ovsdb_idl_create() and the first call
1771 * to ovsdb_idl_run().
1772 */
1773 static void
1774 ovsdb_idl_db_omit_alert(struct ovsdb_idl_db *db,
1775 const struct ovsdb_idl_column *column)
1776 {
1777 *ovsdb_idl_db_get_mode(db, column) &= ~(OVSDB_IDL_ALERT | OVSDB_IDL_TRACK);
1778 }
1779
1780 /* Turns off OVSDB_IDL_ALERT and OVSDB_IDL_TRACK for 'column' in 'idl'.
1781 *
1782 * This function should be called between ovsdb_idl_create() and the first call
1783 * to ovsdb_idl_run().
1784 */
1785 void
1786 ovsdb_idl_omit_alert(struct ovsdb_idl *idl,
1787 const struct ovsdb_idl_column *column)
1788 {
1789 ovsdb_idl_db_omit_alert(&idl->data, column);
1790 }
1791
1792 static void
1793 ovsdb_idl_db_omit(struct ovsdb_idl_db *db,
1794 const struct ovsdb_idl_column *column)
1795 {
1796 *ovsdb_idl_db_get_mode(db, column) = 0;
1797 }
1798
1799 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1800 * OVSDB_IDL_MONITOR for details.
1801 *
1802 * This function should be called between ovsdb_idl_create() and the first call
1803 * to ovsdb_idl_run().
1804 */
1805 void
1806 ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column)
1807 {
1808 ovsdb_idl_db_omit(&idl->data, column);
1809 }
1810
1811 /* Returns the most recent IDL change sequence number that caused a
1812 * insert, modify or delete update to the table with class 'table_class'.
1813 */
1814 unsigned int
1815 ovsdb_idl_table_get_seqno(const struct ovsdb_idl *idl,
1816 const struct ovsdb_idl_table_class *table_class)
1817 {
1818 struct ovsdb_idl_table *table
1819 = ovsdb_idl_db_table_from_class(&idl->data, table_class);
1820 unsigned int max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_INSERT];
1821
1822 if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]) {
1823 max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY];
1824 }
1825 if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_DELETE]) {
1826 max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_DELETE];
1827 }
1828 return max_seqno;
1829 }
1830
1831 /* For each row that contains tracked columns, IDL stores the most
1832 * recent IDL change sequence numbers associateed with insert, modify
1833 * and delete updates to the table.
1834 */
1835 unsigned int
1836 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row *row,
1837 enum ovsdb_idl_change change)
1838 {
1839 return row->change_seqno[change];
1840 }
1841
1842 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1843 * all rows whose 'column' is modified are traced. Similarly, insert
1844 * or delete of rows having 'column' are tracked. Clients are able
1845 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1846 * functions.
1847 *
1848 * This function should be called between ovsdb_idl_create() and
1849 * the first call to ovsdb_idl_run(). The column to be tracked
1850 * should have OVSDB_IDL_ALERT turned on.
1851 */
1852 void
1853 ovsdb_idl_track_add_column(struct ovsdb_idl *idl,
1854 const struct ovsdb_idl_column *column)
1855 {
1856 if (!(*ovsdb_idl_db_get_mode(&idl->data, column) & OVSDB_IDL_ALERT)) {
1857 ovsdb_idl_add_column(idl, column);
1858 }
1859 *ovsdb_idl_db_get_mode(&idl->data, column) |= OVSDB_IDL_TRACK;
1860 }
1861
1862 void
1863 ovsdb_idl_track_add_all(struct ovsdb_idl *idl)
1864 {
1865 size_t i, j;
1866
1867 for (i = 0; i < idl->data.class_->n_tables; i++) {
1868 const struct ovsdb_idl_table_class *tc = &idl->data.class_->tables[i];
1869
1870 for (j = 0; j < tc->n_columns; j++) {
1871 const struct ovsdb_idl_column *column = &tc->columns[j];
1872 ovsdb_idl_track_add_column(idl, column);
1873 }
1874 }
1875 }
1876
1877 /* Returns true if 'table' has any tracked column. */
1878 static bool
1879 ovsdb_idl_track_is_set(struct ovsdb_idl_table *table)
1880 {
1881 size_t i;
1882
1883 for (i = 0; i < table->class_->n_columns; i++) {
1884 if (table->modes[i] & OVSDB_IDL_TRACK) {
1885 return true;
1886 }
1887 }
1888 return false;
1889 }
1890
1891 /* Returns the first tracked row in table with class 'table_class'
1892 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1893 const struct ovsdb_idl_row *
1894 ovsdb_idl_track_get_first(const struct ovsdb_idl *idl,
1895 const struct ovsdb_idl_table_class *table_class)
1896 {
1897 struct ovsdb_idl_table *table
1898 = ovsdb_idl_db_table_from_class(&idl->data, table_class);
1899
1900 if (!ovs_list_is_empty(&table->track_list)) {
1901 return CONTAINER_OF(ovs_list_front(&table->track_list), struct ovsdb_idl_row, track_node);
1902 }
1903 return NULL;
1904 }
1905
1906 /* Returns the next tracked row in table after the specified 'row'
1907 * (in no particular order). Returns NULL if there are no tracked rows */
1908 const struct ovsdb_idl_row *
1909 ovsdb_idl_track_get_next(const struct ovsdb_idl_row *row)
1910 {
1911 if (row->track_node.next != &row->table->track_list) {
1912 return CONTAINER_OF(row->track_node.next, struct ovsdb_idl_row, track_node);
1913 }
1914
1915 return NULL;
1916 }
1917
1918 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1919 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1920 *
1921 * Function returns false if 'column' is not tracked (see
1922 * ovsdb_idl_track_add_column()).
1923 */
1924 bool
1925 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
1926 const struct ovsdb_idl_column *column)
1927 {
1928 const struct ovsdb_idl_table_class *class;
1929 size_t column_idx;
1930
1931 class = row->table->class_;
1932 column_idx = column - class->columns;
1933
1934 if (row->updated && bitmap_is_set(row->updated, column_idx)) {
1935 return true;
1936 } else {
1937 return false;
1938 }
1939 }
1940
1941 /* Flushes the tracked rows. Client calls this function after calling
1942 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1943 * functions. This is usually done at the end of the client's processing
1944 * loop when it is ready to do ovsdb_idl_run() again.
1945 */
1946 static void
1947 ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db)
1948 {
1949 size_t i;
1950
1951 for (i = 0; i < db->class_->n_tables; i++) {
1952 struct ovsdb_idl_table *table = &db->tables[i];
1953
1954 if (!ovs_list_is_empty(&table->track_list)) {
1955 struct ovsdb_idl_row *row, *next;
1956
1957 LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
1958 if (row->updated) {
1959 free(row->updated);
1960 row->updated = NULL;
1961 }
1962 ovs_list_remove(&row->track_node);
1963 ovs_list_init(&row->track_node);
1964 if (ovsdb_idl_row_is_orphan(row) && row->tracked_old_datum) {
1965 ovsdb_idl_row_unparse(row);
1966 const struct ovsdb_idl_table_class *class =
1967 row->table->class_;
1968 for (size_t c = 0; c < class->n_columns; c++) {
1969 ovsdb_datum_destroy(&row->tracked_old_datum[c],
1970 &class->columns[c].type);
1971 }
1972 free(row->tracked_old_datum);
1973 row->tracked_old_datum = NULL;
1974 free(row);
1975 }
1976 }
1977 }
1978 }
1979 }
1980
1981 /* Flushes the tracked rows. Client calls this function after calling
1982 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1983 * functions. This is usually done at the end of the client's processing
1984 * loop when it is ready to do ovsdb_idl_run() again.
1985 */
1986 void
1987 ovsdb_idl_track_clear(struct ovsdb_idl *idl)
1988 {
1989 ovsdb_idl_db_track_clear(&idl->data);
1990 }
1991 \f
1992 static void
1993 ovsdb_idl_send_schema_request(struct ovsdb_idl *idl,
1994 struct ovsdb_idl_db *db)
1995 {
1996 ovsdb_idl_send_request(idl, jsonrpc_create_request(
1997 "get_schema",
1998 json_array_create_1(json_string_create(
1999 db->class_->database)),
2000 NULL));
2001 }
2002
2003 static void
2004 ovsdb_idl_send_db_change_aware(struct ovsdb_idl *idl)
2005 {
2006 struct jsonrpc_msg *msg = jsonrpc_create_request(
2007 "set_db_change_aware", json_array_create_1(json_boolean_create(true)),
2008 NULL);
2009 jsonrpc_session_send(idl->session, msg);
2010 }
2011
2012 static bool
2013 ovsdb_idl_check_server_db(struct ovsdb_idl *idl)
2014 {
2015 const struct serverrec_database *database;
2016 SERVERREC_DATABASE_FOR_EACH (database, idl) {
2017 if (uuid_is_zero(&idl->cid)
2018 ? !strcmp(database->name, idl->data.class_->database)
2019 : database->n_cid && uuid_equals(database->cid, &idl->cid)) {
2020 break;
2021 }
2022 }
2023
2024 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
2025 const char *server_name = jsonrpc_session_get_name(idl->session);
2026 bool ok = false;
2027 if (!database) {
2028 VLOG_INFO_RL(&rl, "%s: server does not have %s database",
2029 server_name, idl->data.class_->database);
2030 } else if (!strcmp(database->model, "clustered")) {
2031 uint64_t index = database->n_index ? *database->index : 0;
2032
2033 if (!database->schema) {
2034 VLOG_INFO("%s: clustered database server has not yet joined "
2035 "cluster; trying another server", server_name);
2036 } else if (!database->connected) {
2037 VLOG_INFO("%s: clustered database server is disconnected "
2038 "from cluster; trying another server", server_name);
2039 } else if (idl->leader_only && !database->leader) {
2040 VLOG_INFO("%s: clustered database server is not cluster "
2041 "leader; trying another server", server_name);
2042 } else if (index < idl->min_index) {
2043 VLOG_WARN("%s: clustered database server has stale data; "
2044 "trying another server", server_name);
2045 } else {
2046 idl->min_index = index;
2047 ok = true;
2048 }
2049 } else {
2050 ok = true;
2051 }
2052 if (!ok) {
2053 ovsdb_idl_retry(idl);
2054 return false;
2055 }
2056
2057 if (idl->state == IDL_S_SERVER_MONITOR_COND_REQUESTED) {
2058 json_destroy(idl->data.schema);
2059 idl->data.schema = json_from_string(database->schema);
2060 ovsdb_idl_send_monitor_request(idl, &idl->data,
2061 OVSDB_IDL_MM_MONITOR_COND_SINCE);
2062 ovsdb_idl_transition(idl, IDL_S_DATA_MONITOR_COND_SINCE_REQUESTED);
2063 }
2064 return true;
2065 }
2066
2067 static void
2068 log_error(struct ovsdb_error *error)
2069 {
2070 char *s = ovsdb_error_to_string_free(error);
2071 VLOG_WARN("error parsing database schema: %s", s);
2072 free(s);
2073 }
2074
2075 /* Frees 'schema', which is in the format returned by parse_schema(). */
2076 static void
2077 free_schema(struct shash *schema)
2078 {
2079 if (schema) {
2080 struct shash_node *node, *next;
2081
2082 SHASH_FOR_EACH_SAFE (node, next, schema) {
2083 struct sset *sset = node->data;
2084 sset_destroy(sset);
2085 free(sset);
2086 shash_delete(schema, node);
2087 }
2088 shash_destroy(schema);
2089 free(schema);
2090 }
2091 }
2092
2093 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
2094 * 7047, to obtain the names of its rows and columns. If successful, returns
2095 * an shash whose keys are table names and whose values are ssets, where each
2096 * sset contains the names of its table's columns. On failure (due to a parse
2097 * error), returns NULL.
2098 *
2099 * It would also be possible to use the general-purpose OVSDB schema parser in
2100 * ovsdb-server, but that's overkill, possibly too strict for the current use
2101 * case, and would require restructuring ovsdb-server to separate the schema
2102 * code from the rest. */
2103 static struct shash *
2104 parse_schema(const struct json *schema_json)
2105 {
2106 struct ovsdb_parser parser;
2107 const struct json *tables_json;
2108 struct ovsdb_error *error;
2109 struct shash_node *node;
2110 struct shash *schema;
2111
2112 ovsdb_parser_init(&parser, schema_json, "database schema");
2113 tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
2114 error = ovsdb_parser_destroy(&parser);
2115 if (error) {
2116 log_error(error);
2117 return NULL;
2118 }
2119
2120 schema = xmalloc(sizeof *schema);
2121 shash_init(schema);
2122 SHASH_FOR_EACH (node, json_object(tables_json)) {
2123 const char *table_name = node->name;
2124 const struct json *json = node->data;
2125 const struct json *columns_json;
2126
2127 ovsdb_parser_init(&parser, json, "table schema for table %s",
2128 table_name);
2129 columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
2130 error = ovsdb_parser_destroy(&parser);
2131 if (error) {
2132 log_error(error);
2133 free_schema(schema);
2134 return NULL;
2135 }
2136
2137 struct sset *columns = xmalloc(sizeof *columns);
2138 sset_init(columns);
2139
2140 struct shash_node *node2;
2141 SHASH_FOR_EACH (node2, json_object(columns_json)) {
2142 const char *column_name = node2->name;
2143 sset_add(columns, column_name);
2144 }
2145 shash_add(schema, table_name, columns);
2146 }
2147 return schema;
2148 }
2149
2150 static void
2151 ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db,
2152 enum ovsdb_idl_monitor_method monitor_method)
2153 {
2154 struct shash *schema = parse_schema(db->schema);
2155 struct json *monitor_requests = json_object_create();
2156
2157 for (size_t i = 0; i < db->class_->n_tables; i++) {
2158 struct ovsdb_idl_table *table = &db->tables[i];
2159 const struct ovsdb_idl_table_class *tc = table->class_;
2160 struct json *monitor_request;
2161 const struct sset *table_schema
2162 = schema ? shash_find_data(schema, table->class_->name) : NULL;
2163
2164 struct json *columns
2165 = table->need_table ? json_array_create_empty() : NULL;
2166 for (size_t j = 0; j < tc->n_columns; j++) {
2167 const struct ovsdb_idl_column *column = &tc->columns[j];
2168 bool db_has_column = (table_schema &&
2169 sset_contains(table_schema, column->name));
2170 if (column->is_synthetic) {
2171 if (db_has_column) {
2172 VLOG_WARN("%s table in %s database has synthetic "
2173 "column %s", table->class_->name,
2174 db->class_->database, column->name);
2175 }
2176 } else if (table->modes[j] & OVSDB_IDL_MONITOR) {
2177 if (table_schema && !db_has_column) {
2178 VLOG_WARN("%s table in %s database lacks %s column "
2179 "(database needs upgrade?)",
2180 table->class_->name, db->class_->database,
2181 column->name);
2182 continue;
2183 }
2184 if (!columns) {
2185 columns = json_array_create_empty();
2186 }
2187 json_array_add(columns, json_string_create(column->name));
2188 }
2189 }
2190
2191 if (columns) {
2192 if (schema && !table_schema) {
2193 VLOG_WARN("%s database lacks %s table "
2194 "(database needs upgrade?)",
2195 db->class_->database, table->class_->name);
2196 json_destroy(columns);
2197 continue;
2198 }
2199
2200 monitor_request = json_object_create();
2201 json_object_put(monitor_request, "columns", columns);
2202
2203 /* Always use acked conditions when requesting
2204 * monitor_cond/monitor_cond_since.
2205 */
2206 const struct ovsdb_idl_condition *cond = table->ack_cond;
2207 if ((monitor_method == OVSDB_IDL_MM_MONITOR_COND ||
2208 monitor_method == OVSDB_IDL_MM_MONITOR_COND_SINCE) &&
2209 cond && !ovsdb_idl_condition_is_true(cond)) {
2210 json_object_put(monitor_request, "where",
2211 ovsdb_idl_condition_to_json(cond));
2212 }
2213 json_object_put(monitor_requests, tc->name,
2214 json_array_create_1(monitor_request));
2215 }
2216 }
2217 free_schema(schema);
2218
2219 struct json *params = json_array_create_3(
2220 json_string_create(db->class_->database),
2221 json_clone(db->monitor_id),
2222 monitor_requests);
2223 const char *method;
2224 switch (monitor_method) {
2225 case OVSDB_IDL_MM_MONITOR:
2226 method = "monitor";
2227 break;
2228 case OVSDB_IDL_MM_MONITOR_COND:
2229 method = "monitor_cond";
2230 break;
2231 case OVSDB_IDL_MM_MONITOR_COND_SINCE:
2232 method = "monitor_cond_since";
2233 struct json *json_last_id = json_string_create_nocopy(
2234 xasprintf(UUID_FMT, UUID_ARGS(&db->last_id)));
2235 json_array_add(params, json_last_id);
2236 break;
2237 default:
2238 OVS_NOT_REACHED();
2239 }
2240
2241 ovsdb_idl_send_request(idl, jsonrpc_create_request(method, params, NULL));
2242 }
2243
2244 static void
2245 log_parse_update_error(struct ovsdb_error *error)
2246 {
2247 if (!VLOG_DROP_WARN(&syntax_rl)) {
2248 char *s = ovsdb_error_to_string(error);
2249 VLOG_WARN_RL(&syntax_rl, "%s", s);
2250 free(s);
2251 }
2252 ovsdb_error_destroy(error);
2253 }
2254
2255 static void
2256 ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db *db,
2257 const struct json *result,
2258 enum ovsdb_idl_monitor_method method)
2259 {
2260 db->change_seqno++;
2261 const struct json *table_updates = result;
2262 bool clear_db = true;
2263 if (method == OVSDB_IDL_MM_MONITOR_COND_SINCE) {
2264 if (result->type != JSON_ARRAY || result->array.n != 3) {
2265 struct ovsdb_error *error = ovsdb_syntax_error(result, NULL,
2266 "Response of monitor_cond_since must "
2267 "be an array with 3 elements.");
2268 log_parse_update_error(error);
2269 return;
2270 }
2271
2272 bool found = json_boolean(result->array.elems[0]);
2273 if (found) {
2274 clear_db = false;
2275 }
2276
2277 const char *last_id = json_string(result->array.elems[1]);
2278 if (!uuid_from_string(&db->last_id, last_id)) {
2279 struct ovsdb_error *error = ovsdb_syntax_error(result, NULL,
2280 "Last-id %s is not in UUID format.",
2281 last_id);
2282 log_parse_update_error(error);
2283 return;
2284 }
2285
2286 table_updates = result->array.elems[2];
2287 }
2288 if (clear_db) {
2289 ovsdb_idl_db_clear(db);
2290 }
2291 ovsdb_idl_db_parse_update(db, table_updates, method);
2292 }
2293
2294 static bool
2295 ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db *db,
2296 const struct jsonrpc_msg *msg)
2297 {
2298 if (msg->type != JSONRPC_NOTIFY) {
2299 return false;
2300 }
2301
2302 enum ovsdb_idl_monitor_method mm;
2303 uint8_t n;
2304 if (!strcmp(msg->method, "update")) {
2305 mm = OVSDB_IDL_MM_MONITOR;
2306 n = 2;
2307 } else if (!strcmp(msg->method, "update2")) {
2308 mm = OVSDB_IDL_MM_MONITOR_COND;
2309 n = 2;
2310 } else if (!strcmp(msg->method, "update3")) {
2311 mm = OVSDB_IDL_MM_MONITOR_COND_SINCE;
2312 n = 3;
2313 } else {
2314 return false;
2315 }
2316
2317 struct json *params = msg->params;
2318 if (params->type != JSON_ARRAY || params->array.n != n) {
2319 struct ovsdb_error *error = ovsdb_syntax_error(params, NULL,
2320 "%s must be an array with %u elements.",
2321 msg->method, n);
2322 log_parse_update_error(error);
2323 return false;
2324 }
2325
2326 if (!json_equal(params->array.elems[0], db->monitor_id)) {
2327 return false;
2328 }
2329
2330 struct json *table_updates = params->array.elems[1];
2331 if (!strcmp(msg->method, "update3")) {
2332 table_updates = params->array.elems[2];
2333 const char *last_id = json_string(params->array.elems[1]);
2334 if (!uuid_from_string(&db->last_id, last_id)) {
2335 struct ovsdb_error *error = ovsdb_syntax_error(params, NULL,
2336 "Last-id %s is not in UUID format.",
2337 last_id);
2338 log_parse_update_error(error);
2339 return false;
2340 }
2341 }
2342 ovsdb_idl_db_parse_update(db, table_updates, mm);
2343 return true;
2344 }
2345
2346 static bool
2347 ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl *idl,
2348 struct ovsdb_idl_db *db,
2349 const struct jsonrpc_msg *msg)
2350 {
2351 if (msg->type != JSONRPC_NOTIFY
2352 || strcmp(msg->method, "monitor_canceled")
2353 || msg->params->type != JSON_ARRAY
2354 || msg->params->array.n != 1
2355 || !json_equal(msg->params->array.elems[0], db->monitor_id)) {
2356 return false;
2357 }
2358
2359 db->monitoring = OVSDB_IDL_NOT_MONITORING;
2360
2361 /* Cancel the other monitor and restart the FSM from the top.
2362 *
2363 * Maybe a more sophisticated response would be better in some cases, but
2364 * it doesn't seem worth optimizing yet. (Although this is already more
2365 * sophisticated than just dropping the connection and reconnecting.) */
2366 struct ovsdb_idl_db *other_db
2367 = db == &idl->data ? &idl->server : &idl->data;
2368 if (other_db->monitoring) {
2369 jsonrpc_session_send(
2370 idl->session,
2371 jsonrpc_create_request(
2372 "monitor_cancel",
2373 json_array_create_1(json_clone(other_db->monitor_id)), NULL));
2374 other_db->monitoring = OVSDB_IDL_NOT_MONITORING;
2375 }
2376 ovsdb_idl_restart_fsm(idl);
2377
2378 return true;
2379 }
2380
2381 static struct ovsdb_error *
2382 ovsdb_idl_db_parse_update__(struct ovsdb_idl_db *db,
2383 const struct json *table_updates,
2384 enum ovsdb_idl_monitor_method method)
2385 {
2386 const struct shash_node *tables_node;
2387 const char *version_suffix;
2388 switch (method) {
2389 case OVSDB_IDL_MM_MONITOR:
2390 version_suffix = "";
2391 break;
2392 case OVSDB_IDL_MM_MONITOR_COND:
2393 case OVSDB_IDL_MM_MONITOR_COND_SINCE:
2394 version_suffix = "2";
2395 break;
2396 default:
2397 OVS_NOT_REACHED();
2398 }
2399
2400 if (table_updates->type != JSON_OBJECT) {
2401 return ovsdb_syntax_error(table_updates, NULL,
2402 "<table_updates%s> is not an object",
2403 version_suffix);
2404 }
2405
2406 SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
2407 const struct json *table_update = tables_node->data;
2408 const struct shash_node *table_node;
2409 struct ovsdb_idl_table *table;
2410
2411 table = shash_find_data(&db->table_by_name, tables_node->name);
2412 if (!table) {
2413 return ovsdb_syntax_error(
2414 table_updates, NULL,
2415 "<table_updates%s> includes unknown table \"%s\"",
2416 version_suffix, tables_node->name);
2417 }
2418
2419 if (table_update->type != JSON_OBJECT) {
2420 return ovsdb_syntax_error(table_update, NULL,
2421 "<table_update%s> for table \"%s\" is "
2422 "not an object",
2423 version_suffix, table->class_->name);
2424 }
2425 SHASH_FOR_EACH (table_node, json_object(table_update)) {
2426 enum update_result result = OVSDB_IDL_UPDATE_NO_CHANGES;
2427 const struct json *row_update = table_node->data;
2428 struct uuid uuid;
2429
2430 if (!uuid_from_string(&uuid, table_node->name)) {
2431 return ovsdb_syntax_error(table_update, NULL,
2432 "<table_update%s> for table \"%s\" "
2433 "contains bad UUID "
2434 "\"%s\" as member name",
2435 version_suffix,
2436 table->class_->name,
2437 table_node->name);
2438 }
2439 if (row_update->type != JSON_OBJECT) {
2440 return ovsdb_syntax_error(row_update, NULL,
2441 "<table_update%s> for table \"%s\" "
2442 "contains <row_update%s> for %s "
2443 "that is not an object",
2444 version_suffix, table->class_->name,
2445 version_suffix, table_node->name);
2446 }
2447
2448 if (method == OVSDB_IDL_MM_MONITOR_COND ||
2449 method == OVSDB_IDL_MM_MONITOR_COND_SINCE) {
2450 const char *ops[] = {"modify", "insert", "delete", "initial"};
2451 const char *operation;
2452 const struct json *row;
2453 int i;
2454
2455 for (i = 0; i < ARRAY_SIZE(ops); i++) {
2456 operation = ops[i];
2457 row = shash_find_data(json_object(row_update), operation);
2458
2459 if (!row) {
2460 continue;
2461 }
2462
2463 result = ovsdb_idl_process_update2(table, &uuid,
2464 operation, row);
2465 break;
2466 }
2467
2468 /* row_update2 should contain one of the objects */
2469 if (i == ARRAY_SIZE(ops)) {
2470 return ovsdb_syntax_error(row_update, NULL,
2471 "<row_update2> includes unknown "
2472 "object");
2473 }
2474 } else {
2475 const struct json *old_json, *new_json;
2476
2477 old_json = shash_find_data(json_object(row_update), "old");
2478 new_json = shash_find_data(json_object(row_update), "new");
2479 if (old_json && old_json->type != JSON_OBJECT) {
2480 return ovsdb_syntax_error(old_json, NULL,
2481 "\"old\" <row> is not object");
2482 } else if (new_json && new_json->type != JSON_OBJECT) {
2483 return ovsdb_syntax_error(new_json, NULL,
2484 "\"new\" <row> is not object");
2485 } else if ((old_json != NULL) + (new_json != NULL)
2486 != shash_count(json_object(row_update))) {
2487 return ovsdb_syntax_error(row_update, NULL,
2488 "<row-update> contains "
2489 "unexpected member");
2490 } else if (!old_json && !new_json) {
2491 return ovsdb_syntax_error(row_update, NULL,
2492 "<row-update> missing \"old\" "
2493 "and \"new\" members");
2494 }
2495
2496 result = ovsdb_idl_process_update(table, &uuid, old_json,
2497 new_json);
2498 }
2499
2500 switch (result) {
2501 case OVSDB_IDL_UPDATE_DB_CHANGED:
2502 db->change_seqno++;
2503 break;
2504 case OVSDB_IDL_UPDATE_NO_CHANGES:
2505 break;
2506 case OVSDB_IDL_UPDATE_INCONSISTENT:
2507 memset(&db->last_id, 0, sizeof db->last_id);
2508 ovsdb_idl_retry(db->idl);
2509 return ovsdb_error(NULL,
2510 "<row_update%s> received for inconsistent "
2511 "IDL: reconnecting IDL and resync all "
2512 "data",
2513 version_suffix);
2514 }
2515 }
2516 }
2517
2518 return NULL;
2519 }
2520
2521 static void
2522 ovsdb_idl_db_parse_update(struct ovsdb_idl_db *db,
2523 const struct json *table_updates,
2524 enum ovsdb_idl_monitor_method method)
2525 {
2526 struct ovsdb_error *error = ovsdb_idl_db_parse_update__(db, table_updates,
2527 method);
2528 if (error) {
2529 log_parse_update_error(error);
2530 }
2531 }
2532
2533 static struct ovsdb_idl_row *
2534 ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
2535 {
2536 struct ovsdb_idl_row *row;
2537
2538 HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) {
2539 if (uuid_equals(&row->uuid, uuid)) {
2540 return row;
2541 }
2542 }
2543 return NULL;
2544 }
2545
2546 /* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
2547 * OVSDB_IDL_MODE_RW changed.
2548 *
2549 * Some IDL inconsistencies can be detected when processing updates:
2550 * - trying to insert an already existing row
2551 * - trying to update a missing row
2552 * - trying to delete a non existent row
2553 *
2554 * In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
2555 * Even though the IDL client could recover, it's best to report the
2556 * inconsistent state because the state the server is in is unknown so the
2557 * safest thing to do is to retry (potentially connecting to a new server).
2558 *
2559 * Returns OVSDB_IDL_UPDATE_NO_CHANGES otherwise.
2560 */
2561 static enum update_result
2562 ovsdb_idl_process_update(struct ovsdb_idl_table *table,
2563 const struct uuid *uuid, const struct json *old,
2564 const struct json *new)
2565 {
2566 struct ovsdb_idl_row *row;
2567
2568 row = ovsdb_idl_get_row(table, uuid);
2569 if (!new) {
2570 /* Delete row. */
2571 if (row && !ovsdb_idl_row_is_orphan(row)) {
2572 /* XXX perhaps we should check the 'old' values? */
2573 ovsdb_idl_delete_row(row);
2574 } else {
2575 VLOG_ERR_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
2576 "from table %s",
2577 UUID_ARGS(uuid), table->class_->name);
2578 return OVSDB_IDL_UPDATE_INCONSISTENT;
2579 }
2580 } else if (!old) {
2581 /* Insert row. */
2582 if (!row) {
2583 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
2584 } else if (ovsdb_idl_row_is_orphan(row)) {
2585 ovsdb_idl_insert_row(row, new);
2586 } else {
2587 VLOG_ERR_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
2588 "table %s", UUID_ARGS(uuid), table->class_->name);
2589 return OVSDB_IDL_UPDATE_INCONSISTENT;
2590 }
2591 } else {
2592 /* Modify row. */
2593 if (row) {
2594 /* XXX perhaps we should check the 'old' values? */
2595 if (!ovsdb_idl_row_is_orphan(row)) {
2596 return ovsdb_idl_modify_row(row, new)
2597 ? OVSDB_IDL_UPDATE_DB_CHANGED
2598 : OVSDB_IDL_UPDATE_NO_CHANGES;
2599 } else {
2600 VLOG_ERR_RL(&semantic_rl, "cannot modify missing but "
2601 "referenced row "UUID_FMT" in table %s",
2602 UUID_ARGS(uuid), table->class_->name);
2603 return OVSDB_IDL_UPDATE_INCONSISTENT;
2604 }
2605 } else {
2606 VLOG_ERR_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
2607 "in table %s", UUID_ARGS(uuid), table->class_->name);
2608 return OVSDB_IDL_UPDATE_INCONSISTENT;
2609 }
2610 }
2611
2612 return OVSDB_IDL_UPDATE_DB_CHANGED;
2613 }
2614
2615 /* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
2616 * OVSDB_IDL_MODE_RW changed.
2617 *
2618 * Some IDL inconsistencies can be detected when processing updates:
2619 * - trying to insert an already existing row
2620 * - trying to update a missing row
2621 * - trying to delete a non existent row
2622 *
2623 * In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
2624 * Even though the IDL client could recover, it's best to report the
2625 * inconsistent state because the state the server is in is unknown so the
2626 * safest thing to do is to retry (potentially connecting to a new server).
2627 *
2628 * Otherwise OVSDB_IDL_UPDATE_NO_CHANGES is returned.
2629 */
2630 static enum update_result
2631 ovsdb_idl_process_update2(struct ovsdb_idl_table *table,
2632 const struct uuid *uuid,
2633 const char *operation,
2634 const struct json *json_row)
2635 {
2636 struct ovsdb_idl_row *row;
2637
2638 row = ovsdb_idl_get_row(table, uuid);
2639 if (!strcmp(operation, "delete")) {
2640 /* Delete row. */
2641 if (row && !ovsdb_idl_row_is_orphan(row)) {
2642 ovsdb_idl_delete_row(row);
2643 } else {
2644 VLOG_ERR_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
2645 "from table %s",
2646 UUID_ARGS(uuid), table->class_->name);
2647 return OVSDB_IDL_UPDATE_INCONSISTENT;
2648 }
2649 } else if (!strcmp(operation, "insert") || !strcmp(operation, "initial")) {
2650 /* Insert row. */
2651 if (!row) {
2652 ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), json_row);
2653 } else if (ovsdb_idl_row_is_orphan(row)) {
2654 ovsdb_idl_insert_row(row, json_row);
2655 } else {
2656 VLOG_ERR_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
2657 "table %s", UUID_ARGS(uuid), table->class_->name);
2658 return OVSDB_IDL_UPDATE_INCONSISTENT;
2659 }
2660 } else if (!strcmp(operation, "modify")) {
2661 /* Modify row. */
2662 if (row) {
2663 if (!ovsdb_idl_row_is_orphan(row)) {
2664 return ovsdb_idl_modify_row_by_diff(row, json_row)
2665 ? OVSDB_IDL_UPDATE_DB_CHANGED
2666 : OVSDB_IDL_UPDATE_NO_CHANGES;
2667 } else {
2668 VLOG_ERR_RL(&semantic_rl, "cannot modify missing but "
2669 "referenced row "UUID_FMT" in table %s",
2670 UUID_ARGS(uuid), table->class_->name);
2671 return OVSDB_IDL_UPDATE_INCONSISTENT;
2672 }
2673 } else {
2674 VLOG_ERR_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
2675 "in table %s", UUID_ARGS(uuid), table->class_->name);
2676 return OVSDB_IDL_UPDATE_INCONSISTENT;
2677 }
2678 } else {
2679 VLOG_ERR_RL(&semantic_rl, "unknown operation %s to "
2680 "table %s", operation, table->class_->name);
2681 return OVSDB_IDL_UPDATE_NO_CHANGES;
2682 }
2683
2684 return OVSDB_IDL_UPDATE_DB_CHANGED;
2685 }
2686
2687 /* Recursively add rows to tracked change lists for current row
2688 * and the rows that reference this row. */
2689 static void
2690 add_tracked_change_for_references(struct ovsdb_idl_row *row)
2691 {
2692 if (ovs_list_is_empty(&row->track_node) &&
2693 ovsdb_idl_track_is_set(row->table)) {
2694 ovs_list_push_back(&row->table->track_list,
2695 &row->track_node);
2696 row->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
2697 = row->table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
2698 = row->table->db->change_seqno + 1;
2699
2700 const struct ovsdb_idl_arc *arc;
2701 LIST_FOR_EACH (arc, dst_node, &row->dst_arcs) {
2702 add_tracked_change_for_references(arc->src);
2703 }
2704 }
2705 }
2706
2707
2708 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2709 * otherwise.
2710 *
2711 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
2712 * Caller needs to provide either valid 'row_json' or 'diff', but not
2713 * both. */
2714 static bool
2715 ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
2716 const struct json *diff_json,
2717 enum ovsdb_idl_change change)
2718 {
2719 struct ovsdb_idl_table *table = row->table;
2720 const struct ovsdb_idl_table_class *class = table->class_;
2721 struct shash_node *node;
2722 bool changed = false;
2723 bool apply_diff = diff_json != NULL;
2724 const struct json *json = apply_diff ? diff_json : row_json;
2725
2726 SHASH_FOR_EACH (node, json_object(json)) {
2727 const char *column_name = node->name;
2728 const struct ovsdb_idl_column *column;
2729 struct ovsdb_datum datum;
2730 struct ovsdb_error *error;
2731 unsigned int column_idx;
2732 struct ovsdb_datum *old;
2733
2734 column = shash_find_data(&table->columns, column_name);
2735 if (!column) {
2736 VLOG_WARN_RL(&syntax_rl, "unknown column %s updating row "UUID_FMT,
2737 column_name, UUID_ARGS(&row->uuid));
2738 continue;
2739 }
2740
2741 column_idx = column - table->class_->columns;
2742 old = &row->old_datum[column_idx];
2743
2744 error = NULL;
2745 if (apply_diff) {
2746 struct ovsdb_datum diff;
2747
2748 ovs_assert(!row_json);
2749 error = ovsdb_transient_datum_from_json(&diff, &column->type,
2750 node->data);
2751 if (!error) {
2752 error = ovsdb_datum_apply_diff(&datum, old, &diff,
2753 &column->type);
2754 ovsdb_datum_destroy(&diff, &column->type);
2755 }
2756 } else {
2757 ovs_assert(!diff_json);
2758 error = ovsdb_datum_from_json(&datum, &column->type, node->data,
2759 NULL);
2760 }
2761
2762 if (!error) {
2763 if (!ovsdb_datum_equals(old, &datum, &column->type)) {
2764 ovsdb_datum_swap(old, &datum);
2765 if (table->modes[column_idx] & OVSDB_IDL_ALERT) {
2766 changed = true;
2767 row->change_seqno[change]
2768 = row->table->change_seqno[change]
2769 = row->table->db->change_seqno + 1;
2770 if (table->modes[column_idx] & OVSDB_IDL_TRACK) {
2771 add_tracked_change_for_references(row);
2772 if (!row->updated) {
2773 row->updated = bitmap_allocate(class->n_columns);
2774 }
2775 bitmap_set1(row->updated, column_idx);
2776 }
2777 }
2778 } else {
2779 /* Didn't really change but the OVSDB monitor protocol always
2780 * includes every value in a row. */
2781 }
2782
2783 ovsdb_datum_destroy(&datum, &column->type);
2784 } else {
2785 char *s = ovsdb_error_to_string_free(error);
2786 VLOG_WARN_RL(&syntax_rl, "error parsing column %s in row "UUID_FMT
2787 " in table %s: %s", column_name,
2788 UUID_ARGS(&row->uuid), table->class_->name, s);
2789 free(s);
2790 }
2791 }
2792 return changed;
2793 }
2794
2795 static bool
2796 ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json,
2797 enum ovsdb_idl_change change)
2798 {
2799 return ovsdb_idl_row_change__(row, row_json, NULL, change);
2800 }
2801
2802 static bool
2803 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *row,
2804 const struct json *diff_json,
2805 enum ovsdb_idl_change change)
2806 {
2807 return ovsdb_idl_row_change__(row, NULL, diff_json, change);
2808 }
2809
2810 /* When a row A refers to row B through a column with a "refTable" constraint,
2811 * but row B does not exist, row B is called an "orphan row". Orphan rows
2812 * should not persist, because the database enforces referential integrity, but
2813 * they can appear transiently as changes from the database are received (the
2814 * database doesn't try to topologically sort them and circular references mean
2815 * it isn't always possible anyhow).
2816 *
2817 * This function returns true if 'row' is an orphan row, otherwise false.
2818 */
2819 static bool
2820 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
2821 {
2822 return !row->old_datum && !row->new_datum;
2823 }
2824
2825 /* Returns true if 'row' is conceptually part of the database as modified by
2826 * the current transaction (if any), false otherwise.
2827 *
2828 * This function will return true if 'row' is not an orphan (see the comment on
2829 * ovsdb_idl_row_is_orphan()) and:
2830 *
2831 * - 'row' exists in the database and has not been deleted within the
2832 * current transaction (if any).
2833 *
2834 * - 'row' was inserted within the current transaction and has not been
2835 * deleted. (In the latter case you should not have passed 'row' in at
2836 * all, because ovsdb_idl_txn_delete() freed it.)
2837 *
2838 * This function will return false if 'row' is an orphan or if 'row' was
2839 * deleted within the current transaction.
2840 */
2841 static bool
2842 ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
2843 {
2844 return row->new_datum != NULL;
2845 }
2846
2847 static void
2848 ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
2849 {
2850 const struct ovsdb_idl_table_class *class = row->table->class_;
2851 size_t i;
2852
2853 if (row->parsed) {
2854 ovsdb_idl_row_unparse(row);
2855 }
2856 for (i = 0; i < class->n_columns; i++) {
2857 const struct ovsdb_idl_column *c = &class->columns[i];
2858 (c->parse)(row, &row->old_datum[i]);
2859 }
2860 row->parsed = true;
2861 }
2862
2863 static void
2864 ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
2865 {
2866 const struct ovsdb_idl_table_class *class = row->table->class_;
2867 size_t i;
2868
2869 if (!row->parsed) {
2870 return;
2871 }
2872 for (i = 0; i < class->n_columns; i++) {
2873 const struct ovsdb_idl_column *c = &class->columns[i];
2874 (c->unparse)(row);
2875 }
2876 row->parsed = false;
2877 }
2878 \f
2879 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2880 * table indexes over one or more columns in the IDL. These indexes provide
2881 * the ability to retrieve rows matching a particular search criteria and to
2882 * iterate over a subset of rows in a defined order.
2883 */
2884
2885 /* Generic comparator that can compare each index, using the custom
2886 * configuration (an struct ovsdb_idl_index) passed to it.
2887 * Not intended for direct usage.
2888 */
2889 static int
2890 ovsdb_idl_index_generic_comparer(const void *a,
2891 const void *b, const void *conf)
2892 {
2893 const struct ovsdb_idl_column *column;
2894 const struct ovsdb_idl_index *index;
2895 size_t i;
2896
2897 index = CONST_CAST(struct ovsdb_idl_index *, conf);
2898
2899 if (a == b) {
2900 return 0;
2901 }
2902
2903 for (i = 0; i < index->n_columns; i++) {
2904 int val;
2905 if (index->columns[i].comparer) {
2906 val = index->columns[i].comparer(a, b);
2907 } else {
2908 column = index->columns[i].column;
2909 const struct ovsdb_idl_row *row_a, *row_b;
2910 row_a = CONST_CAST(struct ovsdb_idl_row *, a);
2911 row_b = CONST_CAST(struct ovsdb_idl_row *, b);
2912 const struct ovsdb_datum *datum_a, *datum_b;
2913 datum_a = ovsdb_idl_read(row_a, column);
2914 datum_b = ovsdb_idl_read(row_b, column);
2915 val = ovsdb_datum_compare_3way(datum_a, datum_b, &column->type);
2916 }
2917
2918 if (val) {
2919 return index->columns[i].order == OVSDB_INDEX_ASC ? val : -val;
2920 }
2921 }
2922
2923 /* If ins_del is true then a row is being inserted into or deleted from
2924 * the index list. In this case, we augment the search key with
2925 * additional values (row UUID and memory address) to create a unique
2926 * search key in order to locate the correct entry efficiently and to
2927 * ensure that the correct entry is deleted in the case of a "delete"
2928 * operation.
2929 */
2930 if (index->ins_del) {
2931 const struct ovsdb_idl_row *row_a, *row_b;
2932
2933 row_a = (const struct ovsdb_idl_row *) a;
2934 row_b = (const struct ovsdb_idl_row *) b;
2935 int value = uuid_compare_3way(&row_a->uuid, &row_b->uuid);
2936
2937 return value ? value : (a < b) - (a > b);
2938 } else {
2939 return 0;
2940 }
2941 }
2942
2943 static struct ovsdb_idl_index *
2944 ovsdb_idl_db_index_create(struct ovsdb_idl_db *db,
2945 const struct ovsdb_idl_index_column *columns,
2946 size_t n)
2947 {
2948 ovs_assert(n > 0);
2949
2950 struct ovsdb_idl_index *index = xzalloc(sizeof *index);
2951
2952 index->table = ovsdb_idl_table_from_column(db, columns[0].column);
2953 for (size_t i = 0; i < n; i++) {
2954 const struct ovsdb_idl_index_column *c = &columns[i];
2955 ovs_assert(ovsdb_idl_table_from_column(db, c->column) == index->table);
2956 ovs_assert(*ovsdb_idl_db_get_mode(db, c->column) & OVSDB_IDL_MONITOR);
2957 }
2958
2959 index->columns = xmemdup(columns, n * sizeof *columns);
2960 index->n_columns = n;
2961 index->skiplist = skiplist_create(ovsdb_idl_index_generic_comparer, index);
2962
2963 ovs_list_push_back(&index->table->indexes, &index->node);
2964
2965 return index;
2966 }
2967
2968 /* Creates a new index for the given 'idl' and with the 'n' specified
2969 * 'columns'.
2970 *
2971 * All indexes must be created before the first call to ovsdb_idl_run(). */
2972 struct ovsdb_idl_index *
2973 ovsdb_idl_index_create(struct ovsdb_idl *idl,
2974 const struct ovsdb_idl_index_column *columns,
2975 size_t n)
2976 {
2977 return ovsdb_idl_db_index_create(&idl->data, columns, n);
2978 }
2979
2980 struct ovsdb_idl_index *
2981 ovsdb_idl_index_create1(struct ovsdb_idl *idl,
2982 const struct ovsdb_idl_column *column1)
2983 {
2984 const struct ovsdb_idl_index_column columns[] = {
2985 { .column = column1 },
2986 };
2987 return ovsdb_idl_index_create(idl, columns, ARRAY_SIZE(columns));
2988 }
2989
2990 struct ovsdb_idl_index *
2991 ovsdb_idl_index_create2(struct ovsdb_idl *idl,
2992 const struct ovsdb_idl_column *column1,
2993 const struct ovsdb_idl_column *column2)
2994 {
2995 const struct ovsdb_idl_index_column columns[] = {
2996 { .column = column1 },
2997 { .column = column2 },
2998 };
2999 return ovsdb_idl_index_create(idl, columns, ARRAY_SIZE(columns));
3000 }
3001
3002 static void
3003 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *table)
3004 {
3005 struct ovsdb_idl_index *index, *next;
3006 LIST_FOR_EACH_SAFE (index, next, node, &table->indexes) {
3007 skiplist_destroy(index->skiplist, NULL);
3008 free(index->columns);
3009 free(index);
3010 }
3011 }
3012
3013 static void
3014 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *row)
3015 {
3016 struct ovsdb_idl_table *table = row->table;
3017 struct ovsdb_idl_index *index;
3018 LIST_FOR_EACH (index, node, &table->indexes) {
3019 index->ins_del = true;
3020 skiplist_insert(index->skiplist, row);
3021 index->ins_del = false;
3022 }
3023 }
3024
3025 static void
3026 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *row)
3027 {
3028 struct ovsdb_idl_table *table = row->table;
3029 struct ovsdb_idl_index *index;
3030 LIST_FOR_EACH (index, node, &table->indexes) {
3031 index->ins_del = true;
3032 skiplist_delete(index->skiplist, row);
3033 index->ins_del = false;
3034 }
3035 }
3036
3037 /* Writes a datum in an ovsdb_idl_row, and updates the corresponding field in
3038 * the table record. Not intended for direct usage. */
3039 void
3040 ovsdb_idl_index_write(struct ovsdb_idl_row *const_row,
3041 const struct ovsdb_idl_column *column,
3042 struct ovsdb_datum *datum,
3043 const struct ovsdb_idl_table_class *class)
3044 {
3045 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, const_row);
3046 size_t column_idx = column - class->columns;
3047
3048 if (bitmap_is_set(row->written, column_idx)) {
3049 free(row->new_datum[column_idx].values);
3050 free(row->new_datum[column_idx].keys);
3051 } else {
3052 bitmap_set1(row->written, column_idx);
3053 }
3054 row->new_datum[column_idx] = *datum;
3055 (column->unparse)(row);
3056 (column->parse)(row, &row->new_datum[column_idx]);
3057 }
3058
3059 /* Magic UUID for index rows */
3060 static const struct uuid index_row_uuid = {
3061 .parts = {0xdeadbeef,
3062 0xdeadbeef,
3063 0xdeadbeef,
3064 0xdeadbeef}};
3065
3066 /* Check if a row is an index row */
3067 static bool
3068 is_index_row(const struct ovsdb_idl_row *row)
3069 {
3070 return uuid_equals(&row->uuid, &index_row_uuid);
3071 }
3072
3073 /* Initializes a row for use in an indexed query.
3074 * Not intended for direct usage.
3075 */
3076 struct ovsdb_idl_row *
3077 ovsdb_idl_index_init_row(struct ovsdb_idl_index *index)
3078 {
3079 const struct ovsdb_idl_table_class *class = index->table->class_;
3080 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
3081 class->row_init(row);
3082 row->uuid = index_row_uuid;
3083 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
3084 row->written = bitmap_allocate(class->n_columns);
3085 row->table = index->table;
3086 /* arcs are not used for index row, but it doesn't harm to initialize */
3087 ovs_list_init(&row->src_arcs);
3088 ovs_list_init(&row->dst_arcs);
3089 return row;
3090 }
3091
3092 /* Destroys 'row_' and frees all associated memory. This function is intended
3093 * to be used indirectly through one of the "index_destroy_row" functions
3094 * generated by ovsdb-idlc.
3095 */
3096 void
3097 ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row *row_)
3098 {
3099 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
3100 const struct ovsdb_idl_table_class *class = row->table->class_;
3101 const struct ovsdb_idl_column *c;
3102 size_t i;
3103
3104 ovs_assert(is_index_row(row_));
3105 ovs_assert(ovs_list_is_empty(&row_->src_arcs));
3106 ovs_assert(ovs_list_is_empty(&row_->dst_arcs));
3107 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
3108 c = &class->columns[i];
3109 (c->unparse) (row);
3110 free(row->new_datum[i].values);
3111 free(row->new_datum[i].keys);
3112 }
3113 free(row->new_datum);
3114 free(row->written);
3115 free(row);
3116 }
3117
3118 struct ovsdb_idl_row *
3119 ovsdb_idl_index_find(struct ovsdb_idl_index *index,
3120 const struct ovsdb_idl_row *target)
3121 {
3122 return skiplist_get_data(skiplist_find(index->skiplist, target));
3123 }
3124
3125 struct ovsdb_idl_cursor
3126 ovsdb_idl_cursor_first(struct ovsdb_idl_index *index)
3127 {
3128 struct skiplist_node *node = skiplist_first(index->skiplist);
3129 return (struct ovsdb_idl_cursor) { index, node };
3130 }
3131
3132 struct ovsdb_idl_cursor
3133 ovsdb_idl_cursor_first_eq(struct ovsdb_idl_index *index,
3134 const struct ovsdb_idl_row *target)
3135 {
3136 struct skiplist_node *node = skiplist_find(index->skiplist, target);
3137 return (struct ovsdb_idl_cursor) { index, node };
3138 }
3139
3140 struct ovsdb_idl_cursor
3141 ovsdb_idl_cursor_first_ge(struct ovsdb_idl_index *index,
3142 const struct ovsdb_idl_row *target)
3143 {
3144 struct skiplist_node *node = (target
3145 ? skiplist_forward_to(index->skiplist,
3146 target)
3147 : skiplist_first(index->skiplist));
3148 return (struct ovsdb_idl_cursor) { index, node };
3149 }
3150
3151 void
3152 ovsdb_idl_cursor_next(struct ovsdb_idl_cursor *cursor)
3153 {
3154 cursor->position = skiplist_next(cursor->position);
3155 }
3156
3157 void
3158 ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor *cursor)
3159 {
3160 struct ovsdb_idl_row *data = skiplist_get_data(cursor->position);
3161 struct skiplist_node *next_position = skiplist_next(cursor->position);
3162 struct ovsdb_idl_row *next_data = skiplist_get_data(next_position);
3163 cursor->position = (!ovsdb_idl_index_compare(cursor->index,
3164 data, next_data)
3165 ? next_position : NULL);
3166 }
3167
3168 struct ovsdb_idl_row *
3169 ovsdb_idl_cursor_data(struct ovsdb_idl_cursor *cursor)
3170 {
3171 return skiplist_get_data(cursor->position);
3172 }
3173
3174 /* Returns the result of comparing two rows using the comparison function
3175 * for this index.
3176 * Returns:
3177 * < 0 if a < b
3178 * 0 if a == b
3179 * > 0 if a > b
3180 * When the pointer to either row is NULL, this function considers NULL to be
3181 * greater than any other value, and NULL == NULL.
3182 */
3183 int
3184 ovsdb_idl_index_compare(struct ovsdb_idl_index *index,
3185 const struct ovsdb_idl_row *a,
3186 const struct ovsdb_idl_row *b)
3187 {
3188 if (a && b) {
3189 return ovsdb_idl_index_generic_comparer(a, b, index);
3190 } else if (!a && !b) {
3191 return 0;
3192 } else if (a) {
3193 return -1;
3194 } else {
3195 return 1;
3196 }
3197 }
3198
3199 static void
3200 ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
3201 {
3202 ovs_assert(row->old_datum == row->new_datum);
3203 if (!ovsdb_idl_row_is_orphan(row)) {
3204 if (ovsdb_idl_track_is_set(row->table)) {
3205 row->tracked_old_datum = row->old_datum;
3206 } else {
3207 const struct ovsdb_idl_table_class *class = row->table->class_;
3208 size_t i;
3209
3210 for (i = 0; i < class->n_columns; i++) {
3211 ovsdb_datum_destroy(&row->old_datum[i],
3212 &class->columns[i].type);
3213 }
3214 free(row->old_datum);
3215 }
3216 row->old_datum = row->new_datum = NULL;
3217 }
3218 }
3219
3220 static void
3221 ovsdb_idl_row_clear_new(struct ovsdb_idl_row *row)
3222 {
3223 if (row->old_datum != row->new_datum) {
3224 if (row->new_datum) {
3225 const struct ovsdb_idl_table_class *class = row->table->class_;
3226 size_t i;
3227
3228 if (row->written) {
3229 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
3230 ovsdb_datum_destroy(&row->new_datum[i],
3231 &class->columns[i].type);
3232 }
3233 }
3234 free(row->new_datum);
3235 free(row->written);
3236 row->written = NULL;
3237 }
3238 row->new_datum = row->old_datum;
3239 }
3240 }
3241
3242 static void
3243 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *row, bool destroy_dsts)
3244 {
3245 struct ovsdb_idl_arc *arc, *next;
3246
3247 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
3248 * that this causes to be unreferenced.
3249 */
3250 LIST_FOR_EACH_SAFE (arc, next, src_node, &row->src_arcs) {
3251 ovs_list_remove(&arc->dst_node);
3252 if (destroy_dsts
3253 && ovsdb_idl_row_is_orphan(arc->dst)
3254 && ovs_list_is_empty(&arc->dst->dst_arcs)) {
3255 ovsdb_idl_row_destroy(arc->dst);
3256 }
3257 free(arc);
3258 }
3259 ovs_list_init(&row->src_arcs);
3260 }
3261
3262 /* Force nodes that reference 'row' to reparse. */
3263 static void
3264 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row)
3265 {
3266 struct ovsdb_idl_arc *arc, *next;
3267
3268 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
3269 * 'arc', so we need to use the "safe" variant of list traversal. However,
3270 * calling an ovsdb_idl_column's 'parse' function will add an arc
3271 * equivalent to 'arc' to row->arcs. That could be a problem for
3272 * traversal, but it adds it at the beginning of the list to prevent us
3273 * from stumbling upon it again.
3274 *
3275 * (If duplicate arcs were possible then we would need to make sure that
3276 * 'next' didn't also point into 'arc''s destination, but we forbid
3277 * duplicate arcs.) */
3278 LIST_FOR_EACH_SAFE (arc, next, dst_node, &row->dst_arcs) {
3279 struct ovsdb_idl_row *ref = arc->src;
3280
3281 ovsdb_idl_row_unparse(ref);
3282 ovsdb_idl_row_clear_arcs(ref, false);
3283 ovsdb_idl_row_parse(ref);
3284 }
3285 }
3286
3287 static struct ovsdb_idl_row *
3288 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
3289 {
3290 struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
3291 class->row_init(row);
3292 ovs_list_init(&row->src_arcs);
3293 ovs_list_init(&row->dst_arcs);
3294 hmap_node_nullify(&row->txn_node);
3295 ovs_list_init(&row->track_node);
3296 return row;
3297 }
3298
3299 static struct ovsdb_idl_row *
3300 ovsdb_idl_row_create(struct ovsdb_idl_table *table, const struct uuid *uuid)
3301 {
3302 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(table->class_);
3303 hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
3304 row->uuid = *uuid;
3305 row->table = table;
3306 row->map_op_written = NULL;
3307 row->map_op_lists = NULL;
3308 row->set_op_written = NULL;
3309 row->set_op_lists = NULL;
3310 return row;
3311 }
3312
3313 static void
3314 ovsdb_idl_row_destroy(struct ovsdb_idl_row *row)
3315 {
3316 if (row) {
3317 ovsdb_idl_row_clear_old(row);
3318 hmap_remove(&row->table->rows, &row->hmap_node);
3319 ovsdb_idl_destroy_all_map_op_lists(row);
3320 ovsdb_idl_destroy_all_set_op_lists(row);
3321 if (ovsdb_idl_track_is_set(row->table)) {
3322 row->change_seqno[OVSDB_IDL_CHANGE_DELETE]
3323 = row->table->change_seqno[OVSDB_IDL_CHANGE_DELETE]
3324 = row->table->db->change_seqno + 1;
3325 }
3326 if (ovs_list_is_empty(&row->track_node)) {
3327 ovs_list_push_back(&row->table->track_list, &row->track_node);
3328 }
3329 }
3330 }
3331
3332 static void
3333 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *row)
3334 {
3335 if (row->map_op_written) {
3336 /* Clear Map Operation Lists */
3337 size_t idx, n_columns;
3338 const struct ovsdb_idl_column *columns;
3339 const struct ovsdb_type *type;
3340 n_columns = row->table->class_->n_columns;
3341 columns = row->table->class_->columns;
3342 BITMAP_FOR_EACH_1 (idx, n_columns, row->map_op_written) {
3343 type = &columns[idx].type;
3344 map_op_list_destroy(row->map_op_lists[idx], type);
3345 }
3346 free(row->map_op_lists);
3347 bitmap_free(row->map_op_written);
3348 row->map_op_lists = NULL;
3349 row->map_op_written = NULL;
3350 }
3351 }
3352
3353 static void
3354 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *row)
3355 {
3356 if (row->set_op_written) {
3357 /* Clear Set Operation Lists */
3358 size_t idx, n_columns;
3359 const struct ovsdb_idl_column *columns;
3360 const struct ovsdb_type *type;
3361 n_columns = row->table->class_->n_columns;
3362 columns = row->table->class_->columns;
3363 BITMAP_FOR_EACH_1 (idx, n_columns, row->set_op_written) {
3364 type = &columns[idx].type;
3365 set_op_list_destroy(row->set_op_lists[idx], type);
3366 }
3367 free(row->set_op_lists);
3368 bitmap_free(row->set_op_written);
3369 row->set_op_lists = NULL;
3370 row->set_op_written = NULL;
3371 }
3372 }
3373
3374 static void
3375 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db *db)
3376 {
3377 size_t i;
3378
3379 for (i = 0; i < db->class_->n_tables; i++) {
3380 struct ovsdb_idl_table *table = &db->tables[i];
3381
3382 if (!ovs_list_is_empty(&table->track_list)) {
3383 struct ovsdb_idl_row *row, *next;
3384
3385 LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
3386 if (!ovsdb_idl_track_is_set(row->table)) {
3387 ovs_list_remove(&row->track_node);
3388 ovsdb_idl_row_unparse(row);
3389 free(row);
3390 }
3391 }
3392 }
3393 }
3394 }
3395
3396 static void
3397 ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
3398 {
3399 const struct ovsdb_idl_table_class *class = row->table->class_;
3400 size_t i, datum_size;
3401
3402 ovs_assert(!row->old_datum && !row->new_datum);
3403 datum_size = class->n_columns * sizeof *row->old_datum;
3404 row->old_datum = row->new_datum = xmalloc(datum_size);
3405 for (i = 0; i < class->n_columns; i++) {
3406 ovsdb_datum_init_default(&row->old_datum[i], &class->columns[i].type);
3407 }
3408 ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_INSERT);
3409 ovsdb_idl_row_parse(row);
3410
3411 ovsdb_idl_row_reparse_backrefs(row);
3412 ovsdb_idl_add_to_indexes(row);
3413 }
3414
3415 static void
3416 ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
3417 {
3418 ovsdb_idl_remove_from_indexes(row);
3419 ovsdb_idl_row_clear_arcs(row, true);
3420 ovsdb_idl_row_clear_old(row);
3421 if (ovs_list_is_empty(&row->dst_arcs)) {
3422 ovsdb_idl_row_destroy(row);
3423 } else {
3424 ovsdb_idl_row_reparse_backrefs(row);
3425 }
3426 }
3427
3428 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
3429 * otherwise. */
3430 static bool
3431 ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
3432 {
3433 bool changed;
3434
3435 ovsdb_idl_remove_from_indexes(row);
3436 ovsdb_idl_row_unparse(row);
3437 ovsdb_idl_row_clear_arcs(row, true);
3438 changed = ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_MODIFY);
3439 ovsdb_idl_row_parse(row);
3440 ovsdb_idl_add_to_indexes(row);
3441
3442 return changed;
3443 }
3444
3445 static bool
3446 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *row,
3447 const struct json *diff_json)
3448 {
3449 bool changed;
3450
3451 ovsdb_idl_remove_from_indexes(row);
3452 ovsdb_idl_row_unparse(row);
3453 ovsdb_idl_row_clear_arcs(row, true);
3454 changed = ovsdb_idl_row_apply_diff(row, diff_json,
3455 OVSDB_IDL_CHANGE_MODIFY);
3456 ovsdb_idl_row_parse(row);
3457 ovsdb_idl_add_to_indexes(row);
3458
3459 return changed;
3460 }
3461
3462 static bool
3463 may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
3464 {
3465 const struct ovsdb_idl_arc *arc;
3466
3467 /* No self-arcs. */
3468 if (src == dst) {
3469 return false;
3470 }
3471
3472 /* No duplicate arcs.
3473 *
3474 * We only need to test whether the first arc in dst->dst_arcs originates
3475 * at 'src', since we add all of the arcs from a given source in a clump
3476 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
3477 * added at the front of the dst_arcs list. */
3478 if (ovs_list_is_empty(&dst->dst_arcs)) {
3479 return true;
3480 }
3481 arc = CONTAINER_OF(dst->dst_arcs.next, struct ovsdb_idl_arc, dst_node);
3482 return arc->src != src;
3483 }
3484
3485 static struct ovsdb_idl_table *
3486 ovsdb_idl_db_table_from_class(const struct ovsdb_idl_db *db,
3487 const struct ovsdb_idl_table_class *table_class)
3488 {
3489 ptrdiff_t idx = table_class - db->class_->tables;
3490 return idx >= 0 && idx < db->class_->n_tables ? &db->tables[idx] : NULL;
3491 }
3492
3493 static struct ovsdb_idl_table *
3494 ovsdb_idl_table_from_class(const struct ovsdb_idl *idl,
3495 const struct ovsdb_idl_table_class *table_class)
3496 {
3497 struct ovsdb_idl_table *table;
3498
3499 table = ovsdb_idl_db_table_from_class(&idl->data, table_class);
3500 if (!table) {
3501 table = ovsdb_idl_db_table_from_class(&idl->server, table_class);
3502 }
3503
3504 return table;
3505 }
3506
3507 /* Called by ovsdb-idlc generated code. */
3508 struct ovsdb_idl_row *
3509 ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
3510 const struct ovsdb_idl_table_class *dst_table_class,
3511 const struct uuid *dst_uuid)
3512 {
3513 struct ovsdb_idl_db *db = src->table->db;
3514 struct ovsdb_idl_table *dst_table;
3515 struct ovsdb_idl_arc *arc;
3516 struct ovsdb_idl_row *dst;
3517
3518 dst_table = ovsdb_idl_db_table_from_class(db, dst_table_class);
3519 dst = ovsdb_idl_get_row(dst_table, dst_uuid);
3520 if (db->txn || is_index_row(src)) {
3521 /* There are two cases we should not update any arcs:
3522 *
3523 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
3524 * any arcs, because the transaction will be backed out at commit or
3525 * abort time and we don't want our graph screwed up.
3526 *
3527 * 2. The row is used as an index for querying purpose only.
3528 *
3529 * In these cases, just return the destination row, if there is one and
3530 * it has not been deleted. */
3531 if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new_datum)) {
3532 return dst;
3533 }
3534 return NULL;
3535 } else {
3536 /* We're being called from some other context. Update the graph. */
3537 if (!dst) {
3538 dst = ovsdb_idl_row_create(dst_table, dst_uuid);
3539 }
3540
3541 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
3542 if (may_add_arc(src, dst)) {
3543 /* The arc *must* be added at the front of the dst_arcs list. See
3544 * ovsdb_idl_row_reparse_backrefs() for details. */
3545 arc = xmalloc(sizeof *arc);
3546 ovs_list_push_front(&src->src_arcs, &arc->src_node);
3547 ovs_list_push_front(&dst->dst_arcs, &arc->dst_node);
3548 arc->src = src;
3549 arc->dst = dst;
3550 }
3551
3552 return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
3553 }
3554 }
3555
3556 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
3557 * pointer to the row if there is one, otherwise a null pointer. */
3558 const struct ovsdb_idl_row *
3559 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
3560 const struct ovsdb_idl_table_class *tc,
3561 const struct uuid *uuid)
3562 {
3563 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
3564 }
3565
3566 static struct ovsdb_idl_row *
3567 next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
3568 {
3569 for (; node; node = hmap_next(&table->rows, node)) {
3570 struct ovsdb_idl_row *row;
3571
3572 row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
3573 if (ovsdb_idl_row_exists(row)) {
3574 return row;
3575 }
3576 }
3577 return NULL;
3578 }
3579
3580 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
3581 * table is empty.
3582 *
3583 * Database tables are internally maintained as hash tables, so adding or
3584 * removing rows while traversing the same table can cause some rows to be
3585 * visited twice or not at apply. */
3586 const struct ovsdb_idl_row *
3587 ovsdb_idl_first_row(const struct ovsdb_idl *idl,
3588 const struct ovsdb_idl_table_class *table_class)
3589 {
3590 struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl,
3591 table_class);
3592 return next_real_row(table, hmap_first(&table->rows));
3593 }
3594
3595 /* Returns a row following 'row' within its table, or a null pointer if 'row'
3596 * is the last row in its table. */
3597 const struct ovsdb_idl_row *
3598 ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
3599 {
3600 struct ovsdb_idl_table *table = row->table;
3601
3602 return next_real_row(table, hmap_next(&table->rows, &row->hmap_node));
3603 }
3604
3605 /* Reads and returns the value of 'column' within 'row'. If an ongoing
3606 * transaction has changed 'column''s value, the modified value is returned.
3607 *
3608 * The caller must not modify or free the returned value.
3609 *
3610 * Various kinds of changes can invalidate the returned value: writing to the
3611 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
3612 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
3613 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
3614 * returned value is needed for a long time, it is best to make a copy of it
3615 * with ovsdb_datum_clone(). */
3616 const struct ovsdb_datum *
3617 ovsdb_idl_read(const struct ovsdb_idl_row *row,
3618 const struct ovsdb_idl_column *column)
3619 {
3620 const struct ovsdb_idl_table_class *class;
3621 size_t column_idx;
3622
3623 ovs_assert(!ovsdb_idl_row_is_synthetic(row));
3624
3625 class = row->table->class_;
3626 column_idx = column - class->columns;
3627
3628 ovs_assert(row->new_datum != NULL);
3629 ovs_assert(column_idx < class->n_columns);
3630
3631 if (row->written && bitmap_is_set(row->written, column_idx)) {
3632 return &row->new_datum[column_idx];
3633 } else if (row->old_datum) {
3634 return &row->old_datum[column_idx];
3635 } else {
3636 return ovsdb_datum_default(&column->type);
3637 }
3638 }
3639
3640 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
3641 * type 'key_type' and value type 'value_type'. (Scalar and set types will
3642 * have a value type of OVSDB_TYPE_VOID.)
3643 *
3644 * This is useful in code that "knows" that a particular column has a given
3645 * type, so that it will abort if someone changes the column's type without
3646 * updating the code that uses it. */
3647 const struct ovsdb_datum *
3648 ovsdb_idl_get(const struct ovsdb_idl_row *row,
3649 const struct ovsdb_idl_column *column,
3650 enum ovsdb_atomic_type key_type OVS_UNUSED,
3651 enum ovsdb_atomic_type value_type OVS_UNUSED)
3652 {
3653 ovs_assert(column->type.key.type == key_type);
3654 ovs_assert(column->type.value.type == value_type);
3655
3656 return ovsdb_idl_read(row, column);
3657 }
3658
3659 /* Returns true if the field represented by 'column' in 'row' may be modified,
3660 * false if it is immutable.
3661 *
3662 * Normally, whether a field is mutable is controlled by its column's schema.
3663 * However, an immutable column can be set to any initial value at the time of
3664 * insertion, so if 'row' is a new row (one that is being added as part of the
3665 * current transaction, supposing that a transaction is in progress) then even
3666 * its "immutable" fields are actually mutable. */
3667 bool
3668 ovsdb_idl_is_mutable(const struct ovsdb_idl_row *row,
3669 const struct ovsdb_idl_column *column)
3670 {
3671 return column->is_mutable || (row->new_datum && !row->old_datum);
3672 }
3673
3674 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
3675 * to all-zero-bits by some other entity. If 'row' was set up some other way
3676 * then the return value is indeterminate. */
3677 bool
3678 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *row)
3679 {
3680 return row->table == NULL;
3681 }
3682 \f
3683 /* Transactions. */
3684
3685 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
3686 enum ovsdb_idl_txn_status);
3687
3688 /* Returns a string representation of 'status'. The caller must not modify or
3689 * free the returned string.
3690 *
3691 * The return value is probably useful only for debug log messages and unit
3692 * tests. */
3693 const char *
3694 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
3695 {
3696 switch (status) {
3697 case TXN_UNCOMMITTED:
3698 return "uncommitted";
3699 case TXN_UNCHANGED:
3700 return "unchanged";
3701 case TXN_INCOMPLETE:
3702 return "incomplete";
3703 case TXN_ABORTED:
3704 return "aborted";
3705 case TXN_SUCCESS:
3706 return "success";
3707 case TXN_TRY_AGAIN:
3708 return "try again";
3709 case TXN_NOT_LOCKED:
3710 return "not locked";
3711 case TXN_ERROR:
3712 return "error";
3713 }
3714 return "<unknown>";
3715 }
3716
3717 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
3718 * active transaction at a time. See the large comment in ovsdb-idl.h for
3719 * general information on transactions. */
3720 struct ovsdb_idl_txn *
3721 ovsdb_idl_txn_create(struct ovsdb_idl *idl)
3722 {
3723 struct ovsdb_idl_txn *txn;
3724
3725 ovs_assert(!idl->data.txn);
3726 idl->data.txn = txn = xmalloc(sizeof *txn);
3727 txn->request_id = NULL;
3728 txn->db = &idl->data;
3729 hmap_init(&txn->txn_rows);
3730 txn->status = TXN_UNCOMMITTED;
3731 txn->error = NULL;
3732 txn->dry_run = false;
3733 ds_init(&txn->comment);
3734
3735 txn->inc_table = NULL;
3736 txn->inc_column = NULL;
3737
3738 hmap_init(&txn->inserted_rows);
3739
3740 return txn;
3741 }
3742
3743 /* Appends 's', which is treated as a printf()-type format string, to the
3744 * comments that will be passed to the OVSDB server when 'txn' is committed.
3745 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
3746 * show-log" can print in a relatively human-readable form.) */
3747 void
3748 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
3749 {
3750 va_list args;
3751
3752 if (txn->comment.length) {
3753 ds_put_char(&txn->comment, '\n');
3754 }
3755
3756 va_start(args, s);
3757 ds_put_format_valist(&txn->comment, s, args);
3758 va_end(args);
3759 }
3760
3761 /* Marks 'txn' as a transaction that will not actually modify the database. In
3762 * almost every way, the transaction is treated like other transactions. It
3763 * must be committed or aborted like other transactions, it will be sent to the
3764 * database server like other transactions, and so on. The only difference is
3765 * that the operations sent to the database server will include, as the last
3766 * step, an "abort" operation, so that any changes made by the transaction will
3767 * not actually take effect. */
3768 void
3769 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
3770 {
3771 txn->dry_run = true;
3772 }
3773
3774 /* Causes 'txn', when committed, to increment the value of 'column' within
3775 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3776 * successfully, the client may retrieve the final (incremented) value of
3777 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3778 *
3779 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3780 * change the database, then 'force' is important. If 'force' is false in this
3781 * case, the IDL suppresses the increment and skips a round trip to the
3782 * database server. If 'force' is true, the IDL will still increment the
3783 * column.
3784 *
3785 * The client could accomplish something similar with ovsdb_idl_read(),
3786 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3787 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3788 * will never (by itself) fail because of a verify error.
3789 *
3790 * The intended use is for incrementing the "next_cfg" column in the
3791 * Open_vSwitch table. */
3792 void
3793 ovsdb_idl_txn_increment(struct ovsdb_idl_txn *txn,
3794 const struct ovsdb_idl_row *row,
3795 const struct ovsdb_idl_column *column,
3796 bool force)
3797 {
3798 ovs_assert(!txn->inc_table);
3799 ovs_assert(column->type.key.type == OVSDB_TYPE_INTEGER);
3800 ovs_assert(column->type.value.type == OVSDB_TYPE_VOID);
3801
3802 txn->inc_table = row->table->class_->name;
3803 txn->inc_column = column->name;
3804 txn->inc_row = row->uuid;
3805 txn->inc_force = force;
3806 }
3807
3808 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3809 * has been called for 'txn' but the commit is still incomplete (that is, the
3810 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3811 * end up committing at the database server, but the client will not be able to
3812 * get any further status information back. */
3813 void
3814 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
3815 {
3816 struct ovsdb_idl_txn_insert *insert, *next;
3817
3818 json_destroy(txn->request_id);
3819 if (txn->status == TXN_INCOMPLETE) {
3820 hmap_remove(&txn->db->outstanding_txns, &txn->hmap_node);
3821 }
3822 ovsdb_idl_txn_abort(txn);
3823 ds_destroy(&txn->comment);
3824 free(txn->error);
3825 HMAP_FOR_EACH_SAFE (insert, next, hmap_node, &txn->inserted_rows) {
3826 free(insert);
3827 }
3828 hmap_destroy(&txn->inserted_rows);
3829 free(txn);
3830 }
3831
3832 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3833 void
3834 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
3835 {
3836 if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
3837 poll_immediate_wake();
3838 }
3839 }
3840
3841 static struct json *
3842 where_uuid_equals(const struct uuid *uuid)
3843 {
3844 return
3845 json_array_create_1(
3846 json_array_create_3(
3847 json_string_create("_uuid"),
3848 json_string_create("=="),
3849 json_array_create_2(
3850 json_string_create("uuid"),
3851 json_string_create_nocopy(
3852 xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
3853 }
3854
3855 static const struct ovsdb_idl_row *
3856 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
3857 {
3858 const struct ovsdb_idl_row *row;
3859
3860 HMAP_FOR_EACH_WITH_HASH (row, txn_node, uuid_hash(uuid), &txn->txn_rows) {
3861 if (uuid_equals(&row->uuid, uuid)) {
3862 return row;
3863 }
3864 }
3865 return NULL;
3866 }
3867
3868 /* XXX there must be a cleaner way to do this */
3869 static struct json *
3870 substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
3871 {
3872 if (json->type == JSON_ARRAY) {
3873 struct uuid uuid;
3874 size_t i;
3875
3876 if (json->array.n == 2
3877 && json->array.elems[0]->type == JSON_STRING
3878 && json->array.elems[1]->type == JSON_STRING
3879 && !strcmp(json->array.elems[0]->string, "uuid")
3880 && uuid_from_string(&uuid, json->array.elems[1]->string)) {
3881 const struct ovsdb_idl_row *row;
3882
3883 row = ovsdb_idl_txn_get_row(txn, &uuid);
3884 if (row && !row->old_datum && row->new_datum) {
3885 json_destroy(json);
3886
3887 return json_array_create_2(
3888 json_string_create("named-uuid"),
3889 json_string_create_nocopy(ovsdb_data_row_name(&uuid)));
3890 }
3891 }
3892
3893 for (i = 0; i < json->array.n; i++) {
3894 json->array.elems[i] = substitute_uuids(json->array.elems[i],
3895 txn);
3896 }
3897 } else if (json->type == JSON_OBJECT) {
3898 struct shash_node *node;
3899
3900 SHASH_FOR_EACH (node, json_object(json)) {
3901 node->data = substitute_uuids(node->data, txn);
3902 }
3903 }
3904 return json;
3905 }
3906
3907 static void
3908 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
3909 {
3910 struct ovsdb_idl_row *row, *next;
3911
3912 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3913 * ovsdb_idl_column's 'parse' function, which will call
3914 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3915 * transaction and fail to update the graph. */
3916 txn->db->txn = NULL;
3917
3918 HMAP_FOR_EACH_SAFE (row, next, txn_node, &txn->txn_rows) {
3919 enum { INSERTED, MODIFIED, DELETED } op
3920 = (!row->new_datum ? DELETED
3921 : !row->old_datum ? INSERTED
3922 : MODIFIED);
3923
3924 if (op != DELETED) {
3925 ovsdb_idl_remove_from_indexes(row);
3926 }
3927
3928 ovsdb_idl_destroy_all_map_op_lists(row);
3929 ovsdb_idl_destroy_all_set_op_lists(row);
3930 if (op != INSERTED) {
3931 if (row->written) {
3932 ovsdb_idl_row_unparse(row);
3933 ovsdb_idl_row_clear_arcs(row, false);
3934 ovsdb_idl_row_parse(row);
3935 }
3936 } else {
3937 ovsdb_idl_row_unparse(row);
3938 }
3939 ovsdb_idl_row_clear_new(row);
3940
3941 free(row->prereqs);
3942 row->prereqs = NULL;
3943
3944 free(row->written);
3945 row->written = NULL;
3946
3947 hmap_remove(&txn->txn_rows, &row->txn_node);
3948 hmap_node_nullify(&row->txn_node);
3949 if (op != INSERTED) {
3950 ovsdb_idl_add_to_indexes(row);
3951 } else {
3952 hmap_remove(&row->table->rows, &row->hmap_node);
3953 free(row);
3954 }
3955 }
3956 hmap_destroy(&txn->txn_rows);
3957 hmap_init(&txn->txn_rows);
3958 }
3959
3960 static bool
3961 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *row,
3962 struct json *mutations)
3963 {
3964 const struct ovsdb_idl_table_class *class = row->table->class_;
3965 size_t idx;
3966 bool any_mutations = false;
3967
3968 if (row->map_op_written) {
3969 BITMAP_FOR_EACH_1(idx, class->n_columns, row->map_op_written) {
3970 struct map_op_list *map_op_list;
3971 const struct ovsdb_idl_column *column;
3972 const struct ovsdb_datum *old_datum;
3973 enum ovsdb_atomic_type key_type, value_type;
3974 struct json *mutation, *map, *col_name, *mutator;
3975 struct json *del_set, *ins_map;
3976 bool any_del, any_ins;
3977
3978 map_op_list = row->map_op_lists[idx];
3979 column = &class->columns[idx];
3980 key_type = column->type.key.type;
3981 value_type = column->type.value.type;
3982
3983 /* Get the value to be changed */
3984 if (row->new_datum && row->written
3985 && bitmap_is_set(row->written,idx)) {
3986 old_datum = &row->new_datum[idx];
3987 } else if (row->old_datum != NULL) {
3988 old_datum = &row->old_datum[idx];
3989 } else {
3990 old_datum = ovsdb_datum_default(&column->type);
3991 }
3992
3993 del_set = json_array_create_empty();
3994 ins_map = json_array_create_empty();
3995 any_del = false;
3996 any_ins = false;
3997
3998 for (struct map_op *map_op = map_op_list_first(map_op_list); map_op;
3999 map_op = map_op_list_next(map_op_list, map_op)) {
4000
4001 if (map_op_type(map_op) == MAP_OP_UPDATE) {
4002 /* Find out if value really changed. */
4003 struct ovsdb_datum *new_datum;
4004 unsigned int pos;
4005 new_datum = map_op_datum(map_op);
4006 pos = ovsdb_datum_find_key(old_datum,
4007 &new_datum->keys[0],
4008 key_type);
4009 if (ovsdb_atom_equals(&new_datum->values[0],
4010 &old_datum->values[pos],
4011 value_type)) {
4012 /* No change in value. Move on to next update. */
4013 continue;
4014 }
4015 } else if (map_op_type(map_op) == MAP_OP_DELETE){
4016 /* Verify that there is a key to delete. */
4017 unsigned int pos;
4018 pos = ovsdb_datum_find_key(old_datum,
4019 &map_op_datum(map_op)->keys[0],
4020 key_type);
4021 if (pos == UINT_MAX) {
4022 /* No key to delete. Move on to next update. */
4023 VLOG_WARN("Trying to delete a key that doesn't "
4024 "exist in the map.");
4025 continue;
4026 }
4027 }
4028
4029 if (map_op_type(map_op) == MAP_OP_INSERT) {
4030 map = json_array_create_2(
4031 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
4032 key_type),
4033 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
4034 value_type));
4035 json_array_add(ins_map, map);
4036 any_ins = true;
4037 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
4038 map = ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
4039 key_type);
4040 json_array_add(del_set, map);
4041 any_del = true;
4042 }
4043
4044 /* Generate an additional insert mutate for updates. */
4045 if (map_op_type(map_op) == MAP_OP_UPDATE) {
4046 map = json_array_create_2(
4047 ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
4048 key_type),
4049 ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
4050 value_type));
4051 json_array_add(ins_map, map);
4052 any_ins = true;
4053 }
4054 }
4055
4056 if (any_del) {
4057 col_name = json_string_create(column->name);
4058 mutator = json_string_create("delete");
4059 map = json_array_create_2(json_string_create("set"), del_set);
4060 mutation = json_array_create_3(col_name, mutator, map);
4061 json_array_add(mutations, mutation);
4062 any_mutations = true;
4063 } else {
4064 json_destroy(del_set);
4065 }
4066 if (any_ins) {
4067 col_name = json_string_create(column->name);
4068 mutator = json_string_create("insert");
4069 map = json_array_create_2(json_string_create("map"), ins_map);
4070 mutation = json_array_create_3(col_name, mutator, map);
4071 json_array_add(mutations, mutation);
4072 any_mutations = true;
4073 } else {
4074 json_destroy(ins_map);
4075 }
4076 }
4077 }
4078 if (row->set_op_written) {
4079 BITMAP_FOR_EACH_1(idx, class->n_columns, row->set_op_written) {
4080 struct set_op_list *set_op_list;
4081 const struct ovsdb_idl_column *column;
4082 const struct ovsdb_datum *old_datum;
4083 enum ovsdb_atomic_type key_type;
4084 struct json *mutation, *set, *col_name, *mutator;
4085 struct json *del_set, *ins_set;
4086 bool any_del, any_ins;
4087
4088 set_op_list = row->set_op_lists[idx];
4089 column = &class->columns[idx];
4090 key_type = column->type.key.type;
4091
4092 /* Get the value to be changed */
4093 if (row->new_datum && row->written
4094 && bitmap_is_set(row->written,idx)) {
4095 old_datum = &row->new_datum[idx];
4096 } else if (row->old_datum != NULL) {
4097 old_datum = &row->old_datum[idx];
4098 } else {
4099 old_datum = ovsdb_datum_default(&column->type);
4100 }
4101
4102 del_set = json_array_create_empty();
4103 ins_set = json_array_create_empty();
4104 any_del = false;
4105 any_ins = false;
4106
4107 for (struct set_op *set_op = set_op_list_first(set_op_list); set_op;
4108 set_op = set_op_list_next(set_op_list, set_op)) {
4109 if (set_op_type(set_op) == SET_OP_INSERT) {
4110 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
4111 key_type);
4112 json_array_add(ins_set, set);
4113 any_ins = true;
4114 } else { /* SETP_OP_DELETE */
4115 /* Verify that there is a key to delete. */
4116 unsigned int pos;
4117 pos = ovsdb_datum_find_key(old_datum,
4118 &set_op_datum(set_op)->keys[0],
4119 key_type);
4120 if (pos == UINT_MAX) {
4121 /* No key to delete. Move on to next update. */
4122 VLOG_WARN("Trying to delete a key that doesn't "
4123 "exist in the set.");
4124 continue;
4125 }
4126 set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
4127 key_type);
4128 json_array_add(del_set, set);
4129 any_del = true;
4130 }
4131 }
4132 if (any_del) {
4133 col_name = json_string_create(column->name);
4134 mutator = json_string_create("delete");
4135 set = json_array_create_2(json_string_create("set"), del_set);
4136 mutation = json_array_create_3(col_name, mutator, set);
4137 json_array_add(mutations, mutation);
4138 any_mutations = true;
4139 } else {
4140 json_destroy(del_set);
4141 }
4142 if (any_ins) {
4143 col_name = json_string_create(column->name);
4144 mutator = json_string_create("insert");
4145 set = json_array_create_2(json_string_create("set"), ins_set);
4146 mutation = json_array_create_3(col_name, mutator, set);
4147 json_array_add(mutations, mutation);
4148 any_mutations = true;
4149 } else {
4150 json_destroy(ins_set);
4151 }
4152 }
4153 }
4154 return any_mutations;
4155 }
4156
4157 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
4158 * of the following TXN_* constants:
4159 *
4160 * TXN_INCOMPLETE:
4161 *
4162 * The transaction is in progress, but not yet complete. The caller
4163 * should call again later, after calling ovsdb_idl_run() to let the IDL
4164 * do OVSDB protocol processing.
4165 *
4166 * TXN_UNCHANGED:
4167 *
4168 * The transaction is complete. (It didn't actually change the database,
4169 * so the IDL didn't send any request to the database server.)
4170 *
4171 * TXN_ABORTED:
4172 *
4173 * The caller previously called ovsdb_idl_txn_abort().
4174 *
4175 * TXN_SUCCESS:
4176 *
4177 * The transaction was successful. The update made by the transaction
4178 * (and possibly other changes made by other database clients) should
4179 * already be visible in the IDL.
4180 *
4181 * TXN_TRY_AGAIN:
4182 *
4183 * The transaction failed for some transient reason, e.g. because a
4184 * "verify" operation reported an inconsistency or due to a network
4185 * problem. The caller should wait for a change to the database, then
4186 * compose a new transaction, and commit the new transaction.
4187 *
4188 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
4189 * the database. It is important to use its return value *before* the
4190 * initial call to ovsdb_idl_txn_commit() as the baseline for this
4191 * purpose, because the change that one should wait for can happen after
4192 * the initial call but before the call that returns TXN_TRY_AGAIN, and
4193 * using some other baseline value in that situation could cause an
4194 * indefinite wait if the database rarely changes.
4195 *
4196 * TXN_NOT_LOCKED:
4197 *
4198 * The transaction failed because the IDL has been configured to require
4199 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
4200 * has already lost it.
4201 *
4202 * Committing a transaction rolls back all of the changes that it made to the
4203 * IDL's copy of the database. If the transaction commits successfully, then
4204 * the database server will send an update and, thus, the IDL will be updated
4205 * with the committed changes. */
4206 enum ovsdb_idl_txn_status
4207 ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
4208 {
4209 struct ovsdb_idl_row *row;
4210 struct json *operations;
4211 bool any_updates;
4212
4213 if (txn != txn->db->txn) {
4214 goto coverage_out;
4215 }
4216
4217 /* If we're still connecting or re-connecting, don't bother sending a
4218 * transaction. */
4219 if (txn->db->idl->state != IDL_S_MONITORING) {
4220 txn->status = TXN_TRY_AGAIN;
4221 goto disassemble_out;
4222 }
4223
4224 /* If we need a lock but don't have it, give up quickly. */
4225 if (txn->db->lock_name && !txn->db->has_lock) {
4226 txn->status = TXN_NOT_LOCKED;
4227 goto disassemble_out;
4228 }
4229
4230 operations = json_array_create_1(
4231 json_string_create(txn->db->class_->database));
4232
4233 /* Assert that we have the required lock (avoiding a race). */
4234 if (txn->db->lock_name) {
4235 struct json *op = json_object_create();
4236 json_array_add(operations, op);
4237 json_object_put_string(op, "op", "assert");
4238 json_object_put_string(op, "lock", txn->db->lock_name);
4239 }
4240
4241 /* Add prerequisites and declarations of new rows. */
4242 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
4243 /* XXX check that deleted rows exist even if no prereqs? */
4244 if (row->prereqs) {
4245 const struct ovsdb_idl_table_class *class = row->table->class_;
4246 size_t n_columns = class->n_columns;
4247 struct json *op, *columns, *row_json;
4248 size_t idx;
4249
4250 op = json_object_create();
4251 json_array_add(operations, op);
4252 json_object_put_string(op, "op", "wait");
4253 json_object_put_string(op, "table", class->name);
4254 json_object_put(op, "timeout", json_integer_create(0));
4255 json_object_put(op, "where", where_uuid_equals(&row->uuid));
4256 json_object_put_string(op, "until", "==");
4257 columns = json_array_create_empty();
4258 json_object_put(op, "columns", columns);
4259 row_json = json_object_create();
4260 json_object_put(op, "rows", json_array_create_1(row_json));
4261
4262 BITMAP_FOR_EACH_1 (idx, n_columns, row->prereqs) {
4263 const struct ovsdb_idl_column *column = &class->columns[idx];
4264 json_array_add(columns, json_string_create(column->name));
4265 json_object_put(row_json, column->name,
4266 ovsdb_datum_to_json(&row->old_datum[idx],
4267 &column->type));
4268 }
4269 }
4270 }
4271
4272 /* Add updates. */
4273 any_updates = false;
4274
4275 /* For tables constrained to have only a single row (a fairly common OVSDB
4276 * pattern for storing global data), identify whether we're inserting a
4277 * row. If so, then verify that the table is empty before inserting the
4278 * row. This gives us a clear verification-related failure if there was an
4279 * insertion race with another client. */
4280 for (size_t i = 0; i < txn->db->class_->n_tables; i++) {
4281 struct ovsdb_idl_table *table = &txn->db->tables[i];
4282 if (table->class_->is_singleton) {
4283 /* Count the number of rows in the table before and after our
4284 * transaction commits. This is O(n) in the number of rows in the
4285 * table, but that's OK since we know that the table should only
4286 * have one row. */
4287 size_t initial_rows = 0;
4288 size_t final_rows = 0;
4289 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
4290 initial_rows += row->old_datum != NULL;
4291 final_rows += row->new_datum != NULL;
4292 }
4293
4294 if (initial_rows == 0 && final_rows == 1) {
4295 struct json *op = json_object_create();
4296 json_array_add(operations, op);
4297 json_object_put_string(op, "op", "wait");
4298 json_object_put_string(op, "table", table->class_->name);
4299 json_object_put(op, "where", json_array_create_empty());
4300 json_object_put(op, "timeout", json_integer_create(0));
4301 json_object_put_string(op, "until", "==");
4302 json_object_put(op, "rows", json_array_create_empty());
4303 }
4304 }
4305 }
4306
4307 HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
4308 const struct ovsdb_idl_table_class *class = row->table->class_;
4309
4310 if (!row->new_datum) {
4311 if (class->is_root) {
4312 struct json *op = json_object_create();
4313 json_object_put_string(op, "op", "delete");
4314 json_object_put_string(op, "table", class->name);
4315 json_object_put(op, "where", where_uuid_equals(&row->uuid));
4316 json_array_add(operations, op);
4317 any_updates = true;
4318 } else {
4319 /* Let ovsdb-server decide whether to really delete it. */
4320 }
4321 } else if (row->old_datum != row->new_datum) {
4322 struct json *row_json;
4323 size_t idx;
4324
4325 struct json *op = json_object_create();
4326 json_object_put_string(op, "op",
4327 row->old_datum ? "update" : "insert");
4328 json_object_put_string(op, "table", class->name);
4329 if (row->old_datum) {
4330 json_object_put(op, "where", where_uuid_equals(&row->uuid));
4331 } else {
4332 struct ovsdb_idl_txn_insert *insert;
4333
4334 any_updates = true;
4335
4336 json_object_put(op, "uuid-name",
4337 json_string_create_nocopy(
4338 ovsdb_data_row_name(&row->uuid)));
4339
4340 insert = xmalloc(sizeof *insert);
4341 insert->dummy = row->uuid;
4342 insert->op_index = operations->array.n - 1;
4343 uuid_zero(&insert->real);
4344 hmap_insert(&txn->inserted_rows, &insert->hmap_node,
4345 uuid_hash(&insert->dummy));
4346 }
4347 row_json = json_object_create();
4348 json_object_put(op, "row", row_json);
4349
4350 if (row->written) {
4351 BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
4352 const struct ovsdb_idl_column *column =
4353 &class->columns[idx];
4354
4355 if (row->old_datum
4356 || !ovsdb_datum_is_default(&row->new_datum[idx],
4357 &column->type)) {
4358 struct json *value;
4359
4360 value = ovsdb_datum_to_json(&row->new_datum[idx],
4361 &column->type);
4362 json_object_put(row_json, column->name,
4363 substitute_uuids(value, txn));
4364
4365 /* If anything really changed, consider it an update.
4366 * We can't suppress not-really-changed values earlier
4367 * or transactions would become nonatomic (see the big
4368 * comment inside ovsdb_idl_txn_write()). */
4369 if (!any_updates && row->old_datum &&
4370 !ovsdb_datum_equals(&row->old_datum[idx],
4371 &row->new_datum[idx],
4372 &column->type)) {
4373 any_updates = true;
4374 }
4375 }
4376 }
4377 }
4378
4379 if (!row->old_datum || !shash_is_empty(json_object(row_json))) {
4380 json_array_add(operations, op);
4381 } else {
4382 json_destroy(op);
4383 }
4384 }
4385
4386 /* Add mutate operation, for partial map or partial set updates. */
4387 if (row->map_op_written || row->set_op_written) {
4388 struct json *op, *mutations;
4389 bool any_mutations;
4390
4391 op = json_object_create();
4392 json_object_put_string(op, "op", "mutate");
4393 json_object_put_string(op, "table", class->name);
4394 json_object_put(op, "where", where_uuid_equals(&row->uuid));
4395 mutations = json_array_create_empty();
4396 any_mutations = ovsdb_idl_txn_extract_mutations(row, mutations);
4397 json_object_put(op, "mutations", mutations);
4398
4399 if (any_mutations) {
4400 op = substitute_uuids(op, txn);
4401 json_array_add(operations, op);
4402 any_updates = true;
4403 } else {
4404 json_destroy(op);
4405 }
4406 }
4407 }
4408
4409 /* Add increment. */
4410 if (txn->inc_table && (any_updates || txn->inc_force)) {
4411 any_updates = true;
4412 txn->inc_index = operations->array.n - 1;
4413
4414 struct json *op = json_object_create();
4415 json_object_put_string(op, "op", "mutate");
4416 json_object_put_string(op, "table", txn->inc_table);
4417 json_object_put(op, "where",
4418 substitute_uuids(where_uuid_equals(&txn->inc_row),
4419 txn));
4420 json_object_put(op, "mutations",
4421 json_array_create_1(
4422 json_array_create_3(
4423 json_string_create(txn->inc_column),
4424 json_string_create("+="),
4425 json_integer_create(1))));
4426 json_array_add(operations, op);
4427
4428 op = json_object_create();
4429 json_object_put_string(op, "op", "select");
4430 json_object_put_string(op, "table", txn->inc_table);
4431 json_object_put(op, "where",
4432 substitute_uuids(where_uuid_equals(&txn->inc_row),
4433 txn));
4434 json_object_put(op, "columns",
4435 json_array_create_1(json_string_create(
4436 txn->inc_column)));
4437 json_array_add(operations, op);
4438 }
4439
4440 if (txn->comment.length) {
4441 struct json *op = json_object_create();
4442 json_object_put_string(op, "op", "comment");
4443 json_object_put_string(op, "comment", ds_cstr(&txn->comment));
4444 json_array_add(operations, op);
4445 }
4446
4447 if (txn->dry_run) {
4448 struct json *op = json_object_create();
4449 json_object_put_string(op, "op", "abort");
4450 json_array_add(operations, op);
4451 }
4452
4453 if (!any_updates) {
4454 txn->status = TXN_UNCHANGED;
4455 json_destroy(operations);
4456 } else if (txn->db->idl->session
4457 && !jsonrpc_session_send(
4458 txn->db->idl->session,
4459 jsonrpc_create_request(
4460 "transact", operations, &txn->request_id))) {
4461 hmap_insert(&txn->db->outstanding_txns, &txn->hmap_node,
4462 json_hash(txn->request_id, 0));
4463 txn->status = TXN_INCOMPLETE;
4464 } else {
4465 txn->status = TXN_TRY_AGAIN;
4466 }
4467
4468 disassemble_out:
4469 ovsdb_idl_txn_disassemble(txn);
4470 coverage_out:
4471 switch (txn->status) {
4472 case TXN_UNCOMMITTED: COVERAGE_INC(txn_uncommitted); break;
4473 case TXN_UNCHANGED: COVERAGE_INC(txn_unchanged); break;
4474 case TXN_INCOMPLETE: COVERAGE_INC(txn_incomplete); break;
4475 case TXN_ABORTED: COVERAGE_INC(txn_aborted); break;
4476 case TXN_SUCCESS: COVERAGE_INC(txn_success); break;
4477 case TXN_TRY_AGAIN: COVERAGE_INC(txn_try_again); break;
4478 case TXN_NOT_LOCKED: COVERAGE_INC(txn_not_locked); break;
4479 case TXN_ERROR: COVERAGE_INC(txn_error); break;
4480 }
4481
4482 return txn->status;
4483 }
4484
4485 /* Attempts to commit 'txn', blocking until the commit either succeeds or
4486 * fails. Returns the final commit status, which may be any TXN_* value other
4487 * than TXN_INCOMPLETE.
4488 *
4489 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
4490 * return value of ovsdb_idl_get_seqno() to change. */
4491 enum ovsdb_idl_txn_status
4492 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
4493 {
4494 enum ovsdb_idl_txn_status status;
4495
4496 fatal_signal_run();
4497 while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
4498 ovsdb_idl_run(txn->db->idl);
4499 ovsdb_idl_wait(txn->db->idl);
4500 ovsdb_idl_txn_wait(txn);
4501 poll_block();
4502 }
4503 return status;
4504 }
4505
4506 /* Returns the final (incremented) value of the column in 'txn' that was set to
4507 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
4508 * successfully. */
4509 int64_t
4510 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
4511 {
4512 ovs_assert(txn->status == TXN_SUCCESS);
4513 return txn->inc_new_value;
4514 }
4515
4516 /* Aborts 'txn' without sending it to the database server. This is effective
4517 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
4518 * Otherwise, it has no effect.
4519 *
4520 * Aborting a transaction doesn't free its memory. Use
4521 * ovsdb_idl_txn_destroy() to do that. */
4522 void
4523 ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
4524 {
4525 ovsdb_idl_txn_disassemble(txn);
4526 if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
4527 txn->status = TXN_ABORTED;
4528 }
4529 }
4530
4531 /* Returns a string that reports the error status for 'txn'. The caller must
4532 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
4533 * for 'txn' may free the returned string.
4534 *
4535 * The return value is ordinarily one of the strings that
4536 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
4537 * due to an error reported by the database server, the return value is that
4538 * error. */
4539 const char *
4540 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
4541 {
4542 if (txn->status != TXN_ERROR) {
4543 return ovsdb_idl_txn_status_to_string(txn->status);
4544 } else if (txn->error) {
4545 return txn->error;
4546 } else {
4547 return "no error details available";
4548 }
4549 }
4550
4551 static void
4552 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
4553 const struct json *json)
4554 {
4555 if (json && txn->error == NULL) {
4556 txn->error = json_to_string(json, JSSF_SORT);
4557 }
4558 }
4559
4560 /* For transaction 'txn' that completed successfully, finds and returns the
4561 * permanent UUID that the database assigned to a newly inserted row, given the
4562 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
4563 *
4564 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
4565 * if it was assigned by that function and then deleted by
4566 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
4567 * and then deleted within a single transaction are never sent to the database
4568 * server, so it never assigns them a permanent UUID.) */
4569 const struct uuid *
4570 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *txn,
4571 const struct uuid *uuid)
4572 {
4573 const struct ovsdb_idl_txn_insert *insert;
4574
4575 ovs_assert(txn->status == TXN_SUCCESS || txn->status == TXN_UNCHANGED);
4576 HMAP_FOR_EACH_IN_BUCKET (insert, hmap_node,
4577 uuid_hash(uuid), &txn->inserted_rows) {
4578 if (uuid_equals(uuid, &insert->dummy)) {
4579 return &insert->real;
4580 }
4581 }
4582 return NULL;
4583 }
4584
4585 static void
4586 ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
4587 enum ovsdb_idl_txn_status status)
4588 {
4589 txn->status = status;
4590 hmap_remove(&txn->db->outstanding_txns, &txn->hmap_node);
4591 }
4592
4593 static void
4594 ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
4595 const struct ovsdb_idl_column *column,
4596 struct ovsdb_datum *datum, bool owns_datum)
4597 {
4598 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4599 const struct ovsdb_idl_table_class *class;
4600 size_t column_idx;
4601 bool write_only;
4602
4603 ovs_assert(!column->is_synthetic);
4604 if (ovsdb_idl_row_is_synthetic(row)) {
4605 goto discard_datum;
4606 }
4607
4608 class = row->table->class_;
4609 column_idx = column - class->columns;
4610 write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
4611
4612 ovs_assert(row->new_datum != NULL);
4613 ovs_assert(column_idx < class->n_columns);
4614 ovs_assert(row->old_datum == NULL ||
4615 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
4616
4617 if (row->table->db->verify_write_only && !write_only) {
4618 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
4619 " explicitly configured not to.", class->name, column->name);
4620 goto discard_datum;
4621 }
4622
4623 /* If this is a write-only column and the datum being written is the same
4624 * as the one already there, just skip the update entirely. This is worth
4625 * optimizing because we have a lot of columns that get periodically
4626 * refreshed into the database but don't actually change that often.
4627 *
4628 * We don't do this for read/write columns because that would break
4629 * atomicity of transactions--some other client might have written a
4630 * different value in that column since we read it. (But if a whole
4631 * transaction only does writes of existing values, without making any real
4632 * changes, we will drop the whole transaction later in
4633 * ovsdb_idl_txn_commit().) */
4634 if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
4635 datum, &column->type)) {
4636 goto discard_datum;
4637 }
4638
4639 bool index_row = is_index_row(row);
4640 if (!index_row) {
4641 ovsdb_idl_remove_from_indexes(row);
4642 }
4643 if (hmap_node_is_null(&row->txn_node)) {
4644 hmap_insert(&row->table->db->txn->txn_rows, &row->txn_node,
4645 uuid_hash(&row->uuid));
4646 }
4647 if (row->old_datum == row->new_datum) {
4648 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
4649 }
4650 if (!row->written) {
4651 row->written = bitmap_allocate(class->n_columns);
4652 }
4653 if (bitmap_is_set(row->written, column_idx)) {
4654 ovsdb_datum_destroy(&row->new_datum[column_idx], &column->type);
4655 } else {
4656 bitmap_set1(row->written, column_idx);
4657 }
4658 if (owns_datum) {
4659 row->new_datum[column_idx] = *datum;
4660 } else {
4661 ovsdb_datum_clone(&row->new_datum[column_idx], datum, &column->type);
4662 }
4663 (column->unparse)(row);
4664 (column->parse)(row, &row->new_datum[column_idx]);
4665 row->parsed = true;
4666 if (!index_row) {
4667 ovsdb_idl_add_to_indexes(row);
4668 }
4669 return;
4670
4671 discard_datum:
4672 if (owns_datum) {
4673 ovsdb_datum_destroy(datum, &column->type);
4674 }
4675 }
4676
4677 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
4678 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
4679 * ovs-vswitchd).
4680 *
4681 * 'datum' must have the correct type for its column, but it needs not be
4682 * sorted or unique because this function will take care of that. The IDL does
4683 * not check that it meets schema constraints, but ovsdb-server will do so at
4684 * commit time so it had better be correct.
4685 *
4686 * A transaction must be in progress. Replication of 'column' must not have
4687 * been disabled (by calling ovsdb_idl_omit()).
4688 *
4689 * Usually this function is used indirectly through one of the "set" functions
4690 * generated by ovsdb-idlc.
4691 *
4692 * Takes ownership of what 'datum' points to (and in some cases destroys that
4693 * data before returning) but makes a copy of 'datum' itself. (Commonly
4694 * 'datum' is on the caller's stack.) */
4695 void
4696 ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
4697 const struct ovsdb_idl_column *column,
4698 struct ovsdb_datum *datum)
4699 {
4700 ovsdb_datum_sort_unique(datum,
4701 column->type.key.type, column->type.value.type);
4702 ovsdb_idl_txn_write__(row, column, datum, true);
4703 }
4704
4705 /* Similar to ovsdb_idl_txn_write(), except:
4706 *
4707 * - The caller retains ownership of 'datum' and what it points to.
4708 *
4709 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
4710 * ovsdb_datum_sort_unique().) */
4711 void
4712 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
4713 const struct ovsdb_idl_column *column,
4714 const struct ovsdb_datum *datum)
4715 {
4716 ovsdb_idl_txn_write__(row, column,
4717 CONST_CAST(struct ovsdb_datum *, datum), false);
4718 }
4719
4720 /* Causes the original contents of 'column' in 'row_' to be verified as a
4721 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
4722 * changed (or if 'row_' was deleted) between the time that the IDL originally
4723 * read its contents and the time that the transaction commits, then the
4724 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
4725 *
4726 * The intention is that, to ensure that no transaction commits based on dirty
4727 * reads, an application should call ovsdb_idl_txn_verify() on each data item
4728 * read as part of a read-modify-write operation.
4729 *
4730 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
4731 * value of 'column' is already known:
4732 *
4733 * - If 'row_' is a row created by the current transaction (returned by
4734 * ovsdb_idl_txn_insert()).
4735 *
4736 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
4737 * within the current transaction.
4738 *
4739 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
4740 * ovsdb_idl_txn_write() for a given read-modify-write.
4741 *
4742 * A transaction must be in progress.
4743 *
4744 * Usually this function is used indirectly through one of the "verify"
4745 * functions generated by ovsdb-idlc. */
4746 void
4747 ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
4748 const struct ovsdb_idl_column *column)
4749 {
4750 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4751 const struct ovsdb_idl_table_class *class;
4752 size_t column_idx;
4753
4754 if (ovsdb_idl_row_is_synthetic(row)) {
4755 return;
4756 }
4757
4758 class = row->table->class_;
4759 column_idx = column - class->columns;
4760
4761 ovs_assert(row->new_datum != NULL);
4762 ovs_assert(row->old_datum == NULL ||
4763 row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
4764 if (!row->old_datum
4765 || (row->written && bitmap_is_set(row->written, column_idx))) {
4766 return;
4767 }
4768
4769 if (hmap_node_is_null(&row->txn_node)) {
4770 hmap_insert(&row->table->db->txn->txn_rows, &row->txn_node,
4771 uuid_hash(&row->uuid));
4772 }
4773 if (!row->prereqs) {
4774 row->prereqs = bitmap_allocate(class->n_columns);
4775 }
4776 bitmap_set1(row->prereqs, column_idx);
4777 }
4778
4779 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4780 * accessed afterward.
4781 *
4782 * A transaction must be in progress.
4783 *
4784 * Usually this function is used indirectly through one of the "delete"
4785 * functions generated by ovsdb-idlc. */
4786 void
4787 ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
4788 {
4789 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
4790
4791 if (ovsdb_idl_row_is_synthetic(row)) {
4792 return;
4793 }
4794
4795 ovs_assert(row->new_datum != NULL);
4796 ovs_assert(!is_index_row(row_));
4797 ovsdb_idl_remove_from_indexes(row_);
4798 if (!row->old_datum) {
4799 ovsdb_idl_row_unparse(row);
4800 ovsdb_idl_row_clear_new(row);
4801 ovs_assert(!row->prereqs);
4802 hmap_remove(&row->table->rows, &row->hmap_node);
4803 hmap_remove(&row->table->db->txn->txn_rows, &row->txn_node);
4804 free(row);
4805 return;
4806 }
4807 if (hmap_node_is_null(&row->txn_node)) {
4808 hmap_insert(&row->table->db->txn->txn_rows, &row->txn_node,
4809 uuid_hash(&row->uuid));
4810 }
4811 ovsdb_idl_row_clear_new(row);
4812 row->new_datum = NULL;
4813 }
4814
4815 /* Inserts and returns a new row in the table with the specified 'class' in the
4816 * database with open transaction 'txn'.
4817 *
4818 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4819 * randomly generated; otherwise 'uuid' should specify a randomly generated
4820 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4821 * 'txn' is committed, but the IDL will replace any uses of the provisional
4822 * UUID in the data to be to be committed by the UUID assigned by
4823 * ovsdb-server.
4824 *
4825 * Usually this function is used indirectly through one of the "insert"
4826 * functions generated by ovsdb-idlc. */
4827 const struct ovsdb_idl_row *
4828 ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
4829 const struct ovsdb_idl_table_class *class,
4830 const struct uuid *uuid)
4831 {
4832 struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);
4833
4834 if (uuid) {
4835 ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
4836 row->uuid = *uuid;
4837 } else {
4838 uuid_generate(&row->uuid);
4839 }
4840
4841 row->table = ovsdb_idl_db_table_from_class(txn->db, class);
4842 row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
4843 hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
4844 hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
4845 ovsdb_idl_add_to_indexes(row);
4846 return row;
4847 }
4848
4849 static void
4850 ovsdb_idl_db_txn_abort_all(struct ovsdb_idl_db *db)
4851 {
4852 struct ovsdb_idl_txn *txn;
4853
4854 HMAP_FOR_EACH (txn, hmap_node, &db->outstanding_txns) {
4855 ovsdb_idl_txn_complete(txn, TXN_TRY_AGAIN);
4856 }
4857 }
4858
4859 static void
4860 ovsdb_idl_txn_abort_all(struct ovsdb_idl *idl)
4861 {
4862 ovsdb_idl_db_txn_abort_all(&idl->server);
4863 ovsdb_idl_db_txn_abort_all(&idl->data);
4864 }
4865
4866 static struct ovsdb_idl_txn *
4867 ovsdb_idl_db_txn_find(struct ovsdb_idl_db *db, const struct json *id)
4868 {
4869 struct ovsdb_idl_txn *txn;
4870
4871 HMAP_FOR_EACH_WITH_HASH (txn, hmap_node,
4872 json_hash(id, 0), &db->outstanding_txns) {
4873 if (json_equal(id, txn->request_id)) {
4874 return txn;
4875 }
4876 }
4877 return NULL;
4878 }
4879
4880 static bool
4881 check_json_type(const struct json *json, enum json_type type, const char *name)
4882 {
4883 if (!json) {
4884 VLOG_WARN_RL(&syntax_rl, "%s is missing", name);
4885 return false;
4886 } else if (json->type != type) {
4887 VLOG_WARN_RL(&syntax_rl, "%s is %s instead of %s",
4888 name, json_type_to_string(json->type),
4889 json_type_to_string(type));
4890 return false;
4891 } else {
4892 return true;
4893 }
4894 }
4895
4896 static bool
4897 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
4898 const struct json_array *results)
4899 {
4900 struct json *count, *rows, *row, *column;
4901 struct shash *mutate, *select;
4902
4903 if (txn->inc_index + 2 > results->n) {
4904 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4905 "for increment (has %"PRIuSIZE", needs %u)",
4906 results->n, txn->inc_index + 2);
4907 return false;
4908 }
4909
4910 /* We know that this is a JSON object because the loop in
4911 * ovsdb_idl_db_txn_process_reply() checked. */
4912 mutate = json_object(results->elems[txn->inc_index]);
4913 count = shash_find_data(mutate, "count");
4914 if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) {
4915 return false;
4916 }
4917 if (count->integer != 1) {
4918 VLOG_WARN_RL(&syntax_rl,
4919 "\"mutate\" reply \"count\" is %lld instead of 1",
4920 count->integer);
4921 return false;
4922 }
4923
4924 select = json_object(results->elems[txn->inc_index + 1]);
4925 rows = shash_find_data(select, "rows");
4926 if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) {
4927 return false;
4928 }
4929 if (rows->array.n != 1) {
4930 VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
4931 "instead of 1",
4932 rows->array.n);
4933 return false;
4934 }
4935 row = rows->array.elems[0];
4936 if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) {
4937 return false;
4938 }
4939 column = shash_find_data(json_object(row), txn->inc_column);
4940 if (!check_json_type(column, JSON_INTEGER,
4941 "\"select\" reply inc column")) {
4942 return false;
4943 }
4944 txn->inc_new_value = column->integer;
4945 return true;
4946 }
4947
4948 static bool
4949 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
4950 const struct json_array *results)
4951 {
4952 static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT;
4953 struct ovsdb_error *error;
4954 struct json *json_uuid;
4955 union ovsdb_atom uuid;
4956 struct shash *reply;
4957
4958 if (insert->op_index >= results->n) {
4959 VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
4960 "for insert (has %"PRIuSIZE", needs %u)",
4961 results->n, insert->op_index);
4962 return false;
4963 }
4964
4965 /* We know that this is a JSON object because the loop in
4966 * ovsdb_idl_txn_process_reply() checked. */
4967 reply = json_object(results->elems[insert->op_index]);
4968 json_uuid = shash_find_data(reply, "uuid");
4969 if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) {
4970 return false;
4971 }
4972
4973 error = ovsdb_atom_from_json(&uuid, &uuid_type, json_uuid, NULL);
4974 if (error) {
4975 char *s = ovsdb_error_to_string_free(error);
4976 VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
4977 "UUID: %s", s);
4978 free(s);
4979 return false;
4980 }
4981
4982 insert->real = uuid.uuid;
4983
4984 return true;
4985 }
4986
4987 static bool
4988 ovsdb_idl_db_txn_process_reply(struct ovsdb_idl_db *db,
4989 const struct jsonrpc_msg *msg)
4990 {
4991 struct ovsdb_idl_txn *txn;
4992 enum ovsdb_idl_txn_status status;
4993
4994 txn = ovsdb_idl_db_txn_find(db, msg->id);
4995 if (!txn) {
4996 return false;
4997 }
4998
4999 if (msg->type == JSONRPC_ERROR) {
5000 if (msg->error
5001 && msg->error->type == JSON_STRING
5002 && !strcmp(json_string(msg->error), "canceled")) {
5003 /* ovsdb-server uses this error message to indicate that the
5004 * transaction was canceled because the database in question was
5005 * removed, converted, etc. */
5006 status = TXN_TRY_AGAIN;
5007 } else {
5008 status = TXN_ERROR;
5009 ovsdb_idl_txn_set_error_json(txn, msg->error);
5010 }
5011 } else if (msg->result->type != JSON_ARRAY) {
5012 VLOG_WARN_RL(&syntax_rl, "reply to \"transact\" is not JSON array");
5013 status = TXN_ERROR;
5014 ovsdb_idl_txn_set_error_json(txn, msg->result);
5015 } else {
5016 struct json_array *ops = &msg->result->array;
5017 int hard_errors = 0;
5018 int soft_errors = 0;
5019 int lock_errors = 0;
5020 size_t i;
5021
5022 for (i = 0; i < ops->n; i++) {
5023 struct json *op = ops->elems[i];
5024
5025 if (op->type == JSON_NULL) {
5026 /* This isn't an error in itself but indicates that some prior
5027 * operation failed, so make sure that we know about it. */
5028 soft_errors++;
5029 } else if (op->type == JSON_OBJECT) {
5030 struct json *error;
5031
5032 error = shash_find_data(json_object(op), "error");
5033 if (error) {
5034 if (error->type == JSON_STRING) {
5035 if (!strcmp(error->string, "timed out")) {
5036 soft_errors++;
5037 } else if (!strcmp(error->string,
5038 "unknown database")) {
5039 ovsdb_idl_retry(db->idl);
5040 soft_errors++;
5041 } else if (!strcmp(error->string, "not owner")) {
5042 lock_errors++;
5043 } else if (!strcmp(error->string, "not allowed")) {
5044 hard_errors++;
5045 ovsdb_idl_txn_set_error_json(txn, op);
5046 } else if (strcmp(error->string, "aborted")) {
5047 hard_errors++;
5048 ovsdb_idl_txn_set_error_json(txn, op);
5049 VLOG_WARN_RL(&other_rl,
5050 "transaction error: %s", txn->error);
5051 }
5052 } else {
5053 hard_errors++;
5054 ovsdb_idl_txn_set_error_json(txn, op);
5055 VLOG_WARN_RL(&syntax_rl,
5056 "\"error\" in reply is not JSON string");
5057 }
5058 }
5059 } else {
5060 hard_errors++;
5061 ovsdb_idl_txn_set_error_json(txn, op);
5062 VLOG_WARN_RL(&syntax_rl,
5063 "operation reply is not JSON null or object");
5064 }
5065 }
5066
5067 if (!soft_errors && !hard_errors && !lock_errors) {
5068 struct ovsdb_idl_txn_insert *insert;
5069
5070 if (txn->inc_table && !ovsdb_idl_txn_process_inc_reply(txn, ops)) {
5071 hard_errors++;
5072 }
5073
5074 HMAP_FOR_EACH (insert, hmap_node, &txn->inserted_rows) {
5075 if (!ovsdb_idl_txn_process_insert_reply(insert, ops)) {
5076 hard_errors++;
5077 }
5078 }
5079 }
5080
5081 status = (hard_errors ? TXN_ERROR
5082 : lock_errors ? TXN_NOT_LOCKED
5083 : soft_errors ? TXN_TRY_AGAIN
5084 : TXN_SUCCESS);
5085 }
5086
5087 ovsdb_idl_txn_complete(txn, status);
5088 return true;
5089 }
5090
5091 /* Returns the transaction currently active for 'row''s IDL. A transaction
5092 * must currently be active. */
5093 struct ovsdb_idl_txn *
5094 ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
5095 {
5096 struct ovsdb_idl_txn *txn = row->table->db->txn;
5097 ovs_assert(txn != NULL);
5098 return txn;
5099 }
5100
5101 /* Returns the IDL on which 'txn' acts. */
5102 struct ovsdb_idl *
5103 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
5104 {
5105 return txn->db->idl;
5106 }
5107
5108 /* Blocks until 'idl' successfully connects to the remote database and
5109 * retrieves its contents. */
5110 void
5111 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *idl)
5112 {
5113 while (1) {
5114 ovsdb_idl_run(idl);
5115 if (ovsdb_idl_has_ever_connected(idl)) {
5116 return;
5117 }
5118 ovsdb_idl_wait(idl);
5119 poll_block();
5120 }
5121 }
5122 \f
5123 static struct jsonrpc_msg *
5124 ovsdb_idl_db_set_lock(struct ovsdb_idl_db *db, const char *lock_name)
5125 {
5126 ovs_assert(!db->txn);
5127 ovs_assert(hmap_is_empty(&db->outstanding_txns));
5128
5129 if (db->lock_name
5130 && (!lock_name || strcmp(lock_name, db->lock_name))) {
5131 /* Release previous lock. */
5132 struct jsonrpc_msg *msg = ovsdb_idl_db_compose_unlock_request(db);
5133 free(db->lock_name);
5134 db->lock_name = NULL;
5135 db->is_lock_contended = false;
5136 return msg;
5137 }
5138
5139 if (lock_name && !db->lock_name) {
5140 /* Acquire new lock. */
5141 db->lock_name = xstrdup(lock_name);
5142 return ovsdb_idl_db_compose_lock_request(db);
5143 }
5144
5145 return NULL;
5146 }
5147
5148 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
5149 * the database server and to avoid modifying the database when the lock cannot
5150 * be acquired (that is, when another client has the same lock).
5151 *
5152 * If 'lock_name' is NULL, drops the locking requirement and releases the
5153 * lock. */
5154 void
5155 ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
5156 {
5157 for (;;) {
5158 struct jsonrpc_msg *msg = ovsdb_idl_db_set_lock(&idl->data, lock_name);
5159 if (!msg) {
5160 break;
5161 }
5162 if (idl->session) {
5163 jsonrpc_session_send(idl->session, msg);
5164 }
5165 }
5166 }
5167
5168 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
5169 *
5170 * Locking and unlocking happens asynchronously from the database client's
5171 * point of view, so the information is only useful for optimization (e.g. if
5172 * the client doesn't have the lock then there's no point in trying to write to
5173 * the database). */
5174 bool
5175 ovsdb_idl_has_lock(const struct ovsdb_idl *idl)
5176 {
5177 return idl->data.has_lock;
5178 }
5179
5180 /* Returns true if 'idl' is configured to obtain a lock but the database server
5181 * has indicated that some other client already owns the requested lock. */
5182 bool
5183 ovsdb_idl_is_lock_contended(const struct ovsdb_idl *idl)
5184 {
5185 return idl->data.is_lock_contended;
5186 }
5187
5188 static void
5189 ovsdb_idl_db_update_has_lock(struct ovsdb_idl_db *db, bool new_has_lock)
5190 {
5191 if (new_has_lock && !db->has_lock) {
5192 if (db->idl->state == IDL_S_MONITORING) {
5193 db->change_seqno++;
5194 } else {
5195 /* We're setting up a session, so don't signal that the database
5196 * changed. Finalizing the session will increment change_seqno
5197 * anyhow. */
5198 }
5199 db->is_lock_contended = false;
5200 }
5201 db->has_lock = new_has_lock;
5202 }
5203
5204 static bool
5205 ovsdb_idl_db_process_lock_replies(struct ovsdb_idl_db *db,
5206 const struct jsonrpc_msg *msg)
5207 {
5208 if (msg->type == JSONRPC_REPLY
5209 && db->lock_request_id
5210 && json_equal(db->lock_request_id, msg->id)) {
5211 /* Reply to our "lock" request. */
5212 ovsdb_idl_db_parse_lock_reply(db, msg->result);
5213 return true;
5214 }
5215
5216 if (msg->type == JSONRPC_NOTIFY) {
5217 if (!strcmp(msg->method, "locked")) {
5218 /* We got our lock. */
5219 return ovsdb_idl_db_parse_lock_notify(db, msg->params, true);
5220 } else if (!strcmp(msg->method, "stolen")) {
5221 /* Someone else stole our lock. */
5222 return ovsdb_idl_db_parse_lock_notify(db, msg->params, false);
5223 }
5224 }
5225
5226 return false;
5227 }
5228
5229 static struct jsonrpc_msg *
5230 ovsdb_idl_db_compose_lock_request__(struct ovsdb_idl_db *db,
5231 const char *method)
5232 {
5233 ovsdb_idl_db_update_has_lock(db, false);
5234
5235 json_destroy(db->lock_request_id);
5236 db->lock_request_id = NULL;
5237
5238 struct json *params = json_array_create_1(json_string_create(
5239 db->lock_name));
5240 return jsonrpc_create_request(method, params, NULL);
5241 }
5242
5243 static struct jsonrpc_msg *
5244 ovsdb_idl_db_compose_lock_request(struct ovsdb_idl_db *db)
5245 {
5246 struct jsonrpc_msg *msg = ovsdb_idl_db_compose_lock_request__(db, "lock");
5247 db->lock_request_id = json_clone(msg->id);
5248 return msg;
5249 }
5250
5251 static struct jsonrpc_msg *
5252 ovsdb_idl_db_compose_unlock_request(struct ovsdb_idl_db *db)
5253 {
5254 return ovsdb_idl_db_compose_lock_request__(db, "unlock");
5255 }
5256
5257 static void
5258 ovsdb_idl_db_parse_lock_reply(struct ovsdb_idl_db *db,
5259 const struct json *result)
5260 {
5261 bool got_lock;
5262
5263 json_destroy(db->lock_request_id);
5264 db->lock_request_id = NULL;
5265
5266 if (result->type == JSON_OBJECT) {
5267 const struct json *locked;
5268
5269 locked = shash_find_data(json_object(result), "locked");
5270 got_lock = locked && locked->type == JSON_TRUE;
5271 } else {
5272 got_lock = false;
5273 }
5274
5275 ovsdb_idl_db_update_has_lock(db, got_lock);
5276 if (!got_lock) {
5277 db->is_lock_contended = true;
5278 }
5279 }
5280
5281 static bool
5282 ovsdb_idl_db_parse_lock_notify(struct ovsdb_idl_db *db,
5283 const struct json *params,
5284 bool new_has_lock)
5285 {
5286 if (db->lock_name
5287 && params->type == JSON_ARRAY
5288 && json_array(params)->n > 0
5289 && json_array(params)->elems[0]->type == JSON_STRING) {
5290 const char *lock_name = json_string(json_array(params)->elems[0]);
5291
5292 if (!strcmp(db->lock_name, lock_name)) {
5293 ovsdb_idl_db_update_has_lock(db, new_has_lock);
5294 if (!new_has_lock) {
5295 db->is_lock_contended = true;
5296 }
5297 return true;
5298 }
5299 }
5300 return false;
5301 }
5302
5303 /* Inserts a new Map Operation into current transaction. */
5304 static void
5305 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *row,
5306 const struct ovsdb_idl_column *column,
5307 struct ovsdb_datum *datum,
5308 enum map_op_type op_type)
5309 {
5310 const struct ovsdb_idl_table_class *class;
5311 size_t column_idx;
5312 struct map_op *map_op;
5313
5314 class = row->table->class_;
5315 column_idx = column - class->columns;
5316
5317 /* Check if a map operation list exists for this column. */
5318 if (!row->map_op_written) {
5319 row->map_op_written = bitmap_allocate(class->n_columns);
5320 row->map_op_lists = xzalloc(class->n_columns *
5321 sizeof *row->map_op_lists);
5322 }
5323 if (!row->map_op_lists[column_idx]) {
5324 row->map_op_lists[column_idx] = map_op_list_create();
5325 }
5326
5327 /* Add a map operation to the corresponding list. */
5328 map_op = map_op_create(datum, op_type);
5329 bitmap_set1(row->map_op_written, column_idx);
5330 map_op_list_add(row->map_op_lists[column_idx], map_op, &column->type);
5331
5332 /* Add this row to transaction's list of rows. */
5333 if (hmap_node_is_null(&row->txn_node)) {
5334 hmap_insert(&row->table->db->txn->txn_rows, &row->txn_node,
5335 uuid_hash(&row->uuid));
5336 }
5337 }
5338
5339 /* Inserts a new Set Operation into current transaction. */
5340 static void
5341 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *row,
5342 const struct ovsdb_idl_column *column,
5343 struct ovsdb_datum *datum,
5344 enum set_op_type op_type)
5345 {
5346 const struct ovsdb_idl_table_class *class;
5347 size_t column_idx;
5348 struct set_op *set_op;
5349
5350 class = row->table->class_;
5351 column_idx = column - class->columns;
5352
5353 /* Check if a set operation list exists for this column. */
5354 if (!row->set_op_written) {
5355 row->set_op_written = bitmap_allocate(class->n_columns);
5356 row->set_op_lists = xzalloc(class->n_columns *
5357 sizeof *row->set_op_lists);
5358 }
5359 if (!row->set_op_lists[column_idx]) {
5360 row->set_op_lists[column_idx] = set_op_list_create();
5361 }
5362
5363 /* Add a set operation to the corresponding list. */
5364 set_op = set_op_create(datum, op_type);
5365 bitmap_set1(row->set_op_written, column_idx);
5366 set_op_list_add(row->set_op_lists[column_idx], set_op, &column->type);
5367
5368 /* Add this row to the transactions's list of rows. */
5369 if (hmap_node_is_null(&row->txn_node)) {
5370 hmap_insert(&row->table->db->txn->txn_rows, &row->txn_node,
5371 uuid_hash(&row->uuid));
5372 }
5373 }
5374
5375 static bool
5376 is_valid_partial_update(const struct ovsdb_idl_row *row,
5377 const struct ovsdb_idl_column *column,
5378 struct ovsdb_datum *datum)
5379 {
5380 /* Verify that this column is being monitored. */
5381 unsigned int column_idx = column - row->table->class_->columns;
5382 if (!(row->table->modes[column_idx] & OVSDB_IDL_MONITOR)) {
5383 VLOG_WARN("cannot partially update non-monitored column");
5384 return false;
5385 }
5386
5387 /* Verify that the update affects a single element. */
5388 if (datum->n != 1) {
5389 VLOG_WARN("invalid datum for partial update");
5390 return false;
5391 }
5392
5393 return true;
5394 }
5395
5396 /* Inserts the value described in 'datum' into the map in 'column' in
5397 * 'row_'. If the value doesn't already exist in 'column' then it's value
5398 * is added. The value in 'datum' must be of the same type as the values
5399 * in 'column'. This function takes ownership of 'datum'.
5400 *
5401 * Usually this function is used indirectly through one of the "update"
5402 * functions generated by vswitch-idl. */
5403 void
5404 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *row_,
5405 const struct ovsdb_idl_column *column,
5406 struct ovsdb_datum *datum)
5407 {
5408 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
5409 enum set_op_type op_type;
5410
5411 if (!is_valid_partial_update(row, column, datum)) {
5412 ovsdb_datum_destroy(datum, &column->type);
5413 free(datum);
5414 return;
5415 }
5416
5417 op_type = SET_OP_INSERT;
5418
5419 ovsdb_idl_txn_add_set_op(row, column, datum, op_type);
5420 }
5421
5422 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
5423 * The value in 'datum' must be of the same type as the keys in 'column'.
5424 * This function takes ownership of 'datum'.
5425 *
5426 * Usually this function is used indirectly through one of the "update"
5427 * functions generated by vswitch-idl. */
5428 void
5429 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *row_,
5430 const struct ovsdb_idl_column *column,
5431 struct ovsdb_datum *datum)
5432 {
5433 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
5434
5435 if (!is_valid_partial_update(row, column, datum)) {
5436 struct ovsdb_type type_ = column->type;
5437 type_.value.type = OVSDB_TYPE_VOID;
5438 ovsdb_datum_destroy(datum, &type_);
5439 free(datum);
5440 return;
5441 }
5442 ovsdb_idl_txn_add_set_op(row, column, datum, SET_OP_DELETE);
5443 }
5444
5445 /* Inserts the key-value specified in 'datum' into the map in 'column' in
5446 * 'row_'. If the key already exist in 'column', then it's value is updated
5447 * with the value in 'datum'. The key-value in 'datum' must be of the same type
5448 * as the keys-values in 'column'. This function takes ownership of 'datum'.
5449 *
5450 * Usually this function is used indirectly through one of the "update"
5451 * functions generated by vswitch-idl. */
5452 void
5453 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *row_,
5454 const struct ovsdb_idl_column *column,
5455 struct ovsdb_datum *datum)
5456 {
5457 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
5458 enum ovsdb_atomic_type key_type;
5459 enum map_op_type op_type;
5460 unsigned int pos;
5461 const struct ovsdb_datum *old_datum;
5462
5463 if (!is_valid_partial_update(row, column, datum)) {
5464 ovsdb_datum_destroy(datum, &column->type);
5465 free(datum);
5466 return;
5467 }
5468
5469 /* Find out if this is an insert or an update. */
5470 key_type = column->type.key.type;
5471 old_datum = ovsdb_idl_read(row, column);
5472 pos = ovsdb_datum_find_key(old_datum, &datum->keys[0], key_type);
5473 op_type = pos == UINT_MAX ? MAP_OP_INSERT : MAP_OP_UPDATE;
5474
5475 ovsdb_idl_txn_add_map_op(row, column, datum, op_type);
5476 }
5477
5478 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
5479 * The key in 'datum' must be of the same type as the keys in 'column'.
5480 * The value in 'datum' must be NULL. This function takes ownership of
5481 * 'datum'.
5482 *
5483 * Usually this function is used indirectly through one of the "update"
5484 * functions generated by vswitch-idl. */
5485 void
5486 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *row_,
5487 const struct ovsdb_idl_column *column,
5488 struct ovsdb_datum *datum)
5489 {
5490 struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
5491
5492 if (!is_valid_partial_update(row, column, datum)) {
5493 struct ovsdb_type type_ = column->type;
5494 type_.value.type = OVSDB_TYPE_VOID;
5495 ovsdb_datum_destroy(datum, &type_);
5496 free(datum);
5497 return;
5498 }
5499 ovsdb_idl_txn_add_map_op(row, column, datum, MAP_OP_DELETE);
5500 }
5501
5502 void
5503 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *loop)
5504 {
5505 if (loop) {
5506 ovsdb_idl_destroy(loop->idl);
5507 }
5508 }
5509
5510 struct ovsdb_idl_txn *
5511 ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
5512 {
5513 ovsdb_idl_run(loop->idl);
5514
5515 /* See if we can commit the loop->committing_txn. */
5516 if (loop->committing_txn) {
5517 ovsdb_idl_try_commit_loop_txn(loop, NULL);
5518 }
5519
5520 loop->open_txn = (loop->committing_txn
5521 || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
5522 ? NULL
5523 : ovsdb_idl_txn_create(loop->idl));
5524 if (loop->open_txn) {
5525 ovsdb_idl_txn_add_comment(loop->open_txn, "%s", program_name);
5526 }
5527 return loop->open_txn;
5528 }
5529
5530 /* Attempts to commit the current transaction, if one is open.
5531 *
5532 * If a transaction was open, in this or a previous iteration of the main loop,
5533 * and had not before finished committing (successfully or unsuccessfully), the
5534 * return value is one of:
5535 *
5536 * 1: The transaction committed successfully (or it did not change anything in
5537 * the database).
5538 * 0: The transaction failed.
5539 * -1: The commit is still in progress.
5540 *
5541 * Thus, the return value is -1 if the transaction is in progress and otherwise
5542 * true for success, false for failure.
5543 *
5544 * (In the corner case where the IDL sends a transaction to the database and
5545 * the database commits it, and the connection between the IDL and the database
5546 * drops before the IDL receives the message confirming the commit, this
5547 * function can return 0 even though the transaction succeeded.)
5548 */
5549 static int
5550 ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop,
5551 bool *may_need_wakeup)
5552 {
5553 if (!loop->committing_txn) {
5554 /* Not a meaningful return value: no transaction was in progress. */
5555 return 1;
5556 }
5557
5558 int retval;
5559 struct ovsdb_idl_txn *txn = loop->committing_txn;
5560
5561 enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
5562 if (status != TXN_INCOMPLETE) {
5563 switch (status) {
5564 case TXN_TRY_AGAIN:
5565 /* We want to re-evaluate the database when it's changed from
5566 * the contents that it had when we started the commit. (That
5567 * might have already happened.) */
5568 loop->skip_seqno = loop->precommit_seqno;
5569 if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno
5570 && may_need_wakeup) {
5571 *may_need_wakeup = true;
5572 }
5573 retval = 0;
5574 break;
5575
5576 case TXN_SUCCESS:
5577 /* Possibly some work on the database was deferred because no
5578 * further transaction could proceed. Wake up again. */
5579 retval = 1;
5580 loop->cur_cfg = loop->next_cfg;
5581 if (may_need_wakeup) {
5582 *may_need_wakeup = true;
5583 }
5584 break;
5585
5586 case TXN_UNCHANGED:
5587 retval = 1;
5588 loop->cur_cfg = loop->next_cfg;
5589 break;
5590
5591 case TXN_ABORTED:
5592 case TXN_NOT_LOCKED:
5593 case TXN_ERROR:
5594 retval = 0;
5595 break;
5596
5597 case TXN_UNCOMMITTED:
5598 case TXN_INCOMPLETE:
5599 default:
5600 OVS_NOT_REACHED();
5601 }
5602 ovsdb_idl_txn_destroy(txn);
5603 loop->committing_txn = NULL;
5604 } else {
5605 retval = -1;
5606 }
5607
5608 return retval;
5609 }
5610
5611 /* Attempts to commit the current transaction, if one is open, and sets up the
5612 * poll loop to wake up when some more work might be needed.
5613 *
5614 * If a transaction was open, in this or a previous iteration of the main loop,
5615 * and had not before finished committing (successfully or unsuccessfully), the
5616 * return value is one of:
5617 *
5618 * 1: The transaction committed successfully (or it did not change anything in
5619 * the database).
5620 * 0: The transaction failed.
5621 * -1: The commit is still in progress.
5622 *
5623 * Thus, the return value is -1 if the transaction is in progress and otherwise
5624 * true for success, false for failure.
5625 *
5626 * (In the corner case where the IDL sends a transaction to the database and
5627 * the database commits it, and the connection between the IDL and the database
5628 * drops before the IDL receives the message confirming the commit, this
5629 * function can return 0 even though the transaction succeeded.)
5630 */
5631 int
5632 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
5633 {
5634 if (loop->open_txn) {
5635 loop->committing_txn = loop->open_txn;
5636 loop->open_txn = NULL;
5637
5638 loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
5639 }
5640
5641 bool may_need_wakeup = false;
5642 int retval = ovsdb_idl_try_commit_loop_txn(loop, &may_need_wakeup);
5643 if (may_need_wakeup) {
5644 poll_immediate_wake();
5645 }
5646 ovsdb_idl_wait(loop->idl);
5647
5648 return retval;
5649 }