summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ovsdb/ovsdb-server.c22
-rw-r--r--ovsdb/relay.c4
-rw-r--r--ovsdb/relay.h2
-rw-r--r--ovsdb/transaction.c6
-rw-r--r--ovsdb/transaction.h3
-rw-r--r--ovsdb/trigger.c41
-rw-r--r--ovsdb/trigger.h7
7 files changed, 65 insertions, 20 deletions
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index b64814076..9bad0c8dd 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -574,7 +574,9 @@ close_db(struct server_config *config, struct db *db, char *comment)
}
static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
-update_schema(struct ovsdb *db, const struct ovsdb_schema *schema,
+update_schema(struct ovsdb *db,
+ const struct ovsdb_schema *schema,
+ const struct uuid *txnid,
bool conversion_with_no_data, void *aux)
{
struct server_config *config = aux;
@@ -591,11 +593,17 @@ update_schema(struct ovsdb *db, const struct ovsdb_schema *schema,
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;
+ /* If conversion was triggered by the current process, we might
+ * already have converted version of a database. */
+ new_db = ovsdb_trigger_find_and_steal_converted_db(db, txnid);
+ if (!new_db) {
+ /* No luck. Converting. */
+ 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 {
@@ -635,7 +643,7 @@ parse_txn(struct server_config *config, struct db *db,
return error;
}
- error = update_schema(db->db, schema, txn_json == NULL, config);
+ error = update_schema(db->db, schema, txnid, txn_json == NULL, config);
if (error) {
return error;
}
diff --git a/ovsdb/relay.c b/ovsdb/relay.c
index 94ffe01e5..377f3285f 100644
--- a/ovsdb/relay.c
+++ b/ovsdb/relay.c
@@ -310,8 +310,8 @@ 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. */
- error = ctx->schema_change_cb(ctx->db, ctx->new_schema, false,
- ctx->schema_change_aux);
+ error = ctx->schema_change_cb(ctx->db, ctx->new_schema, &UUID_ZERO,
+ 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);
diff --git a/ovsdb/relay.h b/ovsdb/relay.h
index 2d66b5e5f..f841554ca 100644
--- a/ovsdb/relay.h
+++ b/ovsdb/relay.h
@@ -22,10 +22,12 @@
struct json;
struct ovsdb;
struct ovsdb_schema;
+struct uuid;
typedef struct ovsdb_error *(*schema_change_callback)(
struct ovsdb *,
const struct ovsdb_schema *,
+ const struct uuid *,
bool conversion_with_no_data,
void *aux);
diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
index f01de2a34..7cf4a851a 100644
--- a/ovsdb/transaction.c
+++ b/ovsdb/transaction.c
@@ -1252,14 +1252,14 @@ ovsdb_txn_precheck_prereq(const struct ovsdb *db)
struct ovsdb_txn_progress *
ovsdb_txn_propose_schema_change(struct ovsdb *db,
const struct ovsdb_schema *schema,
- const struct json *data)
+ const struct json *data,
+ struct uuid *txnid)
{
struct ovsdb_txn_progress *progress = xzalloc(sizeof *progress);
progress->storage = db->storage;
- struct uuid next;
struct ovsdb_write *write = ovsdb_storage_write_schema_change(
- db->storage, schema, data, &db->prereq, &next);
+ db->storage, schema, data, &db->prereq, txnid);
if (!ovsdb_write_is_complete(write)) {
progress->write = write;
} else {
diff --git a/ovsdb/transaction.h b/ovsdb/transaction.h
index 9991f34d2..0e054eef3 100644
--- a/ovsdb/transaction.h
+++ b/ovsdb/transaction.h
@@ -42,7 +42,8 @@ struct ovsdb_error *ovsdb_txn_propose_commit_block(struct ovsdb_txn *,
void ovsdb_txn_complete(struct ovsdb_txn *);
struct ovsdb_txn_progress *ovsdb_txn_propose_schema_change(
- struct ovsdb *, const struct ovsdb_schema *, const struct json *data);
+ struct ovsdb *, const struct ovsdb_schema *,
+ const struct json *data, struct uuid *txnid);
bool ovsdb_txn_progress_is_complete(const struct ovsdb_txn_progress *);
const struct ovsdb_error *ovsdb_txn_progress_get_error(
diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c
index 0706d66cc..0edcdd89c 100644
--- a/ovsdb/trigger.c
+++ b/ovsdb/trigger.c
@@ -31,6 +31,7 @@
#include "transaction-forward.h"
#include "openvswitch/vlog.h"
#include "util.h"
+#include "uuid.h"
VLOG_DEFINE_THIS_MODULE(trigger);
@@ -52,6 +53,7 @@ ovsdb_trigger_init(struct ovsdb_session *session, struct ovsdb *db,
trigger->db = db;
ovs_list_push_back(&trigger->db->triggers, &trigger->node);
trigger->request = request;
+ trigger->converted_db = NULL;
trigger->reply = NULL;
trigger->progress = NULL;
trigger->txn_forward = NULL;
@@ -69,6 +71,7 @@ ovsdb_trigger_destroy(struct ovsdb_trigger *trigger)
ovsdb_txn_progress_destroy(trigger->progress);
ovsdb_txn_forward_destroy(trigger->db, trigger->txn_forward);
ovs_list_remove(&trigger->node);
+ ovsdb_destroy(trigger->converted_db);
jsonrpc_msg_destroy(trigger->request);
jsonrpc_msg_destroy(trigger->reply);
free(trigger->role);
@@ -143,6 +146,30 @@ ovsdb_trigger_prereplace_db(struct ovsdb_trigger *trigger)
}
}
+/* Find among incomplete triggers one that caused database conversion
+ * with specified transaction ID. */
+struct ovsdb *
+ovsdb_trigger_find_and_steal_converted_db(const struct ovsdb *db,
+ const struct uuid *txnid)
+{
+ struct ovsdb *converted_db = NULL;
+ struct ovsdb_trigger *t;
+
+ if (uuid_is_zero(txnid)) {
+ return NULL;
+ }
+
+ LIST_FOR_EACH_SAFE (t, node, &db->triggers) {
+ if (t->db == db && t->converted_db
+ && uuid_equals(&t->conversion_txnid, txnid)) {
+ converted_db = t->converted_db;
+ t->converted_db = NULL;
+ break;
+ }
+ }
+ return converted_db;
+}
+
bool
ovsdb_trigger_run(struct ovsdb *db, long long int now)
{
@@ -200,7 +227,6 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
ovs_assert(!t->progress);
struct ovsdb_txn *txn = NULL;
- struct ovsdb *newdb = NULL;
if (!strcmp(t->request->method, "transact")) {
if (!ovsdb_txn_precheck_prereq(t->db)) {
return false;
@@ -272,7 +298,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
new_schema->name, t->db->schema->name);
}
if (!error) {
- error = ovsdb_convert(t->db, new_schema, &newdb);
+ ovsdb_destroy(t->converted_db);
+ error = ovsdb_convert(t->db, new_schema, &t->converted_db);
}
if (error) {
ovsdb_schema_destroy(new_schema);
@@ -286,12 +313,12 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
} else {
/* Make the new copy into a transaction log record. */
txn_json = ovsdb_to_txn_json(
- newdb, "converted by ovsdb-server", true);
+ t->converted_db, "converted by ovsdb-server", true);
}
/* Propose the change. */
t->progress = ovsdb_txn_propose_schema_change(
- t->db, new_schema, txn_json);
+ t->db, new_schema, txn_json, &t->conversion_txnid);
ovsdb_schema_destroy(new_schema);
json_destroy(txn_json);
t->reply = jsonrpc_create_reply(json_object_create(),
@@ -313,13 +340,13 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
ovsdb_txn_progress_destroy(t->progress);
t->progress = NULL;
ovsdb_trigger_complete(t);
- if (newdb) {
- ovsdb_replace(t->db, newdb);
+ if (t->converted_db) {
+ ovsdb_replace(t->db, t->converted_db);
+ t->converted_db = NULL;
return true;
}
return false;
}
- ovsdb_destroy(newdb);
/* Fall through to the general handling for the "committing" state. We
* abort the transaction--if and when it eventually commits, we'll read
diff --git a/ovsdb/trigger.h b/ovsdb/trigger.h
index d060c72e5..87ff4d053 100644
--- a/ovsdb/trigger.h
+++ b/ovsdb/trigger.h
@@ -17,6 +17,7 @@
#define OVSDB_TRIGGER_H 1
#include "openvswitch/list.h"
+#include "openvswitch/uuid.h"
struct ovsdb;
@@ -54,6 +55,8 @@ struct ovsdb_trigger {
struct ovs_list node;
struct ovsdb_session *session; /* Session that owns this trigger. */
struct ovsdb *db; /* Database on which trigger acts. */
+ struct ovsdb *converted_db; /* Result of the 'convert' request. */
+ struct uuid conversion_txnid; /* txnid of the conversion request. */
struct jsonrpc_msg *request; /* Database request. */
struct jsonrpc_msg *reply; /* Result (null if none yet). */
struct ovsdb_txn_progress *progress;
@@ -77,6 +80,10 @@ void ovsdb_trigger_cancel(struct ovsdb_trigger *, const char *reason);
void ovsdb_trigger_prereplace_db(struct ovsdb_trigger *);
+struct ovsdb *ovsdb_trigger_find_and_steal_converted_db(
+ const struct ovsdb *, const struct uuid *)
+ OVS_WARN_UNUSED_RESULT;
+
bool ovsdb_trigger_run(struct ovsdb *, long long int now);
void ovsdb_trigger_wait(struct ovsdb *, long long int now);