diff --git a/src/box/raft.c b/src/box/raft.c index fb518538eadb5dcfa8219b494c6488e1475e7fda..25da3f5df91bb69ee264c9a518e57aef664dec66 100644 --- a/src/box/raft.c +++ b/src/box/raft.c @@ -287,7 +287,7 @@ box_raft_fence(void) !election_fencing_enabled || box_raft_election_fencing_paused) return; - txn_limbo_freeze(&txn_limbo); + txn_limbo_fence(&txn_limbo); raft_resign(raft); } @@ -563,7 +563,7 @@ box_raft_set_election_fencing_enabled(bool enabled) election_fencing_enabled = enabled; say_info("RAFT: fencing %s", enabled ? "enabled" : "disabled"); if (!enabled) - txn_limbo_unfreeze(&txn_limbo); + txn_limbo_unfence(&txn_limbo); replicaset_on_health_change(); } diff --git a/src/box/txn_limbo.c b/src/box/txn_limbo.c index 8fc953e250bbe02adfca64588558c34b99715cc3..791c68f566060a4b23f30757bdd0345615277c92 100644 --- a/src/box/txn_limbo.c +++ b/src/box/txn_limbo.c @@ -52,13 +52,19 @@ txn_limbo_create(struct txn_limbo *limbo) limbo->rollback_count = 0; limbo->is_in_rollback = false; limbo->svp_confirmed_lsn = -1; - limbo->frozen = false; + limbo->frozen_reasons = 0; +} + +static inline bool +txn_limbo_is_frozen(const struct txn_limbo *limbo) +{ + return limbo->frozen_reasons != 0; } bool txn_limbo_is_ro(struct txn_limbo *limbo) { - return limbo->frozen || + return txn_limbo_is_frozen(limbo) || (limbo->owner_id != REPLICA_ID_NIL && limbo->owner_id != instance_id); } @@ -237,7 +243,7 @@ txn_limbo_wait_complete(struct txn_limbo *limbo, struct txn_limbo_entry *entry) double deadline = start_time + replication_synchro_timeout; double timeout = deadline - fiber_clock(); int rc = fiber_cond_wait_timeout(&limbo->wait_cond, timeout); - if (limbo->frozen) + if (txn_limbo_is_frozen(limbo)) goto wait; if (txn_limbo_entry_is_complete(entry)) goto complete; @@ -586,7 +592,7 @@ txn_limbo_ack(struct txn_limbo *limbo, uint32_t replica_id, int64_t lsn) { if (rlist_empty(&limbo->queue)) return; - if (limbo->frozen) + if (txn_limbo_is_frozen(limbo)) return; assert(!txn_limbo_is_ro(limbo)); /* @@ -849,7 +855,7 @@ txn_limbo_req_commit(struct txn_limbo *limbo, const struct synchro_request *req) if (term > limbo->promote_greatest_term) { limbo->promote_greatest_term = term; if (iproto_type_is_promote_request(req->type)) - txn_limbo_unfreeze(&txn_limbo); + txn_limbo_unfence(&txn_limbo); } } else if (iproto_type_is_promote_request(req->type) && limbo->promote_greatest_term > 1) { @@ -918,7 +924,7 @@ txn_limbo_process(struct txn_limbo *limbo, const struct synchro_request *req) void txn_limbo_on_parameters_change(struct txn_limbo *limbo) { - if (rlist_empty(&limbo->queue) || limbo->frozen) + if (rlist_empty(&limbo->queue) || txn_limbo_is_frozen(limbo)) return; struct txn_limbo_entry *e; int64_t confirm_lsn = -1; @@ -948,16 +954,16 @@ txn_limbo_on_parameters_change(struct txn_limbo *limbo) } void -txn_limbo_freeze(struct txn_limbo *limbo) +txn_limbo_fence(struct txn_limbo *limbo) { - limbo->frozen = true; + limbo->is_frozen_due_to_fencing = true; box_update_ro_summary(); } void -txn_limbo_unfreeze(struct txn_limbo *limbo) +txn_limbo_unfence(struct txn_limbo *limbo) { - limbo->frozen = false; + limbo->is_frozen_due_to_fencing = false; box_update_ro_summary(); } diff --git a/src/box/txn_limbo.h b/src/box/txn_limbo.h index 7db69563d18b6714edb7a1f6689212183fe937a4..095c965a0c53c9ec075682ae3df5ef6644668b66 100644 --- a/src/box/txn_limbo.h +++ b/src/box/txn_limbo.h @@ -189,14 +189,26 @@ struct txn_limbo { * synchro command (promote/demote/...) fails. */ int64_t svp_confirmed_lsn; - /** - * Whether the limbo is frozen. This mode prevents CONFIRMs and - * ROLLBACKs being written by this instance. This mode is turned on when - * quorum is lost if this instance is the current RAFT leader and - * fencing is enabled. Instance leaves this mode when it becomes leader - * again or PROMOTE/DEMOTE arrives from some remote instance. - */ - bool frozen; + union { + /** + * Whether the limbo is frozen. This mode prevents CONFIRMs and + * ROLLBACKs being written by this instance. This, in turn, + * helps to prevent split-brain situations, when a node + * finalizes some transaction before knowing that the + * transaction was already finalized by someone else. + */ + uint8_t frozen_reasons; + struct { + /* + * This mode is turned on when quorum is lost if this + * instance is the current RAFT leader and fencing is + * enabled. Instance leaves this mode when it becomes + * leader again or PROMOTE/DEMOTE arrives from some + * remote instance. + */ + bool is_frozen_due_to_fencing : 1; + }; + }; }; /** @@ -413,13 +425,13 @@ txn_limbo_on_parameters_change(struct txn_limbo *limbo); * Freeze limbo. Prevent CONFIRMs and ROLLBACKs until limbo is unfrozen. */ void -txn_limbo_freeze(struct txn_limbo *limbo); +txn_limbo_fence(struct txn_limbo *limbo); /** * Unfreeze limbo. Continue limbo processing as usual. */ void -txn_limbo_unfreeze(struct txn_limbo *limbo); +txn_limbo_unfence(struct txn_limbo *limbo); /** * Initialize qsync engine.