diff options
author | Eric Milkie <milkie@10gen.com> | 2015-01-23 16:53:12 -0500 |
---|---|---|
committer | Ramon Fernandez <ramon.fernandez@mongodb.com> | 2015-01-26 11:27:29 -0500 |
commit | b51b97381792ba3e02fe02204f02c87863d2f664 (patch) | |
tree | 176545be84b496900a12ca7c70980c2484c2a95a /src/mongo/db/catalog | |
parent | 04b4d5d82e51345c89a4fa53b7c864b4eeb4272b (diff) | |
download | mongo-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.cpp | 40 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_create.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_create.h | 1 |
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) {} |