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