diff options
author | Esha Maharishi <esha.maharishi@mongodb.com> | 2018-06-29 00:19:22 -0400 |
---|---|---|
committer | Esha Maharishi <esha.maharishi@mongodb.com> | 2018-07-26 18:46:59 -0400 |
commit | e9c92f13b6203755f6bd9795ccc2e413dd3bc2bf (patch) | |
tree | 144e6b13f399d4c9e04aa923a672f6d72473a99f /src/mongo/db/transaction_participant.h | |
parent | 30fe08323601fbdb49994b7518ec28e7e3054363 (diff) | |
download | mongo-e9c92f13b6203755f6bd9795ccc2e413dd3bc2bf.tar.gz |
SERVER-35347 Transaction coordinator and participant internal state machines
Diffstat (limited to 'src/mongo/db/transaction_participant.h')
-rw-r--r-- | src/mongo/db/transaction_participant.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h index 57fef52c023..bcb13bef0b1 100644 --- a/src/mongo/db/transaction_participant.h +++ b/src/mongo/db/transaction_participant.h @@ -29,9 +29,13 @@ #pragma once #include <boost/optional.hpp> +#include <iostream> +#include <map> #include "mongo/base/disallow_copying.h" +#include "mongo/util/assert_util.h" #include "mongo/util/decorable.h" +#include "mongo/util/mongoutils/str.h" namespace mongo { @@ -50,6 +54,140 @@ public: static boost::optional<TransactionParticipant>& get(Session* session); static void create(Session* session); + + class StateMachine { + public: + friend class TransactionParticipant; + + // Note: We must differentiate the 'committed/aborted' and 'committed/aborted after prepare' + // states, because it is illegal to receive, for example, a prepare request after a + // commit/abort if no prepare was received before the commit/abort. + enum class State { + kUnprepared, + kAborted, + kCommitted, + kWaitingForDecision, + kAbortedAfterPrepare, + kCommittedAfterPrepare, + + // The state machine transitions to this state when a message that is considered illegal + // to receive in a particular state is received. This indicates either a byzantine + // message, or that the transition table does not accurately reflect an asynchronous + // network. + kBroken, + }; + + // State machine inputs + enum class Event { + kRecvPrepare, + kVoteCommitRejected, + kRecvAbort, + kRecvCommit, + }; + + // State machine outputs + enum class Action { + kNone, + kPrepare, + kAbort, + kCommit, + kSendCommitAck, + kSendAbortAck, + }; + + Action onEvent(Event e); + + State state() { + return _state; + } + + private: + struct Transition { + Transition() : action(Action::kNone) {} + Transition(Action action) : action(action) {} + Transition(Action action, State state) : action(action), nextState(state) {} + + Action action; + boost::optional<State> nextState; + }; + + static const std::map<State, std::map<Event, Transition>> transitionTable; + State _state{State::kUnprepared}; + }; + +private: + StateMachine _stateMachine; }; +inline StringBuilder& operator<<(StringBuilder& sb, + const TransactionParticipant::StateMachine::State& state) { + using State = TransactionParticipant::StateMachine::State; + switch (state) { + // clang-format off + case State::kUnprepared: return sb << "Unprepared"; + case State::kAborted: return sb << "Aborted"; + case State::kCommitted: return sb << "Committed"; + case State::kWaitingForDecision: return sb << "WaitingForDecision"; + case State::kAbortedAfterPrepare: return sb << "AbortedAfterPrepare"; + case State::kCommittedAfterPrepare: return sb << "CommittedAfterPrepare"; + case State::kBroken: return sb << "Broken"; + // clang-format on + default: + MONGO_UNREACHABLE; + }; +} + +inline std::ostream& operator<<(std::ostream& os, + const TransactionParticipant::StateMachine::State& state) { + StringBuilder sb; + sb << state; + return os << sb.str(); +} + +inline StringBuilder& operator<<(StringBuilder& sb, + const TransactionParticipant::StateMachine::Event& event) { + using Event = TransactionParticipant::StateMachine::Event; + switch (event) { + // clang-format off + case Event::kRecvPrepare: return sb << "RecvPrepare"; + case Event::kVoteCommitRejected: return sb << "VoteCommitRejected"; + case Event::kRecvAbort: return sb << "RecvAbort"; + case Event::kRecvCommit: return sb << "RecvCommit"; + // clang-format on + default: + MONGO_UNREACHABLE; + }; +} + +inline std::ostream& operator<<(std::ostream& os, + const TransactionParticipant::StateMachine::Event& event) { + StringBuilder sb; + sb << event; + return os << sb.str(); +} + +inline StringBuilder& operator<<(StringBuilder& sb, + const TransactionParticipant::StateMachine::Action& action) { + using Action = TransactionParticipant::StateMachine::Action; + switch (action) { + // clang-format off + case Action::kNone: return sb << "None"; + case Action::kPrepare: return sb << "Prepare"; + case Action::kAbort: return sb << "Abort"; + case Action::kCommit: return sb << "Commit"; + case Action::kSendCommitAck: return sb << "SendCommitAck"; + case Action::kSendAbortAck: return sb << "SendAbortAck"; + // clang-format on + default: + MONGO_UNREACHABLE; + }; +} + +inline std::ostream& operator<<(std::ostream& os, + const TransactionParticipant::StateMachine::Action& action) { + StringBuilder sb; + sb << action; + return os << sb.str(); +} + } // namespace mongo |