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