summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2015-01-23 16:53:12 -0500
committerRamon Fernandez <ramon.fernandez@mongodb.com>2015-01-26 11:27:29 -0500
commitb51b97381792ba3e02fe02204f02c87863d2f664 (patch)
tree176545be84b496900a12ca7c70980c2484c2a95a /src/mongo/db/catalog
parent04b4d5d82e51345c89a4fa53b7c864b4eeb4272b (diff)
downloadmongo-b51b97381792ba3e02fe02204f02c87863d2f664.tar.gz
SERVER-17030 handle WCE in index builds
(cherry picked from commit dd22b3fdb2cbcc95595b49e95da83b0ff498f95b)
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp40
-rw-r--r--src/mongo/db/catalog/index_create.cpp59
-rw-r--r--src/mongo/db/catalog/index_create.h1
3 files changed, 55 insertions, 45 deletions
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index 3fda0e77759..816e3ccc1f0 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -443,42 +443,24 @@ namespace {
}
IndexCatalog::IndexBuildBlock::~IndexBuildBlock() {
- if ( !_inProgress ) {
- // taken care of already when success() is called
- return;
- }
-
- try {
- fail();
- }
- catch ( const AssertionException& exc ) {
- log() << "exception in ~IndexBuildBlock trying to cleanup: " << exc;
- log() << " going to fassert to preserve state";
- fassertFailed( 17345 );
- }
+ // Don't need to call fail() here, as rollback will clean everything up for us.
}
void IndexCatalog::IndexBuildBlock::fail() {
- try {
- fassert( 17204, _catalog->_collection->ok() ); // defensive
+ fassert( 17204, _catalog->_collection->ok() ); // defensive
- _inProgress = false;
+ _inProgress = false;
- IndexCatalogEntry* entry = _catalog->_entries.find( _indexName );
- invariant( entry == _entry );
+ IndexCatalogEntry* entry = _catalog->_entries.find( _indexName );
+ invariant( entry == _entry );
- if ( entry ) {
- _catalog->_dropIndex(_txn, entry);
- }
- else {
- _catalog->_deleteIndexFromDisk( _txn,
- _indexName,
- _indexNamespace );
- }
+ if ( entry ) {
+ _catalog->_dropIndex(_txn, entry);
}
- catch (const DBException& exc) {
- error() << "exception while cleaning up in-progress index build: " << exc.what();
- fassertFailedWithStatus(17493, exc.toStatus());
+ else {
+ _catalog->_deleteIndexFromDisk( _txn,
+ _indexName,
+ _indexNamespace );
}
}
diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp
index 1fbd0f4452d..60314c24b20 100644
--- a/src/mongo/db/catalog/index_create.cpp
+++ b/src/mongo/db/catalog/index_create.cpp
@@ -43,6 +43,7 @@
#include "mongo/db/background.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/clientcursor.h"
+#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/curop.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/oplog.h"
@@ -72,6 +73,22 @@ namespace mongo {
MultiIndexBlock* const _indexer;
};
+ /**
+ * On rollback in init(), cleans up _indexes so that ~MultiIndexBlock doesn't try to clean
+ * up _indexes manually (since the changes were already rolled back).
+ * Due to this, it is thus legal to call init() again after it fails.
+ */
+ class MultiIndexBlock::CleanupIndexesVectorOnRollback : public RecoveryUnit::Change {
+ public:
+ explicit CleanupIndexesVectorOnRollback(MultiIndexBlock* indexer) : _indexer(indexer) {}
+
+ virtual void commit() {}
+ virtual void rollback() { _indexer->_indexes.clear(); }
+
+ private:
+ MultiIndexBlock* const _indexer;
+ };
+
MultiIndexBlock::MultiIndexBlock(OperationContext* txn, Collection* collection)
: _collection(collection),
_txn(txn),
@@ -84,24 +101,30 @@ namespace mongo {
MultiIndexBlock::~MultiIndexBlock() {
if (!_needToCleanup || _indexes.empty())
return;
-
- try {
- WriteUnitOfWork wunit(_txn);
- // This cleans up all index builds. Because that may need to write, it is done inside
- // of a WUOW. Nothing inside this block can fail, and it is made fatal if it does.
- for (size_t i = 0; i < _indexes.size(); i++) {
- _indexes[i].block->fail();
+ while (true) {
+ try {
+ WriteUnitOfWork wunit(_txn);
+ // This cleans up all index builds.
+ // Because that may need to write, it is done inside
+ // of a WUOW. Nothing inside this block can fail, and it is made fatal if it does.
+ for (size_t i = 0; i < _indexes.size(); i++) {
+ _indexes[i].block->fail();
+ }
+ wunit.commit();
+ return;
}
- wunit.commit();
- return;
- }
- catch (const std::exception& e) {
- error() << "Caught exception while cleaning up partially built indexes: " << e.what();
- }
- catch (...) {
- error() << "Caught unknown exception while cleaning up partially built indexes.";
+ catch (const WriteConflictException& e) {
+ continue;
+ }
+ catch (const std::exception& e) {
+ error() << "Caught exception while cleaning up partially built indexes: "
+ << e.what();
+ }
+ catch (...) {
+ error() << "Caught unknown exception while cleaning up partially built indexes.";
+ }
+ fassertFailed(18644);
}
- fassertFailed(18644);
}
void MultiIndexBlock::removeExistingIndexes(std::vector<BSONObj>* specs) const {
@@ -118,6 +141,10 @@ namespace mongo {
Status MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
WriteUnitOfWork wunit(_txn);
+
+ invariant(_indexes.empty());
+ _txn->recoveryUnit()->registerChange(new CleanupIndexesVectorOnRollback(this));
+
const string& ns = _collection->ns().ns();
Status status = _collection->getIndexCatalog()->checkUnfinished();
diff --git a/src/mongo/db/catalog/index_create.h b/src/mongo/db/catalog/index_create.h
index 4a4be247e77..c4c3badd901 100644
--- a/src/mongo/db/catalog/index_create.h
+++ b/src/mongo/db/catalog/index_create.h
@@ -197,6 +197,7 @@ namespace mongo {
private:
class SetNeedToCleanupOnRollback;
+ class CleanupIndexesVectorOnRollback;
struct IndexToBuild {
IndexToBuild() : real(NULL) {}