summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/catalog/catalog_control.cpp27
-rw-r--r--src/mongo/db/catalog/catalog_control.h1
-rw-r--r--src/mongo/db/catalog/collection.h13
-rw-r--r--src/mongo/db/catalog/collection_catalog.cpp36
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp6
-rw-r--r--src/mongo/db/catalog/collection_impl.h5
-rw-r--r--src/mongo/db/catalog/collection_mock.h8
-rw-r--r--src/mongo/db/storage/storage_engine_impl.cpp14
-rw-r--r--src/mongo/db/storage/storage_engine_impl.h3
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);