diff options
Diffstat (limited to 'ovsdb')
-rw-r--r-- | ovsdb/ovsdb-server.c | 65 | ||||
-rw-r--r-- | ovsdb/ovsdb-tool.c | 35 | ||||
-rw-r--r-- | ovsdb/relay.c | 22 | ||||
-rw-r--r-- | ovsdb/relay.h | 7 |
4 files changed, 93 insertions, 36 deletions
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 4fea2dbda..91c284e99 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -573,8 +573,9 @@ close_db(struct server_config *config, struct db *db, char *comment) } } -static void -update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux) +static struct ovsdb_error * OVS_WARN_UNUSED_RESULT +update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, + bool conversion_with_no_data, void *aux) { struct server_config *config = aux; @@ -586,13 +587,27 @@ update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux) : xasprintf("database %s connected to storage", db->name))); } - ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL)); + if (db->schema && conversion_with_no_data) { + struct ovsdb *new_db = NULL; + struct ovsdb_error *error; + + error = ovsdb_convert(db, schema, &new_db); + if (error) { + /* Should never happen, because conversion should have been + * checked before writing the schema to the storage. */ + return error; + } + ovsdb_replace(db, new_db); + } else { + ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL)); + } /* Force update to schema in _Server database. */ struct db *dbp = shash_find_data(config->all_dbs, db->name); if (dbp) { dbp->row_uuid = UUID_ZERO; } + return NULL; } static struct ovsdb_error * OVS_WARN_UNUSED_RESULT @@ -600,23 +615,30 @@ parse_txn(struct server_config *config, struct db *db, const struct ovsdb_schema *schema, const struct json *txn_json, const struct uuid *txnid) { + struct ovsdb_error *error = NULL; + struct ovsdb_txn *txn = NULL; + if (schema) { - /* We're replacing the schema (and the data). Destroy the database - * (first grabbing its storage), then replace it with the new schema. - * The transaction must also include the replacement data. + /* We're replacing the schema (and the data). If transaction includes + * replacement data, destroy the database (first grabbing its storage), + * then replace it with the new schema. If not, it's a conversion + * without data specified. In this case, convert the current database + * to a new schema instead. * * Only clustered database schema changes and snapshot installs * go through this path. */ - ovs_assert(txn_json); ovs_assert(ovsdb_storage_is_clustered(db->db->storage)); - struct ovsdb_error *error = ovsdb_schema_check_for_ephemeral_columns( - schema); + error = ovsdb_schema_check_for_ephemeral_columns(schema); + if (error) { + return error; + } + + error = update_schema(db->db, schema, txn_json == NULL, config); if (error) { return error; } - update_schema(db->db, schema, config); } if (txn_json) { @@ -624,24 +646,25 @@ parse_txn(struct server_config *config, struct db *db, return ovsdb_error(NULL, "%s: data without schema", db->filename); } - struct ovsdb_txn *txn; - struct ovsdb_error *error; - error = ovsdb_file_txn_from_json(db->db, txn_json, false, &txn); - if (!error) { - ovsdb_txn_set_txnid(txnid, txn); - log_and_free_error(ovsdb_txn_replay_commit(txn)); - } - if (!error && !uuid_is_zero(txnid)) { - db->db->prereq = *txnid; - } if (error) { ovsdb_storage_unread(db->db->storage); return error; } + } else if (schema) { + /* We just performed conversion without data. Transaction history + * was destroyed. Commit a dummy transaction to set the txnid. */ + txn = ovsdb_txn_create(db->db); } - return NULL; + if (txn) { + ovsdb_txn_set_txnid(txnid, txn); + error = ovsdb_txn_replay_commit(txn); + if (!error && !uuid_is_zero(txnid)) { + db->db->prereq = *txnid; + } + } + return error; } static void diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c index ea2b75b46..e26536532 100644 --- a/ovsdb/ovsdb-tool.c +++ b/ovsdb/ovsdb-tool.c @@ -1006,7 +1006,8 @@ raft_header_to_standalone_log(const struct raft_header *h, } static void -raft_record_to_standalone_log(const struct raft_record *r, +raft_record_to_standalone_log(const char *db_file_name, + const struct raft_record *r, struct ovsdb_log *db_log_data) { if (r->type == RAFT_REC_ENTRY) { @@ -1024,15 +1025,30 @@ raft_record_to_standalone_log(const struct raft_record *r, if (schema_json->type != JSON_NULL) { /* This is a database conversion record. Reset the log and - * write the new schema. Data JSON should also be part of - * the conversion. */ + * write the new schema. */ struct ovsdb_schema *schema; + check_ovsdb_error(ovsdb_schema_from_json(schema_json, &schema)); + if (data_json->type == JSON_NULL) { - ovs_fatal( - 0, "Invalid database conversion in the log: no data"); + /* We have a conversion request with no data. There is no + * other way as to read back what we have and convert. */ + struct ovsdb *old_db, *new_db; + + check_ovsdb_error(ovsdb_log_commit_block(db_log_data)); + + old_db = ovsdb_file_read(db_file_name, false); + check_ovsdb_error(ovsdb_convert(old_db, schema, &new_db)); + ovsdb_destroy(old_db); + + pa->elems[1] = ovsdb_to_txn_json( + new_db, "converted by ovsdb-tool", true); + ovsdb_destroy(new_db); + + json_destroy(data_json); + data_json = pa->elems[1]; } - check_ovsdb_error(ovsdb_schema_from_json(schema_json, &schema)); + ovsdb_schema_destroy(schema); check_ovsdb_error(ovsdb_log_reset(db_log_data)); check_ovsdb_error(ovsdb_log_write(db_log_data, schema_json)); @@ -1654,7 +1670,8 @@ do_compare_versions(struct ovs_cmdl_context *ctx) } static void -do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data) +do_convert_to_standalone(const char *db_file_name, + struct ovsdb_log *log, struct ovsdb_log *db_log_data) { for (unsigned int i = 0; ; i++) { struct json *json; @@ -1671,7 +1688,7 @@ do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data) } else { struct raft_record r; check_ovsdb_error(raft_record_from_json(&r, json)); - raft_record_to_standalone_log(&r, db_log_data); + raft_record_to_standalone_log(db_file_name, &r, db_log_data); raft_record_uninit(&r); } json_destroy(json); @@ -1694,7 +1711,7 @@ do_cluster_standalone(struct ovs_cmdl_context *ctx) if (strcmp(ovsdb_log_get_magic(log), RAFT_MAGIC) != 0) { ovs_fatal(0, "Database is not clustered db.\n"); } - do_convert_to_standalone(log, db_log_data); + do_convert_to_standalone(db_file_name, log, db_log_data); check_ovsdb_error(ovsdb_log_commit_block(db_log_data)); ovsdb_log_close(db_log_data); ovsdb_log_close(log); diff --git a/ovsdb/relay.c b/ovsdb/relay.c index 9ff6ed8f3..94ffe01e5 100644 --- a/ovsdb/relay.c +++ b/ovsdb/relay.c @@ -301,6 +301,8 @@ static void ovsdb_relay_parse_update(struct relay_ctx *ctx, const struct ovsdb_cs_update_event *update) { + struct ovsdb_error *error = NULL; + if (!ctx->db) { return; } @@ -308,15 +310,27 @@ ovsdb_relay_parse_update(struct relay_ctx *ctx, if (update->monitor_reply && ctx->new_schema) { /* There was a schema change. Updating a database with a new schema * before processing monitor reply with the new data. */ - ctx->schema_change_cb(ctx->db, ctx->new_schema, - ctx->schema_change_aux); + error = ctx->schema_change_cb(ctx->db, ctx->new_schema, false, + ctx->schema_change_aux); + if (error) { + /* Should never happen, but handle this case anyway. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + char *s = ovsdb_error_to_string_free(error); + + VLOG_ERR_RL(&rl, "%s", s); + free(s); + + ovsdb_cs_flag_inconsistency(ctx->cs); + return; + } ovsdb_schema_destroy(ctx->new_schema); ctx->new_schema = NULL; } struct ovsdb_cs_db_update *du; - struct ovsdb_error *error = ovsdb_cs_parse_db_update(update->table_updates, - update->version, &du); + + error = ovsdb_cs_parse_db_update(update->table_updates, + update->version, &du); if (!error) { if (update->clear) { error = ovsdb_relay_clear(ctx->db); diff --git a/ovsdb/relay.h b/ovsdb/relay.h index 390ea70c8..2d66b5e5f 100644 --- a/ovsdb/relay.h +++ b/ovsdb/relay.h @@ -23,8 +23,11 @@ struct json; struct ovsdb; struct ovsdb_schema; -typedef void (*schema_change_callback)(struct ovsdb *, - const struct ovsdb_schema *, void *aux); +typedef struct ovsdb_error *(*schema_change_callback)( + struct ovsdb *, + const struct ovsdb_schema *, + bool conversion_with_no_data, + void *aux); void ovsdb_relay_add_db(struct ovsdb *, const char *remote, schema_change_callback schema_change_cb, |