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