diff options
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/operation_context.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/operation_context.h | 40 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_external_state_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/service_context.h | 2 | ||||
-rw-r--r-- | src/mongo/db/service_context_d.cpp | 38 | ||||
-rw-r--r-- | src/mongo/db/service_context_d.h | 15 | ||||
-rw-r--r-- | src/mongo/db/service_context_noop.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/service_context_noop.h | 2 |
9 files changed, 55 insertions, 64 deletions
diff --git a/src/mongo/db/operation_context.cpp b/src/mongo/db/operation_context.cpp index 1b79dadcb50..1434ee5ddc7 100644 --- a/src/mongo/db/operation_context.cpp +++ b/src/mongo/db/operation_context.cpp @@ -46,12 +46,13 @@ Client* OperationContext::getClient() const { return _client; } -void OperationContext::markKilled() { - _killPending.store(1); +void OperationContext::markKilled(ErrorCodes::Error killCode) { + invariant(killCode != ErrorCodes::OK); + _killCode.compareAndSwap(ErrorCodes::OK, killCode); } -bool OperationContext::isKillPending() const { - return _killPending.loadRelaxed(); +ErrorCodes::Error OperationContext::getKillStatus() const { + return _killCode.loadRelaxed(); } } // namespace mongo diff --git a/src/mongo/db/operation_context.h b/src/mongo/db/operation_context.h index a146a8f7f14..3a7e3165dda 100644 --- a/src/mongo/db/operation_context.h +++ b/src/mongo/db/operation_context.h @@ -77,7 +77,6 @@ public: */ virtual RecoveryUnit* recoveryUnit() const = 0; - /** * Returns the RecoveryUnit (same return value as recoveryUnit()) but the caller takes * ownership of the returned RecoveryUnit, and the OperationContext instance relinquishes @@ -183,23 +182,33 @@ public: virtual bool writesAreReplicated() const = 0; /** - * Marks this operation as killed. + * Marks this operation as killed so that subsequent calls to checkForInterrupt and + * checkForInterruptNoAssert by the thread executing the operation will start returning the + * specified error code. * - * Subsequent calls to checkForInterrupt and checkForInterruptNoAssert by the thread - * executing the operation will indicate that the operation has been killed. + * If multiple threads kill the same operation with different codes, only the first code will + * be preserved. * - * May be called by any thread that has locked the Client owning this operation context, - * or by the thread executing on behalf of this operation context. + * May be called by any thread that has locked the Client owning this operation context. */ - void markKilled(); + void markKilled(ErrorCodes::Error killCode = ErrorCodes::Interrupted); /** - * Returns true if markKilled has been called on this operation context. + * Returns the code passed to markKilled if this operation context has been killed previously + * or ErrorCodes::OK otherwise. * - * May be called by any thread that has locked the Client owning this operation context, - * or by the thread executing on behalf of this operation context. + * May be called by any thread that has locked the Client owning this operation context, or + * without lock by the thread executing on behalf of this operation context. + */ + ErrorCodes::Error getKillStatus() const; + + /** + * Shortcut method, which checks whether getKillStatus returns a non-OK value. Has the same + * concurrency rules as getKillStatus. */ - bool isKillPending() const; + bool isKillPending() const { + return getKillStatus() != ErrorCodes::OK; + } protected: OperationContext(Client* client, unsigned int opId, Locker* locker); @@ -211,11 +220,14 @@ private: Client* const _client; const unsigned int _opId; - // The lifetime of locker is managed by subclasses of OperationContext, so it is not - // safe to access _locker in the destructor of OperationContext. + // Not owned. Locker* const _locker; - AtomicInt32 _killPending{0}; + // Follows the values of ErrorCodes::Error. The default value is 0 (OK), which means the + // operation is not killed. If killed, it will contain a specific code. This value changes only + // once from OK to some kill code. + AtomicWord<ErrorCodes::Error> _killCode{ErrorCodes::OK}; + WriteConcernOptions _writeConcern; }; diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp index f2c0166876f..b7733958bc2 100644 --- a/src/mongo/db/operation_context_impl.cpp +++ b/src/mongo/db/operation_context_impl.cpp @@ -140,6 +140,7 @@ uint64_t OperationContextImpl::getRemainingMaxTimeMicros() const { MONGO_FP_DECLARE(checkForInterruptFail); namespace { + // Helper function for checkForInterrupt fail point. Decides whether the operation currently // being run by the given Client meet the (probabilistic) conditions for interruption as // specified in the fail point info. @@ -194,8 +195,9 @@ Status OperationContextImpl::checkForInterruptNoAssert() { } } - if (isKillPending()) { - return Status(ErrorCodes::Interrupted, "operation was interrupted"); + const auto killStatus = getKillStatus(); + if (killStatus != ErrorCodes::OK) { + return Status(killStatus, "operation was interrupted"); } return Status::OK(); diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index c42b80a605d..52b0fee436c 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -350,8 +350,8 @@ void ReplicationCoordinatorExternalStateImpl::closeConnections() { } void ReplicationCoordinatorExternalStateImpl::killAllUserOperations(OperationContext* txn) { - ServiceContext* environment = getGlobalServiceContext(); - environment->killAllUserOperations(txn); + ServiceContext* environment = txn->getServiceContext(); + environment->killAllUserOperations(txn, ErrorCodes::InterruptedDueToReplStateChange); } void ReplicationCoordinatorExternalStateImpl::clearShardingState() { diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index 6f9aa36a22f..4e63046726f 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -284,7 +284,7 @@ public: * Kills all operations that have a Client that is associated with an incoming user * connection, except for the one associated with txn. */ - virtual void killAllUserOperations(const OperationContext* txn) = 0; + virtual void killAllUserOperations(const OperationContext* txn, ErrorCodes::Error killCode) = 0; /** * Registers a listener to be notified each time an op is killed. diff --git a/src/mongo/db/service_context_d.cpp b/src/mongo/db/service_context_d.cpp index 3e5fd2d5be7..470dcb927a5 100644 --- a/src/mongo/db/service_context_d.cpp +++ b/src/mongo/db/service_context_d.cpp @@ -220,21 +220,9 @@ bool ServiceContextMongoD::getKillAllOperations() { return _globalKill; } -bool ServiceContextMongoD::_killOperationsAssociatedWithClientAndOpId_inlock(Client* client, - unsigned int opId) { - OperationContext* opCtx = client->getOperationContext(); - if (!opCtx) { - return false; - } - if (opCtx->getOpID() != opId) { - return false; - } - _killOperation_inlock(opCtx); - return true; -} - -void ServiceContextMongoD::_killOperation_inlock(OperationContext* opCtx) { - opCtx->markKilled(); +void ServiceContextMongoD::_killOperation_inlock(OperationContext* opCtx, + ErrorCodes::Error killCode) { + opCtx->markKilled(killCode); for (const auto listener : _killOpListeners) { try { @@ -248,8 +236,10 @@ void ServiceContextMongoD::_killOperation_inlock(OperationContext* opCtx) { bool ServiceContextMongoD::killOperation(unsigned int opId) { for (LockedClientsCursor cursor(this); Client* client = cursor.next();) { stdx::lock_guard<Client> lk(*client); - bool found = _killOperationsAssociatedWithClientAndOpId_inlock(client, opId); - if (found) { + + OperationContext* opCtx = client->getOperationContext(); + if (opCtx && opCtx->getOpID() == opId) { + _killOperation_inlock(opCtx, ErrorCodes::Interrupted); return true; } } @@ -257,7 +247,8 @@ bool ServiceContextMongoD::killOperation(unsigned int opId) { return false; } -void ServiceContextMongoD::killAllUserOperations(const OperationContext* txn) { +void ServiceContextMongoD::killAllUserOperations(const OperationContext* txn, + ErrorCodes::Error killCode) { for (LockedClientsCursor cursor(this); Client* client = cursor.next();) { if (!client->isFromUserConnection()) { // Don't kill system operations. @@ -266,16 +257,11 @@ void ServiceContextMongoD::killAllUserOperations(const OperationContext* txn) { stdx::lock_guard<Client> lk(*client); OperationContext* toKill = client->getOperationContext(); - if (!toKill) { - continue; - } - if (toKill->getOpID() == txn->getOpID()) { - // Don't kill ourself. - continue; + // Don't kill ourself. + if (toKill && toKill->getOpID() != txn->getOpID()) { + _killOperation_inlock(toKill, killCode); } - - _killOperation_inlock(toKill); } } diff --git a/src/mongo/db/service_context_d.h b/src/mongo/db/service_context_d.h index 0c560ff17f4..dc834197e9e 100644 --- a/src/mongo/db/service_context_d.h +++ b/src/mongo/db/service_context_d.h @@ -67,7 +67,7 @@ public: bool killOperation(unsigned int opId) override; - void killAllUserOperations(const OperationContext* txn) override; + void killAllUserOperations(const OperationContext* txn, ErrorCodes::Error killCode) override; void registerKillOpListener(KillOpListenerInterface* listener) override; @@ -79,22 +79,11 @@ private: std::unique_ptr<OperationContext> _newOpCtx(Client* client) override; /** - * Kills the active operation on "client" if that operation is associated with operation id - * "opId". - * - * Returns true if an operation was killed. - * - * Must only be called by a thread owning both this service context's mutex and the - * client's. - */ - bool _killOperationsAssociatedWithClientAndOpId_inlock(Client* client, unsigned int opId); - - /** * Kills the given operation. * * Caller must own the service context's _mutex. */ - void _killOperation_inlock(OperationContext* opCtx); + void _killOperation_inlock(OperationContext* opCtx, ErrorCodes::Error killCode); bool _globalKill; diff --git a/src/mongo/db/service_context_noop.cpp b/src/mongo/db/service_context_noop.cpp index 65184906442..fd94b35db89 100644 --- a/src/mongo/db/service_context_noop.cpp +++ b/src/mongo/db/service_context_noop.cpp @@ -79,7 +79,8 @@ bool ServiceContextNoop::killOperation(unsigned int opId) { return false; } -void ServiceContextNoop::killAllUserOperations(const OperationContext* txn) {} +void ServiceContextNoop::killAllUserOperations(const OperationContext* txn, + ErrorCodes::Error killCode) {} void ServiceContextNoop::registerKillOpListener(KillOpListenerInterface* listener) {} diff --git a/src/mongo/db/service_context_noop.h b/src/mongo/db/service_context_noop.h index 0e74b61b7a2..62e6a169896 100644 --- a/src/mongo/db/service_context_noop.h +++ b/src/mongo/db/service_context_noop.h @@ -49,7 +49,7 @@ public: bool killOperation(unsigned int opId) override; - void killAllUserOperations(const OperationContext* txn) override; + void killAllUserOperations(const OperationContext* txn, ErrorCodes::Error killCode) override; void setKillAllOperations() override; |