diff options
author | Jason Carey <jcarey@argv.me> | 2016-02-19 15:30:41 -0500 |
---|---|---|
committer | Jason Carey <jcarey@argv.me> | 2016-02-19 16:42:54 -0500 |
commit | 401ad1915d6b7edde97c290f82cecab4a26880df (patch) | |
tree | ed421e088dcbab4fa9863d4706506d0bd1eea46e /src/mongo/executor | |
parent | 1d982f5421e93c7a59dab2d7acd5b549ab19790e (diff) | |
download | mongo-401ad1915d6b7edde97c290f82cecab4a26880df.tar.gz |
SERVER-22768 fix ASIO cancelled to cancelled
When operations transition from kCancelled to kCancelled, as when an
operation is cancel()ed twice, an invariant fires. We should handle
that case specially and treat the transition as a noop.
Diffstat (limited to 'src/mongo/executor')
-rw-r--r-- | src/mongo/executor/network_interface_asio.h | 3 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_asio_operation.cpp | 14 |
2 files changed, 16 insertions, 1 deletions
diff --git a/src/mongo/executor/network_interface_asio.h b/src/mongo/executor/network_interface_asio.h index 441e89aceb0..3a175830dc8 100644 --- a/src/mongo/executor/network_interface_asio.h +++ b/src/mongo/executor/network_interface_asio.h @@ -30,6 +30,7 @@ #include <asio.hpp> +#include <array> #include <boost/optional.hpp> #include <memory> #include <string> @@ -424,7 +425,7 @@ private: * We hold an array of states to show the path this AsyncOp has taken. * Must be holding the access control's lock to edit. */ - State _states[kMaxStateTransitions]; + std::array<State, kMaxStateTransitions> _states; }; void _startCommand(AsyncOp* op); diff --git a/src/mongo/executor/network_interface_asio_operation.cpp b/src/mongo/executor/network_interface_asio_operation.cpp index 6919a9b8b50..813ff51dd09 100644 --- a/src/mongo/executor/network_interface_asio_operation.cpp +++ b/src/mongo/executor/network_interface_asio_operation.cpp @@ -371,6 +371,20 @@ void NetworkInterfaceASIO::AsyncOp::_transitionToState_inlock(AsyncOp::State new return; } + // We can transition to cancelled multiple times if cancel() is called + // multiple times. Ignore that transition if we're already cancelled. + if (newState == State::kCanceled) { + // Find the current state + auto iter = std::find_if_not(_states.rbegin(), + _states.rend(), + [](const State& state) { return state == State::kNoState; }); + + // If its cancelled, just return + if (iter != _states.rend() && *iter == State::kCanceled) { + return; + } + } + for (int i = 0; i < kMaxStateTransitions; i++) { // We can't transition to the same state twice. MONGO_ASYNC_OP_INVARIANT(_states[i] != newState, |