diff --git a/ovsdb/raft.c b/ovsdb/raft.c index ac3d37ac4..9c3c351b5 100644 --- a/ovsdb/raft.c +++ b/ovsdb/raft.c @@ -2307,12 +2307,55 @@ raft_get_eid(const struct raft *raft, uint64_t index) return &raft->snap.eid; } -const struct uuid * +static const struct uuid * raft_current_eid(const struct raft *raft) { return raft_get_eid(raft, raft->log_end - 1); } +bool +raft_precheck_prereq(const struct raft *raft, const struct uuid *prereq) +{ + if (!uuid_equals(raft_current_eid(raft), prereq)) { + VLOG_DBG("%s: prerequisites (" UUID_FMT ") " + "do not match current eid (" UUID_FMT ")", + __func__, UUID_ARGS(prereq), + UUID_ARGS(raft_current_eid(raft))); + return false; + } + + /* Incomplete commands on a leader will not change the leader's current + * 'eid' on commit as they are already part of the leader's log. */ + if (raft->role == RAFT_LEADER) { + return true; + } + + /* Having incomplete commands on a follower means that the leader has + * these commands and they will change the prerequisites once added to + * the leader's log. + * + * There is a chance that all these commands will actually fail and the + * record with current prerequisites will in fact succeed, but, since + * these are our own commands, the chances are low. */ + struct raft_command *cmd; + HMAP_FOR_EACH (cmd, hmap_node, &raft->commands) { + /* Skip commands that are already part of the log (have non-zero + * index) and ones that do not carry any data (have zero 'eid'), + * as they can't change prerequisites. + * + * Database will not re-run triggers unless the data changes or + * one of the data-carrying triggers completes. So, pre-check must + * not fail if there are no outstanding data-carrying commands. */ + if (!cmd->index && !uuid_is_zero(&cmd->eid)) { + VLOG_DBG("%s: follower still has an incomplete command " + UUID_FMT, __func__, UUID_ARGS(&cmd->eid)); + return false; + } + } + + return true; +} + static struct raft_command * raft_command_create_completed(enum raft_command_status status) { diff --git a/ovsdb/raft.h b/ovsdb/raft.h index a5b55d9bf..5833aaf23 100644 --- a/ovsdb/raft.h +++ b/ovsdb/raft.h @@ -189,5 +189,5 @@ struct ovsdb_error *raft_store_snapshot(struct raft *, void raft_take_leadership(struct raft *); void raft_transfer_leadership(struct raft *, const char *reason); -const struct uuid *raft_current_eid(const struct raft *); +bool raft_precheck_prereq(const struct raft *, const struct uuid *prereq); #endif /* lib/raft.h */ diff --git a/ovsdb/storage.c b/ovsdb/storage.c index 6c395106c..c5aec5459 100644 --- a/ovsdb/storage.c +++ b/ovsdb/storage.c @@ -661,11 +661,12 @@ ovsdb_storage_write_schema_change(struct ovsdb_storage *storage, return w; } -const struct uuid * -ovsdb_storage_peek_last_eid(struct ovsdb_storage *storage) +bool +ovsdb_storage_precheck_prereq(const struct ovsdb_storage *storage, + const struct uuid *prereq) { if (!storage->raft) { - return NULL; + return true; } - return raft_current_eid(storage->raft); + return raft_precheck_prereq(storage->raft, prereq); } diff --git a/ovsdb/storage.h b/ovsdb/storage.h index 05f40ce93..7079ea261 100644 --- a/ovsdb/storage.h +++ b/ovsdb/storage.h @@ -96,6 +96,9 @@ struct ovsdb_storage *ovsdb_storage_open_standalone(const char *filename, bool rw); struct ovsdb_schema *ovsdb_storage_read_schema(struct ovsdb_storage *); -const struct uuid *ovsdb_storage_peek_last_eid(struct ovsdb_storage *); +/* Checks that there is a chance for a record with specified prerequisites + * to be successfully written to the storage. */ +bool ovsdb_storage_precheck_prereq(const struct ovsdb_storage *, + const struct uuid *prereq); #endif /* ovsdb/storage.h */ diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c index 484a88e1c..65eca6478 100644 --- a/ovsdb/transaction.c +++ b/ovsdb/transaction.c @@ -1277,11 +1277,7 @@ struct ovsdb_txn_progress { bool ovsdb_txn_precheck_prereq(const struct ovsdb *db) { - const struct uuid *eid = ovsdb_storage_peek_last_eid(db->storage); - if (!eid) { - return true; - } - return uuid_equals(&db->prereq, eid); + return ovsdb_storage_precheck_prereq(db->storage, &db->prereq); } struct ovsdb_txn_progress *