summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp12
-rw-r--r--src/mongo/db/startup_recovery.cpp30
-rw-r--r--src/mongo/db/storage/durable_catalog.h6
-rw-r--r--src/mongo/db/storage/durable_catalog_feature_tracker.h195
-rw-r--r--src/mongo/db/storage/durable_catalog_impl.cpp225
-rw-r--r--src/mongo/db/storage/durable_catalog_impl.h19
-rw-r--r--src/mongo/db/storage/kv/SConscript1
-rw-r--r--src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp502
-rw-r--r--src/mongo/db/storage/storage_engine.h14
-rw-r--r--src/mongo/db/storage/storage_engine_impl.cpp20
-rw-r--r--src/mongo/db/storage/storage_engine_impl.h18
-rw-r--r--src/mongo/db/storage/storage_engine_mock.h4
-rw-r--r--src/mongo/db/storage/storage_engine_test_fixture.h1
13 files changed, 33 insertions, 1014 deletions
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index d79c64648d9..155dbbd6825 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -1737,8 +1737,16 @@ Status CollectionImpl::prepareForIndexBuild(OperationContext* opCtx,
bool isBackgroundSecondaryBuild) {
auto durableCatalog = DurableCatalog::get(opCtx);
- auto imd = durableCatalog->prepareIndexMetaDataForIndexBuild(
- opCtx, spec, buildUUID, isBackgroundSecondaryBuild);
+ BSONCollectionCatalogEntry::IndexMetaData imd;
+ imd.spec = spec->infoObj();
+ imd.ready = false;
+ imd.multikey = false;
+ imd.isBackgroundSecondaryBuild = isBackgroundSecondaryBuild;
+ imd.buildUUID = buildUUID;
+
+ if (indexTypeSupportsPathLevelMultikeyTracking(spec->getAccessMethodName())) {
+ imd.multikeyPaths = MultikeyPaths{static_cast<size_t>(spec->keyPattern().nFields())};
+ }
// Confirm that our index is not already in the current metadata.
invariant(-1 == _metadata->findIndexOffset(imd.nameStringData()),
diff --git a/src/mongo/db/startup_recovery.cpp b/src/mongo/db/startup_recovery.cpp
index d91d484d319..ff6d18bf0db 100644
--- a/src/mongo/db/startup_recovery.cpp
+++ b/src/mongo/db/startup_recovery.cpp
@@ -270,34 +270,6 @@ void openDatabases(OperationContext* opCtx, const StorageEngine* storageEngine,
}
}
-// Check for storage engine file compatibility. Exits the process if there is an incompatibility.
-void assertFilesCompatible(OperationContext* opCtx, StorageEngine* storageEngine) {
- auto status = storageEngine->currentFilesCompatible(opCtx);
- if (status.isOK()) {
- return;
- }
-
- if (status.code() == ErrorCodes::CanRepairToDowngrade) {
- // Convert CanRepairToDowngrade statuses to MustUpgrade statuses to avoid logging a
- // potentially confusing and inaccurate message.
- //
- // TODO SERVER-24097: Log a message informing the user that they can start the current
- // version of mongod with --repair and then proceed with normal startup.
- status = {ErrorCodes::MustUpgrade, status.reason()};
- }
- LOGV2_FATAL_CONTINUE(
- 21023,
- "Unable to start mongod due to an incompatibility with the data files and this version "
- "of mongod: {error}. Please consult our documentation when trying to downgrade to a "
- "previous major release",
- "Unable to start mongod due to an incompatibility with the data files and this version "
- "of mongod. Please consult our documentation when trying to downgrade to a previous "
- "major release",
- "error"_attr = redact(status));
- quickExit(EXIT_NEED_UPGRADE);
- MONGO_UNREACHABLE;
-}
-
/**
* Returns 'true' if this server has a configuration document in local.system.replset.
*/
@@ -644,8 +616,6 @@ void repairAndRecoverDatabases(OperationContext* opCtx,
} else {
startupRecovery(opCtx, storageEngine, lastShutdownState);
}
-
- assertFilesCompatible(opCtx, storageEngine);
}
} // namespace startup_recovery
diff --git a/src/mongo/db/storage/durable_catalog.h b/src/mongo/db/storage/durable_catalog.h
index 5d6d24848b7..ffd2a9f3e63 100644
--- a/src/mongo/db/storage/durable_catalog.h
+++ b/src/mongo/db/storage/durable_catalog.h
@@ -140,12 +140,6 @@ public:
const CollectionOptions& collOptions,
const IndexDescriptor* spec) = 0;
- virtual BSONCollectionCatalogEntry::IndexMetaData prepareIndexMetaDataForIndexBuild(
- OperationContext* opCtx,
- const IndexDescriptor* spec,
- boost::optional<UUID> buildUUID,
- bool isBackgroundSecondaryBuild) = 0;
-
/**
* Import a collection by inserting the given metadata into the durable catalog and instructing
* the storage engine to import the corresponding idents. The metadata object should be a valid
diff --git a/src/mongo/db/storage/durable_catalog_feature_tracker.h b/src/mongo/db/storage/durable_catalog_feature_tracker.h
deleted file mode 100644
index 060a0d859a1..00000000000
--- a/src/mongo/db/storage/durable_catalog_feature_tracker.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-#include <type_traits>
-
-#include "mongo/db/storage/durable_catalog_impl.h"
-
-namespace mongo {
-
-class OperationContext;
-class RecordId;
-class RecordStore;
-
-/**
- * Manages the contents of a document in the DurableCatalogImpl used to restrict downgrade
- * compatibility.
- *
- * When a new feature is enabled on a collection or index in the data files, a bit is set in one of
- * the fields of the document. Older versions won't recognize this bit and will fail to start up as
- * a result.
- */
-class DurableCatalogImpl::FeatureTracker {
-public:
- /**
- * Bit flags representing whether a particular feature is enabled on a least one collection or
- * index in the data files. Features included in this enumeration always require user
- * intervention on downgrade.
- *
- * The next feature added to this enumeration should use the current value of 'kNextFeatureBit',
- * and 'kNextFeatureBit' should be changed to the next largest power of two.
- */
- enum class NonRepairableFeature : std::uint64_t {
- kCollation = 1 << 0,
- kNextFeatureBit = 1 << 1
- };
-
- using NonRepairableFeatureMask = std::underlying_type<NonRepairableFeature>::type;
-
- /**
- * Bit flags representing whether a particular feature is enabled on a least one collection or
- * index in the data files. Features included in this enumeration either (a) don't require user
- * intervention on downgrade, or (b) are no longer enabled if --repair is done with an older
- * version.
- *
- * The next feature added to this enumeration should use the current value of 'kNextFeatureBit',
- * and 'kNextFeatureBit' should be changed to the next largest power of two.
- */
- enum class RepairableFeature : std::uint64_t {
- kPathLevelMultikeyTracking = 1 << 0,
- kIndexKeyStringWithLongTypeBits = 1 << 1,
- kNextFeatureBit = 1 << 2
- };
-
- using RepairableFeatureMask = std::underlying_type<RepairableFeature>::type;
-
- /**
- * Returns true if 'obj' represents the contents of the feature document that was previously
- * inserted into the DurableCatalogImpl, and returns false otherwise.
- *
- * This function should return true for at most one document in the DurableCatalogImpl.
- */
- static bool isFeatureDocument(BSONObj obj);
-
- /**
- * Returns a FeatureTracker instance to manage the contents of the feature document located at
- * 'rid' in the record store 'catalog->_rs'.
- *
- * It is invalid to call this function when isFeatureDocument() returns false for the record
- * data associated with 'rid'.
- */
- static std::unique_ptr<FeatureTracker> get(OperationContext* opCtx,
- DurableCatalogImpl* catalog,
- RecordId rid);
-
- /**
- * Returns a FeatureTracker instance to manage the contents of a feature document. The feature
- * document isn't inserted into 'rs' as a result of calling this function. Instead, the feature
- * document is inserted into 'rs' when putInfo() is first called.
- *
- * It is invalid to call this function when isFeatureDocument() returns true for some document
- * in the record store 'catalog->_rs'.
- */
- static std::unique_ptr<FeatureTracker> create(OperationContext* opCtx,
- DurableCatalogImpl* catalog);
-
- /**
- * Returns whethers the data files are compatible with the current code:
- *
- * - Status::OK() if the data files are compatible with the current code.
- *
- * - ErrorCodes::CanRepairToDowngrade if the data files are incompatible with the current
- * code, but a --repair would make them compatible. For example, when rebuilding all indexes
- * in the data files would resolve the incompatibility.
- *
- * - ErrorCodes::MustUpgrade if the data files are incompatible with the current code and a
- * newer version is required to start up.
- */
- Status isCompatibleWithCurrentCode(OperationContext* opCtx) const;
-
- /**
- * Returns true if 'feature' is tracked in the document, and returns false otherwise.
- */
- bool isNonRepairableFeatureInUse(OperationContext* opCtx, NonRepairableFeature feature) const;
-
- /**
- * Sets the specified non-repairable feature as being enabled on at least one collection or
- * index in the data files.
- */
- void markNonRepairableFeatureAsInUse(OperationContext* opCtx, NonRepairableFeature feature);
-
- /**
- * Sets the specified non-repairable feature as not being enabled on any collection or index in
- * the data files.
- */
- void markNonRepairableFeatureAsNotInUse(OperationContext* opCtx, NonRepairableFeature feature);
-
- /**
- * Returns true if 'feature' is tracked in the document, and returns false otherwise.
- */
- bool isRepairableFeatureInUse(OperationContext* opCtx, RepairableFeature feature) const;
-
- /**
- * Sets the specified repairable feature as being enabled on at least one collection or index in
- * the data files.
- */
- void markRepairableFeatureAsInUse(OperationContext* opCtx, RepairableFeature feature);
-
- /**
- * Sets the specified repairable feature as not being enabled on any collection or index in the
- * data files.
- */
- void markRepairableFeatureAsNotInUse(OperationContext* opCtx, RepairableFeature feature);
-
- void setUsedNonRepairableFeaturesMaskForTestingOnly(NonRepairableFeatureMask mask) {
- _usedNonRepairableFeaturesMask = mask;
- }
-
- void setUsedRepairableFeaturesMaskForTestingOnly(RepairableFeatureMask mask) {
- _usedRepairableFeaturesMask = mask;
- }
-
- struct FeatureBits {
- NonRepairableFeatureMask nonRepairableFeatures;
- RepairableFeatureMask repairableFeatures;
- };
-
- FeatureBits getInfo(OperationContext* opCtx) const;
-
- void putInfo(OperationContext* opCtx, const FeatureBits& versionInfo);
-
-private:
- // Must go through FeatureTracker::get() or FeatureTracker::create().
- FeatureTracker(DurableCatalogImpl* catalog, RecordId rid) : _catalog(catalog), _rid(rid) {}
-
- DurableCatalogImpl* _catalog;
- RecordId _rid;
-
- NonRepairableFeatureMask _usedNonRepairableFeaturesMask =
- static_cast<NonRepairableFeatureMask>(NonRepairableFeature::kNextFeatureBit) - 1;
-
- RepairableFeatureMask _usedRepairableFeaturesMask =
- static_cast<RepairableFeatureMask>(RepairableFeature::kNextFeatureBit) - 1;
-};
-
-} // namespace mongo
diff --git a/src/mongo/db/storage/durable_catalog_impl.cpp b/src/mongo/db/storage/durable_catalog_impl.cpp
index c3bc50676fc..e607d606efb 100644
--- a/src/mongo/db/storage/durable_catalog_impl.cpp
+++ b/src/mongo/db/storage/durable_catalog_impl.cpp
@@ -44,7 +44,6 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/server_options.h"
-#include "mongo/db/storage/durable_catalog_feature_tracker.h"
#include "mongo/db/storage/kv/kv_engine.h"
#include "mongo/db/storage/record_store.h"
#include "mongo/db/storage/recovery_unit.h"
@@ -232,7 +231,7 @@ public:
const std::string _ident;
};
-bool DurableCatalogImpl::FeatureTracker::isFeatureDocument(BSONObj obj) {
+bool DurableCatalogImpl::isFeatureDocument(BSONObj obj) {
BSONElement firstElem = obj.firstElement();
if (firstElem.fieldNameStringData() == kIsFeatureDocumentFieldName) {
return firstElem.booleanSafe();
@@ -240,158 +239,6 @@ bool DurableCatalogImpl::FeatureTracker::isFeatureDocument(BSONObj obj) {
return false;
}
-Status DurableCatalogImpl::FeatureTracker::isCompatibleWithCurrentCode(
- OperationContext* opCtx) const {
- FeatureBits versionInfo = getInfo(opCtx);
-
- uint64_t unrecognizedNonRepairableFeatures =
- versionInfo.nonRepairableFeatures & ~_usedNonRepairableFeaturesMask;
- if (unrecognizedNonRepairableFeatures) {
- StringBuilder sb;
- sb << "The data files use features not recognized by this version of mongod; the NR feature"
- " bits in positions ";
- appendPositionsOfBitsSet(unrecognizedNonRepairableFeatures, &sb);
- sb << " aren't recognized by this version of mongod";
- return {ErrorCodes::MustUpgrade, sb.str()};
- }
-
- uint64_t unrecognizedRepairableFeatures =
- versionInfo.repairableFeatures & ~_usedRepairableFeaturesMask;
- if (unrecognizedRepairableFeatures) {
- StringBuilder sb;
- sb << "The data files use features not recognized by this version of mongod; the R feature"
- " bits in positions ";
- appendPositionsOfBitsSet(unrecognizedRepairableFeatures, &sb);
- sb << " aren't recognized by this version of mongod";
- return {ErrorCodes::CanRepairToDowngrade, sb.str()};
- }
-
- return Status::OK();
-}
-
-std::unique_ptr<DurableCatalogImpl::FeatureTracker> DurableCatalogImpl::FeatureTracker::get(
- OperationContext* opCtx, DurableCatalogImpl* catalog, RecordId rid) {
- auto record = catalog->_rs->dataFor(opCtx, rid);
- BSONObj obj = record.toBson();
- invariant(isFeatureDocument(obj));
- return std::unique_ptr<DurableCatalogImpl::FeatureTracker>(
- new DurableCatalogImpl::FeatureTracker(catalog, rid));
-}
-
-std::unique_ptr<DurableCatalogImpl::FeatureTracker> DurableCatalogImpl::FeatureTracker::create(
- OperationContext* opCtx, DurableCatalogImpl* catalog) {
- return std::unique_ptr<DurableCatalogImpl::FeatureTracker>(
- new DurableCatalogImpl::FeatureTracker(catalog, RecordId()));
-}
-
-bool DurableCatalogImpl::FeatureTracker::isNonRepairableFeatureInUse(
- OperationContext* opCtx, NonRepairableFeature feature) const {
- FeatureBits versionInfo = getInfo(opCtx);
- return versionInfo.nonRepairableFeatures & static_cast<NonRepairableFeatureMask>(feature);
-}
-
-void DurableCatalogImpl::FeatureTracker::markNonRepairableFeatureAsInUse(
- OperationContext* opCtx, NonRepairableFeature feature) {
- FeatureBits versionInfo = getInfo(opCtx);
- versionInfo.nonRepairableFeatures |= static_cast<NonRepairableFeatureMask>(feature);
- putInfo(opCtx, versionInfo);
-}
-
-void DurableCatalogImpl::FeatureTracker::markNonRepairableFeatureAsNotInUse(
- OperationContext* opCtx, NonRepairableFeature feature) {
- FeatureBits versionInfo = getInfo(opCtx);
- versionInfo.nonRepairableFeatures &= ~static_cast<NonRepairableFeatureMask>(feature);
- putInfo(opCtx, versionInfo);
-}
-
-bool DurableCatalogImpl::FeatureTracker::isRepairableFeatureInUse(OperationContext* opCtx,
- RepairableFeature feature) const {
- FeatureBits versionInfo = getInfo(opCtx);
- return versionInfo.repairableFeatures & static_cast<RepairableFeatureMask>(feature);
-}
-
-void DurableCatalogImpl::FeatureTracker::markRepairableFeatureAsInUse(OperationContext* opCtx,
- RepairableFeature feature) {
- FeatureBits versionInfo = getInfo(opCtx);
- versionInfo.repairableFeatures |= static_cast<RepairableFeatureMask>(feature);
- putInfo(opCtx, versionInfo);
-}
-
-void DurableCatalogImpl::FeatureTracker::markRepairableFeatureAsNotInUse(
- OperationContext* opCtx, RepairableFeature feature) {
- FeatureBits versionInfo = getInfo(opCtx);
- versionInfo.repairableFeatures &= ~static_cast<RepairableFeatureMask>(feature);
- putInfo(opCtx, versionInfo);
-}
-
-DurableCatalogImpl::FeatureTracker::FeatureBits DurableCatalogImpl::FeatureTracker::getInfo(
- OperationContext* opCtx) const {
- if (_rid.isNull()) {
- return {};
- }
-
- auto record = _catalog->_rs->dataFor(opCtx, _rid);
- BSONObj obj = record.toBson();
- invariant(isFeatureDocument(obj));
-
- BSONElement nonRepairableFeaturesElem;
- auto nonRepairableFeaturesStatus = bsonExtractTypedField(
- obj, kNonRepairableFeaturesFieldName, BSONType::NumberLong, &nonRepairableFeaturesElem);
- if (!nonRepairableFeaturesStatus.isOK()) {
- LOGV2_ERROR(22215,
- "error: exception extracting typed field with obj:{obj}",
- "Exception extracting typed field from obj",
- "obj"_attr = redact(obj),
- "fieldName"_attr = kNonRepairableFeaturesFieldName);
- fassert(40111, nonRepairableFeaturesStatus);
- }
-
- BSONElement repairableFeaturesElem;
- auto repairableFeaturesStatus = bsonExtractTypedField(
- obj, kRepairableFeaturesFieldName, BSONType::NumberLong, &repairableFeaturesElem);
- if (!repairableFeaturesStatus.isOK()) {
- LOGV2_ERROR(22216,
- "error: exception extracting typed field with obj:{obj}",
- "Exception extracting typed field from obj",
- "obj"_attr = redact(obj),
- "fieldName"_attr = kRepairableFeaturesFieldName);
- fassert(40112, repairableFeaturesStatus);
- }
-
- FeatureBits versionInfo;
- versionInfo.nonRepairableFeatures =
- static_cast<NonRepairableFeatureMask>(nonRepairableFeaturesElem.numberLong());
- versionInfo.repairableFeatures =
- static_cast<RepairableFeatureMask>(repairableFeaturesElem.numberLong());
- return versionInfo;
-}
-
-void DurableCatalogImpl::FeatureTracker::putInfo(OperationContext* opCtx,
- const FeatureBits& versionInfo) {
- BSONObjBuilder bob;
- bob.appendBool(kIsFeatureDocumentFieldName, true);
- // We intentionally include the "ns" field with a null value in the feature document to prevent
- // older versions that do 'obj["ns"].String()' from starting up. This way only versions that are
- // aware of the feature document's existence can successfully start up.
- bob.appendNull(kNamespaceFieldName);
- bob.append(kNonRepairableFeaturesFieldName,
- static_cast<long long>(versionInfo.nonRepairableFeatures));
- bob.append(kRepairableFeaturesFieldName,
- static_cast<long long>(versionInfo.repairableFeatures));
- BSONObj obj = bob.done();
-
- if (_rid.isNull()) {
- // This is the first time a feature is being marked as in-use or not in-use, so we must
- // insert the feature document rather than update it.
- auto rid = _catalog->_rs->insertRecord(opCtx, obj.objdata(), obj.objsize(), Timestamp());
- fassert(40113, rid.getStatus());
- _rid = rid.getValue();
- } else {
- auto status = _catalog->_rs->updateRecord(opCtx, _rid, obj.objdata(), obj.objsize());
- fassert(40114, status);
- }
-}
-
DurableCatalogImpl::DurableCatalogImpl(RecordStore* rs,
bool directoryPerDb,
bool directoryForIndexes,
@@ -464,13 +311,8 @@ void DurableCatalogImpl::init(OperationContext* opCtx) {
while (auto record = cursor->next()) {
BSONObj obj = record->data.releaseToBson();
- if (FeatureTracker::isFeatureDocument(obj)) {
- // There should be at most one version document in the catalog.
- invariant(!_featureTracker);
-
- // Initialize the feature tracker and skip over the version document because it doesn't
- // correspond to a namespace entry.
- _featureTracker = FeatureTracker::get(opCtx, this, record->id);
+ // For backwards compatibility where older version have a written feature document
+ if (isFeatureDocument(obj)) {
continue;
}
@@ -480,16 +322,6 @@ void DurableCatalogImpl::init(OperationContext* opCtx) {
_catalogIdToEntryMap[record->id] = Entry(record->id, ident, NamespaceString(ns));
}
- if (!_featureTracker) {
- // If there wasn't a feature document, commit a default one to disk. All deployments will
- // end up with `kPathLevelMultikeyTracking` as every `_id` index build sets this.
- WriteUnitOfWork wuow(opCtx);
- _featureTracker = DurableCatalogImpl::FeatureTracker::create(opCtx, this);
- _featureTracker->markRepairableFeatureAsInUse(
- opCtx, FeatureTracker::RepairableFeature::kPathLevelMultikeyTracking);
- wuow.commit();
- }
-
// In the unlikely event that we have used this _rand before generate a new one.
stdx::lock_guard<Latch> lk(_randLock);
while (_hasEntryCollidingWithRand(lk)) {
@@ -504,7 +336,7 @@ std::vector<DurableCatalog::Entry> DurableCatalogImpl::getAllCatalogEntries(
auto cursor = _rs->getCursor(opCtx);
while (auto record = cursor->next()) {
BSONObj obj = record->data.releaseToBson();
- if (FeatureTracker::isFeatureDocument(obj)) {
+ if (isFeatureDocument(obj)) {
// Skip over the version document because it doesn't correspond to a collection.
continue;
}
@@ -732,7 +564,7 @@ std::vector<std::string> DurableCatalogImpl::getAllIdents(OperationContext* opCt
auto cursor = _rs->getCursor(opCtx);
while (auto record = cursor->next()) {
BSONObj obj = record->data.releaseToBson();
- if (FeatureTracker::isFeatureDocument(obj)) {
+ if (isFeatureDocument(obj)) {
// Skip over the version document because it doesn't correspond to a namespace entry and
// therefore doesn't refer to any idents.
continue;
@@ -839,14 +671,6 @@ StatusWith<std::pair<RecordId, std::unique_ptr<RecordStore>>> DurableCatalogImpl
if (!status.isOK())
return status;
- // Mark collation feature as in use if the collection has a non-simple default collation.
- if (!options.collation.isEmpty()) {
- const auto feature = DurableCatalogImpl::FeatureTracker::NonRepairableFeature::kCollation;
- if (getFeatureTracker()->isNonRepairableFeatureInUse(opCtx, feature)) {
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx, feature);
- }
- }
-
auto ru = opCtx->recoveryUnit();
CollectionUUID uuid = options.uuid.get();
opCtx->recoveryUnit()->onRollback([ru, catalog = this, nss, ident = entry.ident, uuid]() {
@@ -959,14 +783,6 @@ StatusWith<DurableCatalog::ImportResult> DurableCatalogImpl::importCollection(
}
}
- // Mark collation feature as in use if the collection has a non-simple default collation.
- if (!md.options.collation.isEmpty()) {
- const auto feature = DurableCatalogImpl::FeatureTracker::NonRepairableFeature::kCollation;
- if (getFeatureTracker()->isNonRepairableFeatureInUse(opCtx, feature)) {
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx, feature);
- }
- }
-
opCtx->recoveryUnit()->onRollback(
[opCtx, catalog = this, ident = entry.ident, indexIdents = indexIdents]() {
catalog->_engine->getEngine()->dropIdentForImport(opCtx, ident);
@@ -1007,37 +823,6 @@ Status DurableCatalogImpl::dropCollection(OperationContext* opCtx, RecordId cata
return Status::OK();
}
-BSONCollectionCatalogEntry::IndexMetaData DurableCatalogImpl::prepareIndexMetaDataForIndexBuild(
- OperationContext* opCtx,
- const IndexDescriptor* spec,
- boost::optional<UUID> buildUUID,
- bool isBackgroundSecondaryBuild) {
- BSONCollectionCatalogEntry::IndexMetaData imd;
- imd.spec = spec->infoObj();
- imd.ready = false;
- imd.multikey = false;
- imd.isBackgroundSecondaryBuild = isBackgroundSecondaryBuild;
- imd.buildUUID = buildUUID;
-
- if (indexTypeSupportsPathLevelMultikeyTracking(spec->getAccessMethodName())) {
- const auto feature = FeatureTracker::RepairableFeature::kPathLevelMultikeyTracking;
- if (!getFeatureTracker()->isRepairableFeatureInUse(opCtx, feature)) {
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx, feature);
- }
- imd.multikeyPaths = MultikeyPaths{static_cast<size_t>(spec->keyPattern().nFields())};
- }
-
- // Mark collation feature as in use if the index has a non-simple collation.
- if (imd.spec["collation"]) {
- const auto feature = FeatureTracker::NonRepairableFeature::kCollation;
- if (!getFeatureTracker()->isNonRepairableFeatureInUse(opCtx, feature)) {
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx, feature);
- }
- }
-
- return imd;
-}
-
Status DurableCatalogImpl::dropAndRecreateIndexIdentForResume(OperationContext* opCtx,
const CollectionOptions& collOptions,
const IndexDescriptor* spec,
diff --git a/src/mongo/db/storage/durable_catalog_impl.h b/src/mongo/db/storage/durable_catalog_impl.h
index 63a8c9ec062..f0eeba00fed 100644
--- a/src/mongo/db/storage/durable_catalog_impl.h
+++ b/src/mongo/db/storage/durable_catalog_impl.h
@@ -49,7 +49,6 @@ class StorageEngineInterface;
class DurableCatalogImpl : public DurableCatalog {
public:
- class FeatureTracker;
/**
* The RecordStore must be thread-safe, in particular with concurrent calls to
* RecordStore::find, updateRecord, insertRecord, deleteRecord and dataFor. The
@@ -93,11 +92,6 @@ public:
bool isCollectionIdent(StringData ident) const;
- FeatureTracker* getFeatureTracker() const {
- invariant(_featureTracker);
- return _featureTracker.get();
- }
-
RecordStore* getRecordStore() {
return _rs;
}
@@ -120,12 +114,6 @@ public:
const CollectionOptions& collOptions,
const IndexDescriptor* spec);
- BSONCollectionCatalogEntry::IndexMetaData prepareIndexMetaDataForIndexBuild(
- OperationContext* opCtx,
- const IndexDescriptor* spec,
- boost::optional<UUID> buildUUID,
- bool isBackgroundSecondaryBuild);
-
StatusWith<ImportResult> importCollection(OperationContext* opCtx,
const NamespaceString& nss,
const BSONObj& metadata,
@@ -197,6 +185,9 @@ private:
*/
bool _hasEntryCollidingWithRand(WithLock) const;
+ // Allows featureDocuments to be checked with older versions
+ static bool isFeatureDocument(BSONObj obj);
+
RecordStore* _rs; // not owned
const bool _directoryPerDb;
const bool _directoryForIndexes;
@@ -210,10 +201,6 @@ private:
mutable Mutex _catalogIdToEntryMapLock =
MONGO_MAKE_LATCH("DurableCatalogImpl::_catalogIdToEntryMap");
- // Manages the feature document that may be present in the DurableCatalogImpl. '_featureTracker'
- // is guaranteed to be non-null after DurableCatalogImpl::init() is called.
- std::unique_ptr<FeatureTracker> _featureTracker;
-
StorageEngineInterface* const _engine;
};
} // namespace mongo
diff --git a/src/mongo/db/storage/kv/SConscript b/src/mongo/db/storage/kv/SConscript
index 6e16d805457..98011a4a374 100644
--- a/src/mongo/db/storage/kv/SConscript
+++ b/src/mongo/db/storage/kv/SConscript
@@ -17,7 +17,6 @@ env.Library(
env.Library(
target='kv_engine_test_harness',
source=[
- 'durable_catalog_feature_tracker_test.cpp',
'kv_engine_test_harness.cpp',
'kv_engine_timestamps_test.cpp',
],
diff --git a/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp b/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp
deleted file mode 100644
index e7cdf744c35..00000000000
--- a/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/storage/kv/kv_engine_test_harness.h"
-
-#include <memory>
-
-#include "mongo/db/operation_context_noop.h"
-#include "mongo/db/service_context_test_fixture.h"
-#include "mongo/db/storage/durable_catalog_feature_tracker.h"
-#include "mongo/db/storage/kv/kv_engine.h"
-#include "mongo/db/storage/record_store.h"
-#include "mongo/unittest/unittest.h"
-
-namespace mongo {
-namespace {
-
-using NonRepairableFeature = DurableCatalogImpl::FeatureTracker::NonRepairableFeature;
-using NonRepairableFeatureMask = DurableCatalogImpl::FeatureTracker::NonRepairableFeatureMask;
-using RepairableFeature = DurableCatalogImpl::FeatureTracker::RepairableFeature;
-using RepairableFeatureMask = DurableCatalogImpl::FeatureTracker::RepairableFeatureMask;
-
-class DurableCatalogFeatureTrackerTest : public ServiceContextTest {
-public:
- static const NonRepairableFeature kNonRepairableFeature1 =
- static_cast<NonRepairableFeature>(1 << 0);
-
- static const NonRepairableFeature kNonRepairableFeature2 =
- static_cast<NonRepairableFeature>(1 << 1);
-
- static const NonRepairableFeature kNonRepairableFeature3 =
- static_cast<NonRepairableFeature>(1 << 2);
-
- static const RepairableFeature kRepairableFeature1 = static_cast<RepairableFeature>(1 << 0);
-
- static const RepairableFeature kRepairableFeature2 = static_cast<RepairableFeature>(1 << 1);
-
- static const RepairableFeature kRepairableFeature3 = static_cast<RepairableFeature>(1 << 2);
-
- DurableCatalogFeatureTrackerTest() : _helper(KVHarnessHelper::create(getServiceContext())) {}
-
- ServiceContext::UniqueOperationContext newOperationContext() {
- auto opCtx = makeOperationContext();
- opCtx->setRecoveryUnit(
- std::unique_ptr<RecoveryUnit>(_helper->getEngine()->newRecoveryUnit()),
- WriteUnitOfWork::RecoveryUnitState::kNotInUnitOfWork);
- opCtx->swapLockState(std::make_unique<LockerNoop>(), WithLock::withoutLock());
- return opCtx;
- }
-
- void setUp() final {
- auto opCtx = newOperationContext();
- {
- WriteUnitOfWork wuow(opCtx.get());
- ASSERT_OK(_helper->getEngine()->createRecordStore(
- opCtx.get(), "catalog", "catalog", CollectionOptions()));
- _rs = _helper->getEngine()->getRecordStore(
- opCtx.get(), "catalog", "catalog", CollectionOptions());
- wuow.commit();
- }
-
- _catalog = std::make_unique<DurableCatalogImpl>(_rs.get(), false, false, nullptr);
- _catalog->init(opCtx.get());
-
- {
- WriteUnitOfWork wuow(opCtx.get());
- _featureTracker =
- DurableCatalogImpl::FeatureTracker::create(opCtx.get(), _catalog.get());
- wuow.commit();
- }
- }
-
- RecordStore* getRecordStore() const {
- return _rs.get();
- }
-
- DurableCatalogImpl::FeatureTracker* getFeatureTracker() const {
- return _featureTracker.get();
- }
-
-private:
- std::unique_ptr<KVHarnessHelper> _helper;
- std::unique_ptr<RecordStore> _rs;
- std::unique_ptr<DurableCatalogImpl> _catalog;
- std::unique_ptr<DurableCatalogImpl::FeatureTracker> _featureTracker;
-};
-
-TEST_F(DurableCatalogFeatureTrackerTest, CanMarkNonRepairableFeatureAsInUse) {
- {
- auto opCtx = newOperationContext();
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
-
- // Marking the same non-repairable feature as in-use again does nothing.
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- }
-
- // The repairable feature bit in the same position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- }
-
- // The non-repairable feature in a different position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature2));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest, CanMarkNonRepairableFeatureAsNotInUse) {
- {
- auto opCtx = newOperationContext();
-
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
-
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
-
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature2));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature2);
- wuow.commit();
- }
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature2));
- }
-
- {
- auto opCtx = newOperationContext();
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsNotInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
-
- // Marking the same non-repairable feature as not in-use again does nothing.
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsNotInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- }
-
- // The repairable feature bit in the same position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- }
-
- // The non-repairable feature in a different position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature2));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest, CanMarkRepairableFeatureAsInUse) {
- {
- auto opCtx = newOperationContext();
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
-
- // Marking the same repairable feature as in-use again does nothing.
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- }
-
- // The non-repairable feature bit in the same position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- }
-
- // The repairable feature in a different position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature2));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest, CanMarkRepairableFeatureAsNotInUse) {
- {
- auto opCtx = newOperationContext();
-
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
-
- ASSERT(
- !getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
-
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature2));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature2);
- wuow.commit();
- }
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature2));
- }
-
- {
- auto opCtx = newOperationContext();
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsNotInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
-
- // Marking the same repairable feature as not in-use again does nothing.
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsNotInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT(!getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature1));
- }
-
- // The non-repairable feature bit in the same position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(
- getFeatureTracker()->isNonRepairableFeatureInUse(opCtx.get(), kNonRepairableFeature1));
- }
-
- // The repairable feature in a different position is unaffected.
- {
- auto opCtx = newOperationContext();
- ASSERT(getFeatureTracker()->isRepairableFeatureInUse(opCtx.get(), kRepairableFeature2));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest, DataFileAreCompatibleWithRecognizedNonRepairableFeature) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(0ULL);
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(0ULL);
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(
- static_cast<NonRepairableFeatureMask>(kNonRepairableFeature1));
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest,
- DataFilesAreIncompatibleWithAnUnrecognizedNonRepairableFeature) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(0ULL);
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(0ULL);
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- {
- auto opCtx = newOperationContext();
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature1);
- wuow.commit();
- }
-
- auto status = getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get());
- ASSERT_EQ(ErrorCodes::MustUpgrade, status.code());
- ASSERT_EQ(
- "The data files use features not recognized by this version of mongod; the NR feature"
- " bits in positions [ 0 ] aren't recognized by this version of mongod",
- status.reason());
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest,
- DataFilesAreIncompatibleWithMultipleUnrecognizedNonRepairableFeatures) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(
- static_cast<NonRepairableFeatureMask>(kNonRepairableFeature1));
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(0ULL);
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- {
- auto opCtx = newOperationContext();
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature2);
- wuow.commit();
- }
-
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markNonRepairableFeatureAsInUse(opCtx.get(),
- kNonRepairableFeature3);
- wuow.commit();
- }
-
- auto status = getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get());
- ASSERT_EQ(ErrorCodes::MustUpgrade, status.code());
- ASSERT_EQ(
- "The data files use features not recognized by this version of mongod; the NR feature"
- " bits in positions [ 1, 2 ] aren't recognized by this version of mongod",
- status.reason());
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest, DataFilesAreCompatibleWithRecognizedRepairableFeature) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(0ULL);
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(0ULL);
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(
- static_cast<RepairableFeatureMask>(kRepairableFeature1));
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest,
- DataFilesAreIncompatibleWithAnUnrecognizedRepairableFeature) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(0ULL);
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(0ULL);
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- {
- auto opCtx = newOperationContext();
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature1);
- wuow.commit();
- }
-
- auto status = getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get());
- ASSERT_EQ(ErrorCodes::CanRepairToDowngrade, status.code());
- ASSERT_EQ(
- "The data files use features not recognized by this version of mongod; the R feature"
- " bits in positions [ 0 ] aren't recognized by this version of mongod",
- status.reason());
- }
-}
-
-TEST_F(DurableCatalogFeatureTrackerTest,
- DataFilesAreIncompatibleWithMultipleUnrecognizedRepairableFeatures) {
- getFeatureTracker()->setUsedNonRepairableFeaturesMaskForTestingOnly(0ULL);
- getFeatureTracker()->setUsedRepairableFeaturesMaskForTestingOnly(
- static_cast<RepairableFeatureMask>(kRepairableFeature1));
-
- {
- auto opCtx = newOperationContext();
- ASSERT_OK(getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get()));
- }
-
- {
- auto opCtx = newOperationContext();
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature2);
- wuow.commit();
- }
-
- {
- WriteUnitOfWork wuow(opCtx.get());
- getFeatureTracker()->markRepairableFeatureAsInUse(opCtx.get(), kRepairableFeature3);
- wuow.commit();
- }
-
- auto status = getFeatureTracker()->isCompatibleWithCurrentCode(opCtx.get());
- ASSERT_EQ(ErrorCodes::CanRepairToDowngrade, status.code());
- ASSERT_EQ(
- "The data files use features not recognized by this version of mongod; the R feature"
- " bits in positions [ 1, 2 ] aren't recognized by this version of mongod",
- status.reason());
- }
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h
index aed7c3978d4..a99638bf85f 100644
--- a/src/mongo/db/storage/storage_engine.h
+++ b/src/mongo/db/storage/storage_engine.h
@@ -641,20 +641,6 @@ public:
*/
virtual std::string getFilesystemPathForDb(const std::string& dbName) const = 0;
- /**
- * Returns whethers the data files are compatible with the current code:
- *
- * - Status::OK() if the data files are compatible with the current code.
- *
- * - ErrorCodes::CanRepairToDowngrade if the data files are incompatible with the current
- * code, but a --repair would make them compatible. For example, when rebuilding all indexes
- * in the data files would resolve the incompatibility.
- *
- * - ErrorCodes::MustUpgrade if the data files are incompatible with the current code and a
- * newer version is required to start up.
- */
- virtual Status currentFilesCompatible(OperationContext* opCtx) const = 0;
-
virtual int64_t sizeOnDiskForDb(OperationContext* opCtx, StringData dbName) = 0;
virtual bool isUsingDirectoryPerDb() const = 0;
diff --git a/src/mongo/db/storage/storage_engine_impl.cpp b/src/mongo/db/storage/storage_engine_impl.cpp
index 466ed068640..bc2ae2ca72a 100644
--- a/src/mongo/db/storage/storage_engine_impl.cpp
+++ b/src/mongo/db/storage/storage_engine_impl.cpp
@@ -43,7 +43,7 @@
#include "mongo/db/index_builds_coordinator.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/server_options.h"
-#include "mongo/db/storage/durable_catalog_feature_tracker.h"
+#include "mongo/db/storage/durable_catalog_impl.h"
#include "mongo/db/storage/durable_history_pin.h"
#include "mongo/db/storage/kv/kv_engine.h"
#include "mongo/db/storage/kv/temporary_kv_record_store.h"
@@ -992,16 +992,6 @@ bool StorageEngineImpl::supportsRecoveryTimestamp() const {
StatusWith<Timestamp> StorageEngineImpl::recoverToStableTimestamp(OperationContext* opCtx) {
invariant(opCtx->lockState()->isW());
- // The "feature document" should not be rolled back. Perform a non-timestamped update to the
- // feature document to lock in the current state.
- DurableCatalogImpl::FeatureTracker::FeatureBits featureInfo;
- {
- WriteUnitOfWork wuow(opCtx);
- featureInfo = _catalog->getFeatureTracker()->getInfo(opCtx);
- _catalog->getFeatureTracker()->putInfo(opCtx, featureInfo);
- wuow.commit();
- }
-
auto state = catalog::closeCatalog(opCtx);
StatusWith<Timestamp> swTimestamp = _engine->recoverToStableTimestamp(opCtx);
@@ -1270,4 +1260,12 @@ void StorageEngineImpl::setPinnedOplogTimestamp(const Timestamp& pinnedTimestamp
_engine->setPinnedOplogTimestamp(pinnedTimestamp);
}
+DurableCatalog* StorageEngineImpl::getCatalog() {
+ return _catalog.get();
+}
+
+const DurableCatalog* StorageEngineImpl::getCatalog() const {
+ return _catalog.get();
+}
+
} // namespace mongo
diff --git a/src/mongo/db/storage/storage_engine_impl.h b/src/mongo/db/storage/storage_engine_impl.h
index 119de49c4bf..94662c3ede2 100644
--- a/src/mongo/db/storage/storage_engine_impl.h
+++ b/src/mongo/db/storage/storage_engine_impl.h
@@ -39,7 +39,6 @@
#include "mongo/bson/timestamp.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/storage/durable_catalog.h"
-#include "mongo/db/storage/durable_catalog_feature_tracker.h"
#include "mongo/db/storage/journal_listener.h"
#include "mongo/db/storage/kv/kv_drop_pending_ident_reaper.h"
#include "mongo/db/storage/record_store.h"
@@ -320,19 +319,15 @@ public:
void checkpoint() override;
- DurableCatalog* getCatalog() override {
- return _catalog.get();
- }
-
- const DurableCatalog* getCatalog() const override {
- return _catalog.get();
- }
-
StatusWith<ReconcileResult> reconcileCatalogAndIdents(
OperationContext* opCtx, LastShutdownState lastShutdownState) override;
std::string getFilesystemPathForDb(const std::string& dbName) const override;
+ DurableCatalog* getCatalog() override;
+
+ const DurableCatalog* getCatalog() const override;
+
/**
* When loading after an unclean shutdown, this performs cleanup on the DurableCatalogImpl.
*/
@@ -348,11 +343,6 @@ public:
return _dropPendingIdentReaper.getAllIdentNames();
}
- Status currentFilesCompatible(OperationContext* opCtx) const override {
- // Delegate to the FeatureTracker as to whether the data files are compatible or not.
- return _catalog->getFeatureTracker()->isCompatibleWithCurrentCode(opCtx);
- }
-
int64_t sizeOnDiskForDb(OperationContext* opCtx, StringData dbName) override;
bool isUsingDirectoryPerDb() const override {
diff --git a/src/mongo/db/storage/storage_engine_mock.h b/src/mongo/db/storage/storage_engine_mock.h
index 3d69c854a5b..01b7f0409c0 100644
--- a/src/mongo/db/storage/storage_engine_mock.h
+++ b/src/mongo/db/storage/storage_engine_mock.h
@@ -170,9 +170,7 @@ public:
std::shared_ptr<Ident> ident,
DropIdentCallback&& onDrop) final {}
void checkpoint() final {}
- Status currentFilesCompatible(OperationContext* opCtx) const final {
- return Status::OK();
- }
+
int64_t sizeOnDiskForDb(OperationContext* opCtx, StringData dbName) final {
return 0;
}
diff --git a/src/mongo/db/storage/storage_engine_test_fixture.h b/src/mongo/db/storage/storage_engine_test_fixture.h
index 57b50a1d32c..0a3d839fae5 100644
--- a/src/mongo/db/storage/storage_engine_test_fixture.h
+++ b/src/mongo/db/storage/storage_engine_test_fixture.h
@@ -37,6 +37,7 @@
#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/db/storage/durable_catalog.h"
+#include "mongo/db/storage/durable_catalog_impl.h"
#include "mongo/db/storage/kv/kv_engine.h"
#include "mongo/db/storage/storage_engine_impl.h"
#include "mongo/db/storage/storage_repair_observer.h"