diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-06-18 16:25:13 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-06-21 20:35:00 -0400 |
commit | d4b054976ab484cce590feee49f284c540ce8bc3 (patch) | |
tree | e4896391b2254a6acd1c4c2fab5588f8414f62b8 /src/mongo/db | |
parent | 45dc520352849b4b1c958e11f5cec322fb67e8f2 (diff) | |
download | mongo-d4b054976ab484cce590feee49f284c540ce8bc3.tar.gz |
SERVER-16413 Storage engines that allow online compaction should not take an exclusive lock
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/catalog/collection_compact.cpp | 65 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_compact.h | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/compact.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store.h | 9 | ||||
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h | 3 |
5 files changed, 74 insertions, 37 deletions
diff --git a/src/mongo/db/catalog/collection_compact.cpp b/src/mongo/db/catalog/collection_compact.cpp index c3e886d27eb..60c06b561e0 100644 --- a/src/mongo/db/catalog/collection_compact.cpp +++ b/src/mongo/db/catalog/collection_compact.cpp @@ -31,22 +31,58 @@ #include "mongo/db/catalog/collection_compact.h" +#include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/catalog/document_validation.h" #include "mongo/db/catalog/index_key_validate.h" #include "mongo/db/catalog/multi_index_block.h" +#include "mongo/db/db_raii.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index_builds_coordinator.h" #include "mongo/db/operation_context.h" +#include "mongo/db/views/view_catalog.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" namespace mongo { +using logger::LogComponent; + +namespace { + +Collection* getCollectionForCompact(OperationContext* opCtx, + Database* database, + const NamespaceString& collectionNss) { + invariant(opCtx->lockState()->isCollectionLockedForMode(collectionNss, MODE_IX)); + + CollectionCatalog& collectionCatalog = CollectionCatalog::get(opCtx); + Collection* collection = collectionCatalog.lookupCollectionByNamespace(collectionNss); + + if (!collection) { + std::shared_ptr<ViewDefinition> view = + ViewCatalog::get(database)->lookup(opCtx, collectionNss.ns()); + uassert(ErrorCodes::CommandNotSupportedOnView, "can't compact a view", !view); + uasserted(ErrorCodes::NamespaceNotFound, "collection does not exist"); + } + + return collection; +} + +} // namespace + StatusWith<CompactStats> compactCollection(OperationContext* opCtx, - Collection* collection, + const NamespaceString& collectionNss, const CompactOptions* compactOptions) { - dassert(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X)); + AutoGetDb autoDb(opCtx, collectionNss.db(), MODE_IX); + Database* database = autoDb.getDb(); + uassert(ErrorCodes::NamespaceNotFound, "database does not exist", database); + + // The collection lock will be downgraded to an intent lock if the record store supports + // online compaction. + boost::optional<Lock::CollectionLock> collLk; + collLk.emplace(opCtx, collectionNss, MODE_X); + Collection* collection = getCollectionForCompact(opCtx, database, collectionNss); DisableDocumentValidation validationDisabler(opCtx); auto recordStore = collection->getRecordStore(); @@ -58,6 +94,19 @@ StatusWith<CompactStats> compactCollection(OperationContext* opCtx, << "cannot compact collection with record store: " << recordStore->name()); + if (recordStore->supportsOnlineCompaction()) { + // Storage engines that allow online compaction should do so using an intent lock on the + // collection. + collLk.emplace(opCtx, collectionNss, MODE_IX); + + // Ensure the collection was not dropped during the re-lock. + collection = getCollectionForCompact(opCtx, database, collectionNss); + } + + OldClientContext ctx(opCtx, collectionNss.ns()); + log(LogComponent::kCommand) << "compact " << collectionNss + << " begin, options: " << *compactOptions; + if (recordStore->compactsInPlace()) { CompactStats stats; Status status = recordStore->compact(opCtx); @@ -69,12 +118,17 @@ StatusWith<CompactStats> compactCollection(OperationContext* opCtx, if (!status.isOK()) return StatusWith<CompactStats>(status); + log() << "compact " << collectionNss << " end"; return StatusWith<CompactStats>(stats); } - if (indexCatalog->numIndexesInProgress(opCtx)) - return StatusWith<CompactStats>(ErrorCodes::BadValue, - "cannot compact when indexes in progress"); + invariant(opCtx->lockState()->isCollectionLockedForMode(collectionNss, MODE_X)); + + // If the storage engine doesn't support compacting in place, make sure no background operations + // or indexes are running. + const UUID collectionUUID = collection->uuid().get(); + BackgroundOperation::assertNoBgOpInProgForNs(collectionNss); + IndexBuildsCoordinator::get(opCtx)->assertNoIndexBuildInProgForCollection(collectionUUID); std::vector<BSONObj> indexSpecs; { @@ -148,6 +202,7 @@ StatusWith<CompactStats> compactCollection(OperationContext* opCtx, wunit.commit(); } + log() << "compact " << collectionNss << " end"; return StatusWith<CompactStats>(stats); } diff --git a/src/mongo/db/catalog/collection_compact.h b/src/mongo/db/catalog/collection_compact.h index b17b0ec3886..a3aefc1833e 100644 --- a/src/mongo/db/catalog/collection_compact.h +++ b/src/mongo/db/catalog/collection_compact.h @@ -30,7 +30,6 @@ #pragma once #include "mongo/base/status_with.h" -#include "mongo/db/catalog/collection.h" #include "mongo/db/storage/record_store.h" namespace mongo { @@ -40,7 +39,7 @@ namespace mongo { * See record_store.h for CompactStats and CompactOptions definitions. */ StatusWith<CompactStats> compactCollection(OperationContext* opCtx, - Collection* collection, + const NamespaceString& collectionNss, const CompactOptions* options); } // namespace mongo diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index d78af120927..a1262f66412 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -42,8 +42,6 @@ #include "mongo/db/commands.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/curop.h" -#include "mongo/db/db_raii.h" -#include "mongo/db/index_builds_coordinator.h" #include "mongo/db/jsobj.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/views/view_catalog.h" @@ -117,34 +115,7 @@ public: if (cmdObj.hasElement("validate")) compactOptions.validateDocuments = cmdObj["validate"].trueValue(); - AutoGetDb autoDb(opCtx, db, MODE_X); - Database* const collDB = autoDb.getDb(); - - Collection* collection = collDB ? collDB->getCollection(opCtx, nss) : nullptr; - auto view = - collDB && !collection ? ViewCatalog::get(collDB)->lookup(opCtx, nss.ns()) : nullptr; - - // If db/collection does not exist, short circuit and return. - if (!collDB || !collection) { - if (view) - uasserted(ErrorCodes::CommandNotSupportedOnView, "can't compact a view"); - else - uasserted(ErrorCodes::NamespaceNotFound, "collection does not exist"); - } - - OldClientContext ctx(opCtx, nss.ns()); - BackgroundOperation::assertNoBgOpInProgForNs(nss.ns()); - invariant(collection->uuid()); - IndexBuildsCoordinator::get(opCtx)->assertNoIndexBuildInProgForCollection( - collection->uuid().get()); - - log() << "compact " << nss.ns() << " begin, options: " << compactOptions; - - StatusWith<CompactStats> status = compactCollection(opCtx, collection, &compactOptions); - uassertStatusOK(status.getStatus()); - - log() << "compact " << nss.ns() << " end"; - + uassertStatusOK(compactCollection(opCtx, nss, &compactOptions)); return true; } }; diff --git a/src/mongo/db/storage/record_store.h b/src/mongo/db/storage/record_store.h index 93f01d8c81a..d4a5151faff 100644 --- a/src/mongo/db/storage/record_store.h +++ b/src/mongo/db/storage/record_store.h @@ -488,6 +488,15 @@ public: } /** + * If compact() supports online compaction. + * + * Only called if compactSupported() returns true. + */ + virtual bool supportsOnlineCompaction() const { + MONGO_UNREACHABLE; + } + + /** * Attempt to reduce the storage space used by this RecordStore. * * Only called if compactSupported() returns true. diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h index 8bdfdaecdd6..b448e76ea52 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h @@ -178,6 +178,9 @@ public: virtual bool compactsInPlace() const { return true; } + virtual bool supportsOnlineCompaction() const { + return true; + } virtual Timestamp getPinnedOplog() const final; |