diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/catalog_control.cpp | 27 | ||||
-rw-r--r-- | src/mongo/db/catalog/catalog_control.h | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection.h | 13 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.h | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_mock.h | 8 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_impl.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_impl.h | 3 |
9 files changed, 99 insertions, 14 deletions
diff --git a/src/mongo/db/catalog/catalog_control.cpp b/src/mongo/db/catalog/catalog_control.cpp index f1e77df3a5c..59e0769ff9f 100644 --- a/src/mongo/db/catalog/catalog_control.cpp +++ b/src/mongo/db/catalog/catalog_control.cpp @@ -100,6 +100,20 @@ void reopenAllDatabasesAndReloadCollectionCatalog(OperationContext* opCtx, writableCollection->setMinimumVisibleSnapshot(minVisible); } + if (auto it = previousCatalogState.minValidTimestampMap.find(collection->uuid()); + it != previousCatalogState.minValidTimestampMap.end()) { + // After rolling back to a stable timestamp T, the minimum valid timestamp for each + // collection must be reset to (at least) its value at T. When the min valid + // timestamp is clamped to the stable timestamp we may end up with a pessimistic + // minimum valid timestamp set where the last DDL operation occured earlier. This is + // fine as this is just an optimization when to avoid reading the catalog from WT. + auto minValid = std::min(stableTimestamp, it->second); + auto writableCollection = + catalogWriter.value()->lookupCollectionByUUIDForMetadataWrite( + opCtx, collection->uuid()); + writableCollection->setMinimumValidSnapshot(minValid); + } + if (collection->getTimeseriesOptions()) { bool extendedRangeSetting; if (auto it = previousCatalogState.requiresTimestampExtendedRangeSupportMap.find( @@ -172,6 +186,19 @@ PreviousCatalogState closeCatalog(OperationContext* opCtx) { previousCatalogState.minVisibleTimestampMap[coll->uuid()] = *minVisible; } + boost::optional<Timestamp> minValid = coll->getMinimumValidSnapshot(); + + // If there's a minimum valid, invariant there's also a UUID. + if (minValid) { + LOGV2_DEBUG(6825500, + 1, + "closeCatalog: preserving min valid timestamp.", + "ns"_attr = coll->ns(), + "uuid"_attr = coll->uuid(), + "minVisible"_attr = minValid); + previousCatalogState.minValidTimestampMap[coll->uuid()] = *minValid; + } + if (coll->getTimeseriesOptions()) { previousCatalogState.requiresTimestampExtendedRangeSupportMap[coll->uuid()] = coll->getRequiresTimeseriesExtendedRangeSupport(); diff --git a/src/mongo/db/catalog/catalog_control.h b/src/mongo/db/catalog/catalog_control.h index f7bc3fbbdba..20fe8ab511b 100644 --- a/src/mongo/db/catalog/catalog_control.h +++ b/src/mongo/db/catalog/catalog_control.h @@ -39,6 +39,7 @@ using MinVisibleTimestampMap = std::map<UUID, MinVisibleTimestamp>; using RequiresTimestampExtendedRangeSupportMap = std::map<UUID, bool>; struct PreviousCatalogState { MinVisibleTimestampMap minVisibleTimestampMap; + MinVisibleTimestampMap minValidTimestampMap; RequiresTimestampExtendedRangeSupportMap requiresTimestampExtendedRangeSupportMap; }; diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index e5bf833ad20..9d27e481fab 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -673,6 +673,19 @@ public: virtual void setMinimumVisibleSnapshot(Timestamp name) = 0; + + /** + * Get the timestamp this Collection instance was most recently changed at. + * TODO SERVER-68270: Should currently not be used until min visible snapshot is removed + */ + virtual boost::optional<Timestamp> getMinimumValidSnapshot() const = 0; + + /** + * Sets the timestamp this Collection instance was most recently changed at. + * TODO SERVER-68270: Should currently not be used until min visible snapshot is removed + */ + virtual void setMinimumValidSnapshot(Timestamp name) = 0; + /** * Returns the time-series options for this buckets collection, or boost::none if not a * time-series buckets collection. diff --git a/src/mongo/db/catalog/collection_catalog.cpp b/src/mongo/db/catalog/collection_catalog.cpp index 9bb5d66d80b..cf846066f0e 100644 --- a/src/mongo/db/catalog/collection_catalog.cpp +++ b/src/mongo/db/catalog/collection_catalog.cpp @@ -95,7 +95,12 @@ public: static constexpr size_t kNumStaticActions = 2; static void setCollectionInCatalog(CollectionCatalog& catalog, - std::shared_ptr<Collection> collection) { + std::shared_ptr<Collection> collection, + boost::optional<Timestamp> commitTime) { + if (commitTime) { + collection->setMinimumValidSnapshot(*commitTime); + } + catalog._collections[collection->ns()] = collection; catalog._catalog[collection->uuid()] = collection; auto dbIdPair = std::make_pair(collection->ns().dbName(), collection->uuid()); @@ -124,10 +129,10 @@ public: for (auto&& entry : entries) { switch (entry.action) { case UncommittedCatalogUpdates::Entry::Action::kWritableCollection: { - writeJobs.push_back( - [collection = std::move(entry.collection)](CollectionCatalog& catalog) { - setCollectionInCatalog(catalog, std::move(collection)); - }); + writeJobs.push_back([collection = std::move(entry.collection), + commitTime](CollectionCatalog& catalog) { + setCollectionInCatalog(catalog, std::move(collection), commitTime); + }); break; } case UncommittedCatalogUpdates::Entry::Action::kRenamedCollection: { @@ -155,7 +160,11 @@ public: case UncommittedCatalogUpdates::Entry::Action::kRecreatedCollection: { writeJobs.push_back([opCtx = _opCtx, collection = entry.collection, - uuid = *entry.externalUUID](CollectionCatalog& catalog) { + uuid = *entry.externalUUID, + commitTime](CollectionCatalog& catalog) { + if (commitTime) { + collection->setMinimumValidSnapshot(commitTime.value()); + } catalog.registerCollection(opCtx, uuid, std::move(collection)); }); // Fallthrough to the createCollection case to finish committing the collection. @@ -175,6 +184,7 @@ public: // call setCommitted(true). if (commitTime) { collPtr->setMinimumVisibleSnapshot(commitTime.value()); + collPtr->setMinimumValidSnapshot(commitTime.value()); } collPtr->setCommitted(true); break; @@ -795,8 +805,11 @@ Collection* CollectionCatalog::lookupCollectionByUUIDForMetadataWrite(OperationC // on the thread doing the batch write and it would trigger the regular path where we do a // copy-on-write on the catalog when committing. if (_isCatalogBatchWriter()) { - PublishCatalogUpdates::setCollectionInCatalog(*batchedCatalogWriteInstance, - std::move(cloned)); + // Do not update min valid timestamp in batched write as the write is not corresponding to + // an oplog entry. If the write require an update to this timestamp it is the responsibility + // of the user. + PublishCatalogUpdates::setCollectionInCatalog( + *batchedCatalogWriteInstance, std::move(cloned), boost::none); return ptr; } @@ -898,8 +911,11 @@ Collection* CollectionCatalog::lookupCollectionByNamespaceForMetadataWrite( // on the thread doing the batch write and it would trigger the regular path where we do a // copy-on-write on the catalog when committing. if (_isCatalogBatchWriter()) { - PublishCatalogUpdates::setCollectionInCatalog(*batchedCatalogWriteInstance, - std::move(cloned)); + // Do not update min valid timestamp in batched write as the write is not corresponding to + // an oplog entry. If the write require an update to this timestamp it is the responsibility + // of the user. + PublishCatalogUpdates::setCollectionInCatalog( + *batchedCatalogWriteInstance, std::move(cloned), boost::none); return ptr; } diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index a66ba8a7063..b9ed0bb2f83 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -704,6 +704,12 @@ void CollectionImpl::setMinimumVisibleSnapshot(Timestamp newMinimumVisibleSnapsh } } +void CollectionImpl::setMinimumValidSnapshot(Timestamp newMinimumValidSnapshot) { + if (!_minValidSnapshot || (newMinimumValidSnapshot > _minValidSnapshot.value())) { + _minValidSnapshot = newMinimumValidSnapshot; + } +} + void CollectionImpl::deleteDocument(OperationContext* opCtx, StmtId stmtId, const RecordId& loc, diff --git a/src/mongo/db/catalog/collection_impl.h b/src/mongo/db/catalog/collection_impl.h index c93fff30855..cf7cfaaf805 100644 --- a/src/mongo/db/catalog/collection_impl.h +++ b/src/mongo/db/catalog/collection_impl.h @@ -336,12 +336,16 @@ public: boost::optional<Timestamp> getMinimumVisibleSnapshot() const final { return _minVisibleSnapshot; } + boost::optional<Timestamp> getMinimumValidSnapshot() const final { + return _minValidSnapshot; + } /** * Updates the minimum visible snapshot. The 'newMinimumVisibleSnapshot' is ignored if it would * set the minimum visible snapshot backwards in time. */ void setMinimumVisibleSnapshot(Timestamp newMinimumVisibleSnapshot) final; + void setMinimumValidSnapshot(Timestamp newMinimumValidSnapshot) final; boost::optional<TimeseriesOptions> getTimeseriesOptions() const final; void setTimeseriesOptions(OperationContext* opCtx, const TimeseriesOptions& tsOptions) final; @@ -500,6 +504,7 @@ private: // The earliest snapshot that is allowed to use this collection. boost::optional<Timestamp> _minVisibleSnapshot; + boost::optional<Timestamp> _minValidSnapshot; bool _initialized = false; }; diff --git a/src/mongo/db/catalog/collection_mock.h b/src/mongo/db/catalog/collection_mock.h index 52e2b5bcf92..c5e1e138ec1 100644 --- a/src/mongo/db/catalog/collection_mock.h +++ b/src/mongo/db/catalog/collection_mock.h @@ -324,6 +324,14 @@ public: MONGO_UNREACHABLE; } + boost::optional<Timestamp> getMinimumValidSnapshot() const { + MONGO_UNREACHABLE; + } + + void setMinimumValidSnapshot(Timestamp name) override { + // no-op, called by unittests + } + boost::optional<TimeseriesOptions> getTimeseriesOptions() const { MONGO_UNREACHABLE; } diff --git a/src/mongo/db/storage/storage_engine_impl.cpp b/src/mongo/db/storage/storage_engine_impl.cpp index 24ac37a2f3b..a79d22a96b4 100644 --- a/src/mongo/db/storage/storage_engine_impl.cpp +++ b/src/mongo/db/storage/storage_engine_impl.cpp @@ -326,6 +326,7 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx, LastShutdownState l } Timestamp minVisibleTs = Timestamp::min(); + Timestamp minValidTs = minVisibleTs; // If there's no recovery timestamp, every collection is available. if (boost::optional<Timestamp> recoveryTs = _engine->getRecoveryTimestamp()) { // Otherwise choose a minimum visible timestamp that's at least as large as the true @@ -334,6 +335,10 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx, LastShutdownState l // `oldestTimestamp` and conservatively choose the `recoveryTimestamp` for everything // else. minVisibleTs = recoveryTs.value(); + // Minimum valid timestamp is always set to the recovery timestamp. Even if the + // collection exists at the oldest timestamp we do not know if it would be in sync with + // the durable catalog due to collMod or index changes. + minValidTs = minVisibleTs; if (existedAtOldestTs.find(entry.catalogId) != existedAtOldestTs.end()) { // Collections found at the `oldestTimestamp` on startup can have their minimum // visible timestamp pulled back to that value. @@ -350,7 +355,8 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx, LastShutdownState l }); } - _initCollection(opCtx, entry.catalogId, entry.nss, _options.forRepair, minVisibleTs); + _initCollection( + opCtx, entry.catalogId, entry.nss, _options.forRepair, minVisibleTs, minValidTs); if (entry.nss.isOrphanCollection()) { LOGV2(22248, "Orphaned collection found", logAttrs(entry.nss)); @@ -364,7 +370,8 @@ void StorageEngineImpl::_initCollection(OperationContext* opCtx, RecordId catalogId, const NamespaceString& nss, bool forRepair, - Timestamp minVisibleTs) { + Timestamp minVisibleTs, + Timestamp minValidTs) { auto md = _catalog->getMetaData(opCtx, catalogId); uassert(ErrorCodes::MustDowngrade, str::stream() << "Collection does not have UUID in KVCatalog. Collection: " << nss, @@ -385,6 +392,7 @@ void StorageEngineImpl::_initCollection(OperationContext* opCtx, auto collectionFactory = Collection::Factory::get(getGlobalServiceContext()); auto collection = collectionFactory->make(opCtx, nss, catalogId, md, std::move(rs)); collection->setMinimumVisibleSnapshot(minVisibleTs); + collection->setMinimumValidSnapshot(minValidTs); CollectionCatalog::write(opCtx, [&](CollectionCatalog& catalog) { catalog.registerCollection(opCtx, md->options.uuid.value(), std::move(collection)); @@ -984,7 +992,7 @@ Status StorageEngineImpl::repairRecordStore(OperationContext* opCtx, // When repairing a record store, keep the existing behavior of not installing a minimum visible // timestamp. - _initCollection(opCtx, catalogId, nss, false, Timestamp::min()); + _initCollection(opCtx, catalogId, nss, false, Timestamp::min(), Timestamp::min()); return status; } diff --git a/src/mongo/db/storage/storage_engine_impl.h b/src/mongo/db/storage/storage_engine_impl.h index e9a979e382d..5a318744268 100644 --- a/src/mongo/db/storage/storage_engine_impl.h +++ b/src/mongo/db/storage/storage_engine_impl.h @@ -372,7 +372,8 @@ private: RecordId catalogId, const NamespaceString& nss, bool forRepair, - Timestamp minVisibleTs); + Timestamp minVisibleTs, + Timestamp minValidTs); Status _dropCollectionsNoTimestamp(OperationContext* opCtx, const std::vector<UUID>& toDrop); |