]>
Commit | Line | Data |
---|---|---|
120fb2ca | 1 | /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2016, 2017 Nicira, Inc. |
bd06962a BP |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at: | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | */ | |
15 | ||
16 | #include <config.h> | |
17 | ||
18 | #include "file.h" | |
19 | ||
ada496b5 | 20 | #include <errno.h> |
bd06962a | 21 | #include <fcntl.h> |
ada496b5 | 22 | #include <unistd.h> |
bd06962a | 23 | |
17d18afb | 24 | #include "bitmap.h" |
bd06962a BP |
25 | #include "column.h" |
26 | #include "log.h" | |
ee89ea7b | 27 | #include "openvswitch/json.h" |
ada496b5 | 28 | #include "lockfile.h" |
bd06962a BP |
29 | #include "ovsdb.h" |
30 | #include "ovsdb-error.h" | |
31 | #include "row.h" | |
ada496b5 | 32 | #include "socket-util.h" |
1b1d2e6d | 33 | #include "storage.h" |
bd06962a | 34 | #include "table.h" |
d171b584 | 35 | #include "timeval.h" |
bd06962a | 36 | #include "transaction.h" |
2ccd66f5 | 37 | #include "unixctl.h" |
bd06962a BP |
38 | #include "uuid.h" |
39 | #include "util.h" | |
e6211adc | 40 | #include "openvswitch/vlog.h" |
bd06962a | 41 | |
d98e6007 | 42 | VLOG_DEFINE_THIS_MODULE(ovsdb_file); |
5136ce49 | 43 | |
a3d573ed BP |
44 | /* A transaction being converted to JSON for writing to a file. */ |
45 | struct ovsdb_file_txn { | |
46 | struct json *json; /* JSON for the whole transaction. */ | |
47 | struct json *table_json; /* JSON for 'table''s transaction. */ | |
48 | struct ovsdb_table *table; /* Table described in 'table_json'. */ | |
49 | }; | |
50 | ||
51 | static void ovsdb_file_txn_init(struct ovsdb_file_txn *); | |
52 | static void ovsdb_file_txn_add_row(struct ovsdb_file_txn *, | |
53 | const struct ovsdb_row *old, | |
17d18afb BP |
54 | const struct ovsdb_row *new, |
55 | const unsigned long int *changed); | |
bd06962a | 56 | |
2ccd66f5 IM |
57 | /* If set to 'true', file transactions will contain difference between |
58 | * datums of old and new rows and not the whole new datum for the column. */ | |
59 | static bool use_column_diff = true; | |
60 | ||
61 | static void | |
62 | ovsdb_file_column_diff_enable(struct unixctl_conn *conn, int argc OVS_UNUSED, | |
63 | const char *argv[] OVS_UNUSED, | |
64 | void *arg OVS_UNUSED) | |
65 | { | |
66 | use_column_diff = true; | |
67 | unixctl_command_reply(conn, NULL); | |
68 | } | |
69 | ||
70 | void | |
71 | ovsdb_file_column_diff_disable(void) | |
72 | { | |
73 | if (!use_column_diff) { | |
74 | return; | |
75 | } | |
76 | use_column_diff = false; | |
77 | unixctl_command_register("ovsdb/file/column-diff-enable", "", | |
78 | 0, 0, ovsdb_file_column_diff_enable, NULL); | |
79 | } | |
80 | ||
1e19e50e BP |
81 | static struct ovsdb_error * |
82 | ovsdb_file_update_row_from_json(struct ovsdb_row *row, bool converting, | |
2ccd66f5 | 83 | bool row_contains_diff, |
1e19e50e BP |
84 | const struct json *json) |
85 | { | |
86 | struct ovsdb_table_schema *schema = row->table->schema; | |
87 | struct ovsdb_error *error; | |
88 | struct shash_node *node; | |
89 | ||
90 | if (json->type != JSON_OBJECT) { | |
91 | return ovsdb_syntax_error(json, NULL, "row must be JSON object"); | |
92 | } | |
93 | ||
94 | SHASH_FOR_EACH (node, json_object(json)) { | |
95 | const char *column_name = node->name; | |
96 | const struct ovsdb_column *column; | |
97 | struct ovsdb_datum datum; | |
98 | ||
99 | column = ovsdb_table_schema_get_column(schema, column_name); | |
100 | if (!column) { | |
101 | if (converting) { | |
102 | continue; | |
103 | } | |
104 | return ovsdb_syntax_error(json, "unknown column", | |
105 | "No column %s in table %s.", | |
106 | column_name, schema->name); | |
107 | } | |
108 | ||
109 | error = ovsdb_datum_from_json(&datum, &column->type, node->data, NULL); | |
110 | if (error) { | |
111 | return error; | |
112 | } | |
2ccd66f5 IM |
113 | if (row_contains_diff |
114 | && !ovsdb_datum_is_default(&row->fields[column->index], | |
115 | &column->type)) { | |
116 | struct ovsdb_datum new_datum; | |
117 | ||
118 | error = ovsdb_datum_apply_diff(&new_datum, | |
119 | &row->fields[column->index], | |
120 | &datum, &column->type); | |
121 | ovsdb_datum_destroy(&datum, &column->type); | |
122 | if (error) { | |
123 | return error; | |
124 | } | |
125 | ovsdb_datum_swap(&datum, &new_datum); | |
126 | } | |
1e19e50e BP |
127 | ovsdb_datum_swap(&row->fields[column->index], &datum); |
128 | ovsdb_datum_destroy(&datum, &column->type); | |
129 | } | |
130 | ||
131 | return NULL; | |
132 | } | |
133 | ||
bd06962a BP |
134 | static struct ovsdb_error * |
135 | ovsdb_file_txn_row_from_json(struct ovsdb_txn *txn, struct ovsdb_table *table, | |
2ccd66f5 | 136 | bool converting, bool row_contains_diff, |
bd06962a BP |
137 | const struct uuid *row_uuid, struct json *json) |
138 | { | |
139 | const struct ovsdb_row *row = ovsdb_table_get_row(table, row_uuid); | |
140 | if (json->type == JSON_NULL) { | |
141 | if (!row) { | |
142 | return ovsdb_syntax_error(NULL, NULL, "transaction deletes " | |
143 | "row "UUID_FMT" that does not exist", | |
144 | UUID_ARGS(row_uuid)); | |
145 | } | |
146 | ovsdb_txn_row_delete(txn, row); | |
147 | return NULL; | |
148 | } else if (row) { | |
1e19e50e | 149 | return ovsdb_file_update_row_from_json(ovsdb_txn_row_modify(txn, row), |
2ccd66f5 IM |
150 | converting, row_contains_diff, |
151 | json); | |
bd06962a BP |
152 | } else { |
153 | struct ovsdb_error *error; | |
154 | struct ovsdb_row *new; | |
155 | ||
156 | new = ovsdb_row_create(table); | |
157 | *ovsdb_row_get_uuid_rw(new) = *row_uuid; | |
2ccd66f5 IM |
158 | error = ovsdb_file_update_row_from_json(new, converting, |
159 | row_contains_diff, json); | |
bd06962a BP |
160 | if (error) { |
161 | ovsdb_row_destroy(new); | |
3697c062 BP |
162 | } else { |
163 | ovsdb_txn_row_insert(txn, new); | |
bd06962a | 164 | } |
bd06962a BP |
165 | return error; |
166 | } | |
167 | } | |
168 | ||
169 | static struct ovsdb_error * | |
170 | ovsdb_file_txn_table_from_json(struct ovsdb_txn *txn, | |
1e19e50e | 171 | struct ovsdb_table *table, |
2ccd66f5 IM |
172 | bool converting, |
173 | bool row_contains_diff, | |
174 | struct json *json) | |
bd06962a BP |
175 | { |
176 | struct shash_node *node; | |
177 | ||
178 | if (json->type != JSON_OBJECT) { | |
179 | return ovsdb_syntax_error(json, NULL, "object expected"); | |
180 | } | |
181 | ||
fa37affa | 182 | SHASH_FOR_EACH (node, json->object) { |
bd06962a BP |
183 | const char *uuid_string = node->name; |
184 | struct json *txn_row_json = node->data; | |
185 | struct ovsdb_error *error; | |
186 | struct uuid row_uuid; | |
187 | ||
188 | if (!uuid_from_string(&row_uuid, uuid_string)) { | |
189 | return ovsdb_syntax_error(json, NULL, "\"%s\" is not a valid UUID", | |
190 | uuid_string); | |
191 | } | |
192 | ||
1e19e50e | 193 | error = ovsdb_file_txn_row_from_json(txn, table, converting, |
2ccd66f5 | 194 | row_contains_diff, |
1e19e50e | 195 | &row_uuid, txn_row_json); |
bd06962a BP |
196 | if (error) { |
197 | return error; | |
198 | } | |
199 | } | |
200 | ||
201 | return NULL; | |
202 | } | |
203 | ||
ada496b5 BP |
204 | /* Converts 'json' to an ovsdb_txn for 'db', storing the new transaction in |
205 | * '*txnp'. Returns NULL if successful, otherwise an error. | |
206 | * | |
207 | * If 'converting' is true, then unknown table and column names are ignored | |
208 | * (which can ease upgrading and downgrading schemas); otherwise, they are | |
2958f35b | 209 | * treated as errors. */ |
1b1d2e6d | 210 | struct ovsdb_error * |
bd06962a | 211 | ovsdb_file_txn_from_json(struct ovsdb *db, const struct json *json, |
2958f35b | 212 | bool converting, struct ovsdb_txn **txnp) |
bd06962a BP |
213 | { |
214 | struct ovsdb_error *error; | |
215 | struct shash_node *node; | |
216 | struct ovsdb_txn *txn; | |
217 | ||
218 | *txnp = NULL; | |
ada496b5 | 219 | |
bd06962a BP |
220 | if (json->type != JSON_OBJECT) { |
221 | return ovsdb_syntax_error(json, NULL, "object expected"); | |
222 | } | |
223 | ||
2ccd66f5 IM |
224 | struct json *is_diff = shash_find_data(json->object, "_is_diff"); |
225 | bool row_contains_diff = false; | |
226 | ||
227 | if (is_diff && is_diff->type == JSON_TRUE) { | |
228 | row_contains_diff = true; | |
229 | } | |
230 | ||
bd06962a | 231 | txn = ovsdb_txn_create(db); |
fa37affa | 232 | SHASH_FOR_EACH (node, json->object) { |
bd06962a | 233 | const char *table_name = node->name; |
ada496b5 | 234 | struct json *node_json = node->data; |
bd06962a BP |
235 | struct ovsdb_table *table; |
236 | ||
237 | table = shash_find_data(&db->tables, table_name); | |
238 | if (!table) { | |
d171b584 | 239 | if (!strcmp(table_name, "_date") |
ada496b5 | 240 | && node_json->type == JSON_INTEGER) { |
ada496b5 | 241 | continue; |
2ccd66f5 IM |
242 | } else if (!strcmp(table_name, "_is_diff") |
243 | && (node_json->type == JSON_TRUE | |
244 | || node_json->type == JSON_FALSE)) { | |
245 | continue; | |
ada496b5 | 246 | } else if (!strcmp(table_name, "_comment") || converting) { |
d171b584 BP |
247 | continue; |
248 | } | |
249 | ||
bd06962a BP |
250 | error = ovsdb_syntax_error(json, "unknown table", |
251 | "No table named %s.", table_name); | |
252 | goto error; | |
253 | } | |
254 | ||
1e19e50e | 255 | error = ovsdb_file_txn_table_from_json(txn, table, converting, |
2ccd66f5 | 256 | row_contains_diff, node_json); |
bd06962a BP |
257 | if (error) { |
258 | goto error; | |
259 | } | |
260 | } | |
261 | *txnp = txn; | |
262 | return NULL; | |
263 | ||
264 | error: | |
265 | ovsdb_txn_abort(txn); | |
266 | return error; | |
267 | } | |
1e19e50e | 268 | |
1b1d2e6d BP |
269 | static struct ovsdb_error * OVS_WARN_UNUSED_RESULT |
270 | ovsdb_convert_table(struct ovsdb_txn *txn, | |
271 | const struct ovsdb_table *src_table, | |
272 | struct ovsdb_table *dst_table) | |
1e19e50e | 273 | { |
1b1d2e6d BP |
274 | const struct ovsdb_row *src_row; |
275 | HMAP_FOR_EACH (src_row, hmap_node, &src_table->rows) { | |
276 | struct ovsdb_row *dst_row = ovsdb_row_create(dst_table); | |
277 | *ovsdb_row_get_uuid_rw(dst_row) = *ovsdb_row_get_uuid(src_row); | |
1e19e50e | 278 | |
1b1d2e6d BP |
279 | struct shash_node *node; |
280 | SHASH_FOR_EACH (node, &src_table->schema->columns) { | |
281 | const struct ovsdb_column *src_column = node->data; | |
282 | if (src_column->index == OVSDB_COL_UUID || | |
283 | src_column->index == OVSDB_COL_VERSION) { | |
284 | continue; | |
285 | } | |
1e19e50e | 286 | |
1b1d2e6d BP |
287 | const struct ovsdb_column *dst_column |
288 | = shash_find_data(&dst_table->schema->columns, | |
289 | src_column->name); | |
290 | if (!dst_column) { | |
291 | continue; | |
292 | } | |
1e19e50e | 293 | |
dee6478d DS |
294 | ovsdb_datum_destroy(&dst_row->fields[dst_column->index], |
295 | &dst_column->type); | |
296 | ||
1b1d2e6d BP |
297 | struct ovsdb_error *error = ovsdb_datum_convert( |
298 | &dst_row->fields[dst_column->index], &dst_column->type, | |
299 | &src_row->fields[src_column->index], &src_column->type); | |
300 | if (error) { | |
dee6478d | 301 | ovsdb_datum_init_empty(&dst_row->fields[dst_column->index]); |
1b1d2e6d BP |
302 | ovsdb_row_destroy(dst_row); |
303 | return error; | |
304 | } | |
1e19e50e | 305 | } |
1e19e50e | 306 | |
1b1d2e6d | 307 | ovsdb_txn_row_insert(txn, dst_row); |
1e19e50e | 308 | } |
1b1d2e6d | 309 | return NULL; |
1e19e50e | 310 | } |
ada496b5 | 311 | |
1b1d2e6d BP |
312 | /* Copies the data in 'src', converts it into the schema specified in |
313 | * 'new_schema', and puts it into a newly created, unbacked database, and | |
314 | * stores a pointer to the new database in '*dstp'. Returns null if | |
315 | * successful, otherwise an error; on error, stores NULL in '*dstp'. */ | |
316 | struct ovsdb_error * OVS_WARN_UNUSED_RESULT | |
317 | ovsdb_convert(const struct ovsdb *src, const struct ovsdb_schema *new_schema, | |
318 | struct ovsdb **dstp) | |
ada496b5 | 319 | { |
1b1d2e6d BP |
320 | struct ovsdb *dst = ovsdb_create(ovsdb_schema_clone(new_schema), |
321 | ovsdb_storage_create_unbacked()); | |
322 | struct ovsdb_txn *txn = ovsdb_txn_create(dst); | |
323 | struct ovsdb_error *error = NULL; | |
e1ebc8ce | 324 | |
1b1d2e6d BP |
325 | struct shash_node *node; |
326 | SHASH_FOR_EACH (node, &src->tables) { | |
327 | const char *table_name = node->name; | |
328 | struct ovsdb_table *src_table = node->data; | |
329 | struct ovsdb_table *dst_table = shash_find_data(&dst->tables, | |
330 | table_name); | |
331 | if (!dst_table) { | |
332 | continue; | |
333 | } | |
bd06962a | 334 | |
1b1d2e6d BP |
335 | error = ovsdb_convert_table(txn, src_table, dst_table); |
336 | if (error) { | |
337 | goto error; | |
338 | } | |
ada496b5 BP |
339 | } |
340 | ||
1b1d2e6d BP |
341 | error = ovsdb_txn_replay_commit(txn); |
342 | if (error) { | |
343 | txn = NULL; /* ovsdb_txn_replay_commit() already aborted. */ | |
344 | goto error; | |
345 | } | |
ada496b5 | 346 | |
1b1d2e6d | 347 | *dstp = dst; |
ada496b5 | 348 | return NULL; |
bd06962a | 349 | |
1b1d2e6d BP |
350 | error: |
351 | ovsdb_destroy(dst); | |
352 | if (txn) { | |
353 | ovsdb_txn_abort(txn); | |
354 | } | |
355 | *dstp = NULL; | |
356 | return error; | |
357 | } | |
358 | \f | |
bd06962a | 359 | static bool |
afe20d5c BP |
360 | ovsdb_file_change_cb(const struct ovsdb_row *old, |
361 | const struct ovsdb_row *new, | |
362 | const unsigned long int *changed, | |
363 | void *ftxn_) | |
a3d573ed BP |
364 | { |
365 | struct ovsdb_file_txn *ftxn = ftxn_; | |
17d18afb | 366 | ovsdb_file_txn_add_row(ftxn, old, new, changed); |
a3d573ed BP |
367 | return true; |
368 | } | |
369 | ||
4d0a31b6 | 370 | struct json * |
1b1d2e6d | 371 | ovsdb_to_txn_json(const struct ovsdb *db, const char *comment) |
4d0a31b6 | 372 | { |
1b1d2e6d BP |
373 | struct ovsdb_file_txn ftxn; |
374 | ||
375 | ovsdb_file_txn_init(&ftxn); | |
376 | ||
377 | struct shash_node *node; | |
378 | SHASH_FOR_EACH (node, &db->tables) { | |
379 | const struct ovsdb_table *table = node->data; | |
380 | const struct ovsdb_row *row; | |
381 | ||
382 | HMAP_FOR_EACH (row, hmap_node, &table->rows) { | |
383 | ovsdb_file_txn_add_row(&ftxn, NULL, row, NULL); | |
384 | } | |
4d0a31b6 | 385 | } |
1b1d2e6d BP |
386 | |
387 | return ovsdb_file_txn_annotate(ftxn.json, comment); | |
4d0a31b6 BP |
388 | } |
389 | ||
53178986 BP |
390 | /* Returns 'txn' transformed into the JSON format that is used in OVSDB files. |
391 | * (But the caller must use ovsdb_file_txn_annotate() to add the _comment and | |
392 | * _date members.) If 'txn' doesn't actually change anything, returns NULL */ | |
1b1d2e6d | 393 | struct json * |
53178986 | 394 | ovsdb_file_txn_to_json(const struct ovsdb_txn *txn) |
a3d573ed | 395 | { |
a3d573ed BP |
396 | struct ovsdb_file_txn ftxn; |
397 | ||
398 | ovsdb_file_txn_init(&ftxn); | |
afe20d5c | 399 | ovsdb_txn_for_each_change(txn, ovsdb_file_change_cb, &ftxn); |
53178986 BP |
400 | return ftxn.json; |
401 | } | |
402 | ||
1b1d2e6d BP |
403 | struct json * |
404 | ovsdb_file_txn_annotate(struct json *json, const char *comment) | |
ada496b5 | 405 | { |
1b1d2e6d BP |
406 | if (!json) { |
407 | json = json_object_create(); | |
ada496b5 | 408 | } |
1b1d2e6d BP |
409 | if (comment) { |
410 | json_object_put_string(json, "_comment", comment); | |
120fb2ca | 411 | } |
2ccd66f5 IM |
412 | if (use_column_diff) { |
413 | json_object_put(json, "_is_diff", json_boolean_create(true)); | |
414 | } | |
1b1d2e6d BP |
415 | json_object_put(json, "_date", json_integer_create(time_wall_msec())); |
416 | return json; | |
a3d573ed | 417 | } |
a3d573ed BP |
418 | \f |
419 | static void | |
420 | ovsdb_file_txn_init(struct ovsdb_file_txn *ftxn) | |
421 | { | |
422 | ftxn->json = NULL; | |
423 | ftxn->table_json = NULL; | |
424 | ftxn->table = NULL; | |
425 | } | |
426 | ||
427 | static void | |
428 | ovsdb_file_txn_add_row(struct ovsdb_file_txn *ftxn, | |
429 | const struct ovsdb_row *old, | |
17d18afb BP |
430 | const struct ovsdb_row *new, |
431 | const unsigned long int *changed) | |
bd06962a | 432 | { |
bd06962a BP |
433 | struct json *row; |
434 | ||
435 | if (!new) { | |
436 | row = json_null_create(); | |
437 | } else { | |
438 | struct shash_node *node; | |
439 | ||
88942565 | 440 | row = old ? NULL : json_object_create(); |
bd06962a BP |
441 | SHASH_FOR_EACH (node, &new->table->schema->columns) { |
442 | const struct ovsdb_column *column = node->data; | |
443 | const struct ovsdb_type *type = &column->type; | |
444 | unsigned int idx = column->index; | |
2ccd66f5 IM |
445 | struct ovsdb_datum datum; |
446 | struct json *column_json; | |
bd06962a BP |
447 | |
448 | if (idx != OVSDB_COL_UUID && column->persistent | |
c532bf9d | 449 | && (old |
17d18afb | 450 | ? bitmap_is_set(changed, idx) |
c532bf9d | 451 | : !ovsdb_datum_is_default(&new->fields[idx], type))) |
bd06962a | 452 | { |
2ccd66f5 IM |
453 | if (old && use_column_diff) { |
454 | ovsdb_datum_diff(&datum, &old->fields[idx], | |
455 | &new->fields[idx], type); | |
456 | column_json = ovsdb_datum_to_json(&datum, type); | |
457 | ovsdb_datum_destroy(&datum, type); | |
458 | } else { | |
459 | column_json = ovsdb_datum_to_json(&new->fields[idx], type); | |
460 | } | |
bd06962a BP |
461 | if (!row) { |
462 | row = json_object_create(); | |
463 | } | |
2ccd66f5 | 464 | json_object_put(row, column->name, column_json); |
bd06962a BP |
465 | } |
466 | } | |
467 | } | |
468 | ||
469 | if (row) { | |
470 | struct ovsdb_table *table = new ? new->table : old->table; | |
471 | char uuid[UUID_LEN + 1]; | |
472 | ||
a3d573ed | 473 | if (table != ftxn->table) { |
bd06962a | 474 | /* Create JSON object for transaction overall. */ |
a3d573ed BP |
475 | if (!ftxn->json) { |
476 | ftxn->json = json_object_create(); | |
bd06962a BP |
477 | } |
478 | ||
479 | /* Create JSON object for transaction on this table. */ | |
a3d573ed BP |
480 | ftxn->table_json = json_object_create(); |
481 | ftxn->table = table; | |
482 | json_object_put(ftxn->json, table->schema->name, ftxn->table_json); | |
bd06962a BP |
483 | } |
484 | ||
485 | /* Add row to transaction for this table. */ | |
486 | snprintf(uuid, sizeof uuid, | |
487 | UUID_FMT, UUID_ARGS(ovsdb_row_get_uuid(new ? new : old))); | |
a3d573ed | 488 | json_object_put(ftxn->table_json, uuid, row); |
bd06962a | 489 | } |
bd06962a | 490 | } |
53178986 | 491 | \f |
1b1d2e6d BP |
492 | static struct ovsdb * |
493 | ovsdb_file_read__(const char *filename, bool rw, | |
494 | struct ovsdb_schema *new_schema) | |
53178986 | 495 | { |
1b1d2e6d BP |
496 | struct ovsdb_storage *storage = ovsdb_storage_open_standalone(filename, |
497 | rw); | |
498 | struct ovsdb_schema *schema = ovsdb_storage_read_schema(storage); | |
499 | if (new_schema) { | |
500 | ovsdb_schema_destroy(schema); | |
501 | schema = new_schema; | |
502 | } | |
503 | struct ovsdb *ovsdb = ovsdb_create(schema, storage); | |
504 | for (;;) { | |
505 | /* Read a transaction. Bail if end-of-file. */ | |
506 | struct json *txn_json; | |
507 | struct ovsdb_schema *schema2; | |
508 | struct ovsdb_error *error = ovsdb_storage_read(storage, &schema2, | |
509 | &txn_json, NULL); | |
510 | if (error) { | |
511 | ovs_fatal(0, "%s", ovsdb_error_to_string_free(error)); | |
53178986 | 512 | } |
1b1d2e6d BP |
513 | ovs_assert(!schema2); |
514 | if (!txn_json) { | |
515 | break; | |
53178986 BP |
516 | } |
517 | ||
1b1d2e6d BP |
518 | /* Apply transaction to database. */ |
519 | struct ovsdb_txn *txn; | |
520 | error = ovsdb_file_txn_from_json(ovsdb, txn_json, new_schema != NULL, | |
521 | &txn); | |
53178986 | 522 | if (error) { |
1b1d2e6d | 523 | ovs_fatal(0, "%s", ovsdb_error_to_string_free(error)); |
53178986 | 524 | } |
53178986 | 525 | json_destroy(txn_json); |
1b1d2e6d BP |
526 | |
527 | error = ovsdb_txn_replay_commit(txn); | |
53178986 | 528 | if (error) { |
1b1d2e6d BP |
529 | ovsdb_storage_unread(storage); |
530 | break; | |
53178986 BP |
531 | } |
532 | } | |
1b1d2e6d BP |
533 | return ovsdb; |
534 | } | |
53178986 | 535 | |
1b1d2e6d BP |
536 | /* Reads 'filename' as a standalone database. Returns the new database. On |
537 | * error, prints a message on stderr and terminates the process. | |
538 | * | |
539 | * If 'rw' is true, opens the database for read/write access, otherwise | |
540 | * read-only. | |
541 | * | |
542 | * Consumes 'schema'. */ | |
543 | struct ovsdb * | |
544 | ovsdb_file_read(const char *filename, bool rw) | |
545 | { | |
546 | return ovsdb_file_read__(filename, rw, NULL); | |
547 | } | |
53178986 | 548 | |
1b1d2e6d BP |
549 | /* Reads 'filename' as a standalone database, using 'schema' in place of the |
550 | * schema embedded in the file. Returns the new database. On error, | |
551 | * prints a message on stderr and terminates the process. | |
552 | * | |
553 | * Consumes 'schema'. */ | |
554 | struct ovsdb * | |
555 | ovsdb_file_read_as_schema(const char *filename, struct ovsdb_schema *schema) | |
556 | { | |
557 | return ovsdb_file_read__(filename, false, schema); | |
53178986 | 558 | } |