summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorHenrik Edin <henrik.edin@mongodb.com>2022-08-16 21:00:33 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-08-16 22:47:50 +0000
commite6e66274ce5e2740b5a8265a4ba0fb20856cecca (patch)
treea158921fc330a153c5008c03910b09a76d7bfd84 /src/mongo
parent77c20f24deb5d4d930161e37a635ffe7cf11761f (diff)
downloadmongo-e6e66274ce5e2740b5a8265a4ba0fb20856cecca.tar.gz
SERVER-68255 Add minValidTimestamp to Collections
It is the timestamp of the most recent DDL operation on the collection. Has different semantics from minVisibleSnapshot and will eventually replace it.
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);