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