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