2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

ovsdb-cs: New module that factors out code from ovsdb-idl.

This new module has a single direct user now.  In the future, it
will also be used by OVN.

Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Ben Pfaff
2020-12-01 18:15:11 -08:00
parent 81f06e2b8f
commit a5c067a8b9
4 changed files with 471 additions and 369 deletions

View File

@@ -32,6 +32,7 @@
#include "jsonrpc.h"
#include "ovsdb/ovsdb.h"
#include "ovsdb/table.h"
#include "ovsdb-cs.h"
#include "ovsdb-data.h"
#include "ovsdb-error.h"
#include "ovsdb-idl-provider.h"
@@ -311,8 +312,8 @@ static struct vlog_rate_limit other_rl = VLOG_RATE_LIMIT_INIT(1, 5);
static void ovsdb_idl_clear(struct ovsdb_idl *);
static void ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db *,
const struct json *result,
enum ovsdb_idl_monitor_method method);
const struct json *result,
int version);
static bool ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db *,
const struct jsonrpc_msg *);
static bool ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl *,
@@ -320,25 +321,18 @@ static bool ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl *,
const struct jsonrpc_msg *);
static void ovsdb_idl_db_parse_update(struct ovsdb_idl_db *,
const struct json *table_updates,
enum ovsdb_idl_monitor_method method);
int version);
enum update_result {
OVSDB_IDL_UPDATE_DB_CHANGED,
OVSDB_IDL_UPDATE_NO_CHANGES,
OVSDB_IDL_UPDATE_INCONSISTENT,
};
static enum update_result ovsdb_idl_process_update(struct ovsdb_idl_table *,
const struct uuid *,
const struct json *old,
const struct json *new);
static enum update_result ovsdb_idl_process_update2(struct ovsdb_idl_table *,
const struct uuid *,
const char *operation,
const struct json *row);
static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct json *);
static enum update_result ovsdb_idl_process_update(
struct ovsdb_idl_table *, const struct ovsdb_cs_row_update *);
static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct shash *);
static void ovsdb_idl_delete_row(struct ovsdb_idl_row *);
static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct json *);
static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *,
const struct json *);
static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct shash *,
bool xor);
static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *);
static struct ovsdb_idl_row *ovsdb_idl_row_create__(
@@ -776,8 +770,7 @@ ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
case IDL_S_SERVER_MONITOR_COND_REQUESTED:
if (ok) {
idl->server.monitoring = OVSDB_IDL_MONITORING_COND;
ovsdb_idl_db_parse_monitor_reply(&idl->server, msg->result,
OVSDB_IDL_MM_MONITOR_COND);
ovsdb_idl_db_parse_monitor_reply(&idl->server, msg->result, 2);
if (ovsdb_idl_check_server_db(idl)) {
ovsdb_idl_send_db_change_aware(idl);
}
@@ -804,8 +797,7 @@ ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
} else {
idl->data.monitoring = OVSDB_IDL_MONITORING_COND_SINCE;
ovsdb_idl_transition(idl, IDL_S_MONITORING);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
OVSDB_IDL_MM_MONITOR_COND_SINCE);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result, 3);
}
break;
@@ -818,16 +810,14 @@ ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
} else {
idl->data.monitoring = OVSDB_IDL_MONITORING_COND;
ovsdb_idl_transition(idl, IDL_S_MONITORING);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
OVSDB_IDL_MM_MONITOR_COND);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result, 2);
}
break;
case IDL_S_DATA_MONITOR_REQUESTED:
idl->data.monitoring = OVSDB_IDL_MONITORING;
ovsdb_idl_transition(idl, IDL_S_MONITORING);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result,
OVSDB_IDL_MM_MONITOR);
ovsdb_idl_db_parse_monitor_reply(&idl->data, msg->result, 1);
idl->data.change_seqno++;
break;
@@ -2100,94 +2090,11 @@ ovsdb_idl_check_server_db(struct ovsdb_idl *idl)
return true;
}
static void
log_error(struct ovsdb_error *error)
{
char *s = ovsdb_error_to_string_free(error);
VLOG_WARN("error parsing database schema: %s", s);
free(s);
}
/* Frees 'schema', which is in the format returned by parse_schema(). */
static void
free_schema(struct shash *schema)
{
if (schema) {
struct shash_node *node, *next;
SHASH_FOR_EACH_SAFE (node, next, schema) {
struct sset *sset = node->data;
sset_destroy(sset);
free(sset);
shash_delete(schema, node);
}
shash_destroy(schema);
free(schema);
}
}
/* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
* 7047, to obtain the names of its rows and columns. If successful, returns
* an shash whose keys are table names and whose values are ssets, where each
* sset contains the names of its table's columns. On failure (due to a parse
* error), returns NULL.
*
* It would also be possible to use the general-purpose OVSDB schema parser in
* ovsdb-server, but that's overkill, possibly too strict for the current use
* case, and would require restructuring ovsdb-server to separate the schema
* code from the rest. */
static struct shash *
parse_schema(const struct json *schema_json)
{
struct ovsdb_parser parser;
const struct json *tables_json;
struct ovsdb_error *error;
struct shash_node *node;
struct shash *schema;
ovsdb_parser_init(&parser, schema_json, "database schema");
tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
error = ovsdb_parser_destroy(&parser);
if (error) {
log_error(error);
return NULL;
}
schema = xmalloc(sizeof *schema);
shash_init(schema);
SHASH_FOR_EACH (node, json_object(tables_json)) {
const char *table_name = node->name;
const struct json *json = node->data;
const struct json *columns_json;
ovsdb_parser_init(&parser, json, "table schema for table %s",
table_name);
columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
error = ovsdb_parser_destroy(&parser);
if (error) {
log_error(error);
free_schema(schema);
return NULL;
}
struct sset *columns = xmalloc(sizeof *columns);
sset_init(columns);
struct shash_node *node2;
SHASH_FOR_EACH (node2, json_object(columns_json)) {
const char *column_name = node2->name;
sset_add(columns, column_name);
}
shash_add(schema, table_name, columns);
}
return schema;
}
static void
ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db,
enum ovsdb_idl_monitor_method monitor_method)
{
struct shash *schema = parse_schema(db->schema);
struct shash *schema = ovsdb_cs_parse_schema(db->schema);
struct json *monitor_requests = json_object_create();
for (size_t i = 0; i < db->class_->n_tables; i++) {
@@ -2250,7 +2157,7 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db,
json_array_create_1(monitor_request));
}
}
free_schema(schema);
ovsdb_cs_free_schema(schema);
struct json *params = json_array_create_3(
json_string_create(db->class_->database),
@@ -2290,13 +2197,12 @@ log_parse_update_error(struct ovsdb_error *error)
static void
ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db *db,
const struct json *result,
enum ovsdb_idl_monitor_method method)
const struct json *result, int version)
{
db->change_seqno++;
const struct json *table_updates = result;
bool clear_db = true;
if (method == OVSDB_IDL_MM_MONITOR_COND_SINCE) {
if (version == 3) {
if (result->type != JSON_ARRAY || result->array.n != 3) {
struct ovsdb_error *error = ovsdb_syntax_error(result, NULL,
"Response of monitor_cond_since must "
@@ -2324,7 +2230,7 @@ ovsdb_idl_db_parse_monitor_reply(struct ovsdb_idl_db *db,
if (clear_db) {
ovsdb_idl_db_clear(db);
}
ovsdb_idl_db_parse_update(db, table_updates, method);
ovsdb_idl_db_parse_update(db, table_updates, version);
}
static bool
@@ -2335,16 +2241,16 @@ ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db *db,
return false;
}
enum ovsdb_idl_monitor_method mm;
int version;
uint8_t n;
if (!strcmp(msg->method, "update")) {
mm = OVSDB_IDL_MM_MONITOR;
version = 1;
n = 2;
} else if (!strcmp(msg->method, "update2")) {
mm = OVSDB_IDL_MM_MONITOR_COND;
version = 2;
n = 2;
} else if (!strcmp(msg->method, "update3")) {
mm = OVSDB_IDL_MM_MONITOR_COND_SINCE;
version = 3;
n = 3;
} else {
return false;
@@ -2375,7 +2281,7 @@ ovsdb_idl_db_parse_update_rpc(struct ovsdb_idl_db *db,
return false;
}
}
ovsdb_idl_db_parse_update(db, table_updates, mm);
ovsdb_idl_db_parse_update(db, table_updates, version);
return true;
}
@@ -2416,124 +2322,21 @@ ovsdb_idl_handle_monitor_canceled(struct ovsdb_idl *idl,
static struct ovsdb_error *
ovsdb_idl_db_parse_update__(struct ovsdb_idl_db *db,
const struct json *table_updates,
enum ovsdb_idl_monitor_method method)
const struct ovsdb_cs_db_update *du)
{
const struct shash_node *tables_node;
const char *version_suffix;
switch (method) {
case OVSDB_IDL_MM_MONITOR:
version_suffix = "";
break;
case OVSDB_IDL_MM_MONITOR_COND:
case OVSDB_IDL_MM_MONITOR_COND_SINCE:
version_suffix = "2";
break;
default:
OVS_NOT_REACHED();
}
for (size_t i = 0; i < du->n; i++) {
const struct ovsdb_cs_table_update *tu = &du->table_updates[i];
if (table_updates->type != JSON_OBJECT) {
return ovsdb_syntax_error(table_updates, NULL,
"<table_updates%s> is not an object",
version_suffix);
}
SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
const struct json *table_update = tables_node->data;
const struct shash_node *table_node;
struct ovsdb_idl_table *table;
table = shash_find_data(&db->table_by_name, tables_node->name);
struct ovsdb_idl_table *table = shash_find_data(&db->table_by_name,
tu->table_name);
if (!table) {
return ovsdb_syntax_error(
table_updates, NULL,
"<table_updates%s> includes unknown table \"%s\"",
version_suffix, tables_node->name);
NULL, NULL, "update to unknown table \"%s\"", tu->table_name);
}
if (table_update->type != JSON_OBJECT) {
return ovsdb_syntax_error(table_update, NULL,
"<table_update%s> for table \"%s\" is "
"not an object",
version_suffix, table->class_->name);
}
SHASH_FOR_EACH (table_node, json_object(table_update)) {
enum update_result result = OVSDB_IDL_UPDATE_NO_CHANGES;
const struct json *row_update = table_node->data;
struct uuid uuid;
if (!uuid_from_string(&uuid, table_node->name)) {
return ovsdb_syntax_error(table_update, NULL,
"<table_update%s> for table \"%s\" "
"contains bad UUID "
"\"%s\" as member name",
version_suffix,
table->class_->name,
table_node->name);
}
if (row_update->type != JSON_OBJECT) {
return ovsdb_syntax_error(row_update, NULL,
"<table_update%s> for table \"%s\" "
"contains <row_update%s> for %s "
"that is not an object",
version_suffix, table->class_->name,
version_suffix, table_node->name);
}
if (method == OVSDB_IDL_MM_MONITOR_COND ||
method == OVSDB_IDL_MM_MONITOR_COND_SINCE) {
const char *ops[] = {"modify", "insert", "delete", "initial"};
const char *operation;
const struct json *row;
int i;
for (i = 0; i < ARRAY_SIZE(ops); i++) {
operation = ops[i];
row = shash_find_data(json_object(row_update), operation);
if (!row) {
continue;
}
result = ovsdb_idl_process_update2(table, &uuid,
operation, row);
break;
}
/* row_update2 should contain one of the objects */
if (i == ARRAY_SIZE(ops)) {
return ovsdb_syntax_error(row_update, NULL,
"<row_update2> includes unknown "
"object");
}
} else {
const struct json *old_json, *new_json;
old_json = shash_find_data(json_object(row_update), "old");
new_json = shash_find_data(json_object(row_update), "new");
if (old_json && old_json->type != JSON_OBJECT) {
return ovsdb_syntax_error(old_json, NULL,
"\"old\" <row> is not object");
} else if (new_json && new_json->type != JSON_OBJECT) {
return ovsdb_syntax_error(new_json, NULL,
"\"new\" <row> is not object");
} else if ((old_json != NULL) + (new_json != NULL)
!= shash_count(json_object(row_update))) {
return ovsdb_syntax_error(row_update, NULL,
"<row-update> contains "
"unexpected member");
} else if (!old_json && !new_json) {
return ovsdb_syntax_error(row_update, NULL,
"<row-update> missing \"old\" "
"and \"new\" members");
}
result = ovsdb_idl_process_update(table, &uuid, old_json,
new_json);
}
switch (result) {
for (size_t j = 0; j < tu->n; j++) {
const struct ovsdb_cs_row_update *ru = &tu->row_updates[j];
switch (ovsdb_idl_process_update(table, ru)) {
case OVSDB_IDL_UPDATE_DB_CHANGED:
db->change_seqno++;
break;
@@ -2543,10 +2346,9 @@ ovsdb_idl_db_parse_update__(struct ovsdb_idl_db *db,
memset(&db->last_id, 0, sizeof db->last_id);
ovsdb_idl_retry(db->idl);
return ovsdb_error(NULL,
"<row_update%s> received for inconsistent "
"row update received for inconsistent "
"IDL: reconnecting IDL and resync all "
"data",
version_suffix);
"data");
}
}
}
@@ -2556,11 +2358,16 @@ ovsdb_idl_db_parse_update__(struct ovsdb_idl_db *db,
static void
ovsdb_idl_db_parse_update(struct ovsdb_idl_db *db,
const struct json *table_updates,
enum ovsdb_idl_monitor_method method)
const struct json *json_table_updates,
int version)
{
struct ovsdb_error *error = ovsdb_idl_db_parse_update__(db, table_updates,
method);
struct ovsdb_cs_db_update *du;
struct ovsdb_error *error = ovsdb_cs_parse_db_update(
json_table_updates, version, &du);
if (!error) {
error = ovsdb_idl_db_parse_update__(db, du);
}
ovsdb_cs_db_update_destroy(du);
if (error) {
log_parse_update_error(error);
}
@@ -2596,14 +2403,13 @@ ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
*/
static enum update_result
ovsdb_idl_process_update(struct ovsdb_idl_table *table,
const struct uuid *uuid, const struct json *old,
const struct json *new)
const struct ovsdb_cs_row_update *ru)
{
struct ovsdb_idl_row *row;
const struct uuid *uuid = &ru->row_uuid;
struct ovsdb_idl_row *row = ovsdb_idl_get_row(table, uuid);
row = ovsdb_idl_get_row(table, uuid);
if (!new) {
/* Delete row. */
switch (ru->type) {
case OVSDB_CS_ROW_DELETE:
if (row && !ovsdb_idl_row_is_orphan(row)) {
/* XXX perhaps we should check the 'old' values? */
ovsdb_idl_delete_row(row);
@@ -2613,23 +2419,27 @@ ovsdb_idl_process_update(struct ovsdb_idl_table *table,
UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else if (!old) {
/* Insert row. */
break;
case OVSDB_CS_ROW_INSERT:
if (!row) {
ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid),
ru->columns);
} else if (ovsdb_idl_row_is_orphan(row)) {
ovsdb_idl_insert_row(row, new);
ovsdb_idl_insert_row(row, ru->columns);
} else {
VLOG_ERR_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
"table %s", UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else {
/* Modify row. */
break;
case OVSDB_CS_ROW_UPDATE:
case OVSDB_CS_ROW_XOR:
if (row) {
/* XXX perhaps we should check the 'old' values? */
if (!ovsdb_idl_row_is_orphan(row)) {
return ovsdb_idl_modify_row(row, new)
return ovsdb_idl_modify_row(row, ru->columns,
ru->type == OVSDB_CS_ROW_XOR)
? OVSDB_IDL_UPDATE_DB_CHANGED
: OVSDB_IDL_UPDATE_NO_CHANGES;
} else {
@@ -2643,78 +2453,10 @@ ovsdb_idl_process_update(struct ovsdb_idl_table *table,
"in table %s", UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
}
break;
return OVSDB_IDL_UPDATE_DB_CHANGED;
}
/* Returns OVSDB_IDL_UPDATE_DB_CHANGED if a column with mode
* OVSDB_IDL_MODE_RW changed.
*
* Some IDL inconsistencies can be detected when processing updates:
* - trying to insert an already existing row
* - trying to update a missing row
* - trying to delete a non existent row
*
* In such cases OVSDB_IDL_UPDATE_INCONSISTENT is returned.
* Even though the IDL client could recover, it's best to report the
* inconsistent state because the state the server is in is unknown so the
* safest thing to do is to retry (potentially connecting to a new server).
*
* Otherwise OVSDB_IDL_UPDATE_NO_CHANGES is returned.
*/
static enum update_result
ovsdb_idl_process_update2(struct ovsdb_idl_table *table,
const struct uuid *uuid,
const char *operation,
const struct json *json_row)
{
struct ovsdb_idl_row *row;
row = ovsdb_idl_get_row(table, uuid);
if (!strcmp(operation, "delete")) {
/* Delete row. */
if (row && !ovsdb_idl_row_is_orphan(row)) {
ovsdb_idl_delete_row(row);
} else {
VLOG_ERR_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
"from table %s",
UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else if (!strcmp(operation, "insert") || !strcmp(operation, "initial")) {
/* Insert row. */
if (!row) {
ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), json_row);
} else if (ovsdb_idl_row_is_orphan(row)) {
ovsdb_idl_insert_row(row, json_row);
} else {
VLOG_ERR_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
"table %s", UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else if (!strcmp(operation, "modify")) {
/* Modify row. */
if (row) {
if (!ovsdb_idl_row_is_orphan(row)) {
return ovsdb_idl_modify_row_by_diff(row, json_row)
? OVSDB_IDL_UPDATE_DB_CHANGED
: OVSDB_IDL_UPDATE_NO_CHANGES;
} else {
VLOG_ERR_RL(&semantic_rl, "cannot modify missing but "
"referenced row "UUID_FMT" in table %s",
UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else {
VLOG_ERR_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
"in table %s", UUID_ARGS(uuid), table->class_->name);
return OVSDB_IDL_UPDATE_INCONSISTENT;
}
} else {
VLOG_ERR_RL(&semantic_rl, "unknown operation %s to "
"table %s", operation, table->class_->name);
return OVSDB_IDL_UPDATE_NO_CHANGES;
default:
OVS_NOT_REACHED();
}
return OVSDB_IDL_UPDATE_DB_CHANGED;
@@ -2751,18 +2493,14 @@ add_tracked_change_for_references(struct ovsdb_idl_row *row)
* Caller needs to provide either valid 'row_json' or 'diff', but not
* both. */
static bool
ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
const struct json *diff_json,
enum ovsdb_idl_change change)
ovsdb_idl_row_change(struct ovsdb_idl_row *row, const struct shash *values,
bool xor, enum ovsdb_idl_change change)
{
struct ovsdb_idl_table *table = row->table;
const struct ovsdb_idl_table_class *class = table->class_;
struct shash_node *node;
bool changed = false;
bool apply_diff = diff_json != NULL;
const struct json *json = apply_diff ? diff_json : row_json;
SHASH_FOR_EACH (node, json_object(json)) {
SHASH_FOR_EACH (node, values) {
const char *column_name = node->name;
const struct ovsdb_idl_column *column;
struct ovsdb_datum datum;
@@ -2781,10 +2519,9 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
old = &row->old_datum[column_idx];
error = NULL;
if (apply_diff) {
if (xor) {
struct ovsdb_datum diff;
ovs_assert(!row_json);
error = ovsdb_transient_datum_from_json(&diff, &column->type,
node->data);
if (!error) {
@@ -2793,7 +2530,6 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
ovsdb_datum_destroy(&diff, &column->type);
}
} else {
ovs_assert(!diff_json);
error = ovsdb_datum_from_json(&datum, &column->type, node->data,
NULL);
}
@@ -2838,21 +2574,6 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
return changed;
}
static bool
ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json,
enum ovsdb_idl_change change)
{
return ovsdb_idl_row_change__(row, row_json, NULL, change);
}
static bool
ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *row,
const struct json *diff_json,
enum ovsdb_idl_change change)
{
return ovsdb_idl_row_change__(row, NULL, diff_json, change);
}
/* When a row A refers to row B through a column with a "refTable" constraint,
* but row B does not exist, row B is called an "orphan row". Orphan rows
* should not persist, because the database enforces referential integrity, but
@@ -3440,7 +3161,7 @@ ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl_db *db)
}
static void
ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct shash *data)
{
const struct ovsdb_idl_table_class *class = row->table->class_;
size_t i, datum_size;
@@ -3451,7 +3172,7 @@ ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
for (i = 0; i < class->n_columns; i++) {
ovsdb_datum_init_default(&row->old_datum[i], &class->columns[i].type);
}
ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_INSERT);
ovsdb_idl_row_change(row, data, false, OVSDB_IDL_CHANGE_INSERT);
ovsdb_idl_row_parse(row);
ovsdb_idl_row_reparse_backrefs(row);
@@ -3474,31 +3195,14 @@ ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
/* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
* otherwise. */
static bool
ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct shash *values,
bool xor)
{
bool changed;
ovsdb_idl_remove_from_indexes(row);
ovsdb_idl_row_unparse(row);
ovsdb_idl_row_clear_arcs(row, true);
changed = ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_MODIFY);
ovsdb_idl_row_parse(row);
ovsdb_idl_add_to_indexes(row);
return changed;
}
static bool
ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *row,
const struct json *diff_json)
{
bool changed;
ovsdb_idl_remove_from_indexes(row);
ovsdb_idl_row_unparse(row);
ovsdb_idl_row_clear_arcs(row, true);
changed = ovsdb_idl_row_apply_diff(row, diff_json,
OVSDB_IDL_CHANGE_MODIFY);
bool changed = ovsdb_idl_row_change(row, values, xor,
OVSDB_IDL_CHANGE_MODIFY);
ovsdb_idl_row_parse(row);
ovsdb_idl_add_to_indexes(row);