1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
2 * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "ovsdb-idl.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "openvswitch/json.h"
33 #include "ovsdb/ovsdb.h"
34 #include "ovsdb/table.h"
35 #include "ovsdb-data.h"
36 #include "ovsdb-error.h"
37 #include "ovsdb-idl-provider.h"
38 #include "ovsdb-parser.h"
39 #include "openvswitch/poll-loop.h"
40 #include "openvswitch/shash.h"
45 #include "openvswitch/vlog.h"
47 VLOG_DEFINE_THIS_MODULE(ovsdb_idl
);
49 COVERAGE_DEFINE(txn_uncommitted
);
50 COVERAGE_DEFINE(txn_unchanged
);
51 COVERAGE_DEFINE(txn_incomplete
);
52 COVERAGE_DEFINE(txn_aborted
);
53 COVERAGE_DEFINE(txn_success
);
54 COVERAGE_DEFINE(txn_try_again
);
55 COVERAGE_DEFINE(txn_not_locked
);
56 COVERAGE_DEFINE(txn_error
);
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
62 * Arcs from a row to itself are omitted, that is, src and dst are always
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.
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.
72 * The source and destination row may be in the same table or in different
75 struct ovsdb_idl_arc
{
76 struct ovs_list src_node
; /* In src->src_arcs list. */
77 struct ovs_list dst_node
; /* In dst->dst_arcs list. */
78 struct ovsdb_idl_row
*src
; /* Source row. */
79 struct ovsdb_idl_row
*dst
; /* Destination row. */
82 /* Connection state machine.
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. */
87 enum ovsdb_idl_state
{
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. */
91 IDL_S_SCHEMA_REQUESTED
,
93 /* Waits for "monitor_cond" reply:
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.
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. */
101 IDL_S_MONITOR_COND_REQUESTED
,
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
,
107 /* Terminal states that process "update2" (IDL_S_MONITORING_COND) or
108 * "update" (IDL_S_MONITORING) notifications. */
109 IDL_S_MONITORING_COND
,
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. */
122 const struct ovsdb_idl_class
*class_
;
123 struct shash table_by_name
; /* Contains "struct ovsdb_idl_table *"s.*/
124 struct ovsdb_idl_table
*tables
; /* Array of ->class_->n_tables elements. */
125 unsigned int change_seqno
;
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. */
139 /* Database locking. */
140 char *lock_name
; /* Name of lock we need, NULL if none. */
141 bool has_lock
; /* Has db server told us we have the lock? */
142 bool is_lock_contended
; /* Has db server told us we can't get lock? */
143 struct json
*lock_request_id
; /* JSON-RPC ID of in-flight lock request. */
145 /* Transaction support. */
146 struct ovsdb_idl_txn
*txn
;
147 struct hmap outstanding_txns
;
148 bool verify_write_only
;
150 /* Conditional monitoring. */
152 unsigned int cond_seqno
; /* Keep track of condition clauses changes
153 over a single conditional monitoring session.
154 Reverts to zero when idl session
158 struct ovsdb_idl_txn
{
159 struct hmap_node hmap_node
;
160 struct json
*request_id
;
161 struct ovsdb_idl
*idl
;
162 struct hmap txn_rows
;
163 enum ovsdb_idl_txn_status status
;
169 const char *inc_table
;
170 const char *inc_column
;
173 unsigned int inc_index
;
174 int64_t inc_new_value
;
177 struct hmap inserted_rows
; /* Contains "struct ovsdb_idl_txn_insert"s. */
180 struct ovsdb_idl_txn_insert
{
181 struct hmap_node hmap_node
; /* In struct ovsdb_idl_txn's inserted_rows. */
182 struct uuid dummy
; /* Dummy UUID used locally. */
183 int op_index
; /* Index into transaction's operation array. */
184 struct uuid real
; /* Real UUID used by database server. */
187 enum ovsdb_update_version
{
188 OVSDB_UPDATE
, /* RFC 7047 "update" method. */
189 OVSDB_UPDATE2
/* "update2" Extension to RFC 7047.
190 See ovsdb-server(1) for more information. */
193 /* Name arrays indexed by 'enum ovsdb_update_version'. */
194 static const char *table_updates_names
[] = {"table_updates", "table_updates2"};
195 static const char *table_update_names
[] = {"table_update", "table_update2"};
196 static const char *row_update_names
[] = {"row_update", "row_update2"};
198 static struct vlog_rate_limit syntax_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
199 static struct vlog_rate_limit semantic_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
200 static struct vlog_rate_limit other_rl
= VLOG_RATE_LIMIT_INIT(1, 5);
202 static void ovsdb_idl_clear(struct ovsdb_idl
*);
203 static void ovsdb_idl_send_schema_request(struct ovsdb_idl
*);
204 static void ovsdb_idl_send_monitor_request(struct ovsdb_idl
*);
205 static void ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl
*);
206 static void ovsdb_idl_parse_update(struct ovsdb_idl
*, const struct json
*,
207 enum ovsdb_update_version
);
208 static struct ovsdb_error
*ovsdb_idl_parse_update__(struct ovsdb_idl
*,
210 enum ovsdb_update_version
);
211 static bool ovsdb_idl_process_update(struct ovsdb_idl_table
*,
213 const struct json
*old
,
214 const struct json
*new);
215 static bool ovsdb_idl_process_update2(struct ovsdb_idl_table
*,
217 const char *operation
,
218 const struct json
*row
);
219 static void ovsdb_idl_insert_row(struct ovsdb_idl_row
*, const struct json
*);
220 static void ovsdb_idl_delete_row(struct ovsdb_idl_row
*);
221 static bool ovsdb_idl_modify_row(struct ovsdb_idl_row
*, const struct json
*);
222 static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*,
223 const struct json
*);
225 static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*);
226 static struct ovsdb_idl_row
*ovsdb_idl_row_create__(
227 const struct ovsdb_idl_table_class
*);
228 static struct ovsdb_idl_row
*ovsdb_idl_row_create(struct ovsdb_idl_table
*,
229 const struct uuid
*);
230 static void ovsdb_idl_row_destroy(struct ovsdb_idl_row
*);
231 static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*);
232 static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*);
233 static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*);
235 static void ovsdb_idl_row_parse(struct ovsdb_idl_row
*);
236 static void ovsdb_idl_row_unparse(struct ovsdb_idl_row
*);
237 static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*);
238 static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*);
239 static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*, bool destroy_dsts
);
241 static void ovsdb_idl_txn_abort_all(struct ovsdb_idl
*);
242 static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl
*,
243 const struct jsonrpc_msg
*msg
);
244 static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*,
246 static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*,
247 const struct ovsdb_idl_column
*,
248 struct ovsdb_datum
*,
250 static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*,
251 const struct ovsdb_idl_column
*,
252 struct ovsdb_datum
*,
255 static void ovsdb_idl_send_lock_request(struct ovsdb_idl
*);
256 static void ovsdb_idl_send_unlock_request(struct ovsdb_idl
*);
257 static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*,
258 const struct json
*);
259 static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*,
260 const struct json
*params
,
262 static struct ovsdb_idl_table
*
263 ovsdb_idl_table_from_class(const struct ovsdb_idl
*,
264 const struct ovsdb_idl_table_class
*);
265 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
);
266 static void ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
);
268 static struct ovsdb_idl_index
*ovsdb_idl_create_index_(const struct
269 ovsdb_idl_table
*table
,
270 size_t allocated_cols
);
272 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
);
273 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*);
274 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*);
276 /* Creates and returns a connection to database 'remote', which should be in a
277 * form acceptable to jsonrpc_session_open(). The connection will maintain an
278 * in-memory replica of the remote database whose schema is described by
279 * 'class'. (Ordinarily 'class' is compiled from an OVSDB schema automatically
282 * Passes 'retry' to jsonrpc_session_open(). See that function for
285 * If 'monitor_everything_by_default' is true, then everything in the remote
286 * database will be replicated by default. ovsdb_idl_omit() and
287 * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
290 * If 'monitor_everything_by_default' is false, then no columns or tables will
291 * be replicated by default. ovsdb_idl_add_column() and ovsdb_idl_add_table()
292 * must be used to choose some columns or tables to replicate.
295 ovsdb_idl_create(const char *remote
, const struct ovsdb_idl_class
*class,
296 bool monitor_everything_by_default
, bool retry
)
298 struct ovsdb_idl
*idl
;
299 uint8_t default_mode
;
302 default_mode
= (monitor_everything_by_default
303 ? OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
306 idl
= xzalloc(sizeof *idl
);
308 idl
->session
= jsonrpc_session_open(remote
, retry
);
309 shash_init(&idl
->table_by_name
);
310 idl
->tables
= xmalloc(class->n_tables
* sizeof *idl
->tables
);
311 for (i
= 0; i
< class->n_tables
; i
++) {
312 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
313 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
316 shash_add_assert(&idl
->table_by_name
, tc
->name
, table
);
318 table
->modes
= xmalloc(tc
->n_columns
);
319 memset(table
->modes
, default_mode
, tc
->n_columns
);
320 table
->need_table
= false;
321 shash_init(&table
->columns
);
322 shash_init(&table
->indexes
);
323 for (j
= 0; j
< tc
->n_columns
; j
++) {
324 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
326 shash_add_assert(&table
->columns
, column
->name
, column
);
328 hmap_init(&table
->rows
);
329 ovs_list_init(&table
->track_list
);
330 table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
]
331 = table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]
332 = table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
] = 0;
334 ovsdb_idl_condition_init(&table
->condition
);
335 ovsdb_idl_condition_add_clause_true(&table
->condition
);
336 table
->cond_changed
= false;
339 idl
->cond_changed
= false;
341 idl
->state_seqno
= UINT_MAX
;
342 idl
->request_id
= NULL
;
345 hmap_init(&idl
->outstanding_txns
);
350 /* Changes the remote and creates a new session. */
352 ovsdb_idl_set_remote(struct ovsdb_idl
*idl
, const char *remote
,
356 ovs_assert(!idl
->txn
);
357 jsonrpc_session_close(idl
->session
);
358 idl
->session
= jsonrpc_session_open(remote
, retry
);
359 idl
->state_seqno
= UINT_MAX
;
363 /* Destroys 'idl' and all of the data structures that it manages. */
365 ovsdb_idl_destroy(struct ovsdb_idl
*idl
)
370 ovs_assert(!idl
->txn
);
371 ovsdb_idl_clear(idl
);
372 jsonrpc_session_close(idl
->session
);
374 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
375 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
376 ovsdb_idl_condition_destroy(&table
->condition
);
377 ovsdb_idl_destroy_indexes(table
);
378 shash_destroy(&table
->columns
);
379 hmap_destroy(&table
->rows
);
382 shash_destroy(&idl
->table_by_name
);
384 json_destroy(idl
->request_id
);
385 free(idl
->lock_name
);
386 json_destroy(idl
->lock_request_id
);
387 json_destroy(idl
->schema
);
388 hmap_destroy(&idl
->outstanding_txns
);
394 ovsdb_idl_clear(struct ovsdb_idl
*idl
)
396 bool changed
= false;
399 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
400 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
401 struct ovsdb_idl_row
*row
, *next_row
;
403 table
->cond_changed
= false;
404 if (hmap_is_empty(&table
->rows
)) {
409 HMAP_FOR_EACH_SAFE (row
, next_row
, hmap_node
, &table
->rows
) {
410 struct ovsdb_idl_arc
*arc
, *next_arc
;
412 if (!ovsdb_idl_row_is_orphan(row
)) {
413 ovsdb_idl_remove_from_indexes(row
);
414 ovsdb_idl_row_unparse(row
);
416 LIST_FOR_EACH_SAFE (arc
, next_arc
, src_node
, &row
->src_arcs
) {
419 /* No need to do anything with dst_arcs: some node has those arcs
420 * as forward arcs and will destroy them itself. */
422 if (!ovs_list_is_empty(&row
->track_node
)) {
423 ovs_list_remove(&row
->track_node
);
426 ovsdb_idl_row_destroy(row
);
430 idl
->cond_changed
= false;
432 ovsdb_idl_track_clear(idl
);
439 /* Processes a batch of messages from the database server on 'idl'. This may
440 * cause the IDL's contents to change. The client may check for that with
441 * ovsdb_idl_get_seqno(). */
443 ovsdb_idl_run(struct ovsdb_idl
*idl
)
447 ovs_assert(!idl
->txn
);
449 ovsdb_idl_send_cond_change(idl
);
451 jsonrpc_session_run(idl
->session
);
452 for (i
= 0; jsonrpc_session_is_connected(idl
->session
) && i
< 50; i
++) {
453 struct jsonrpc_msg
*msg
;
456 seqno
= jsonrpc_session_get_seqno(idl
->session
);
457 if (idl
->state_seqno
!= seqno
) {
458 idl
->state_seqno
= seqno
;
459 json_destroy(idl
->request_id
);
460 idl
->request_id
= NULL
;
461 ovsdb_idl_txn_abort_all(idl
);
463 ovsdb_idl_send_schema_request(idl
);
464 idl
->state
= IDL_S_SCHEMA_REQUESTED
;
465 if (idl
->lock_name
) {
466 ovsdb_idl_send_lock_request(idl
);
470 msg
= jsonrpc_session_recv(idl
->session
);
475 if (msg
->type
== JSONRPC_NOTIFY
476 && !strcmp(msg
->method
, "update2")
477 && msg
->params
->type
== JSON_ARRAY
478 && msg
->params
->u
.array
.n
== 2
479 && msg
->params
->u
.array
.elems
[0]->type
== JSON_STRING
) {
480 /* Database contents changed. */
481 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
483 } else if (msg
->type
== JSONRPC_REPLY
485 && json_equal(idl
->request_id
, msg
->id
)) {
486 json_destroy(idl
->request_id
);
487 idl
->request_id
= NULL
;
489 switch (idl
->state
) {
490 case IDL_S_SCHEMA_REQUESTED
:
491 /* Reply to our "get_schema" request. */
492 idl
->schema
= json_clone(msg
->result
);
493 ovsdb_idl_send_monitor_cond_request(idl
);
494 idl
->state
= IDL_S_MONITOR_COND_REQUESTED
;
497 case IDL_S_MONITOR_REQUESTED
:
498 case IDL_S_MONITOR_COND_REQUESTED
:
499 /* Reply to our "monitor" or "monitor_cond" request. */
501 ovsdb_idl_clear(idl
);
502 if (idl
->state
== IDL_S_MONITOR_REQUESTED
) {
503 idl
->state
= IDL_S_MONITORING
;
504 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE
);
505 } else { /* IDL_S_MONITOR_COND_REQUESTED. */
506 idl
->state
= IDL_S_MONITORING_COND
;
507 ovsdb_idl_parse_update(idl
, msg
->result
, OVSDB_UPDATE2
);
510 /* Schema is not useful after monitor request is accepted
512 json_destroy(idl
->schema
);
516 case IDL_S_MONITORING_COND
:
517 /* Conditional monitor clauses were updated. Send out
518 * the next condition changes, in any, immediately. */
519 ovsdb_idl_send_cond_change(idl
);
523 case IDL_S_MONITORING
:
524 case IDL_S_NO_SCHEMA
:
528 } else if (msg
->type
== JSONRPC_NOTIFY
529 && !strcmp(msg
->method
, "update")
530 && msg
->params
->type
== JSON_ARRAY
531 && msg
->params
->u
.array
.n
== 2
532 && msg
->params
->u
.array
.elems
[0]->type
== JSON_STRING
) {
533 /* Database contents changed. */
534 ovsdb_idl_parse_update(idl
, msg
->params
->u
.array
.elems
[1],
536 } else if (msg
->type
== JSONRPC_REPLY
537 && idl
->lock_request_id
538 && json_equal(idl
->lock_request_id
, msg
->id
)) {
539 /* Reply to our "lock" request. */
540 ovsdb_idl_parse_lock_reply(idl
, msg
->result
);
541 } else if (msg
->type
== JSONRPC_NOTIFY
542 && !strcmp(msg
->method
, "locked")) {
543 /* We got our lock. */
544 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, true);
545 } else if (msg
->type
== JSONRPC_NOTIFY
546 && !strcmp(msg
->method
, "stolen")) {
547 /* Someone else stole our lock. */
548 ovsdb_idl_parse_lock_notify(idl
, msg
->params
, false);
549 } else if (msg
->type
== JSONRPC_ERROR
550 && idl
->state
== IDL_S_MONITOR_COND_REQUESTED
552 && json_equal(idl
->request_id
, msg
->id
)) {
553 if (msg
->error
&& msg
->error
->type
== JSON_STRING
554 && !strcmp(json_string(msg
->error
), "unknown method")) {
555 /* Fall back to using "monitor" method. */
556 json_destroy(idl
->request_id
);
557 idl
->request_id
= NULL
;
558 ovsdb_idl_send_monitor_request(idl
);
559 idl
->state
= IDL_S_MONITOR_REQUESTED
;
561 } else if (msg
->type
== JSONRPC_ERROR
562 && idl
->state
== IDL_S_MONITORING_COND
564 && json_equal(idl
->request_id
, msg
->id
)) {
565 json_destroy(idl
->request_id
);
566 idl
->request_id
= NULL
;
567 VLOG_ERR("%s: conditional monitor update failed",
568 jsonrpc_session_get_name(idl
->session
));
569 idl
->state
= IDL_S_NO_SCHEMA
;
570 } else if (msg
->type
== JSONRPC_ERROR
571 && idl
->state
== IDL_S_SCHEMA_REQUESTED
573 && json_equal(idl
->request_id
, msg
->id
)) {
574 json_destroy(idl
->request_id
);
575 idl
->request_id
= NULL
;
576 VLOG_ERR("%s: requested schema not found",
577 jsonrpc_session_get_name(idl
->session
));
578 idl
->state
= IDL_S_NO_SCHEMA
;
579 } else if ((msg
->type
== JSONRPC_ERROR
580 || msg
->type
== JSONRPC_REPLY
)
581 && ovsdb_idl_txn_process_reply(idl
, msg
)) {
582 /* ovsdb_idl_txn_process_reply() did everything needful. */
584 /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
585 * a transaction before we receive the reply, so keep the log level
587 VLOG_DBG("%s: received unexpected %s message",
588 jsonrpc_session_get_name(idl
->session
),
589 jsonrpc_msg_type_to_string(msg
->type
));
591 jsonrpc_msg_destroy(msg
);
593 ovsdb_idl_row_destroy_postprocess(idl
);
596 /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
597 * do or when activity occurs on a transaction on 'idl'. */
599 ovsdb_idl_wait(struct ovsdb_idl
*idl
)
601 jsonrpc_session_wait(idl
->session
);
602 jsonrpc_session_recv_wait(idl
->session
);
605 /* Returns a "sequence number" that represents the state of 'idl'. When
606 * ovsdb_idl_run() changes the database, the sequence number changes. The
607 * initial fetch of the entire contents of the remote database is considered to
608 * be one kind of change. Successfully acquiring a lock, if one has been
609 * configured with ovsdb_idl_set_lock(), is also considered to be a change.
611 * As long as the sequence number does not change, the client may continue to
612 * use any data structures it obtains from 'idl'. But when it changes, the
613 * client must not access any of these data structures again, because they
614 * could have freed or reused for other purposes.
616 * The sequence number can occasionally change even if the database does not.
617 * This happens if the connection to the database drops and reconnects, which
618 * causes the database contents to be reloaded even if they didn't change. (It
619 * could also happen if the database server sends out a "change" that reflects
620 * what the IDL already thought was in the database. The database server is
621 * not supposed to do that, but bugs could in theory cause it to do so.) */
623 ovsdb_idl_get_seqno(const struct ovsdb_idl
*idl
)
625 return idl
->change_seqno
;
628 /* Returns a "sequence number" that represents the number of conditional
629 * monitoring updates successfully received by the OVSDB server of an IDL
632 * ovsdb_idl_set_condition() sets a new condition that is different from
633 * the current condtion, the next expected "sequence number" is returned.
635 * Whenever ovsdb_idl_get_cond_seqno() returns a value that matches
636 * the return value of ovsdb_idl_set_condition(), The client is
638 * - The ovsdb_idl_set_condition() changes has been acknowledged by
641 * - 'idl' now contains the content matches the new conditions. */
643 ovsdb_idl_get_condition_seqno(const struct ovsdb_idl
*idl
)
645 return idl
->cond_seqno
;
648 /* Returns true if 'idl' successfully connected to the remote database and
649 * retrieved its contents (even if the connection subsequently dropped and is
650 * in the process of reconnecting). If so, then 'idl' contains an atomic
651 * snapshot of the database's contents (but it might be arbitrarily old if the
652 * connection dropped).
654 * Returns false if 'idl' has never connected or retrieved the database's
655 * contents. If so, 'idl' is empty. */
657 ovsdb_idl_has_ever_connected(const struct ovsdb_idl
*idl
)
659 return ovsdb_idl_get_seqno(idl
) != 0;
662 /* Reconfigures 'idl' so that it would reconnect to the database, if
663 * connection was dropped. */
665 ovsdb_idl_enable_reconnect(struct ovsdb_idl
*idl
)
667 jsonrpc_session_enable_reconnect(idl
->session
);
670 /* Forces 'idl' to drop its connection to the database and reconnect. In the
671 * meantime, the contents of 'idl' will not change. */
673 ovsdb_idl_force_reconnect(struct ovsdb_idl
*idl
)
675 jsonrpc_session_force_reconnect(idl
->session
);
678 /* Some IDL users should only write to write-only columns. Furthermore,
679 * writing to a column which is not write-only can cause serious performance
680 * degradations for these users. This function causes 'idl' to reject writes
681 * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
683 ovsdb_idl_verify_write_only(struct ovsdb_idl
*idl
)
685 idl
->verify_write_only
= true;
688 /* Returns true if 'idl' is currently connected or trying to connect
689 * and a negative response to a schema request has not been received */
691 ovsdb_idl_is_alive(const struct ovsdb_idl
*idl
)
693 return jsonrpc_session_is_alive(idl
->session
) &&
694 idl
->state
!= IDL_S_NO_SCHEMA
;
697 /* Returns the last error reported on a connection by 'idl'. The return value
698 * is 0 only if no connection made by 'idl' has ever encountered an error and
699 * a negative response to a schema request has never been received. See
700 * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
703 ovsdb_idl_get_last_error(const struct ovsdb_idl
*idl
)
707 err
= jsonrpc_session_get_last_error(idl
->session
);
711 } else if (idl
->state
== IDL_S_NO_SCHEMA
) {
718 /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
722 ovsdb_idl_set_probe_interval(const struct ovsdb_idl
*idl
, int probe_interval
)
724 jsonrpc_session_set_probe_interval(idl
->session
, probe_interval
);
728 find_uuid_in_array(const struct uuid
*target
,
729 const struct uuid
*array
, size_t n
)
731 for (size_t i
= 0; i
< n
; i
++) {
732 if (uuid_equals(&array
[i
], target
)) {
740 array_contains_uuid(const struct uuid
*target
,
741 const struct uuid
*array
, size_t n
)
743 return find_uuid_in_array(target
, array
, n
) != SIZE_MAX
;
747 remove_uuid_from_array(const struct uuid
*target
,
748 struct uuid
*array
, size_t *n
)
750 size_t i
= find_uuid_in_array(target
, array
, *n
);
752 array
[i
] = array
[--*n
];
760 add_row_references(const struct ovsdb_base_type
*type
,
761 const union ovsdb_atom
*atoms
, size_t n_atoms
,
762 const struct uuid
*exclude_uuid
,
763 struct uuid
**dstsp
, size_t *n_dstsp
,
764 size_t *allocated_dstsp
)
766 if (type
->type
!= OVSDB_TYPE_UUID
|| !type
->u
.uuid
.refTableName
) {
770 for (size_t i
= 0; i
< n_atoms
; i
++) {
771 const struct uuid
*uuid
= &atoms
[i
].uuid
;
772 if (!uuid_equals(uuid
, exclude_uuid
)
773 && !array_contains_uuid(uuid
, *dstsp
, *n_dstsp
)) {
774 if (*n_dstsp
>= *allocated_dstsp
) {
775 *dstsp
= x2nrealloc(*dstsp
, allocated_dstsp
,
779 (*dstsp
)[*n_dstsp
] = *uuid
;
785 /* Checks for consistency in 'idl''s graph of arcs between database rows. Each
786 * reference from one row to a different row should be reflected as a "struct
787 * ovsdb_idl_arc" between those rows.
789 * This function is slow, big-O wise, and aborts if it finds an inconsistency,
790 * thus it is only for use in test programs. */
792 ovsdb_idl_check_consistency(const struct ovsdb_idl
*idl
)
794 /* Consistency is broken while a transaction is in progress. */
801 struct uuid
*dsts
= NULL
;
802 size_t allocated_dsts
= 0;
804 for (size_t i
= 0; i
< idl
->class_
->n_tables
; i
++) {
805 const struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
806 const struct ovsdb_idl_table_class
*class = table
->class_
;
808 const struct ovsdb_idl_row
*row
;
809 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
811 if (row
->new_datum
) {
812 size_t n_columns
= shash_count(&row
->table
->columns
);
813 for (size_t j
= 0; j
< n_columns
; j
++) {
814 const struct ovsdb_type
*type
= &class->columns
[j
].type
;
815 const struct ovsdb_datum
*datum
= &row
->new_datum
[j
];
816 add_row_references(&type
->key
,
817 datum
->keys
, datum
->n
, &row
->uuid
,
818 &dsts
, &n_dsts
, &allocated_dsts
);
819 add_row_references(&type
->value
,
820 datum
->values
, datum
->n
, &row
->uuid
,
821 &dsts
, &n_dsts
, &allocated_dsts
);
824 const struct ovsdb_idl_arc
*arc
;
825 LIST_FOR_EACH (arc
, src_node
, &row
->src_arcs
) {
826 if (!remove_uuid_from_array(&arc
->dst
->uuid
,
828 VLOG_ERR("unexpected arc from %s row "UUID_FMT
" to %s "
831 UUID_ARGS(&row
->uuid
),
832 arc
->dst
->table
->class_
->name
,
833 UUID_ARGS(&arc
->dst
->uuid
));
837 for (size_t j
= 0; j
< n_dsts
; j
++) {
838 VLOG_ERR("%s row "UUID_FMT
" missing arc to row "UUID_FMT
,
839 table
->class_
->name
, UUID_ARGS(&row
->uuid
),
840 UUID_ARGS(&dsts
[j
]));
849 const struct ovsdb_idl_class
*
850 ovsdb_idl_get_class(const struct ovsdb_idl
*idl
)
855 /* Given 'column' in some table in 'class', returns the table's class. */
856 const struct ovsdb_idl_table_class
*
857 ovsdb_idl_table_class_from_column(const struct ovsdb_idl_class
*class,
858 const struct ovsdb_idl_column
*column
)
860 for (size_t i
= 0; i
< class->n_tables
; i
++) {
861 const struct ovsdb_idl_table_class
*tc
= &class->tables
[i
];
862 if (column
>= tc
->columns
&& column
< &tc
->columns
[tc
->n_columns
]) {
870 /* Given 'column' in some table in 'idl', returns the table. */
871 static struct ovsdb_idl_table
*
872 ovsdb_idl_table_from_column(struct ovsdb_idl
*idl
,
873 const struct ovsdb_idl_column
*column
)
875 const struct ovsdb_idl_table_class
*tc
=
876 ovsdb_idl_table_class_from_column(idl
->class_
, column
);
877 return &idl
->tables
[tc
- idl
->class_
->tables
];
880 static unsigned char *
881 ovsdb_idl_get_mode(struct ovsdb_idl
*idl
,
882 const struct ovsdb_idl_column
*column
)
884 ovs_assert(!idl
->change_seqno
);
886 const struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_column(idl
,
888 return &table
->modes
[column
- table
->class_
->columns
];
892 add_ref_table(struct ovsdb_idl
*idl
, const struct ovsdb_base_type
*base
)
894 if (base
->type
== OVSDB_TYPE_UUID
&& base
->u
.uuid
.refTableName
) {
895 struct ovsdb_idl_table
*table
;
897 table
= shash_find_data(&idl
->table_by_name
,
898 base
->u
.uuid
.refTableName
);
900 table
->need_table
= true;
902 VLOG_WARN("%s IDL class missing referenced table %s",
903 idl
->class_
->database
, base
->u
.uuid
.refTableName
);
908 /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'. Also
909 * ensures that any tables referenced by 'column' will be replicated, even if
910 * no columns in that table are selected for replication (see
911 * ovsdb_idl_add_table() for more information).
913 * This function is only useful if 'monitor_everything_by_default' was false in
914 * the call to ovsdb_idl_create(). This function should be called between
915 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
918 ovsdb_idl_add_column(struct ovsdb_idl
*idl
,
919 const struct ovsdb_idl_column
*column
)
921 *ovsdb_idl_get_mode(idl
, column
) = OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
;
922 add_ref_table(idl
, &column
->type
.key
);
923 add_ref_table(idl
, &column
->type
.value
);
926 /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
927 * no columns are selected for replication. Just the necessary data for table
928 * references will be replicated (the UUID of the rows, for instance), any
929 * columns not selected for replication will remain unreplicated.
930 * This can be useful because it allows 'idl' to keep track of what rows in the
931 * table actually exist, which in turn allows columns that reference the table
932 * to have accurate contents. (The IDL presents the database with references to
933 * rows that do not exist removed.)
935 * This function is only useful if 'monitor_everything_by_default' was false in
936 * the call to ovsdb_idl_create(). This function should be called between
937 * ovsdb_idl_create() and the first call to ovsdb_idl_run().
940 ovsdb_idl_add_table(struct ovsdb_idl
*idl
,
941 const struct ovsdb_idl_table_class
*tc
)
945 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
946 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
948 if (table
->class_
== tc
) {
949 table
->need_table
= true;
957 /* A single clause within an ovsdb_idl_condition. */
958 struct ovsdb_idl_clause
{
959 struct hmap_node hmap_node
; /* In struct ovsdb_idl_condition. */
960 enum ovsdb_function function
; /* Never OVSDB_F_TRUE or OVSDB_F_FALSE. */
961 const struct ovsdb_idl_column
*column
; /* Must be nonnull. */
962 struct ovsdb_datum arg
; /* Has ovsdb_type ->column->type. */
966 ovsdb_idl_clause_hash(const struct ovsdb_idl_clause
*clause
)
968 uint32_t hash
= hash_pointer(clause
->column
, clause
->function
);
969 return ovsdb_datum_hash(&clause
->arg
, &clause
->column
->type
, hash
);
973 ovsdb_idl_clause_equals(const struct ovsdb_idl_clause
*a
,
974 const struct ovsdb_idl_clause
*b
)
976 return (a
->function
== b
->function
977 && a
->column
== b
->column
978 && ovsdb_datum_equals(&a
->arg
, &b
->arg
, &a
->column
->type
));
982 ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause
*clause
)
984 const char *function
= ovsdb_function_to_string(clause
->function
);
985 return json_array_create_3(json_string_create(clause
->column
->name
),
986 json_string_create(function
),
987 ovsdb_datum_to_json(&clause
->arg
,
988 &clause
->column
->type
));
992 ovsdb_idl_clause_destroy(struct ovsdb_idl_clause
*clause
)
995 ovsdb_datum_destroy(&clause
->arg
, &clause
->column
->type
);
1000 /* ovsdb_idl_condition. */
1003 ovsdb_idl_condition_init(struct ovsdb_idl_condition
*cnd
)
1005 hmap_init(&cnd
->clauses
);
1006 cnd
->is_true
= false;
1010 ovsdb_idl_condition_destroy(struct ovsdb_idl_condition
*cond
)
1013 ovsdb_idl_condition_clear(cond
);
1014 hmap_destroy(&cond
->clauses
);
1019 ovsdb_idl_condition_clear(struct ovsdb_idl_condition
*cond
)
1021 struct ovsdb_idl_clause
*clause
, *next
;
1022 HMAP_FOR_EACH_SAFE (clause
, next
, hmap_node
, &cond
->clauses
) {
1023 hmap_remove(&cond
->clauses
, &clause
->hmap_node
);
1024 ovsdb_idl_clause_destroy(clause
);
1026 cond
->is_true
= false;
1030 ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition
*condition
)
1032 return condition
->is_true
;
1035 static struct ovsdb_idl_clause
*
1036 ovsdb_idl_condition_find_clause(const struct ovsdb_idl_condition
*condition
,
1037 const struct ovsdb_idl_clause
*target
,
1040 struct ovsdb_idl_clause
*clause
;
1041 HMAP_FOR_EACH_WITH_HASH (clause
, hmap_node
, hash
, &condition
->clauses
) {
1042 if (ovsdb_idl_clause_equals(clause
, target
)) {
1050 ovsdb_idl_condition_add_clause__(struct ovsdb_idl_condition
*condition
,
1051 const struct ovsdb_idl_clause
*src
,
1054 struct ovsdb_idl_clause
*clause
= xmalloc(sizeof *clause
);
1055 clause
->function
= src
->function
;
1056 clause
->column
= src
->column
;
1057 ovsdb_datum_clone(&clause
->arg
, &src
->arg
, &src
->column
->type
);
1058 hmap_insert(&condition
->clauses
, &clause
->hmap_node
, hash
);
1061 /* Adds a clause to the condition for replicating the table with class 'tc' in
1064 * The IDL replicates only rows in a table that satisfy at least one clause in
1065 * the table's condition. The default condition for a table has a single
1066 * clause with function OVSDB_F_TRUE, so that the IDL replicates all rows in
1067 * the table. When the IDL client replaces the default condition by one of its
1068 * own, the condition can have any number of clauses. If it has no conditions,
1069 * then no rows are replicated.
1071 * Two distinct of clauses can usefully be added:
1073 * - A 'function' of OVSDB_F_TRUE. A "true" clause causes every row to be
1074 * replicated, regardless of whether other clauses exist. 'column' and
1075 * 'arg' are ignored.
1077 * - Binary 'functions' add a clause of the form "<column> <function>
1078 * <arg>", e.g. "column == 5" or "column <= 10". In this case, 'arg' must
1079 * have a type that is compatible with 'column'.
1082 ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition
*condition
,
1083 enum ovsdb_function function
,
1084 const struct ovsdb_idl_column
*column
,
1085 const struct ovsdb_datum
*arg
)
1087 if (condition
->is_true
) {
1088 /* Adding a clause to an always-true condition has no effect. */
1089 } else if (function
== OVSDB_F_TRUE
) {
1090 ovsdb_idl_condition_add_clause_true(condition
);
1091 } else if (function
== OVSDB_F_FALSE
) {
1092 /* Adding a "false" clause never has any effect. */
1094 struct ovsdb_idl_clause clause
= {
1095 .function
= function
,
1099 uint32_t hash
= ovsdb_idl_clause_hash(&clause
);
1100 if (!ovsdb_idl_condition_find_clause(condition
, &clause
, hash
)) {
1101 ovsdb_idl_condition_add_clause__(condition
, &clause
, hash
);
1107 ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition
*condition
)
1109 if (!condition
->is_true
) {
1110 ovsdb_idl_condition_clear(condition
);
1111 condition
->is_true
= true;
1116 ovsdb_idl_condition_equals(const struct ovsdb_idl_condition
*a
,
1117 const struct ovsdb_idl_condition
*b
)
1119 if (hmap_count(&a
->clauses
) != hmap_count(&b
->clauses
)) {
1122 if (a
->is_true
!= b
->is_true
) {
1126 const struct ovsdb_idl_clause
*clause
;
1127 HMAP_FOR_EACH (clause
, hmap_node
, &a
->clauses
) {
1128 if (!ovsdb_idl_condition_find_clause(b
, clause
,
1129 clause
->hmap_node
.hash
)) {
1137 ovsdb_idl_condition_clone(struct ovsdb_idl_condition
*dst
,
1138 const struct ovsdb_idl_condition
*src
)
1140 ovsdb_idl_condition_init(dst
);
1142 dst
->is_true
= src
->is_true
;
1144 const struct ovsdb_idl_clause
*clause
;
1145 HMAP_FOR_EACH (clause
, hmap_node
, &src
->clauses
) {
1146 ovsdb_idl_condition_add_clause__(dst
, clause
, clause
->hmap_node
.hash
);
1150 /* Sets the replication condition for 'tc' in 'idl' to 'condition' and
1151 * arranges to send the new condition to the database server.
1153 * Return the next conditional update sequence number. When this
1154 * value and ovsdb_idl_get_condition_seqno() matches, the 'idl'
1155 * contains rows that match the 'condition'. */
1157 ovsdb_idl_set_condition(struct ovsdb_idl
*idl
,
1158 const struct ovsdb_idl_table_class
*tc
,
1159 const struct ovsdb_idl_condition
*condition
)
1161 struct ovsdb_idl_table
*table
= ovsdb_idl_table_from_class(idl
, tc
);
1162 unsigned int seqno
= idl
->cond_seqno
;
1163 if (!ovsdb_idl_condition_equals(condition
, &table
->condition
)) {
1164 ovsdb_idl_condition_destroy(&table
->condition
);
1165 ovsdb_idl_condition_clone(&table
->condition
, condition
);
1166 idl
->cond_changed
= table
->cond_changed
= true;
1167 poll_immediate_wake();
1174 static struct json
*
1175 ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition
*cnd
)
1178 return json_array_create_empty();
1181 size_t n
= hmap_count(&cnd
->clauses
);
1183 return json_array_create_1(json_boolean_create(false));
1186 struct json
**clauses
= xmalloc(n
* sizeof *clauses
);
1187 const struct ovsdb_idl_clause
*clause
;
1189 HMAP_FOR_EACH (clause
, hmap_node
, &cnd
->clauses
) {
1190 clauses
[i
++] = ovsdb_idl_clause_to_json(clause
);
1193 return json_array_create(clauses
, n
);
1196 static struct json
*
1197 ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table
*table
)
1199 const struct ovsdb_idl_condition
*cond
= &table
->condition
;
1200 struct json
*monitor_cond_change_request
= json_object_create();
1201 struct json
*cond_json
= ovsdb_idl_condition_to_json(cond
);
1203 json_object_put(monitor_cond_change_request
, "where", cond_json
);
1205 return monitor_cond_change_request
;
1209 ovsdb_idl_send_cond_change(struct ovsdb_idl
*idl
)
1212 struct json
*params
;
1213 struct jsonrpc_msg
*request
;
1215 /* When 'idl-request_id' is not NULL, there is an outstanding
1216 * conditional monitoring update request that we have not heard
1217 * from the server yet. Don't generate another request in this case. */
1218 if (!idl
->cond_changed
|| !jsonrpc_session_is_connected(idl
->session
) ||
1219 idl
->state
!= IDL_S_MONITORING_COND
|| idl
->request_id
) {
1223 struct json
*monitor_cond_change_requests
= NULL
;
1225 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1226 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1228 if (table
->cond_changed
) {
1229 struct json
*req
= ovsdb_idl_create_cond_change_req(table
);
1231 if (!monitor_cond_change_requests
) {
1232 monitor_cond_change_requests
= json_object_create();
1234 json_object_put(monitor_cond_change_requests
,
1235 table
->class_
->name
,
1236 json_array_create_1(req
));
1238 table
->cond_changed
= false;
1242 /* Send request if not empty. */
1243 if (monitor_cond_change_requests
) {
1244 params
= json_array_create_3(json_string_create("monid"),
1245 json_string_create("monid"),
1246 monitor_cond_change_requests
);
1248 request
= jsonrpc_create_request("monitor_cond_change", params
,
1250 jsonrpc_session_send(idl
->session
, request
);
1252 idl
->cond_changed
= false;
1255 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
1257 * This function should be called between ovsdb_idl_create() and the first call
1258 * to ovsdb_idl_run().
1261 ovsdb_idl_omit_alert(struct ovsdb_idl
*idl
,
1262 const struct ovsdb_idl_column
*column
)
1264 *ovsdb_idl_get_mode(idl
, column
) &= ~OVSDB_IDL_ALERT
;
1267 /* Sets the mode for 'column' in 'idl' to 0. See the big comment above
1268 * OVSDB_IDL_MONITOR for details.
1270 * This function should be called between ovsdb_idl_create() and the first call
1271 * to ovsdb_idl_run().
1274 ovsdb_idl_omit(struct ovsdb_idl
*idl
, const struct ovsdb_idl_column
*column
)
1276 *ovsdb_idl_get_mode(idl
, column
) = 0;
1279 /* Returns the most recent IDL change sequence number that caused a
1280 * insert, modify or delete update to the table with class 'table_class'.
1283 ovsdb_idl_table_get_seqno(const struct ovsdb_idl
*idl
,
1284 const struct ovsdb_idl_table_class
*table_class
)
1286 struct ovsdb_idl_table
*table
1287 = ovsdb_idl_table_from_class(idl
, table_class
);
1288 unsigned int max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_INSERT
];
1290 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
]) {
1291 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_MODIFY
];
1293 if (max_seqno
< table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]) {
1294 max_seqno
= table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
];
1299 /* For each row that contains tracked columns, IDL stores the most
1300 * recent IDL change sequence numbers associateed with insert, modify
1301 * and delete updates to the table.
1304 ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row
*row
,
1305 enum ovsdb_idl_change change
)
1307 return row
->change_seqno
[change
];
1310 /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
1311 * all rows whose 'column' is modified are traced. Similarly, insert
1312 * or delete of rows having 'column' are tracked. Clients are able
1313 * to retrive the tracked rows with the ovsdb_idl_track_get_*()
1316 * This function should be called between ovsdb_idl_create() and
1317 * the first call to ovsdb_idl_run(). The column to be tracked
1318 * should have OVSDB_IDL_ALERT turned on.
1321 ovsdb_idl_track_add_column(struct ovsdb_idl
*idl
,
1322 const struct ovsdb_idl_column
*column
)
1324 if (!(*ovsdb_idl_get_mode(idl
, column
) & OVSDB_IDL_ALERT
)) {
1325 ovsdb_idl_add_column(idl
, column
);
1327 *ovsdb_idl_get_mode(idl
, column
) |= OVSDB_IDL_TRACK
;
1331 ovsdb_idl_track_add_all(struct ovsdb_idl
*idl
)
1335 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1336 const struct ovsdb_idl_table_class
*tc
= &idl
->class_
->tables
[i
];
1338 for (j
= 0; j
< tc
->n_columns
; j
++) {
1339 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1340 ovsdb_idl_track_add_column(idl
, column
);
1345 /* Returns true if 'table' has any tracked column. */
1347 ovsdb_idl_track_is_set(struct ovsdb_idl_table
*table
)
1351 for (i
= 0; i
< table
->class_
->n_columns
; i
++) {
1352 if (table
->modes
[i
] & OVSDB_IDL_TRACK
) {
1359 /* Returns the first tracked row in table with class 'table_class'
1360 * for the specified 'idl'. Returns NULL if there are no tracked rows */
1361 const struct ovsdb_idl_row
*
1362 ovsdb_idl_track_get_first(const struct ovsdb_idl
*idl
,
1363 const struct ovsdb_idl_table_class
*table_class
)
1365 struct ovsdb_idl_table
*table
1366 = ovsdb_idl_table_from_class(idl
, table_class
);
1368 if (!ovs_list_is_empty(&table
->track_list
)) {
1369 return CONTAINER_OF(ovs_list_front(&table
->track_list
), struct ovsdb_idl_row
, track_node
);
1374 /* Returns the next tracked row in table after the specified 'row'
1375 * (in no particular order). Returns NULL if there are no tracked rows */
1376 const struct ovsdb_idl_row
*
1377 ovsdb_idl_track_get_next(const struct ovsdb_idl_row
*row
)
1379 if (row
->track_node
.next
!= &row
->table
->track_list
) {
1380 return CONTAINER_OF(row
->track_node
.next
, struct ovsdb_idl_row
, track_node
);
1386 /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
1387 * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
1389 * Function returns false if 'column' is not tracked (see
1390 * ovsdb_idl_track_add_column()).
1393 ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
*row
,
1394 const struct ovsdb_idl_column
*column
)
1396 const struct ovsdb_idl_table_class
*class;
1399 class = row
->table
->class_
;
1400 column_idx
= column
- class->columns
;
1402 if (row
->updated
&& bitmap_is_set(row
->updated
, column_idx
)) {
1409 /* Flushes the tracked rows. Client calls this function after calling
1410 * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
1411 * functions. This is usually done at the end of the client's processing
1412 * loop when it is ready to do ovsdb_idl_run() again.
1415 ovsdb_idl_track_clear(const struct ovsdb_idl
*idl
)
1419 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1420 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1422 if (!ovs_list_is_empty(&table
->track_list
)) {
1423 struct ovsdb_idl_row
*row
, *next
;
1425 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
1428 row
->updated
= NULL
;
1430 ovs_list_remove(&row
->track_node
);
1431 ovs_list_init(&row
->track_node
);
1432 if (ovsdb_idl_row_is_orphan(row
)) {
1433 ovsdb_idl_row_clear_old(row
);
1443 ovsdb_idl_send_schema_request(struct ovsdb_idl
*idl
)
1445 struct jsonrpc_msg
*msg
;
1447 json_destroy(idl
->request_id
);
1448 msg
= jsonrpc_create_request(
1450 json_array_create_1(json_string_create(idl
->class_
->database
)),
1452 jsonrpc_session_send(idl
->session
, msg
);
1456 log_error(struct ovsdb_error
*error
)
1458 char *s
= ovsdb_error_to_string(error
);
1459 VLOG_WARN("error parsing database schema: %s", s
);
1461 ovsdb_error_destroy(error
);
1464 /* Frees 'schema', which is in the format returned by parse_schema(). */
1466 free_schema(struct shash
*schema
)
1469 struct shash_node
*node
, *next
;
1471 SHASH_FOR_EACH_SAFE (node
, next
, schema
) {
1472 struct sset
*sset
= node
->data
;
1475 shash_delete(schema
, node
);
1477 shash_destroy(schema
);
1482 /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
1483 * 7047, to obtain the names of its rows and columns. If successful, returns
1484 * an shash whose keys are table names and whose values are ssets, where each
1485 * sset contains the names of its table's columns. On failure (due to a parse
1486 * error), returns NULL.
1488 * It would also be possible to use the general-purpose OVSDB schema parser in
1489 * ovsdb-server, but that's overkill, possibly too strict for the current use
1490 * case, and would require restructuring ovsdb-server to separate the schema
1491 * code from the rest. */
1492 static struct shash
*
1493 parse_schema(const struct json
*schema_json
)
1495 struct ovsdb_parser parser
;
1496 const struct json
*tables_json
;
1497 struct ovsdb_error
*error
;
1498 struct shash_node
*node
;
1499 struct shash
*schema
;
1501 ovsdb_parser_init(&parser
, schema_json
, "database schema");
1502 tables_json
= ovsdb_parser_member(&parser
, "tables", OP_OBJECT
);
1503 error
= ovsdb_parser_destroy(&parser
);
1509 schema
= xmalloc(sizeof *schema
);
1511 SHASH_FOR_EACH (node
, json_object(tables_json
)) {
1512 const char *table_name
= node
->name
;
1513 const struct json
*json
= node
->data
;
1514 const struct json
*columns_json
;
1516 ovsdb_parser_init(&parser
, json
, "table schema for table %s",
1518 columns_json
= ovsdb_parser_member(&parser
, "columns", OP_OBJECT
);
1519 error
= ovsdb_parser_destroy(&parser
);
1522 free_schema(schema
);
1526 struct sset
*columns
= xmalloc(sizeof *columns
);
1529 struct shash_node
*node2
;
1530 SHASH_FOR_EACH (node2
, json_object(columns_json
)) {
1531 const char *column_name
= node2
->name
;
1532 sset_add(columns
, column_name
);
1534 shash_add(schema
, table_name
, columns
);
1540 ovsdb_idl_send_monitor_request__(struct ovsdb_idl
*idl
,
1543 struct shash
*schema
;
1544 struct json
*monitor_requests
;
1545 struct jsonrpc_msg
*msg
;
1548 schema
= parse_schema(idl
->schema
);
1549 monitor_requests
= json_object_create();
1550 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
1551 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
1552 const struct ovsdb_idl_table_class
*tc
= table
->class_
;
1553 struct json
*monitor_request
, *columns
, *where
;
1554 const struct sset
*table_schema
;
1557 table_schema
= (schema
1558 ? shash_find_data(schema
, table
->class_
->name
)
1561 columns
= table
->need_table
? json_array_create_empty() : NULL
;
1562 for (j
= 0; j
< tc
->n_columns
; j
++) {
1563 const struct ovsdb_idl_column
*column
= &tc
->columns
[j
];
1564 if (table
->modes
[j
] & OVSDB_IDL_MONITOR
) {
1566 && !sset_contains(table_schema
, column
->name
)) {
1567 VLOG_WARN("%s table in %s database lacks %s column "
1568 "(database needs upgrade?)",
1569 table
->class_
->name
, idl
->class_
->database
,
1574 columns
= json_array_create_empty();
1576 json_array_add(columns
, json_string_create(column
->name
));
1581 if (schema
&& !table_schema
) {
1582 VLOG_WARN("%s database lacks %s table "
1583 "(database needs upgrade?)",
1584 idl
->class_
->database
, table
->class_
->name
);
1585 json_destroy(columns
);
1589 monitor_request
= json_object_create();
1590 json_object_put(monitor_request
, "columns", columns
);
1591 if (!strcmp(method
, "monitor_cond")
1592 && !ovsdb_idl_condition_is_true(&table
->condition
)) {
1593 where
= ovsdb_idl_condition_to_json(&table
->condition
);
1594 json_object_put(monitor_request
, "where", where
);
1595 table
->cond_changed
= false;
1597 json_object_put(monitor_requests
, tc
->name
, monitor_request
);
1600 free_schema(schema
);
1602 json_destroy(idl
->request_id
);
1604 msg
= jsonrpc_create_request(
1606 json_array_create_3(json_string_create(idl
->class_
->database
),
1607 json_string_create("monid"), monitor_requests
),
1609 jsonrpc_session_send(idl
->session
, msg
);
1610 idl
->cond_changed
= false;
1614 ovsdb_idl_send_monitor_request(struct ovsdb_idl
*idl
)
1616 ovsdb_idl_send_monitor_request__(idl
, "monitor");
1620 log_parse_update_error(struct ovsdb_error
*error
)
1622 if (!VLOG_DROP_WARN(&syntax_rl
)) {
1623 char *s
= ovsdb_error_to_string(error
);
1624 VLOG_WARN_RL(&syntax_rl
, "%s", s
);
1627 ovsdb_error_destroy(error
);
1631 ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl
*idl
)
1633 ovsdb_idl_send_monitor_request__(idl
, "monitor_cond");
1637 ovsdb_idl_parse_update(struct ovsdb_idl
*idl
, const struct json
*table_updates
,
1638 enum ovsdb_update_version version
)
1640 struct ovsdb_error
*error
= ovsdb_idl_parse_update__(idl
, table_updates
,
1643 log_parse_update_error(error
);
1647 static struct ovsdb_error
*
1648 ovsdb_idl_parse_update__(struct ovsdb_idl
*idl
,
1649 const struct json
*table_updates
,
1650 enum ovsdb_update_version version
)
1652 const struct shash_node
*tables_node
;
1653 const char *table_updates_name
= table_updates_names
[version
];
1654 const char *table_update_name
= table_update_names
[version
];
1655 const char *row_update_name
= row_update_names
[version
];
1657 if (table_updates
->type
!= JSON_OBJECT
) {
1658 return ovsdb_syntax_error(table_updates
, NULL
,
1659 "<%s> is not an object",
1660 table_updates_name
);
1663 SHASH_FOR_EACH (tables_node
, json_object(table_updates
)) {
1664 const struct json
*table_update
= tables_node
->data
;
1665 const struct shash_node
*table_node
;
1666 struct ovsdb_idl_table
*table
;
1668 table
= shash_find_data(&idl
->table_by_name
, tables_node
->name
);
1670 return ovsdb_syntax_error(
1671 table_updates
, NULL
,
1672 "<%s> includes unknown table \"%s\"",
1677 if (table_update
->type
!= JSON_OBJECT
) {
1678 return ovsdb_syntax_error(table_update
, NULL
,
1679 "<%s> for table \"%s\" is "
1682 table
->class_
->name
);
1684 SHASH_FOR_EACH (table_node
, json_object(table_update
)) {
1685 const struct json
*row_update
= table_node
->data
;
1686 const struct json
*old_json
, *new_json
;
1689 if (!uuid_from_string(&uuid
, table_node
->name
)) {
1690 return ovsdb_syntax_error(table_update
, NULL
,
1691 "<%s> for table \"%s\" "
1692 "contains bad UUID "
1693 "\"%s\" as member name",
1695 table
->class_
->name
,
1698 if (row_update
->type
!= JSON_OBJECT
) {
1699 return ovsdb_syntax_error(row_update
, NULL
,
1700 "<%s> for table \"%s\" "
1701 "contains <%s> for %s that "
1704 table
->class_
->name
,
1711 old_json
= shash_find_data(json_object(row_update
), "old");
1712 new_json
= shash_find_data(json_object(row_update
), "new");
1713 if (old_json
&& old_json
->type
!= JSON_OBJECT
) {
1714 return ovsdb_syntax_error(old_json
, NULL
,
1715 "\"old\" <row> is not object");
1716 } else if (new_json
&& new_json
->type
!= JSON_OBJECT
) {
1717 return ovsdb_syntax_error(new_json
, NULL
,
1718 "\"new\" <row> is not object");
1719 } else if ((old_json
!= NULL
) + (new_json
!= NULL
)
1720 != shash_count(json_object(row_update
))) {
1721 return ovsdb_syntax_error(row_update
, NULL
,
1722 "<row-update> contains "
1723 "unexpected member");
1724 } else if (!old_json
&& !new_json
) {
1725 return ovsdb_syntax_error(row_update
, NULL
,
1726 "<row-update> missing \"old\" "
1727 "and \"new\" members");
1730 if (ovsdb_idl_process_update(table
, &uuid
, old_json
,
1732 idl
->change_seqno
++;
1736 case OVSDB_UPDATE2
: {
1737 const char *ops
[] = {"modify", "insert", "delete", "initial"};
1738 const char *operation
;
1739 const struct json
*row
;
1742 for (i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
1744 row
= shash_find_data(json_object(row_update
), operation
);
1747 if (ovsdb_idl_process_update2(table
, &uuid
, operation
,
1749 idl
->change_seqno
++;
1755 /* row_update2 should contain one of the objects */
1756 if (i
== ARRAY_SIZE(ops
)) {
1757 return ovsdb_syntax_error(row_update
, NULL
,
1758 "<row_update2> includes unknown "
1773 static struct ovsdb_idl_row
*
1774 ovsdb_idl_get_row(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
1776 struct ovsdb_idl_row
*row
;
1778 HMAP_FOR_EACH_WITH_HASH (row
, hmap_node
, uuid_hash(uuid
), &table
->rows
) {
1779 if (uuid_equals(&row
->uuid
, uuid
)) {
1786 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1789 ovsdb_idl_process_update(struct ovsdb_idl_table
*table
,
1790 const struct uuid
*uuid
, const struct json
*old
,
1791 const struct json
*new)
1793 struct ovsdb_idl_row
*row
;
1795 row
= ovsdb_idl_get_row(table
, uuid
);
1798 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1799 /* XXX perhaps we should check the 'old' values? */
1800 ovsdb_idl_delete_row(row
);
1802 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1804 UUID_ARGS(uuid
), table
->class_
->name
);
1810 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1811 } else if (ovsdb_idl_row_is_orphan(row
)) {
1812 ovsdb_idl_insert_row(row
, new);
1814 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1815 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1816 return ovsdb_idl_modify_row(row
, new);
1821 /* XXX perhaps we should check the 'old' values? */
1822 if (!ovsdb_idl_row_is_orphan(row
)) {
1823 return ovsdb_idl_modify_row(row
, new);
1825 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1826 "referenced row "UUID_FMT
" in table %s",
1827 UUID_ARGS(uuid
), table
->class_
->name
);
1828 ovsdb_idl_insert_row(row
, new);
1831 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1832 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1833 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), new);
1840 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1843 ovsdb_idl_process_update2(struct ovsdb_idl_table
*table
,
1844 const struct uuid
*uuid
,
1845 const char *operation
,
1846 const struct json
*json_row
)
1848 struct ovsdb_idl_row
*row
;
1850 row
= ovsdb_idl_get_row(table
, uuid
);
1851 if (!strcmp(operation
, "delete")) {
1853 if (row
&& !ovsdb_idl_row_is_orphan(row
)) {
1854 ovsdb_idl_delete_row(row
);
1856 VLOG_WARN_RL(&semantic_rl
, "cannot delete missing row "UUID_FMT
" "
1858 UUID_ARGS(uuid
), table
->class_
->name
);
1861 } else if (!strcmp(operation
, "insert") || !strcmp(operation
, "initial")) {
1864 ovsdb_idl_insert_row(ovsdb_idl_row_create(table
, uuid
), json_row
);
1865 } else if (ovsdb_idl_row_is_orphan(row
)) {
1866 ovsdb_idl_insert_row(row
, json_row
);
1868 VLOG_WARN_RL(&semantic_rl
, "cannot add existing row "UUID_FMT
" to "
1869 "table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1870 ovsdb_idl_delete_row(row
);
1871 ovsdb_idl_insert_row(row
, json_row
);
1873 } else if (!strcmp(operation
, "modify")) {
1876 if (!ovsdb_idl_row_is_orphan(row
)) {
1877 return ovsdb_idl_modify_row_by_diff(row
, json_row
);
1879 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing but "
1880 "referenced row "UUID_FMT
" in table %s",
1881 UUID_ARGS(uuid
), table
->class_
->name
);
1885 VLOG_WARN_RL(&semantic_rl
, "cannot modify missing row "UUID_FMT
" "
1886 "in table %s", UUID_ARGS(uuid
), table
->class_
->name
);
1890 VLOG_WARN_RL(&semantic_rl
, "unknown operation %s to "
1891 "table %s", operation
, table
->class_
->name
);
1898 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
1901 * Change 'row' either with the content of 'row_json' or by apply 'diff'.
1902 * Caller needs to provide either valid 'row_json' or 'diff', but not
1905 ovsdb_idl_row_change__(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1906 const struct json
*diff_json
,
1907 enum ovsdb_idl_change change
)
1909 struct ovsdb_idl_table
*table
= row
->table
;
1910 const struct ovsdb_idl_table_class
*class = table
->class_
;
1911 struct shash_node
*node
;
1912 bool changed
= false;
1913 bool apply_diff
= diff_json
!= NULL
;
1914 const struct json
*json
= apply_diff
? diff_json
: row_json
;
1916 SHASH_FOR_EACH (node
, json_object(json
)) {
1917 const char *column_name
= node
->name
;
1918 const struct ovsdb_idl_column
*column
;
1919 struct ovsdb_datum datum
;
1920 struct ovsdb_error
*error
;
1921 unsigned int column_idx
;
1922 struct ovsdb_datum
*old
;
1924 column
= shash_find_data(&table
->columns
, column_name
);
1926 VLOG_WARN_RL(&syntax_rl
, "unknown column %s updating row "UUID_FMT
,
1927 column_name
, UUID_ARGS(&row
->uuid
));
1931 column_idx
= column
- table
->class_
->columns
;
1932 old
= &row
->old_datum
[column_idx
];
1936 struct ovsdb_datum diff
;
1938 ovs_assert(!row_json
);
1939 error
= ovsdb_transient_datum_from_json(&diff
, &column
->type
,
1942 error
= ovsdb_datum_apply_diff(&datum
, old
, &diff
,
1944 ovsdb_datum_destroy(&diff
, &column
->type
);
1947 ovs_assert(!diff_json
);
1948 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
1953 if (!ovsdb_datum_equals(old
, &datum
, &column
->type
)) {
1954 ovsdb_datum_swap(old
, &datum
);
1955 if (table
->modes
[column_idx
] & OVSDB_IDL_ALERT
) {
1957 row
->change_seqno
[change
]
1958 = row
->table
->change_seqno
[change
]
1959 = row
->table
->idl
->change_seqno
+ 1;
1960 if (table
->modes
[column_idx
] & OVSDB_IDL_TRACK
) {
1961 if (!ovs_list_is_empty(&row
->track_node
)) {
1962 ovs_list_remove(&row
->track_node
);
1964 ovs_list_push_back(&row
->table
->track_list
,
1966 if (!row
->updated
) {
1967 row
->updated
= bitmap_allocate(class->n_columns
);
1969 bitmap_set1(row
->updated
, column_idx
);
1973 /* Didn't really change but the OVSDB monitor protocol always
1974 * includes every value in a row. */
1977 ovsdb_datum_destroy(&datum
, &column
->type
);
1979 char *s
= ovsdb_error_to_string(error
);
1980 VLOG_WARN_RL(&syntax_rl
, "error parsing column %s in row "UUID_FMT
1981 " in table %s: %s", column_name
,
1982 UUID_ARGS(&row
->uuid
), table
->class_
->name
, s
);
1984 ovsdb_error_destroy(error
);
1991 ovsdb_idl_row_update(struct ovsdb_idl_row
*row
, const struct json
*row_json
,
1992 enum ovsdb_idl_change change
)
1994 return ovsdb_idl_row_change__(row
, row_json
, NULL
, change
);
1998 ovsdb_idl_row_apply_diff(struct ovsdb_idl_row
*row
,
1999 const struct json
*diff_json
,
2000 enum ovsdb_idl_change change
)
2002 return ovsdb_idl_row_change__(row
, NULL
, diff_json
, change
);
2005 /* When a row A refers to row B through a column with a "refTable" constraint,
2006 * but row B does not exist, row B is called an "orphan row". Orphan rows
2007 * should not persist, because the database enforces referential integrity, but
2008 * they can appear transiently as changes from the database are received (the
2009 * database doesn't try to topologically sort them and circular references mean
2010 * it isn't always possible anyhow).
2012 * This function returns true if 'row' is an orphan row, otherwise false.
2015 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row
*row
)
2017 return !row
->old_datum
&& !row
->new_datum
;
2020 /* Returns true if 'row' is conceptually part of the database as modified by
2021 * the current transaction (if any), false otherwise.
2023 * This function will return true if 'row' is not an orphan (see the comment on
2024 * ovsdb_idl_row_is_orphan()) and:
2026 * - 'row' exists in the database and has not been deleted within the
2027 * current transaction (if any).
2029 * - 'row' was inserted within the current transaction and has not been
2030 * deleted. (In the latter case you should not have passed 'row' in at
2031 * all, because ovsdb_idl_txn_delete() freed it.)
2033 * This function will return false if 'row' is an orphan or if 'row' was
2034 * deleted within the current transaction.
2037 ovsdb_idl_row_exists(const struct ovsdb_idl_row
*row
)
2039 return row
->new_datum
!= NULL
;
2043 ovsdb_idl_row_parse(struct ovsdb_idl_row
*row
)
2045 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2048 for (i
= 0; i
< class->n_columns
; i
++) {
2049 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2050 (c
->parse
)(row
, &row
->old_datum
[i
]);
2055 ovsdb_idl_row_unparse(struct ovsdb_idl_row
*row
)
2057 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2060 for (i
= 0; i
< class->n_columns
; i
++) {
2061 const struct ovsdb_idl_column
*c
= &class->columns
[i
];
2066 /* The OVSDB-IDL Compound Indexes feature allows for the creation of custom
2067 * table indexes over one or more columns in the IDL. These indexes provide
2068 * the ability to retrieve rows matching a particular search criteria and to
2069 * iterate over a subset of rows in a defined order.
2072 /* Creates a new index with the provided name, attached to the given idl and
2073 * table. Note that all indexes must be created and indexing columns added
2074 * before the first call to ovsdb_idl_run() is made.
2076 struct ovsdb_idl_index
*
2077 ovsdb_idl_create_index(struct ovsdb_idl
*idl
,
2078 const struct ovsdb_idl_table_class
*tc
,
2079 const char *index_name
)
2081 struct ovsdb_idl_index
*index
;
2084 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
2085 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
2087 if (table
->class_
== tc
) {
2088 index
= ovsdb_idl_create_index_(table
, 1);
2089 if (!shash_add_once(&table
->indexes
, index_name
, index
)) {
2090 VLOG_ERR("Duplicate index name '%s' in table %s",
2091 index_name
, table
->class_
->name
);
2094 index
->index_name
= index_name
;
2102 /* Generic comparator that can compare each index, using the custom
2103 * configuration (an struct ovsdb_idl_index) passed to it.
2104 * Not intended for direct usage.
2107 ovsdb_idl_index_generic_comparer(const void *a
,
2108 const void *b
, const void *conf
)
2110 const struct ovsdb_idl_column
*column
;
2111 const struct ovsdb_idl_index
*index
;
2114 index
= CONST_CAST(struct ovsdb_idl_index
*, conf
);
2120 for (i
= 0; i
< index
->n_columns
; i
++) {
2122 if (index
->columns
[i
].comparer
) {
2123 val
= index
->columns
[i
].comparer(a
, b
);
2125 column
= index
->columns
[i
].column
;
2126 const struct ovsdb_idl_row
*row_a
, *row_b
;
2127 row_a
= CONST_CAST(struct ovsdb_idl_row
*, a
);
2128 row_b
= CONST_CAST(struct ovsdb_idl_row
*, b
);
2129 const struct ovsdb_datum
*datum_a
, *datum_b
;
2130 datum_a
= ovsdb_idl_read(row_a
, column
);
2131 datum_b
= ovsdb_idl_read(row_b
, column
);
2132 val
= ovsdb_datum_compare_3way(datum_a
, datum_b
, &column
->type
);
2136 return val
* index
->columns
[i
].sorting_order
;
2140 /* If ins_del is true then a row is being inserted into or deleted from
2141 * the index list. In this case, we augment the search key with
2142 * additional values (row UUID and memory address) to create a unique
2143 * search key in order to locate the correct entry efficiently and to
2144 * ensure that the correct entry is deleted in the case of a "delete"
2147 if (index
->ins_del
) {
2148 const struct ovsdb_idl_row
*row_a
, *row_b
;
2150 row_a
= (const struct ovsdb_idl_row
*) a
;
2151 row_b
= (const struct ovsdb_idl_row
*) b
;
2152 int value
= uuid_compare_3way(&row_a
->uuid
, &row_b
->uuid
);
2154 return value
? value
: (a
< b
) - (a
> b
);
2160 static struct ovsdb_idl_index
*
2161 ovsdb_idl_create_index_(const struct ovsdb_idl_table
*table
,
2162 size_t allocated_cols
)
2164 struct ovsdb_idl_index
*index
;
2166 index
= xmalloc(sizeof (struct ovsdb_idl_index
));
2167 index
->n_columns
= 0;
2168 index
->alloc_columns
= allocated_cols
;
2169 index
->skiplist
= skiplist_create(ovsdb_idl_index_generic_comparer
, index
);
2170 index
->columns
= xmalloc(allocated_cols
*
2171 sizeof (struct ovsdb_idl_index_column
));
2172 index
->ins_del
= false;
2173 index
->table
= table
;
2178 ovsdb_idl_destroy_indexes(struct ovsdb_idl_table
*table
)
2180 struct ovsdb_idl_index
*index
;
2181 struct shash_node
*node
;
2183 SHASH_FOR_EACH (node
, &(table
->indexes
)) {
2185 skiplist_destroy(index
->skiplist
, NULL
);
2186 free(index
->columns
);
2188 shash_destroy_free_data(&table
->indexes
);
2192 ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row
*row
)
2194 struct ovsdb_idl_table
*table
= row
->table
;
2195 struct ovsdb_idl_index
*index
;
2196 struct shash_node
*node
;
2198 SHASH_FOR_EACH (node
, &(table
->indexes
)) {
2200 index
->ins_del
= true;
2201 skiplist_insert(index
->skiplist
, row
);
2202 index
->ins_del
= false;
2207 ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row
*row
)
2209 struct ovsdb_idl_table
*table
= row
->table
;
2210 struct ovsdb_idl_index
*index
;
2211 struct shash_node
*node
;
2213 SHASH_FOR_EACH (node
, &(table
->indexes
)) {
2215 index
->ins_del
= true;
2216 skiplist_delete(index
->skiplist
, row
);
2217 index
->ins_del
= false;
2221 /* Adds a column to an existing index (note that columns can only be added to
2222 * an index before the first call to ovsdb_idl_run()). The 'order' parameter
2223 * specifies whether the sort order should be ascending (OVSDB_INDEX_ASC) or
2224 * descending (OVSDB_INDEX_DESC). The 'custom_comparer' parameter, if non-NULL,
2225 * contains a pointer to a custom comparison function. A default comparison
2226 * function is used if a custom comparison function is not provided (the
2227 * default comparison function can only be used for columns of type string,
2228 * uuid, integer, real, or boolean).
2231 ovsdb_idl_index_add_column(struct ovsdb_idl_index
*index
,
2232 const struct ovsdb_idl_column
*column
,
2233 int order
, column_comparator
*custom_comparer
)
2235 /* Check that the column or table is tracked */
2236 if (!index
->table
->need_table
&&
2237 !((OVSDB_IDL_MONITOR
| OVSDB_IDL_ALERT
) &
2238 *ovsdb_idl_get_mode(index
->table
->idl
, column
))) {
2239 VLOG_ERR("Can't add unmonitored column '%s' at index '%s' in "
2241 column
->name
, index
->index_name
, index
->table
->class_
->name
);
2243 if (!ovsdb_type_is_scalar(&column
->type
) && !custom_comparer
) {
2244 VLOG_WARN("Comparing non-scalar values.");
2247 /* Allocate more memory for column configuration */
2248 if (index
->n_columns
== index
->alloc_columns
) {
2249 index
->alloc_columns
++;
2250 index
->columns
= xrealloc(index
->columns
,
2251 index
->alloc_columns
*
2252 sizeof(struct ovsdb_idl_index_column
));
2255 /* Append column to index */
2256 int i
= index
->n_columns
;
2258 index
->columns
[i
].column
= column
;
2259 index
->columns
[i
].comparer
= custom_comparer
? custom_comparer
: NULL
;
2260 if (order
== OVSDB_INDEX_ASC
) {
2261 index
->columns
[i
].sorting_order
= OVSDB_INDEX_ASC
;
2263 index
->columns
[i
].sorting_order
= OVSDB_INDEX_DESC
;
2269 ovsdb_idl_initialize_cursor(struct ovsdb_idl
*idl
,
2270 const struct ovsdb_idl_table_class
*tc
,
2271 const char *index_name
,
2272 struct ovsdb_idl_index_cursor
*cursor
)
2276 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
2277 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
2279 if (table
->class_
== tc
) {
2280 struct shash_node
*node
= shash_find(&table
->indexes
, index_name
);
2282 if (!node
|| !node
->data
) {
2283 VLOG_ERR("Cursor initialization failed, "
2284 "index %s at table %s does not exist.",
2285 index_name
, tc
->name
);
2286 cursor
->index
= NULL
;
2287 cursor
->position
= NULL
;
2290 cursor
->index
= node
->data
;
2291 cursor
->position
= skiplist_first(cursor
->index
->skiplist
);
2295 VLOG_ERR("Cursor initialization failed, "
2296 "index %s at table %s does not exist.", index_name
, tc
->name
);
2300 /* ovsdb_idl_index_write_ writes a datum in an ovsdb_idl_row,
2301 * and updates the corresponding field in the table record.
2302 * Not intended for direct usage.
2305 ovsdb_idl_index_write_(struct ovsdb_idl_row
*const_row
,
2306 const struct ovsdb_idl_column
*column
,
2307 struct ovsdb_datum
*datum
,
2308 const struct ovsdb_idl_table_class
*class)
2310 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, const_row
);
2311 size_t column_idx
= column
- class->columns
;
2313 if (bitmap_is_set(row
->written
, column_idx
)) {
2314 free(row
->new_datum
[column_idx
].values
);
2315 free(row
->new_datum
[column_idx
].keys
);
2317 bitmap_set1(row
->written
, column_idx
);
2319 row
->new_datum
[column_idx
] = *datum
;
2320 (column
->unparse
)(row
);
2321 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
2324 /* Magic UUID for index rows */
2325 static const struct uuid index_row_uuid
= {
2326 .parts
= {0xdeadbeef,
2331 /* Check if a row is an index row */
2333 is_index_row(struct ovsdb_idl_row
*row
)
2335 return uuid_equals(&row
->uuid
, &index_row_uuid
);
2338 /* Initializes a row for use in an indexed query.
2339 * Not intended for direct usage.
2341 struct ovsdb_idl_row
*
2342 ovsdb_idl_index_init_row(struct ovsdb_idl
* idl
,
2343 const struct ovsdb_idl_table_class
*class)
2345 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2346 class->row_init(row
);
2347 row
->uuid
= index_row_uuid
;
2348 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
2349 row
->written
= bitmap_allocate(class->n_columns
);
2350 row
->table
= ovsdb_idl_table_from_class(idl
, class);
2351 /* arcs are not used for index row, but it doesn't harm to initialize */
2352 ovs_list_init(&row
->src_arcs
);
2353 ovs_list_init(&row
->dst_arcs
);
2357 /* Destroys 'row_' and frees all associated memory. This function is intended
2358 * to be used indirectly through one of the "index_destroy_row" functions
2359 * generated by ovsdb-idlc.
2362 ovsdb_idl_index_destroy_row__(const struct ovsdb_idl_row
*row_
)
2364 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
2365 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2366 const struct ovsdb_idl_column
*c
;
2369 ovs_assert(ovs_list_is_empty(&row_
->src_arcs
));
2370 ovs_assert(ovs_list_is_empty(&row_
->dst_arcs
));
2371 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2372 c
= &class->columns
[i
];
2374 free(row
->new_datum
[i
].values
);
2375 free(row
->new_datum
[i
].keys
);
2377 free(row
->new_datum
);
2382 /* Moves the cursor to the first entry in the index. Returns a pointer to the
2383 * corresponding ovsdb_idl_row, or NULL if the index list is empy.
2385 struct ovsdb_idl_row
*
2386 ovsdb_idl_index_first(struct ovsdb_idl_index_cursor
*cursor
)
2388 cursor
->position
= skiplist_first(cursor
->index
->skiplist
);
2389 return ovsdb_idl_index_data(cursor
);
2392 /* Moves the cursor to the next record in the index list.
2394 struct ovsdb_idl_row
*
2395 ovsdb_idl_index_next(struct ovsdb_idl_index_cursor
*cursor
)
2397 if (!cursor
->position
) {
2400 cursor
->position
= skiplist_next(cursor
->position
);
2401 return ovsdb_idl_index_data(cursor
);
2404 /* Returns the ovsdb_idl_row pointer corresponding to the record at the
2405 * current cursor location.
2407 struct ovsdb_idl_row
*
2408 ovsdb_idl_index_data(struct ovsdb_idl_index_cursor
*cursor
)
2410 return skiplist_get_data(cursor
->position
);
2413 /* Moves the cursor to the first entry in the index matching the specified
2414 * value. If 'value' is NULL, the cursor is moved to the last entry in the
2415 * list. Returns a pointer to the corresponding ovsdb_idl_row or NULL.
2417 struct ovsdb_idl_row
*
2418 ovsdb_idl_index_find(struct ovsdb_idl_index_cursor
*cursor
,
2419 struct ovsdb_idl_row
*value
)
2422 cursor
->position
= skiplist_find(cursor
->index
->skiplist
, value
);
2424 cursor
->position
= skiplist_first(cursor
->index
->skiplist
);
2426 return ovsdb_idl_index_data(cursor
);
2429 /* Moves the cursor to the first entry in the index with a value greater than
2430 * or equal to the given value. If 'value' is NULL, the cursor is moved to the
2431 * first entry in the index. Returns a pointer to the corresponding
2432 * ovsdb_idl_row or NULL if such a row does not exist.
2434 struct ovsdb_idl_row
*
2435 ovsdb_idl_index_forward_to(struct ovsdb_idl_index_cursor
*cursor
,
2436 struct ovsdb_idl_row
*value
)
2439 cursor
->position
= skiplist_forward_to(cursor
->index
->skiplist
, value
);
2441 cursor
->position
= skiplist_first(cursor
->index
->skiplist
);
2443 return ovsdb_idl_index_data(cursor
);
2446 /* Returns the result of comparing two rows using the comparison function
2452 * When the pointer to either row is NULL, this function considers NULL to be
2453 * greater than any other value, and NULL == NULL.
2456 ovsdb_idl_index_compare(struct ovsdb_idl_index_cursor
*cursor
,
2457 struct ovsdb_idl_row
*a
, struct ovsdb_idl_row
*b
)
2460 return ovsdb_idl_index_generic_comparer(a
, b
, cursor
->index
);
2461 } else if (!a
&& !b
) {
2471 ovsdb_idl_row_clear_old(struct ovsdb_idl_row
*row
)
2473 ovs_assert(row
->old_datum
== row
->new_datum
);
2474 if (!ovsdb_idl_row_is_orphan(row
)) {
2475 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2478 for (i
= 0; i
< class->n_columns
; i
++) {
2479 ovsdb_datum_destroy(&row
->old_datum
[i
], &class->columns
[i
].type
);
2481 free(row
->old_datum
);
2482 row
->old_datum
= row
->new_datum
= NULL
;
2487 ovsdb_idl_row_clear_new(struct ovsdb_idl_row
*row
)
2489 if (row
->old_datum
!= row
->new_datum
) {
2490 if (row
->new_datum
) {
2491 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2495 BITMAP_FOR_EACH_1 (i
, class->n_columns
, row
->written
) {
2496 ovsdb_datum_destroy(&row
->new_datum
[i
],
2497 &class->columns
[i
].type
);
2500 free(row
->new_datum
);
2502 row
->written
= NULL
;
2504 row
->new_datum
= row
->old_datum
;
2509 ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row
*row
, bool destroy_dsts
)
2511 struct ovsdb_idl_arc
*arc
, *next
;
2513 /* Delete all forward arcs. If 'destroy_dsts', destroy any orphaned rows
2514 * that this causes to be unreferenced, if tracking is not enabled.
2515 * If tracking is enabled, orphaned nodes are removed from hmap but not
2518 LIST_FOR_EACH_SAFE (arc
, next
, src_node
, &row
->src_arcs
) {
2519 ovs_list_remove(&arc
->dst_node
);
2521 && ovsdb_idl_row_is_orphan(arc
->dst
)
2522 && ovs_list_is_empty(&arc
->dst
->dst_arcs
)) {
2523 ovsdb_idl_row_destroy(arc
->dst
);
2527 ovs_list_init(&row
->src_arcs
);
2530 /* Force nodes that reference 'row' to reparse. */
2532 ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row
*row
)
2534 struct ovsdb_idl_arc
*arc
, *next
;
2536 /* This is trickier than it looks. ovsdb_idl_row_clear_arcs() will destroy
2537 * 'arc', so we need to use the "safe" variant of list traversal. However,
2538 * calling an ovsdb_idl_column's 'parse' function will add an arc
2539 * equivalent to 'arc' to row->arcs. That could be a problem for
2540 * traversal, but it adds it at the beginning of the list to prevent us
2541 * from stumbling upon it again.
2543 * (If duplicate arcs were possible then we would need to make sure that
2544 * 'next' didn't also point into 'arc''s destination, but we forbid
2545 * duplicate arcs.) */
2546 LIST_FOR_EACH_SAFE (arc
, next
, dst_node
, &row
->dst_arcs
) {
2547 struct ovsdb_idl_row
*ref
= arc
->src
;
2549 ovsdb_idl_row_unparse(ref
);
2550 ovsdb_idl_row_clear_arcs(ref
, false);
2551 ovsdb_idl_row_parse(ref
);
2555 static struct ovsdb_idl_row
*
2556 ovsdb_idl_row_create__(const struct ovsdb_idl_table_class
*class)
2558 struct ovsdb_idl_row
*row
= xzalloc(class->allocation_size
);
2559 class->row_init(row
);
2560 ovs_list_init(&row
->src_arcs
);
2561 ovs_list_init(&row
->dst_arcs
);
2562 hmap_node_nullify(&row
->txn_node
);
2563 ovs_list_init(&row
->track_node
);
2567 static struct ovsdb_idl_row
*
2568 ovsdb_idl_row_create(struct ovsdb_idl_table
*table
, const struct uuid
*uuid
)
2570 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(table
->class_
);
2571 hmap_insert(&table
->rows
, &row
->hmap_node
, uuid_hash(uuid
));
2574 row
->map_op_written
= NULL
;
2575 row
->map_op_lists
= NULL
;
2576 row
->set_op_written
= NULL
;
2577 row
->set_op_lists
= NULL
;
2582 ovsdb_idl_row_destroy(struct ovsdb_idl_row
*row
)
2585 ovsdb_idl_row_clear_old(row
);
2586 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
2587 ovsdb_idl_destroy_all_map_op_lists(row
);
2588 ovsdb_idl_destroy_all_set_op_lists(row
);
2589 if (ovsdb_idl_track_is_set(row
->table
)) {
2590 row
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2591 = row
->table
->change_seqno
[OVSDB_IDL_CHANGE_DELETE
]
2592 = row
->table
->idl
->change_seqno
+ 1;
2594 if (!ovs_list_is_empty(&row
->track_node
)) {
2595 ovs_list_remove(&row
->track_node
);
2597 ovs_list_push_back(&row
->table
->track_list
, &row
->track_node
);
2602 ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row
*row
)
2604 if (row
->map_op_written
) {
2605 /* Clear Map Operation Lists */
2606 size_t idx
, n_columns
;
2607 const struct ovsdb_idl_column
*columns
;
2608 const struct ovsdb_type
*type
;
2609 n_columns
= row
->table
->class_
->n_columns
;
2610 columns
= row
->table
->class_
->columns
;
2611 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->map_op_written
) {
2612 type
= &columns
[idx
].type
;
2613 map_op_list_destroy(row
->map_op_lists
[idx
], type
);
2615 free(row
->map_op_lists
);
2616 bitmap_free(row
->map_op_written
);
2617 row
->map_op_lists
= NULL
;
2618 row
->map_op_written
= NULL
;
2623 ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row
*row
)
2625 if (row
->set_op_written
) {
2626 /* Clear Set Operation Lists */
2627 size_t idx
, n_columns
;
2628 const struct ovsdb_idl_column
*columns
;
2629 const struct ovsdb_type
*type
;
2630 n_columns
= row
->table
->class_
->n_columns
;
2631 columns
= row
->table
->class_
->columns
;
2632 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->set_op_written
) {
2633 type
= &columns
[idx
].type
;
2634 set_op_list_destroy(row
->set_op_lists
[idx
], type
);
2636 free(row
->set_op_lists
);
2637 bitmap_free(row
->set_op_written
);
2638 row
->set_op_lists
= NULL
;
2639 row
->set_op_written
= NULL
;
2644 ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl
*idl
)
2648 for (i
= 0; i
< idl
->class_
->n_tables
; i
++) {
2649 struct ovsdb_idl_table
*table
= &idl
->tables
[i
];
2651 if (!ovs_list_is_empty(&table
->track_list
)) {
2652 struct ovsdb_idl_row
*row
, *next
;
2654 LIST_FOR_EACH_SAFE(row
, next
, track_node
, &table
->track_list
) {
2655 if (!ovsdb_idl_track_is_set(row
->table
)) {
2656 ovs_list_remove(&row
->track_node
);
2665 ovsdb_idl_insert_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
2667 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
2668 size_t i
, datum_size
;
2670 ovs_assert(!row
->old_datum
&& !row
->new_datum
);
2671 datum_size
= class->n_columns
* sizeof *row
->old_datum
;
2672 row
->old_datum
= row
->new_datum
= xmalloc(datum_size
);
2673 for (i
= 0; i
< class->n_columns
; i
++) {
2674 ovsdb_datum_init_default(&row
->old_datum
[i
], &class->columns
[i
].type
);
2676 ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_INSERT
);
2677 ovsdb_idl_row_parse(row
);
2679 ovsdb_idl_row_reparse_backrefs(row
);
2680 ovsdb_idl_add_to_indexes(row
);
2684 ovsdb_idl_delete_row(struct ovsdb_idl_row
*row
)
2686 ovsdb_idl_remove_from_indexes(row
);
2687 ovsdb_idl_row_unparse(row
);
2688 ovsdb_idl_row_clear_arcs(row
, true);
2689 ovsdb_idl_row_clear_old(row
);
2690 if (ovs_list_is_empty(&row
->dst_arcs
)) {
2691 ovsdb_idl_row_destroy(row
);
2693 ovsdb_idl_row_reparse_backrefs(row
);
2697 /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
2700 ovsdb_idl_modify_row(struct ovsdb_idl_row
*row
, const struct json
*row_json
)
2704 ovsdb_idl_remove_from_indexes(row
);
2705 ovsdb_idl_row_unparse(row
);
2706 ovsdb_idl_row_clear_arcs(row
, true);
2707 changed
= ovsdb_idl_row_update(row
, row_json
, OVSDB_IDL_CHANGE_MODIFY
);
2708 ovsdb_idl_row_parse(row
);
2709 ovsdb_idl_add_to_indexes(row
);
2715 ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row
*row
,
2716 const struct json
*diff_json
)
2720 ovsdb_idl_row_unparse(row
);
2721 ovsdb_idl_row_clear_arcs(row
, true);
2722 changed
= ovsdb_idl_row_apply_diff(row
, diff_json
,
2723 OVSDB_IDL_CHANGE_MODIFY
);
2724 ovsdb_idl_row_parse(row
);
2730 may_add_arc(const struct ovsdb_idl_row
*src
, const struct ovsdb_idl_row
*dst
)
2732 const struct ovsdb_idl_arc
*arc
;
2739 /* No duplicate arcs.
2741 * We only need to test whether the first arc in dst->dst_arcs originates
2742 * at 'src', since we add all of the arcs from a given source in a clump
2743 * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
2744 * added at the front of the dst_arcs list. */
2745 if (ovs_list_is_empty(&dst
->dst_arcs
)) {
2748 arc
= CONTAINER_OF(dst
->dst_arcs
.next
, struct ovsdb_idl_arc
, dst_node
);
2749 return arc
->src
!= src
;
2752 static struct ovsdb_idl_table
*
2753 ovsdb_idl_table_from_class(const struct ovsdb_idl
*idl
,
2754 const struct ovsdb_idl_table_class
*table_class
)
2756 return &idl
->tables
[table_class
- idl
->class_
->tables
];
2759 /* Called by ovsdb-idlc generated code. */
2760 struct ovsdb_idl_row
*
2761 ovsdb_idl_get_row_arc(struct ovsdb_idl_row
*src
,
2762 const struct ovsdb_idl_table_class
*dst_table_class
,
2763 const struct uuid
*dst_uuid
)
2765 struct ovsdb_idl
*idl
= src
->table
->idl
;
2766 struct ovsdb_idl_table
*dst_table
;
2767 struct ovsdb_idl_arc
*arc
;
2768 struct ovsdb_idl_row
*dst
;
2770 dst_table
= ovsdb_idl_table_from_class(idl
, dst_table_class
);
2771 dst
= ovsdb_idl_get_row(dst_table
, dst_uuid
);
2772 if (idl
->txn
|| is_index_row(src
)) {
2773 /* There are two cases we should not update any arcs:
2775 * 1. We're being called from ovsdb_idl_txn_write(). We must not update
2776 * any arcs, because the transaction will be backed out at commit or
2777 * abort time and we don't want our graph screwed up.
2779 * 2. The row is used as an index for querying purpose only.
2781 * In these cases, just return the destination row, if there is one and
2782 * it has not been deleted. */
2783 if (dst
&& (hmap_node_is_null(&dst
->txn_node
) || dst
->new_datum
)) {
2788 /* We're being called from some other context. Update the graph. */
2790 dst
= ovsdb_idl_row_create(dst_table
, dst_uuid
);
2793 /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
2794 if (may_add_arc(src
, dst
)) {
2795 /* The arc *must* be added at the front of the dst_arcs list. See
2796 * ovsdb_idl_row_reparse_backrefs() for details. */
2797 arc
= xmalloc(sizeof *arc
);
2798 ovs_list_push_front(&src
->src_arcs
, &arc
->src_node
);
2799 ovs_list_push_front(&dst
->dst_arcs
, &arc
->dst_node
);
2804 return !ovsdb_idl_row_is_orphan(dst
) ? dst
: NULL
;
2808 /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'. Returns a
2809 * pointer to the row if there is one, otherwise a null pointer. */
2810 const struct ovsdb_idl_row
*
2811 ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl
*idl
,
2812 const struct ovsdb_idl_table_class
*tc
,
2813 const struct uuid
*uuid
)
2815 return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl
, tc
), uuid
);
2818 static struct ovsdb_idl_row
*
2819 next_real_row(struct ovsdb_idl_table
*table
, struct hmap_node
*node
)
2821 for (; node
; node
= hmap_next(&table
->rows
, node
)) {
2822 struct ovsdb_idl_row
*row
;
2824 row
= CONTAINER_OF(node
, struct ovsdb_idl_row
, hmap_node
);
2825 if (ovsdb_idl_row_exists(row
)) {
2832 /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
2835 * Database tables are internally maintained as hash tables, so adding or
2836 * removing rows while traversing the same table can cause some rows to be
2837 * visited twice or not at apply. */
2838 const struct ovsdb_idl_row
*
2839 ovsdb_idl_first_row(const struct ovsdb_idl
*idl
,
2840 const struct ovsdb_idl_table_class
*table_class
)
2842 struct ovsdb_idl_table
*table
2843 = ovsdb_idl_table_from_class(idl
, table_class
);
2844 return next_real_row(table
, hmap_first(&table
->rows
));
2847 /* Returns a row following 'row' within its table, or a null pointer if 'row'
2848 * is the last row in its table. */
2849 const struct ovsdb_idl_row
*
2850 ovsdb_idl_next_row(const struct ovsdb_idl_row
*row
)
2852 struct ovsdb_idl_table
*table
= row
->table
;
2854 return next_real_row(table
, hmap_next(&table
->rows
, &row
->hmap_node
));
2857 /* Reads and returns the value of 'column' within 'row'. If an ongoing
2858 * transaction has changed 'column''s value, the modified value is returned.
2860 * The caller must not modify or free the returned value.
2862 * Various kinds of changes can invalidate the returned value: writing to the
2863 * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
2864 * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
2865 * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()). If the
2866 * returned value is needed for a long time, it is best to make a copy of it
2867 * with ovsdb_datum_clone(). */
2868 const struct ovsdb_datum
*
2869 ovsdb_idl_read(const struct ovsdb_idl_row
*row
,
2870 const struct ovsdb_idl_column
*column
)
2872 const struct ovsdb_idl_table_class
*class;
2875 ovs_assert(!ovsdb_idl_row_is_synthetic(row
));
2877 class = row
->table
->class_
;
2878 column_idx
= column
- class->columns
;
2880 ovs_assert(row
->new_datum
!= NULL
);
2881 ovs_assert(column_idx
< class->n_columns
);
2883 if (row
->written
&& bitmap_is_set(row
->written
, column_idx
)) {
2884 return &row
->new_datum
[column_idx
];
2885 } else if (row
->old_datum
) {
2886 return &row
->old_datum
[column_idx
];
2888 return ovsdb_datum_default(&column
->type
);
2892 /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
2893 * type 'key_type' and value type 'value_type'. (Scalar and set types will
2894 * have a value type of OVSDB_TYPE_VOID.)
2896 * This is useful in code that "knows" that a particular column has a given
2897 * type, so that it will abort if someone changes the column's type without
2898 * updating the code that uses it. */
2899 const struct ovsdb_datum
*
2900 ovsdb_idl_get(const struct ovsdb_idl_row
*row
,
2901 const struct ovsdb_idl_column
*column
,
2902 enum ovsdb_atomic_type key_type OVS_UNUSED
,
2903 enum ovsdb_atomic_type value_type OVS_UNUSED
)
2905 ovs_assert(column
->type
.key
.type
== key_type
);
2906 ovs_assert(column
->type
.value
.type
== value_type
);
2908 return ovsdb_idl_read(row
, column
);
2911 /* Returns true if the field represented by 'column' in 'row' may be modified,
2912 * false if it is immutable.
2914 * Normally, whether a field is mutable is controlled by its column's schema.
2915 * However, an immutable column can be set to any initial value at the time of
2916 * insertion, so if 'row' is a new row (one that is being added as part of the
2917 * current transaction, supposing that a transaction is in progress) then even
2918 * its "immutable" fields are actually mutable. */
2920 ovsdb_idl_is_mutable(const struct ovsdb_idl_row
*row
,
2921 const struct ovsdb_idl_column
*column
)
2923 return column
->is_mutable
|| (row
->new_datum
&& !row
->old_datum
);
2926 /* Returns false if 'row' was obtained from the IDL, true if it was initialized
2927 * to all-zero-bits by some other entity. If 'row' was set up some other way
2928 * then the return value is indeterminate. */
2930 ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row
*row
)
2932 return row
->table
== NULL
;
2937 static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
2938 enum ovsdb_idl_txn_status
);
2940 /* Returns a string representation of 'status'. The caller must not modify or
2941 * free the returned string.
2943 * The return value is probably useful only for debug log messages and unit
2946 ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status
)
2949 case TXN_UNCOMMITTED
:
2950 return "uncommitted";
2953 case TXN_INCOMPLETE
:
2954 return "incomplete";
2961 case TXN_NOT_LOCKED
:
2962 return "not locked";
2969 /* Starts a new transaction on 'idl'. A given ovsdb_idl may only have a single
2970 * active transaction at a time. See the large comment in ovsdb-idl.h for
2971 * general information on transactions. */
2972 struct ovsdb_idl_txn
*
2973 ovsdb_idl_txn_create(struct ovsdb_idl
*idl
)
2975 struct ovsdb_idl_txn
*txn
;
2977 ovs_assert(!idl
->txn
);
2978 idl
->txn
= txn
= xmalloc(sizeof *txn
);
2979 txn
->request_id
= NULL
;
2981 hmap_init(&txn
->txn_rows
);
2982 txn
->status
= TXN_UNCOMMITTED
;
2984 txn
->dry_run
= false;
2985 ds_init(&txn
->comment
);
2987 txn
->inc_table
= NULL
;
2988 txn
->inc_column
= NULL
;
2990 hmap_init(&txn
->inserted_rows
);
2995 /* Appends 's', which is treated as a printf()-type format string, to the
2996 * comments that will be passed to the OVSDB server when 'txn' is committed.
2997 * (The comment will be committed to the OVSDB log, which "ovsdb-tool
2998 * show-log" can print in a relatively human-readable form.) */
3000 ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn
*txn
, const char *s
, ...)
3004 if (txn
->comment
.length
) {
3005 ds_put_char(&txn
->comment
, '\n');
3009 ds_put_format_valist(&txn
->comment
, s
, args
);
3013 /* Marks 'txn' as a transaction that will not actually modify the database. In
3014 * almost every way, the transaction is treated like other transactions. It
3015 * must be committed or aborted like other transactions, it will be sent to the
3016 * database server like other transactions, and so on. The only difference is
3017 * that the operations sent to the database server will include, as the last
3018 * step, an "abort" operation, so that any changes made by the transaction will
3019 * not actually take effect. */
3021 ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn
*txn
)
3023 txn
->dry_run
= true;
3026 /* Causes 'txn', when committed, to increment the value of 'column' within
3027 * 'row' by 1. 'column' must have an integer type. After 'txn' commits
3028 * successfully, the client may retrieve the final (incremented) value of
3029 * 'column' with ovsdb_idl_txn_get_increment_new_value().
3031 * If at time of commit the transaction is otherwise empty, that is, it doesn't
3032 * change the database, then 'force' is important. If 'force' is false in this
3033 * case, the IDL suppresses the increment and skips a round trip to the
3034 * database server. If 'force' is true, the IDL will still increment the
3037 * The client could accomplish something similar with ovsdb_idl_read(),
3038 * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
3039 * generated wrappers for these functions. However, ovsdb_idl_txn_increment()
3040 * will never (by itself) fail because of a verify error.
3042 * The intended use is for incrementing the "next_cfg" column in the
3043 * Open_vSwitch table. */
3045 ovsdb_idl_txn_increment(struct ovsdb_idl_txn
*txn
,
3046 const struct ovsdb_idl_row
*row
,
3047 const struct ovsdb_idl_column
*column
,
3050 ovs_assert(!txn
->inc_table
);
3051 ovs_assert(column
->type
.key
.type
== OVSDB_TYPE_INTEGER
);
3052 ovs_assert(column
->type
.value
.type
== OVSDB_TYPE_VOID
);
3054 txn
->inc_table
= row
->table
->class_
->name
;
3055 txn
->inc_column
= column
->name
;
3056 txn
->inc_row
= row
->uuid
;
3057 txn
->inc_force
= force
;
3060 /* Destroys 'txn' and frees all associated memory. If ovsdb_idl_txn_commit()
3061 * has been called for 'txn' but the commit is still incomplete (that is, the
3062 * last call returned TXN_INCOMPLETE) then the transaction may or may not still
3063 * end up committing at the database server, but the client will not be able to
3064 * get any further status information back. */
3066 ovsdb_idl_txn_destroy(struct ovsdb_idl_txn
*txn
)
3068 struct ovsdb_idl_txn_insert
*insert
, *next
;
3070 json_destroy(txn
->request_id
);
3071 if (txn
->status
== TXN_INCOMPLETE
) {
3072 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
3074 ovsdb_idl_txn_abort(txn
);
3075 ds_destroy(&txn
->comment
);
3077 HMAP_FOR_EACH_SAFE (insert
, next
, hmap_node
, &txn
->inserted_rows
) {
3080 hmap_destroy(&txn
->inserted_rows
);
3084 /* Causes poll_block() to wake up if 'txn' has completed committing. */
3086 ovsdb_idl_txn_wait(const struct ovsdb_idl_txn
*txn
)
3088 if (txn
->status
!= TXN_UNCOMMITTED
&& txn
->status
!= TXN_INCOMPLETE
) {
3089 poll_immediate_wake();
3093 static struct json
*
3094 where_uuid_equals(const struct uuid
*uuid
)
3097 json_array_create_1(
3098 json_array_create_3(
3099 json_string_create("_uuid"),
3100 json_string_create("=="),
3101 json_array_create_2(
3102 json_string_create("uuid"),
3103 json_string_create_nocopy(
3104 xasprintf(UUID_FMT
, UUID_ARGS(uuid
))))));
3108 uuid_name_from_uuid(const struct uuid
*uuid
)
3113 name
= xasprintf("row"UUID_FMT
, UUID_ARGS(uuid
));
3114 for (p
= name
; *p
!= '\0'; p
++) {
3123 static const struct ovsdb_idl_row
*
3124 ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn
*txn
, const struct uuid
*uuid
)
3126 const struct ovsdb_idl_row
*row
;
3128 HMAP_FOR_EACH_WITH_HASH (row
, txn_node
, uuid_hash(uuid
), &txn
->txn_rows
) {
3129 if (uuid_equals(&row
->uuid
, uuid
)) {
3136 /* XXX there must be a cleaner way to do this */
3137 static struct json
*
3138 substitute_uuids(struct json
*json
, const struct ovsdb_idl_txn
*txn
)
3140 if (json
->type
== JSON_ARRAY
) {
3144 if (json
->u
.array
.n
== 2
3145 && json
->u
.array
.elems
[0]->type
== JSON_STRING
3146 && json
->u
.array
.elems
[1]->type
== JSON_STRING
3147 && !strcmp(json
->u
.array
.elems
[0]->u
.string
, "uuid")
3148 && uuid_from_string(&uuid
, json
->u
.array
.elems
[1]->u
.string
)) {
3149 const struct ovsdb_idl_row
*row
;
3151 row
= ovsdb_idl_txn_get_row(txn
, &uuid
);
3152 if (row
&& !row
->old_datum
&& row
->new_datum
) {
3155 return json_array_create_2(
3156 json_string_create("named-uuid"),
3157 json_string_create_nocopy(uuid_name_from_uuid(&uuid
)));
3161 for (i
= 0; i
< json
->u
.array
.n
; i
++) {
3162 json
->u
.array
.elems
[i
] = substitute_uuids(json
->u
.array
.elems
[i
],
3165 } else if (json
->type
== JSON_OBJECT
) {
3166 struct shash_node
*node
;
3168 SHASH_FOR_EACH (node
, json_object(json
)) {
3169 node
->data
= substitute_uuids(node
->data
, txn
);
3176 ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn
*txn
)
3178 struct ovsdb_idl_row
*row
, *next
;
3180 /* This must happen early. Otherwise, ovsdb_idl_row_parse() will call an
3181 * ovsdb_idl_column's 'parse' function, which will call
3182 * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
3183 * transaction and fail to update the graph. */
3184 txn
->idl
->txn
= NULL
;
3186 HMAP_FOR_EACH_SAFE (row
, next
, txn_node
, &txn
->txn_rows
) {
3187 ovsdb_idl_destroy_all_map_op_lists(row
);
3188 ovsdb_idl_destroy_all_set_op_lists(row
);
3189 if (row
->old_datum
) {
3191 ovsdb_idl_row_unparse(row
);
3192 ovsdb_idl_row_clear_arcs(row
, false);
3193 ovsdb_idl_row_parse(row
);
3196 ovsdb_idl_row_unparse(row
);
3198 ovsdb_idl_row_clear_new(row
);
3201 row
->prereqs
= NULL
;
3204 row
->written
= NULL
;
3206 hmap_remove(&txn
->txn_rows
, &row
->txn_node
);
3207 hmap_node_nullify(&row
->txn_node
);
3208 if (!row
->old_datum
) {
3209 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
3213 hmap_destroy(&txn
->txn_rows
);
3214 hmap_init(&txn
->txn_rows
);
3218 ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row
*row
,
3219 struct json
*mutations
)
3221 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3223 bool any_mutations
= false;
3225 if (row
->map_op_written
) {
3226 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->map_op_written
) {
3227 struct map_op_list
*map_op_list
;
3228 const struct ovsdb_idl_column
*column
;
3229 const struct ovsdb_datum
*old_datum
;
3230 enum ovsdb_atomic_type key_type
, value_type
;
3231 struct json
*mutation
, *map
, *col_name
, *mutator
;
3232 struct json
*del_set
, *ins_map
;
3233 bool any_del
, any_ins
;
3235 map_op_list
= row
->map_op_lists
[idx
];
3236 column
= &class->columns
[idx
];
3237 key_type
= column
->type
.key
.type
;
3238 value_type
= column
->type
.value
.type
;
3240 /* Get the value to be changed */
3241 if (row
->new_datum
&& row
->written
3242 && bitmap_is_set(row
->written
,idx
)) {
3243 old_datum
= &row
->new_datum
[idx
];
3244 } else if (row
->old_datum
!= NULL
) {
3245 old_datum
= &row
->old_datum
[idx
];
3247 old_datum
= ovsdb_datum_default(&column
->type
);
3250 del_set
= json_array_create_empty();
3251 ins_map
= json_array_create_empty();
3255 for (struct map_op
*map_op
= map_op_list_first(map_op_list
); map_op
;
3256 map_op
= map_op_list_next(map_op_list
, map_op
)) {
3258 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3259 /* Find out if value really changed. */
3260 struct ovsdb_datum
*new_datum
;
3262 new_datum
= map_op_datum(map_op
);
3263 pos
= ovsdb_datum_find_key(old_datum
,
3264 &new_datum
->keys
[0],
3266 if (ovsdb_atom_equals(&new_datum
->values
[0],
3267 &old_datum
->values
[pos
],
3269 /* No change in value. Move on to next update. */
3272 } else if (map_op_type(map_op
) == MAP_OP_DELETE
){
3273 /* Verify that there is a key to delete. */
3275 pos
= ovsdb_datum_find_key(old_datum
,
3276 &map_op_datum(map_op
)->keys
[0],
3278 if (pos
== UINT_MAX
) {
3279 /* No key to delete. Move on to next update. */
3280 VLOG_WARN("Trying to delete a key that doesn't "
3281 "exist in the map.");
3286 if (map_op_type(map_op
) == MAP_OP_INSERT
) {
3287 map
= json_array_create_2(
3288 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3290 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3292 json_array_add(ins_map
, map
);
3294 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
3295 map
= ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3297 json_array_add(del_set
, map
);
3301 /* Generate an additional insert mutate for updates. */
3302 if (map_op_type(map_op
) == MAP_OP_UPDATE
) {
3303 map
= json_array_create_2(
3304 ovsdb_atom_to_json(&map_op_datum(map_op
)->keys
[0],
3306 ovsdb_atom_to_json(&map_op_datum(map_op
)->values
[0],
3308 json_array_add(ins_map
, map
);
3314 col_name
= json_string_create(column
->name
);
3315 mutator
= json_string_create("delete");
3316 map
= json_array_create_2(json_string_create("set"), del_set
);
3317 mutation
= json_array_create_3(col_name
, mutator
, map
);
3318 json_array_add(mutations
, mutation
);
3319 any_mutations
= true;
3321 json_destroy(del_set
);
3324 col_name
= json_string_create(column
->name
);
3325 mutator
= json_string_create("insert");
3326 map
= json_array_create_2(json_string_create("map"), ins_map
);
3327 mutation
= json_array_create_3(col_name
, mutator
, map
);
3328 json_array_add(mutations
, mutation
);
3329 any_mutations
= true;
3331 json_destroy(ins_map
);
3335 if (row
->set_op_written
) {
3336 BITMAP_FOR_EACH_1(idx
, class->n_columns
, row
->set_op_written
) {
3337 struct set_op_list
*set_op_list
;
3338 const struct ovsdb_idl_column
*column
;
3339 const struct ovsdb_datum
*old_datum
;
3340 enum ovsdb_atomic_type key_type
;
3341 struct json
*mutation
, *set
, *col_name
, *mutator
;
3342 struct json
*del_set
, *ins_set
;
3343 bool any_del
, any_ins
;
3345 set_op_list
= row
->set_op_lists
[idx
];
3346 column
= &class->columns
[idx
];
3347 key_type
= column
->type
.key
.type
;
3349 /* Get the value to be changed */
3350 if (row
->new_datum
&& row
->written
3351 && bitmap_is_set(row
->written
,idx
)) {
3352 old_datum
= &row
->new_datum
[idx
];
3353 } else if (row
->old_datum
!= NULL
) {
3354 old_datum
= &row
->old_datum
[idx
];
3356 old_datum
= ovsdb_datum_default(&column
->type
);
3359 del_set
= json_array_create_empty();
3360 ins_set
= json_array_create_empty();
3364 for (struct set_op
*set_op
= set_op_list_first(set_op_list
); set_op
;
3365 set_op
= set_op_list_next(set_op_list
, set_op
)) {
3366 if (set_op_type(set_op
) == SET_OP_INSERT
) {
3367 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3369 json_array_add(ins_set
, set
);
3371 } else { /* SETP_OP_DELETE */
3372 /* Verify that there is a key to delete. */
3374 pos
= ovsdb_datum_find_key(old_datum
,
3375 &set_op_datum(set_op
)->keys
[0],
3377 if (pos
== UINT_MAX
) {
3378 /* No key to delete. Move on to next update. */
3379 VLOG_WARN("Trying to delete a key that doesn't "
3380 "exist in the set.");
3383 set
= ovsdb_atom_to_json(&set_op_datum(set_op
)->keys
[0],
3385 json_array_add(del_set
, set
);
3390 col_name
= json_string_create(column
->name
);
3391 mutator
= json_string_create("delete");
3392 set
= json_array_create_2(json_string_create("set"), del_set
);
3393 mutation
= json_array_create_3(col_name
, mutator
, set
);
3394 json_array_add(mutations
, mutation
);
3395 any_mutations
= true;
3397 json_destroy(del_set
);
3400 col_name
= json_string_create(column
->name
);
3401 mutator
= json_string_create("insert");
3402 set
= json_array_create_2(json_string_create("set"), ins_set
);
3403 mutation
= json_array_create_3(col_name
, mutator
, set
);
3404 json_array_add(mutations
, mutation
);
3405 any_mutations
= true;
3407 json_destroy(ins_set
);
3411 return any_mutations
;
3414 /* Attempts to commit 'txn'. Returns the status of the commit operation, one
3415 * of the following TXN_* constants:
3419 * The transaction is in progress, but not yet complete. The caller
3420 * should call again later, after calling ovsdb_idl_run() to let the IDL
3421 * do OVSDB protocol processing.
3425 * The transaction is complete. (It didn't actually change the database,
3426 * so the IDL didn't send any request to the database server.)
3430 * The caller previously called ovsdb_idl_txn_abort().
3434 * The transaction was successful. The update made by the transaction
3435 * (and possibly other changes made by other database clients) should
3436 * already be visible in the IDL.
3440 * The transaction failed for some transient reason, e.g. because a
3441 * "verify" operation reported an inconsistency or due to a network
3442 * problem. The caller should wait for a change to the database, then
3443 * compose a new transaction, and commit the new transaction.
3445 * Use the return value of ovsdb_idl_get_seqno() to wait for a change in
3446 * the database. It is important to use its return value *before* the
3447 * initial call to ovsdb_idl_txn_commit() as the baseline for this
3448 * purpose, because the change that one should wait for can happen after
3449 * the initial call but before the call that returns TXN_TRY_AGAIN, and
3450 * using some other baseline value in that situation could cause an
3451 * indefinite wait if the database rarely changes.
3455 * The transaction failed because the IDL has been configured to require
3456 * a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
3457 * has already lost it.
3459 * Committing a transaction rolls back all of the changes that it made to the
3460 * IDL's copy of the database. If the transaction commits successfully, then
3461 * the database server will send an update and, thus, the IDL will be updated
3462 * with the committed changes. */
3463 enum ovsdb_idl_txn_status
3464 ovsdb_idl_txn_commit(struct ovsdb_idl_txn
*txn
)
3466 struct ovsdb_idl_row
*row
;
3467 struct json
*operations
;
3470 if (txn
!= txn
->idl
->txn
) {
3474 /* If we need a lock but don't have it, give up quickly. */
3475 if (txn
->idl
->lock_name
&& !ovsdb_idl_has_lock(txn
->idl
)) {
3476 txn
->status
= TXN_NOT_LOCKED
;
3477 goto disassemble_out
;
3480 operations
= json_array_create_1(
3481 json_string_create(txn
->idl
->class_
->database
));
3483 /* Assert that we have the required lock (avoiding a race). */
3484 if (txn
->idl
->lock_name
) {
3485 struct json
*op
= json_object_create();
3486 json_array_add(operations
, op
);
3487 json_object_put_string(op
, "op", "assert");
3488 json_object_put_string(op
, "lock", txn
->idl
->lock_name
);
3491 /* Add prerequisites and declarations of new rows. */
3492 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3493 /* XXX check that deleted rows exist even if no prereqs? */
3495 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3496 size_t n_columns
= class->n_columns
;
3497 struct json
*op
, *columns
, *row_json
;
3500 op
= json_object_create();
3501 json_array_add(operations
, op
);
3502 json_object_put_string(op
, "op", "wait");
3503 json_object_put_string(op
, "table", class->name
);
3504 json_object_put(op
, "timeout", json_integer_create(0));
3505 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3506 json_object_put_string(op
, "until", "==");
3507 columns
= json_array_create_empty();
3508 json_object_put(op
, "columns", columns
);
3509 row_json
= json_object_create();
3510 json_object_put(op
, "rows", json_array_create_1(row_json
));
3512 BITMAP_FOR_EACH_1 (idx
, n_columns
, row
->prereqs
) {
3513 const struct ovsdb_idl_column
*column
= &class->columns
[idx
];
3514 json_array_add(columns
, json_string_create(column
->name
));
3515 json_object_put(row_json
, column
->name
,
3516 ovsdb_datum_to_json(&row
->old_datum
[idx
],
3523 any_updates
= false;
3524 HMAP_FOR_EACH (row
, txn_node
, &txn
->txn_rows
) {
3525 const struct ovsdb_idl_table_class
*class = row
->table
->class_
;
3527 if (!row
->new_datum
) {
3528 if (class->is_root
) {
3529 struct json
*op
= json_object_create();
3530 json_object_put_string(op
, "op", "delete");
3531 json_object_put_string(op
, "table", class->name
);
3532 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3533 json_array_add(operations
, op
);
3536 /* Let ovsdb-server decide whether to really delete it. */
3538 } else if (row
->old_datum
!= row
->new_datum
) {
3539 struct json
*row_json
;
3542 if (!row
->old_datum
&& class->is_singleton
) {
3543 /* We're inserting a row into a table that allows only a
3544 * single row. (This is a fairly common OVSDB pattern for
3545 * storing global data.) Verify that the table is empty
3546 * before inserting the row, so that we get a clear
3547 * verification-related failure if there was an insertion
3548 * race with another client. */
3549 struct json
*op
= json_object_create();
3550 json_array_add(operations
, op
);
3551 json_object_put_string(op
, "op", "wait");
3552 json_object_put_string(op
, "table", class->name
);
3553 json_object_put(op
, "where", json_array_create_empty());
3554 json_object_put(op
, "timeout", json_integer_create(0));
3555 json_object_put_string(op
, "until", "==");
3556 json_object_put(op
, "rows", json_array_create_empty());
3559 struct json
*op
= json_object_create();
3560 json_object_put_string(op
, "op",
3561 row
->old_datum
? "update" : "insert");
3562 json_object_put_string(op
, "table", class->name
);
3563 if (row
->old_datum
) {
3564 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3566 struct ovsdb_idl_txn_insert
*insert
;
3570 json_object_put(op
, "uuid-name",
3571 json_string_create_nocopy(
3572 uuid_name_from_uuid(&row
->uuid
)));
3574 insert
= xmalloc(sizeof *insert
);
3575 insert
->dummy
= row
->uuid
;
3576 insert
->op_index
= operations
->u
.array
.n
- 1;
3577 uuid_zero(&insert
->real
);
3578 hmap_insert(&txn
->inserted_rows
, &insert
->hmap_node
,
3579 uuid_hash(&insert
->dummy
));
3581 row_json
= json_object_create();
3582 json_object_put(op
, "row", row_json
);
3585 BITMAP_FOR_EACH_1 (idx
, class->n_columns
, row
->written
) {
3586 const struct ovsdb_idl_column
*column
=
3587 &class->columns
[idx
];
3590 || !ovsdb_datum_is_default(&row
->new_datum
[idx
],
3594 value
= ovsdb_datum_to_json(&row
->new_datum
[idx
],
3596 json_object_put(row_json
, column
->name
,
3597 substitute_uuids(value
, txn
));
3599 /* If anything really changed, consider it an update.
3600 * We can't suppress not-really-changed values earlier
3601 * or transactions would become nonatomic (see the big
3602 * comment inside ovsdb_idl_txn_write()). */
3603 if (!any_updates
&& row
->old_datum
&&
3604 !ovsdb_datum_equals(&row
->old_datum
[idx
],
3605 &row
->new_datum
[idx
],
3613 if (!row
->old_datum
|| !shash_is_empty(json_object(row_json
))) {
3614 json_array_add(operations
, op
);
3620 /* Add mutate operation, for partial map or partial set updates. */
3621 if (row
->map_op_written
|| row
->set_op_written
) {
3622 struct json
*op
, *mutations
;
3625 op
= json_object_create();
3626 json_object_put_string(op
, "op", "mutate");
3627 json_object_put_string(op
, "table", class->name
);
3628 json_object_put(op
, "where", where_uuid_equals(&row
->uuid
));
3629 mutations
= json_array_create_empty();
3630 any_mutations
= ovsdb_idl_txn_extract_mutations(row
, mutations
);
3631 json_object_put(op
, "mutations", mutations
);
3633 if (any_mutations
) {
3634 op
= substitute_uuids(op
, txn
);
3635 json_array_add(operations
, op
);
3643 /* Add increment. */
3644 if (txn
->inc_table
&& (any_updates
|| txn
->inc_force
)) {
3646 txn
->inc_index
= operations
->u
.array
.n
- 1;
3648 struct json
*op
= json_object_create();
3649 json_object_put_string(op
, "op", "mutate");
3650 json_object_put_string(op
, "table", txn
->inc_table
);
3651 json_object_put(op
, "where",
3652 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
3654 json_object_put(op
, "mutations",
3655 json_array_create_1(
3656 json_array_create_3(
3657 json_string_create(txn
->inc_column
),
3658 json_string_create("+="),
3659 json_integer_create(1))));
3660 json_array_add(operations
, op
);
3662 op
= json_object_create();
3663 json_object_put_string(op
, "op", "select");
3664 json_object_put_string(op
, "table", txn
->inc_table
);
3665 json_object_put(op
, "where",
3666 substitute_uuids(where_uuid_equals(&txn
->inc_row
),
3668 json_object_put(op
, "columns",
3669 json_array_create_1(json_string_create(
3671 json_array_add(operations
, op
);
3674 if (txn
->comment
.length
) {
3675 struct json
*op
= json_object_create();
3676 json_object_put_string(op
, "op", "comment");
3677 json_object_put_string(op
, "comment", ds_cstr(&txn
->comment
));
3678 json_array_add(operations
, op
);
3682 struct json
*op
= json_object_create();
3683 json_object_put_string(op
, "op", "abort");
3684 json_array_add(operations
, op
);
3688 txn
->status
= TXN_UNCHANGED
;
3689 json_destroy(operations
);
3690 } else if (!jsonrpc_session_send(
3692 jsonrpc_create_request(
3693 "transact", operations
, &txn
->request_id
))) {
3694 hmap_insert(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
,
3695 json_hash(txn
->request_id
, 0));
3696 txn
->status
= TXN_INCOMPLETE
;
3698 txn
->status
= TXN_TRY_AGAIN
;
3702 ovsdb_idl_txn_disassemble(txn
);
3704 switch (txn
->status
) {
3705 case TXN_UNCOMMITTED
: COVERAGE_INC(txn_uncommitted
); break;
3706 case TXN_UNCHANGED
: COVERAGE_INC(txn_unchanged
); break;
3707 case TXN_INCOMPLETE
: COVERAGE_INC(txn_incomplete
); break;
3708 case TXN_ABORTED
: COVERAGE_INC(txn_aborted
); break;
3709 case TXN_SUCCESS
: COVERAGE_INC(txn_success
); break;
3710 case TXN_TRY_AGAIN
: COVERAGE_INC(txn_try_again
); break;
3711 case TXN_NOT_LOCKED
: COVERAGE_INC(txn_not_locked
); break;
3712 case TXN_ERROR
: COVERAGE_INC(txn_error
); break;
3718 /* Attempts to commit 'txn', blocking until the commit either succeeds or
3719 * fails. Returns the final commit status, which may be any TXN_* value other
3720 * than TXN_INCOMPLETE.
3722 * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
3723 * return value of ovsdb_idl_get_seqno() to change. */
3724 enum ovsdb_idl_txn_status
3725 ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn
*txn
)
3727 enum ovsdb_idl_txn_status status
;
3730 while ((status
= ovsdb_idl_txn_commit(txn
)) == TXN_INCOMPLETE
) {
3731 ovsdb_idl_run(txn
->idl
);
3732 ovsdb_idl_wait(txn
->idl
);
3733 ovsdb_idl_txn_wait(txn
);
3739 /* Returns the final (incremented) value of the column in 'txn' that was set to
3740 * be incremented by ovsdb_idl_txn_increment(). 'txn' must have committed
3743 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn
*txn
)
3745 ovs_assert(txn
->status
== TXN_SUCCESS
);
3746 return txn
->inc_new_value
;
3749 /* Aborts 'txn' without sending it to the database server. This is effective
3750 * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
3751 * Otherwise, it has no effect.
3753 * Aborting a transaction doesn't free its memory. Use
3754 * ovsdb_idl_txn_destroy() to do that. */
3756 ovsdb_idl_txn_abort(struct ovsdb_idl_txn
*txn
)
3758 ovsdb_idl_txn_disassemble(txn
);
3759 if (txn
->status
== TXN_UNCOMMITTED
|| txn
->status
== TXN_INCOMPLETE
) {
3760 txn
->status
= TXN_ABORTED
;
3764 /* Returns a string that reports the error status for 'txn'. The caller must
3765 * not modify or free the returned string. A call to ovsdb_idl_txn_destroy()
3766 * for 'txn' may free the returned string.
3768 * The return value is ordinarily one of the strings that
3769 * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
3770 * due to an error reported by the database server, the return value is that
3773 ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn
*txn
)
3775 if (txn
->status
!= TXN_ERROR
) {
3776 return ovsdb_idl_txn_status_to_string(txn
->status
);
3777 } else if (txn
->error
) {
3780 return "no error details available";
3785 ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn
*txn
,
3786 const struct json
*json
)
3788 if (txn
->error
== NULL
) {
3789 txn
->error
= json_to_string(json
, JSSF_SORT
);
3793 /* For transaction 'txn' that completed successfully, finds and returns the
3794 * permanent UUID that the database assigned to a newly inserted row, given the
3795 * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
3797 * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
3798 * if it was assigned by that function and then deleted by
3799 * ovsdb_idl_txn_delete() within the same transaction. (Rows that are inserted
3800 * and then deleted within a single transaction are never sent to the database
3801 * server, so it never assigns them a permanent UUID.) */
3803 ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn
*txn
,
3804 const struct uuid
*uuid
)
3806 const struct ovsdb_idl_txn_insert
*insert
;
3808 ovs_assert(txn
->status
== TXN_SUCCESS
|| txn
->status
== TXN_UNCHANGED
);
3809 HMAP_FOR_EACH_IN_BUCKET (insert
, hmap_node
,
3810 uuid_hash(uuid
), &txn
->inserted_rows
) {
3811 if (uuid_equals(uuid
, &insert
->dummy
)) {
3812 return &insert
->real
;
3819 ovsdb_idl_txn_complete(struct ovsdb_idl_txn
*txn
,
3820 enum ovsdb_idl_txn_status status
)
3822 txn
->status
= status
;
3823 hmap_remove(&txn
->idl
->outstanding_txns
, &txn
->hmap_node
);
3827 ovsdb_idl_txn_write__(const struct ovsdb_idl_row
*row_
,
3828 const struct ovsdb_idl_column
*column
,
3829 struct ovsdb_datum
*datum
, bool owns_datum
)
3831 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3832 const struct ovsdb_idl_table_class
*class;
3836 if (ovsdb_idl_row_is_synthetic(row
)) {
3840 class = row
->table
->class_
;
3841 column_idx
= column
- class->columns
;
3842 write_only
= row
->table
->modes
[column_idx
] == OVSDB_IDL_MONITOR
;
3844 ovs_assert(row
->new_datum
!= NULL
);
3845 ovs_assert(column_idx
< class->n_columns
);
3846 ovs_assert(row
->old_datum
== NULL
||
3847 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3849 if (row
->table
->idl
->verify_write_only
&& !write_only
) {
3850 VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
3851 " explicitly configured not to.", class->name
, column
->name
);
3855 /* If this is a write-only column and the datum being written is the same
3856 * as the one already there, just skip the update entirely. This is worth
3857 * optimizing because we have a lot of columns that get periodically
3858 * refreshed into the database but don't actually change that often.
3860 * We don't do this for read/write columns because that would break
3861 * atomicity of transactions--some other client might have written a
3862 * different value in that column since we read it. (But if a whole
3863 * transaction only does writes of existing values, without making any real
3864 * changes, we will drop the whole transaction later in
3865 * ovsdb_idl_txn_commit().) */
3866 if (write_only
&& ovsdb_datum_equals(ovsdb_idl_read(row
, column
),
3867 datum
, &column
->type
)) {
3871 if (hmap_node_is_null(&row
->txn_node
)) {
3872 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3873 uuid_hash(&row
->uuid
));
3875 if (row
->old_datum
== row
->new_datum
) {
3876 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
3878 if (!row
->written
) {
3879 row
->written
= bitmap_allocate(class->n_columns
);
3881 if (bitmap_is_set(row
->written
, column_idx
)) {
3882 ovsdb_datum_destroy(&row
->new_datum
[column_idx
], &column
->type
);
3884 bitmap_set1(row
->written
, column_idx
);
3887 row
->new_datum
[column_idx
] = *datum
;
3889 ovsdb_datum_clone(&row
->new_datum
[column_idx
], datum
, &column
->type
);
3891 (column
->unparse
)(row
);
3892 (column
->parse
)(row
, &row
->new_datum
[column_idx
]);
3897 ovsdb_datum_destroy(datum
, &column
->type
);
3901 /* Writes 'datum' to the specified 'column' in 'row_'. Updates both 'row_'
3902 * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
3905 * 'datum' must have the correct type for its column, but it needs not be
3906 * sorted or unique because this function will take care of that. The IDL does
3907 * not check that it meets schema constraints, but ovsdb-server will do so at
3908 * commit time so it had better be correct.
3910 * A transaction must be in progress. Replication of 'column' must not have
3911 * been disabled (by calling ovsdb_idl_omit()).
3913 * Usually this function is used indirectly through one of the "set" functions
3914 * generated by ovsdb-idlc.
3916 * Takes ownership of what 'datum' points to (and in some cases destroys that
3917 * data before returning) but makes a copy of 'datum' itself. (Commonly
3918 * 'datum' is on the caller's stack.) */
3920 ovsdb_idl_txn_write(const struct ovsdb_idl_row
*row
,
3921 const struct ovsdb_idl_column
*column
,
3922 struct ovsdb_datum
*datum
)
3924 ovsdb_datum_sort_unique(datum
,
3925 column
->type
.key
.type
, column
->type
.value
.type
);
3926 ovsdb_idl_txn_write__(row
, column
, datum
, true);
3929 /* Similar to ovsdb_idl_txn_write(), except:
3931 * - The caller retains ownership of 'datum' and what it points to.
3933 * - The caller must ensure that 'datum' is sorted and unique (e.g. via
3934 * ovsdb_datum_sort_unique().) */
3936 ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row
*row
,
3937 const struct ovsdb_idl_column
*column
,
3938 const struct ovsdb_datum
*datum
)
3940 ovsdb_idl_txn_write__(row
, column
,
3941 CONST_CAST(struct ovsdb_datum
*, datum
), false);
3944 /* Causes the original contents of 'column' in 'row_' to be verified as a
3945 * prerequisite to completing the transaction. That is, if 'column' in 'row_'
3946 * changed (or if 'row_' was deleted) between the time that the IDL originally
3947 * read its contents and the time that the transaction commits, then the
3948 * transaction aborts and ovsdb_idl_txn_commit() returns TXN_TRY_AGAIN.
3950 * The intention is that, to ensure that no transaction commits based on dirty
3951 * reads, an application should call ovsdb_idl_txn_verify() on each data item
3952 * read as part of a read-modify-write operation.
3954 * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
3955 * value of 'column' is already known:
3957 * - If 'row_' is a row created by the current transaction (returned by
3958 * ovsdb_idl_txn_insert()).
3960 * - If 'column' has already been modified (with ovsdb_idl_txn_write())
3961 * within the current transaction.
3963 * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
3964 * ovsdb_idl_txn_write() for a given read-modify-write.
3966 * A transaction must be in progress.
3968 * Usually this function is used indirectly through one of the "verify"
3969 * functions generated by ovsdb-idlc. */
3971 ovsdb_idl_txn_verify(const struct ovsdb_idl_row
*row_
,
3972 const struct ovsdb_idl_column
*column
)
3974 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
3975 const struct ovsdb_idl_table_class
*class;
3978 if (ovsdb_idl_row_is_synthetic(row
)) {
3982 class = row
->table
->class_
;
3983 column_idx
= column
- class->columns
;
3985 ovs_assert(row
->new_datum
!= NULL
);
3986 ovs_assert(row
->old_datum
== NULL
||
3987 row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
);
3989 || (row
->written
&& bitmap_is_set(row
->written
, column_idx
))) {
3993 if (hmap_node_is_null(&row
->txn_node
)) {
3994 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
3995 uuid_hash(&row
->uuid
));
3997 if (!row
->prereqs
) {
3998 row
->prereqs
= bitmap_allocate(class->n_columns
);
4000 bitmap_set1(row
->prereqs
, column_idx
);
4003 /* Deletes 'row_' from its table. May free 'row_', so it must not be
4004 * accessed afterward.
4006 * A transaction must be in progress.
4008 * Usually this function is used indirectly through one of the "delete"
4009 * functions generated by ovsdb-idlc. */
4011 ovsdb_idl_txn_delete(const struct ovsdb_idl_row
*row_
)
4013 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4015 if (ovsdb_idl_row_is_synthetic(row
)) {
4019 ovs_assert(row
->new_datum
!= NULL
);
4020 if (!row
->old_datum
) {
4021 ovsdb_idl_row_unparse(row
);
4022 ovsdb_idl_row_clear_new(row
);
4023 ovs_assert(!row
->prereqs
);
4024 hmap_remove(&row
->table
->rows
, &row
->hmap_node
);
4025 hmap_remove(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
);
4029 if (hmap_node_is_null(&row
->txn_node
)) {
4030 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
4031 uuid_hash(&row
->uuid
));
4033 ovsdb_idl_row_clear_new(row
);
4034 row
->new_datum
= NULL
;
4037 /* Inserts and returns a new row in the table with the specified 'class' in the
4038 * database with open transaction 'txn'.
4040 * The new row is assigned a provisional UUID. If 'uuid' is null then one is
4041 * randomly generated; otherwise 'uuid' should specify a randomly generated
4042 * UUID not otherwise in use. ovsdb-server will assign a different UUID when
4043 * 'txn' is committed, but the IDL will replace any uses of the provisional
4044 * UUID in the data to be to be committed by the UUID assigned by
4047 * Usually this function is used indirectly through one of the "insert"
4048 * functions generated by ovsdb-idlc. */
4049 const struct ovsdb_idl_row
*
4050 ovsdb_idl_txn_insert(struct ovsdb_idl_txn
*txn
,
4051 const struct ovsdb_idl_table_class
*class,
4052 const struct uuid
*uuid
)
4054 struct ovsdb_idl_row
*row
= ovsdb_idl_row_create__(class);
4057 ovs_assert(!ovsdb_idl_txn_get_row(txn
, uuid
));
4060 uuid_generate(&row
->uuid
);
4063 row
->table
= ovsdb_idl_table_from_class(txn
->idl
, class);
4064 row
->new_datum
= xmalloc(class->n_columns
* sizeof *row
->new_datum
);
4065 hmap_insert(&row
->table
->rows
, &row
->hmap_node
, uuid_hash(&row
->uuid
));
4066 hmap_insert(&txn
->txn_rows
, &row
->txn_node
, uuid_hash(&row
->uuid
));
4071 ovsdb_idl_txn_abort_all(struct ovsdb_idl
*idl
)
4073 struct ovsdb_idl_txn
*txn
;
4075 HMAP_FOR_EACH (txn
, hmap_node
, &idl
->outstanding_txns
) {
4076 ovsdb_idl_txn_complete(txn
, TXN_TRY_AGAIN
);
4080 static struct ovsdb_idl_txn
*
4081 ovsdb_idl_txn_find(struct ovsdb_idl
*idl
, const struct json
*id
)
4083 struct ovsdb_idl_txn
*txn
;
4085 HMAP_FOR_EACH_WITH_HASH (txn
, hmap_node
,
4086 json_hash(id
, 0), &idl
->outstanding_txns
) {
4087 if (json_equal(id
, txn
->request_id
)) {
4095 check_json_type(const struct json
*json
, enum json_type type
, const char *name
)
4098 VLOG_WARN_RL(&syntax_rl
, "%s is missing", name
);
4100 } else if (json
->type
!= type
) {
4101 VLOG_WARN_RL(&syntax_rl
, "%s is %s instead of %s",
4102 name
, json_type_to_string(json
->type
),
4103 json_type_to_string(type
));
4111 ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn
*txn
,
4112 const struct json_array
*results
)
4114 struct json
*count
, *rows
, *row
, *column
;
4115 struct shash
*mutate
, *select
;
4117 if (txn
->inc_index
+ 2 > results
->n
) {
4118 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4119 "for increment (has %"PRIuSIZE
", needs %u)",
4120 results
->n
, txn
->inc_index
+ 2);
4124 /* We know that this is a JSON object because the loop in
4125 * ovsdb_idl_txn_process_reply() checked. */
4126 mutate
= json_object(results
->elems
[txn
->inc_index
]);
4127 count
= shash_find_data(mutate
, "count");
4128 if (!check_json_type(count
, JSON_INTEGER
, "\"mutate\" reply \"count\"")) {
4131 if (count
->u
.integer
!= 1) {
4132 VLOG_WARN_RL(&syntax_rl
,
4133 "\"mutate\" reply \"count\" is %lld instead of 1",
4138 select
= json_object(results
->elems
[txn
->inc_index
+ 1]);
4139 rows
= shash_find_data(select
, "rows");
4140 if (!check_json_type(rows
, JSON_ARRAY
, "\"select\" reply \"rows\"")) {
4143 if (rows
->u
.array
.n
!= 1) {
4144 VLOG_WARN_RL(&syntax_rl
, "\"select\" reply \"rows\" has %"PRIuSIZE
" elements "
4149 row
= rows
->u
.array
.elems
[0];
4150 if (!check_json_type(row
, JSON_OBJECT
, "\"select\" reply row")) {
4153 column
= shash_find_data(json_object(row
), txn
->inc_column
);
4154 if (!check_json_type(column
, JSON_INTEGER
,
4155 "\"select\" reply inc column")) {
4158 txn
->inc_new_value
= column
->u
.integer
;
4163 ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert
*insert
,
4164 const struct json_array
*results
)
4166 static const struct ovsdb_base_type uuid_type
= OVSDB_BASE_UUID_INIT
;
4167 struct ovsdb_error
*error
;
4168 struct json
*json_uuid
;
4169 union ovsdb_atom uuid
;
4170 struct shash
*reply
;
4172 if (insert
->op_index
>= results
->n
) {
4173 VLOG_WARN_RL(&syntax_rl
, "reply does not contain enough operations "
4174 "for insert (has %"PRIuSIZE
", needs %u)",
4175 results
->n
, insert
->op_index
);
4179 /* We know that this is a JSON object because the loop in
4180 * ovsdb_idl_txn_process_reply() checked. */
4181 reply
= json_object(results
->elems
[insert
->op_index
]);
4182 json_uuid
= shash_find_data(reply
, "uuid");
4183 if (!check_json_type(json_uuid
, JSON_ARRAY
, "\"insert\" reply \"uuid\"")) {
4187 error
= ovsdb_atom_from_json(&uuid
, &uuid_type
, json_uuid
, NULL
);
4189 char *s
= ovsdb_error_to_string(error
);
4190 VLOG_WARN_RL(&syntax_rl
, "\"insert\" reply \"uuid\" is not a JSON "
4193 ovsdb_error_destroy(error
);
4197 insert
->real
= uuid
.uuid
;
4203 ovsdb_idl_txn_process_reply(struct ovsdb_idl
*idl
,
4204 const struct jsonrpc_msg
*msg
)
4206 struct ovsdb_idl_txn
*txn
;
4207 enum ovsdb_idl_txn_status status
;
4209 txn
= ovsdb_idl_txn_find(idl
, msg
->id
);
4214 if (msg
->type
== JSONRPC_ERROR
) {
4216 } else if (msg
->result
->type
!= JSON_ARRAY
) {
4217 VLOG_WARN_RL(&syntax_rl
, "reply to \"transact\" is not JSON array");
4220 struct json_array
*ops
= &msg
->result
->u
.array
;
4221 int hard_errors
= 0;
4222 int soft_errors
= 0;
4223 int lock_errors
= 0;
4226 for (i
= 0; i
< ops
->n
; i
++) {
4227 struct json
*op
= ops
->elems
[i
];
4229 if (op
->type
== JSON_NULL
) {
4230 /* This isn't an error in itself but indicates that some prior
4231 * operation failed, so make sure that we know about it. */
4233 } else if (op
->type
== JSON_OBJECT
) {
4236 error
= shash_find_data(json_object(op
), "error");
4238 if (error
->type
== JSON_STRING
) {
4239 if (!strcmp(error
->u
.string
, "timed out")) {
4241 } else if (!strcmp(error
->u
.string
, "not owner")) {
4243 } else if (!strcmp(error
->u
.string
, "not allowed")) {
4245 ovsdb_idl_txn_set_error_json(txn
, op
);
4246 } else if (strcmp(error
->u
.string
, "aborted")) {
4248 ovsdb_idl_txn_set_error_json(txn
, op
);
4249 VLOG_WARN_RL(&other_rl
,
4250 "transaction error: %s", txn
->error
);
4254 ovsdb_idl_txn_set_error_json(txn
, op
);
4255 VLOG_WARN_RL(&syntax_rl
,
4256 "\"error\" in reply is not JSON string");
4261 ovsdb_idl_txn_set_error_json(txn
, op
);
4262 VLOG_WARN_RL(&syntax_rl
,
4263 "operation reply is not JSON null or object");
4267 if (!soft_errors
&& !hard_errors
&& !lock_errors
) {
4268 struct ovsdb_idl_txn_insert
*insert
;
4270 if (txn
->inc_table
&& !ovsdb_idl_txn_process_inc_reply(txn
, ops
)) {
4274 HMAP_FOR_EACH (insert
, hmap_node
, &txn
->inserted_rows
) {
4275 if (!ovsdb_idl_txn_process_insert_reply(insert
, ops
)) {
4281 status
= (hard_errors
? TXN_ERROR
4282 : lock_errors
? TXN_NOT_LOCKED
4283 : soft_errors
? TXN_TRY_AGAIN
4287 ovsdb_idl_txn_complete(txn
, status
);
4291 /* Returns the transaction currently active for 'row''s IDL. A transaction
4292 * must currently be active. */
4293 struct ovsdb_idl_txn
*
4294 ovsdb_idl_txn_get(const struct ovsdb_idl_row
*row
)
4296 struct ovsdb_idl_txn
*txn
= row
->table
->idl
->txn
;
4297 ovs_assert(txn
!= NULL
);
4301 /* Returns the IDL on which 'txn' acts. */
4303 ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn
*txn
)
4308 /* Blocks until 'idl' successfully connects to the remote database and
4309 * retrieves its contents. */
4311 ovsdb_idl_get_initial_snapshot(struct ovsdb_idl
*idl
)
4315 if (ovsdb_idl_has_ever_connected(idl
)) {
4318 ovsdb_idl_wait(idl
);
4323 /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
4324 * the database server and to avoid modifying the database when the lock cannot
4325 * be acquired (that is, when another client has the same lock).
4327 * If 'lock_name' is NULL, drops the locking requirement and releases the
4330 ovsdb_idl_set_lock(struct ovsdb_idl
*idl
, const char *lock_name
)
4332 ovs_assert(!idl
->txn
);
4333 ovs_assert(hmap_is_empty(&idl
->outstanding_txns
));
4335 if (idl
->lock_name
&& (!lock_name
|| strcmp(lock_name
, idl
->lock_name
))) {
4336 /* Release previous lock. */
4337 ovsdb_idl_send_unlock_request(idl
);
4338 free(idl
->lock_name
);
4339 idl
->lock_name
= NULL
;
4340 idl
->is_lock_contended
= false;
4343 if (lock_name
&& !idl
->lock_name
) {
4344 /* Acquire new lock. */
4345 idl
->lock_name
= xstrdup(lock_name
);
4346 ovsdb_idl_send_lock_request(idl
);
4350 /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
4352 * Locking and unlocking happens asynchronously from the database client's
4353 * point of view, so the information is only useful for optimization (e.g. if
4354 * the client doesn't have the lock then there's no point in trying to write to
4357 ovsdb_idl_has_lock(const struct ovsdb_idl
*idl
)
4359 return idl
->has_lock
;
4362 /* Returns true if 'idl' is configured to obtain a lock but the database server
4363 * has indicated that some other client already owns the requested lock. */
4365 ovsdb_idl_is_lock_contended(const struct ovsdb_idl
*idl
)
4367 return idl
->is_lock_contended
;
4371 ovsdb_idl_update_has_lock(struct ovsdb_idl
*idl
, bool new_has_lock
)
4373 if (new_has_lock
&& !idl
->has_lock
) {
4374 if (idl
->state
== IDL_S_MONITORING
||
4375 idl
->state
== IDL_S_MONITORING_COND
) {
4376 idl
->change_seqno
++;
4378 /* We're setting up a session, so don't signal that the database
4379 * changed. Finalizing the session will increment change_seqno
4382 idl
->is_lock_contended
= false;
4384 idl
->has_lock
= new_has_lock
;
4388 ovsdb_idl_send_lock_request__(struct ovsdb_idl
*idl
, const char *method
,
4391 ovsdb_idl_update_has_lock(idl
, false);
4393 json_destroy(idl
->lock_request_id
);
4394 idl
->lock_request_id
= NULL
;
4396 if (jsonrpc_session_is_connected(idl
->session
)) {
4397 struct json
*params
;
4399 params
= json_array_create_1(json_string_create(idl
->lock_name
));
4400 jsonrpc_session_send(idl
->session
,
4401 jsonrpc_create_request(method
, params
, idp
));
4406 ovsdb_idl_send_lock_request(struct ovsdb_idl
*idl
)
4408 ovsdb_idl_send_lock_request__(idl
, "lock", &idl
->lock_request_id
);
4412 ovsdb_idl_send_unlock_request(struct ovsdb_idl
*idl
)
4414 ovsdb_idl_send_lock_request__(idl
, "unlock", NULL
);
4418 ovsdb_idl_parse_lock_reply(struct ovsdb_idl
*idl
, const struct json
*result
)
4422 json_destroy(idl
->lock_request_id
);
4423 idl
->lock_request_id
= NULL
;
4425 if (result
->type
== JSON_OBJECT
) {
4426 const struct json
*locked
;
4428 locked
= shash_find_data(json_object(result
), "locked");
4429 got_lock
= locked
&& locked
->type
== JSON_TRUE
;
4434 ovsdb_idl_update_has_lock(idl
, got_lock
);
4436 idl
->is_lock_contended
= true;
4441 ovsdb_idl_parse_lock_notify(struct ovsdb_idl
*idl
,
4442 const struct json
*params
,
4446 && params
->type
== JSON_ARRAY
4447 && json_array(params
)->n
> 0
4448 && json_array(params
)->elems
[0]->type
== JSON_STRING
) {
4449 const char *lock_name
= json_string(json_array(params
)->elems
[0]);
4451 if (!strcmp(idl
->lock_name
, lock_name
)) {
4452 ovsdb_idl_update_has_lock(idl
, new_has_lock
);
4453 if (!new_has_lock
) {
4454 idl
->is_lock_contended
= true;
4460 /* Inserts a new Map Operation into current transaction. */
4462 ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row
*row
,
4463 const struct ovsdb_idl_column
*column
,
4464 struct ovsdb_datum
*datum
,
4465 enum map_op_type op_type
)
4467 const struct ovsdb_idl_table_class
*class;
4469 struct map_op
*map_op
;
4471 class = row
->table
->class_
;
4472 column_idx
= column
- class->columns
;
4474 /* Check if a map operation list exists for this column. */
4475 if (!row
->map_op_written
) {
4476 row
->map_op_written
= bitmap_allocate(class->n_columns
);
4477 row
->map_op_lists
= xzalloc(class->n_columns
*
4478 sizeof *row
->map_op_lists
);
4480 if (!row
->map_op_lists
[column_idx
]) {
4481 row
->map_op_lists
[column_idx
] = map_op_list_create();
4484 /* Add a map operation to the corresponding list. */
4485 map_op
= map_op_create(datum
, op_type
);
4486 bitmap_set1(row
->map_op_written
, column_idx
);
4487 map_op_list_add(row
->map_op_lists
[column_idx
], map_op
, &column
->type
);
4489 /* Add this row to transaction's list of rows. */
4490 if (hmap_node_is_null(&row
->txn_node
)) {
4491 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
4492 uuid_hash(&row
->uuid
));
4496 /* Inserts a new Set Operation into current transaction. */
4498 ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row
*row
,
4499 const struct ovsdb_idl_column
*column
,
4500 struct ovsdb_datum
*datum
,
4501 enum set_op_type op_type
)
4503 const struct ovsdb_idl_table_class
*class;
4505 struct set_op
*set_op
;
4507 class = row
->table
->class_
;
4508 column_idx
= column
- class->columns
;
4510 /* Check if a set operation list exists for this column. */
4511 if (!row
->set_op_written
) {
4512 row
->set_op_written
= bitmap_allocate(class->n_columns
);
4513 row
->set_op_lists
= xzalloc(class->n_columns
*
4514 sizeof *row
->set_op_lists
);
4516 if (!row
->set_op_lists
[column_idx
]) {
4517 row
->set_op_lists
[column_idx
] = set_op_list_create();
4520 /* Add a set operation to the corresponding list. */
4521 set_op
= set_op_create(datum
, op_type
);
4522 bitmap_set1(row
->set_op_written
, column_idx
);
4523 set_op_list_add(row
->set_op_lists
[column_idx
], set_op
, &column
->type
);
4525 /* Add this row to the transactions's list of rows. */
4526 if (hmap_node_is_null(&row
->txn_node
)) {
4527 hmap_insert(&row
->table
->idl
->txn
->txn_rows
, &row
->txn_node
,
4528 uuid_hash(&row
->uuid
));
4533 is_valid_partial_update(const struct ovsdb_idl_row
*row
,
4534 const struct ovsdb_idl_column
*column
,
4535 struct ovsdb_datum
*datum
)
4537 /* Verify that this column is being monitored. */
4538 unsigned int column_idx
= column
- row
->table
->class_
->columns
;
4539 if (!(row
->table
->modes
[column_idx
] & OVSDB_IDL_MONITOR
)) {
4540 VLOG_WARN("cannot partially update non-monitored column");
4544 /* Verify that the update affects a single element. */
4545 if (datum
->n
!= 1) {
4546 VLOG_WARN("invalid datum for partial update");
4553 /* Inserts the value described in 'datum' into the map in 'column' in
4554 * 'row_'. If the value doesn't already exist in 'column' then it's value
4555 * is added. The value in 'datum' must be of the same type as the values
4556 * in 'column'. This function takes ownership of 'datum'.
4558 * Usually this function is used indirectly through one of the "update"
4559 * functions generated by vswitch-idl. */
4561 ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row
*row_
,
4562 const struct ovsdb_idl_column
*column
,
4563 struct ovsdb_datum
*datum
)
4565 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4566 enum set_op_type op_type
;
4568 if (!is_valid_partial_update(row
, column
, datum
)) {
4569 ovsdb_datum_destroy(datum
, &column
->type
);
4574 op_type
= SET_OP_INSERT
;
4576 ovsdb_idl_txn_add_set_op(row
, column
, datum
, op_type
);
4579 /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
4580 * The value in 'datum' must be of the same type as the keys in 'column'.
4581 * This function takes ownership of 'datum'.
4583 * Usually this function is used indirectly through one of the "update"
4584 * functions generated by vswitch-idl. */
4586 ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row
*row_
,
4587 const struct ovsdb_idl_column
*column
,
4588 struct ovsdb_datum
*datum
)
4590 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4592 if (!is_valid_partial_update(row
, column
, datum
)) {
4593 struct ovsdb_type type_
= column
->type
;
4594 type_
.value
.type
= OVSDB_TYPE_VOID
;
4595 ovsdb_datum_destroy(datum
, &type_
);
4599 ovsdb_idl_txn_add_set_op(row
, column
, datum
, SET_OP_DELETE
);
4602 /* Inserts the key-value specified in 'datum' into the map in 'column' in
4603 * 'row_'. If the key already exist in 'column', then it's value is updated
4604 * with the value in 'datum'. The key-value in 'datum' must be of the same type
4605 * as the keys-values in 'column'. This function takes ownership of 'datum'.
4607 * Usually this function is used indirectly through one of the "update"
4608 * functions generated by vswitch-idl. */
4610 ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row
*row_
,
4611 const struct ovsdb_idl_column
*column
,
4612 struct ovsdb_datum
*datum
)
4614 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4615 enum ovsdb_atomic_type key_type
;
4616 enum map_op_type op_type
;
4618 const struct ovsdb_datum
*old_datum
;
4620 if (!is_valid_partial_update(row
, column
, datum
)) {
4621 ovsdb_datum_destroy(datum
, &column
->type
);
4626 /* Find out if this is an insert or an update. */
4627 key_type
= column
->type
.key
.type
;
4628 old_datum
= ovsdb_idl_read(row
, column
);
4629 pos
= ovsdb_datum_find_key(old_datum
, &datum
->keys
[0], key_type
);
4630 op_type
= pos
== UINT_MAX
? MAP_OP_INSERT
: MAP_OP_UPDATE
;
4632 ovsdb_idl_txn_add_map_op(row
, column
, datum
, op_type
);
4635 /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
4636 * The key in 'datum' must be of the same type as the keys in 'column'.
4637 * The value in 'datum' must be NULL. This function takes ownership of
4640 * Usually this function is used indirectly through one of the "update"
4641 * functions generated by vswitch-idl. */
4643 ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row
*row_
,
4644 const struct ovsdb_idl_column
*column
,
4645 struct ovsdb_datum
*datum
)
4647 struct ovsdb_idl_row
*row
= CONST_CAST(struct ovsdb_idl_row
*, row_
);
4649 if (!is_valid_partial_update(row
, column
, datum
)) {
4650 struct ovsdb_type type_
= column
->type
;
4651 type_
.value
.type
= OVSDB_TYPE_VOID
;
4652 ovsdb_datum_destroy(datum
, &type_
);
4656 ovsdb_idl_txn_add_map_op(row
, column
, datum
, MAP_OP_DELETE
);
4660 ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*loop
)
4663 ovsdb_idl_destroy(loop
->idl
);
4667 struct ovsdb_idl_txn
*
4668 ovsdb_idl_loop_run(struct ovsdb_idl_loop
*loop
)
4670 ovsdb_idl_run(loop
->idl
);
4671 loop
->open_txn
= (loop
->committing_txn
4672 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
4674 : ovsdb_idl_txn_create(loop
->idl
));
4675 return loop
->open_txn
;
4678 /* Attempts to commit the current transaction, if one is open, and sets up the
4679 * poll loop to wake up when some more work might be needed.
4681 * If a transaction was open, in this or a previous iteration of the main loop,
4682 * and had not before finished committing (successfully or unsuccessfully), the
4683 * return value is one of:
4685 * 1: The transaction committed successfully (or it did not change anything in
4687 * 0: The transaction failed.
4688 * -1: The commit is still in progress.
4690 * Thus, the return value is -1 if the transaction is in progress and otherwise
4691 * true for success, false for failure.
4693 * (In the corner case where the IDL sends a transaction to the database and
4694 * the database commits it, and the connection between the IDL and the database
4695 * drops before the IDL receives the message confirming the commit, this
4696 * function can return 0 even though the transaction succeeded.)
4699 ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop
*loop
)
4701 if (loop
->open_txn
) {
4702 loop
->committing_txn
= loop
->open_txn
;
4703 loop
->open_txn
= NULL
;
4705 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
4708 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
4711 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
4712 if (status
!= TXN_INCOMPLETE
) {
4715 /* We want to re-evaluate the database when it's changed from
4716 * the contents that it had when we started the commit. (That
4717 * might have already happened.) */
4718 loop
->skip_seqno
= loop
->precommit_seqno
;
4719 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
4720 poll_immediate_wake();
4726 /* Possibly some work on the database was deferred because no
4727 * further transaction could proceed. Wake up again. */
4729 loop
->cur_cfg
= loop
->next_cfg
;
4730 poll_immediate_wake();
4735 loop
->cur_cfg
= loop
->next_cfg
;
4739 case TXN_NOT_LOCKED
:
4744 case TXN_UNCOMMITTED
:
4745 case TXN_INCOMPLETE
:
4749 ovsdb_idl_txn_destroy(txn
);
4750 loop
->committing_txn
= NULL
;
4755 /* Not a meaningful return value: no transaction was in progress. */
4759 ovsdb_idl_wait(loop
->idl
);