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