diff options
author | Benety Goh <benety@mongodb.com> | 2018-11-21 06:01:03 -0500 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2018-11-21 06:01:03 -0500 |
commit | f8de654b888ef3b9a9f210499b0b8f5d727dfffd (patch) | |
tree | 33c59555d11f534b9a451e0349fdbdbce3c387ef /src/mongo/db/catalog/multi_index_block_impl.cpp | |
parent | 9cc66d04356cf7b542df77ebe9dbe94445308240 (diff) | |
download | mongo-f8de654b888ef3b9a9f210499b0b8f5d727dfffd.tar.gz |
SERVER-37763 add support for aborting MultiIndexBlock index builds
Diffstat (limited to 'src/mongo/db/catalog/multi_index_block_impl.cpp')
-rw-r--r-- | src/mongo/db/catalog/multi_index_block_impl.cpp | 109 |
1 files changed, 108 insertions, 1 deletions
diff --git a/src/mongo/db/catalog/multi_index_block_impl.cpp b/src/mongo/db/catalog/multi_index_block_impl.cpp index 941b89e6c17..28f90ae1249 100644 --- a/src/mongo/db/catalog/multi_index_block_impl.cpp +++ b/src/mongo/db/catalog/multi_index_block_impl.cpp @@ -34,6 +34,8 @@ #include "mongo/db/catalog/multi_index_block_impl.h" +#include <ostream> + #include "mongo/base/error_codes.h" #include "mongo/base/init.h" #include "mongo/db/audit.h" @@ -50,6 +52,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/server_parameters.h" +#include "mongo/logger/redaction.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/mutex.h" #include "mongo/util/fail_point.h" @@ -209,6 +212,19 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlockImpl::init(const BSONObj& spec) } StatusWith<std::vector<BSONObj>> MultiIndexBlockImpl::init(const std::vector<BSONObj>& indexSpecs) { + if (State::kAborted == _getState()) { + return {ErrorCodes::IndexBuildAborted, + str::stream() << "Index build aborted: " << _abortReason + << ". Cannot initialize index builder: " + << _collection->ns().ns() + << "(" + << *_collection->uuid() + << "): " + << indexSpecs.size() + << " provided. First index spec: " + << (indexSpecs.empty() ? BSONObj() : indexSpecs[0])}; + } + WriteUnitOfWork wunit(_opCtx); invariant(_indexes.empty()); @@ -313,6 +329,8 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlockImpl::init(const std::vector<BSO } } + _setState(State::kRunning); + return indexInfoObjs; } @@ -481,6 +499,17 @@ Status MultiIndexBlockImpl::insertAllDocumentsInCollection() { Status MultiIndexBlockImpl::insert(const BSONObj& doc, const RecordId& loc, std::vector<BSONObj>* const dupKeysInserted) { + if (State::kAborted == _getState()) { + return {ErrorCodes::IndexBuildAborted, + str::stream() << "Index build aborted: " << _abortReason + << ". Cannot insert document into index builder: " + << _collection->ns().ns() + << "(" + << *_collection->uuid() + << "): " + << redact(doc)}; + } + for (size_t i = 0; i < _indexes.size(); i++) { if (_indexes[i].filterExpression && !_indexes[i].filterExpression->matchesBSON(doc)) { continue; @@ -516,9 +545,18 @@ Status MultiIndexBlockImpl::doneInserting(std::set<RecordId>* dupRecords) { Status MultiIndexBlockImpl::doneInserting(std::vector<BSONObj>* dupKeysInserted) { return _doneInserting(nullptr, dupKeysInserted); } - Status MultiIndexBlockImpl::_doneInserting(std::set<RecordId>* dupRecords, std::vector<BSONObj>* dupKeysInserted) { + if (State::kAborted == _getState()) { + return {ErrorCodes::IndexBuildAborted, + str::stream() << "Index build aborted: " << _abortReason + << ". Cannot complete insertion phase: " + << _collection->ns().ns() + << "(" + << *_collection->uuid() + << ")"}; + } + invariant(_opCtx->lockState()->isNoop() || !_opCtx->lockState()->inAWriteUnitOfWork()); for (size_t i = 0; i < _indexes.size(); i++) { if (_indexes[i].bulk == NULL) @@ -536,10 +574,13 @@ Status MultiIndexBlockImpl::_doneInserting(std::set<RecordId>* dupRecords, } } + _setState(State::kPreCommit); + return Status::OK(); } void MultiIndexBlockImpl::abortWithoutCleanup() { + _setStateToAbortedIfNotCommitted("aborted without cleanup"_sd); _indexes.clear(); _needToCleanup = false; } @@ -549,6 +590,16 @@ Status MultiIndexBlockImpl::commit() { } Status MultiIndexBlockImpl::commit(stdx::function<void(const BSONObj& spec)> onCreateFn) { + if (State::kAborted == _getState()) { + return {ErrorCodes::IndexBuildAborted, + str::stream() << "Index build aborted: " << _abortReason + << ". Cannot commit index builder: " + << _collection->ns().ns() + << "(" + << *_collection->uuid() + << ")"}; + } + // Do not interfere with writing multikey information when committing index builds. auto restartTracker = MakeGuard([this] { MultikeyPathTracker::get(_opCtx).startTrackingMultikeyPathInfo(); }); @@ -582,10 +633,66 @@ Status MultiIndexBlockImpl::commit(stdx::function<void(const BSONObj& spec)> onC } } + // The state of this index build is set to Committed only when the WUOW commits. + // It is possible for abort() to be called after the check at the beginning of this function and + // before the WUOW is committed. If the WUOW commits, the final state of this index builder will + // be Committed. Otherwise, the index builder state will remain as Aborted and further attempts + // to commit this index build will fail. _opCtx->recoveryUnit()->registerChange(new SetNeedToCleanupOnRollback(this)); + _opCtx->recoveryUnit()->onCommit( + [this](boost::optional<Timestamp> commitTime) { this->_setState(State::kCommitted); }); _needToCleanup = false; return Status::OK(); } +bool MultiIndexBlockImpl::isCommitted() const { + return State::kCommitted == _getState(); +} + +void MultiIndexBlockImpl::abort(StringData reason) { + _setStateToAbortedIfNotCommitted(reason); +} + + +MultiIndexBlockImpl::State MultiIndexBlockImpl::getState_forTest() const { + return _getState(); +} + +MultiIndexBlockImpl::State MultiIndexBlockImpl::_getState() const { + stdx::lock_guard<stdx::mutex> lock(_mutex); + return _state; +} + +void MultiIndexBlockImpl::_setState(State newState) { + invariant(State::kAborted != newState); + stdx::lock_guard<stdx::mutex> lock(_mutex); + _state = newState; +} + +void MultiIndexBlockImpl::_setStateToAbortedIfNotCommitted(StringData reason) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + if (State::kCommitted == _state) { + return; + } + _state = State::kAborted; + _abortReason = reason.toString(); +} + +std::ostream& operator<<(std::ostream& os, const MultiIndexBlockImpl::State& state) { + switch (state) { + case MultiIndexBlockImpl::State::kUninitialized: + return os << "Uninitialized"; + case MultiIndexBlockImpl::State::kRunning: + return os << "Running"; + case MultiIndexBlockImpl::State::kPreCommit: + return os << "PreCommit"; + case MultiIndexBlockImpl::State::kCommitted: + return os << "Committed"; + case MultiIndexBlockImpl::State::kAborted: + return os << "Aborted"; + } + MONGO_UNREACHABLE; +} + } // namespace mongo |