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