summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/multi_index_block_impl.cpp
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2018-11-21 06:01:03 -0500
committerBenety Goh <benety@mongodb.com>2018-11-21 06:01:03 -0500
commitf8de654b888ef3b9a9f210499b0b8f5d727dfffd (patch)
tree33c59555d11f534b9a451e0349fdbdbce3c387ef /src/mongo/db/catalog/multi_index_block_impl.cpp
parent9cc66d04356cf7b542df77ebe9dbe94445308240 (diff)
downloadmongo-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.cpp109
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