SERVER-120247 Add test coverage for collStats on timeseries collections during FCV upgrade/downgrade (#49534)
GitOrigin-RevId: 3a81fd59de3ba33796fc5873d8502a42bd6cb603
This commit is contained in:
parent
94b1b630ca
commit
0201e895be
@ -118,7 +118,6 @@ selector:
|
||||
- requires_getmore
|
||||
- requires_non_retryable_writes
|
||||
- requires_multi_updates
|
||||
- requires_collstats
|
||||
roots:
|
||||
- jstests/core/**/*.js
|
||||
- jstests/fle2/**/*.js
|
||||
|
||||
@ -252,7 +252,6 @@ selector:
|
||||
- requires_getmore
|
||||
- requires_non_retryable_writes
|
||||
- requires_multi_updates
|
||||
- requires_collstats
|
||||
roots:
|
||||
- jstests/core/**/*.js
|
||||
- jstests/core_sharding/**/*.js
|
||||
|
||||
@ -138,7 +138,6 @@ selector:
|
||||
- requires_getmore
|
||||
- requires_non_retryable_writes
|
||||
- requires_multi_updates
|
||||
- requires_collstats
|
||||
roots:
|
||||
- jstests/core/**/*.js
|
||||
- jstests/fle2/**/*.js
|
||||
|
||||
@ -40,6 +40,3 @@
|
||||
# they fail with InterruptedDueToTimeseriesUpgradeDowngrade error.
|
||||
# TODO SPM-1153 remove this tag
|
||||
- requires_multi_updates
|
||||
# Collstats could miss timeseries section when executed concurrently with timeseries upgrade/downgrade
|
||||
# TODO SERVER-120247 remove this tag once the bug is fixed
|
||||
- requires_collstats
|
||||
|
||||
@ -123,6 +123,25 @@ export const $config = (function () {
|
||||
const count = withRetryOnTimeseriesUpgradeDowngradeError(() => coll.countDocuments({}));
|
||||
assert.eq(count, expectedDocs.length);
|
||||
},
|
||||
|
||||
collStatsCmd: function (db, collName) {
|
||||
const coll = getCollection(db, Random.randInt(numCollections));
|
||||
|
||||
const result = withRetryOnTimeseriesUpgradeDowngradeError(() =>
|
||||
assert.commandWorked(db.runCommand({collStats: coll.getName()})),
|
||||
);
|
||||
assert.hasFields(result, ["timeseries"]);
|
||||
},
|
||||
|
||||
collStatsAgg: function (db, collName) {
|
||||
const coll = getCollection(db, Random.randInt(numCollections));
|
||||
|
||||
const result = withRetryOnTimeseriesUpgradeDowngradeError(() =>
|
||||
coll.aggregate([{$collStats: {storageStats: {}}}]).toArray(),
|
||||
);
|
||||
assert.hasFields(result[0], ["storageStats"]);
|
||||
assert.hasFields(result[0].storageStats, ["timeseries"]);
|
||||
},
|
||||
};
|
||||
|
||||
const setup = function (db, collName, cluster) {
|
||||
|
||||
@ -176,6 +176,7 @@ mongo_cc_library(
|
||||
"//src/mongo/db/shard_role",
|
||||
"//src/mongo/db/shard_role/shard_catalog:collection_options",
|
||||
"//src/mongo/db/shard_role/shard_catalog:index_catalog",
|
||||
"//src/mongo/db/timeseries:catalog_helper",
|
||||
"//src/mongo/db/timeseries/bucket_catalog",
|
||||
"//src/mongo/util/concurrency:spin_lock",
|
||||
],
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "mongo/db/storage/record_store.h"
|
||||
#include "mongo/db/timeseries/bucket_catalog/bucket_catalog.h"
|
||||
#include "mongo/db/timeseries/bucket_catalog/global_bucket_catalog.h"
|
||||
#include "mongo/db/timeseries/catalog_helper.h"
|
||||
#include "mongo/db/topology/cluster_role.h"
|
||||
#include "mongo/logv2/log.h"
|
||||
#include "mongo/stdx/unordered_map.h"
|
||||
@ -319,40 +320,32 @@ Status appendCollectionStorageStats(OperationContext* opCtx,
|
||||
bool numericOnly = storageStatsSpec.getNumericOnly();
|
||||
static constexpr auto kStorageStatsField = "storageStats"_sd;
|
||||
|
||||
// TODO(SERVER-110087): Remove this legacy timeseries translation logic once v9.0 is last LTS
|
||||
const auto bucketNss =
|
||||
nss.isTimeseriesBucketsCollection() ? nss : nss.makeTimeseriesBucketsNamespace();
|
||||
// Hold reference to the catalog for collection lookup without locks to be safe.
|
||||
auto catalog = CollectionCatalog::get(opCtx);
|
||||
auto bucketsColl = catalog->lookupCollectionByNamespace(opCtx, bucketNss);
|
||||
const bool mayBeLegacyTimeseries = bucketsColl && bucketsColl->getTimeseriesOptions();
|
||||
const auto collNss = (mayBeLegacyTimeseries && !nss.isTimeseriesBucketsCollection())
|
||||
? std::move(bucketNss)
|
||||
: nss;
|
||||
|
||||
auto failed = [&](const DBException& ex) {
|
||||
LOGV2_DEBUG(3088801,
|
||||
2,
|
||||
"Failed to retrieve storage statistics",
|
||||
logAttrs(collNss),
|
||||
"error"_attr = ex);
|
||||
LOGV2_DEBUG(
|
||||
3088801, 2, "Failed to retrieve storage statistics", logAttrs(nss), "error"_attr = ex);
|
||||
return Status::OK();
|
||||
};
|
||||
|
||||
boost::optional<CollectionAcquisition> collectionAcquisition;
|
||||
try {
|
||||
collectionAcquisition = acquireCollectionMaybeLockFree(
|
||||
opCtx,
|
||||
CollectionAcquisitionRequest::fromOpCtx(opCtx,
|
||||
collNss,
|
||||
AcquisitionPrerequisites::kRead,
|
||||
waitForLock ? Date_t::max() : Date_t::now()));
|
||||
// TODO(SERVER-110087): switch to acquireCollection once v9.0 is last LTS
|
||||
collectionAcquisition = timeseries::acquireCollectionWithBucketsLookup(
|
||||
opCtx,
|
||||
CollectionAcquisitionRequest::fromOpCtx(
|
||||
opCtx,
|
||||
nss,
|
||||
AcquisitionPrerequisites::kRead,
|
||||
waitForLock ? Date_t::max() : Date_t::now()),
|
||||
MODE_IS)
|
||||
.first;
|
||||
} catch (const ExceptionFor<ErrorCodes::LockTimeout>& ex) {
|
||||
return failed(ex);
|
||||
} catch (const ExceptionFor<ErrorCodes::MaxTimeMSExpired>& ex) {
|
||||
return failed(ex);
|
||||
}
|
||||
|
||||
const auto& collNss = collectionAcquisition->nss();
|
||||
|
||||
AutoStatsTracker statsTracker(opCtx,
|
||||
collNss,
|
||||
Top::LockType::ReadLocked,
|
||||
@ -360,17 +353,7 @@ Status appendCollectionStorageStats(OperationContext* opCtx,
|
||||
DatabaseProfileSettings::get(opCtx->getServiceContext())
|
||||
.getDatabaseProfileLevel(collNss.dbName()));
|
||||
|
||||
const auto& collectionPtr =
|
||||
collectionAcquisition->getCollectionPtr(); // Will be set if present
|
||||
const bool isTimeseries = collectionPtr && collectionPtr->getTimeseriesOptions().has_value();
|
||||
|
||||
// We decided the requested namespace was a time series view, so we redirected to the underlying
|
||||
// buckets collection. However, when we tried to acquire that collection, it did not exist or it
|
||||
// did not have time series options, which means it was dropped and potentially recreated in
|
||||
// between the two calls. Logically, the collection that we were looking for does not exist.
|
||||
bool logicallyNotFound = collNss != nss && !isTimeseries;
|
||||
|
||||
if (!collectionPtr || logicallyNotFound) {
|
||||
if (!collectionAcquisition->exists()) {
|
||||
result->appendNumber("size", 0);
|
||||
result->appendNumber("count", 0);
|
||||
result->appendNumber("numOrphanDocs", 0);
|
||||
@ -385,6 +368,8 @@ Status appendCollectionStorageStats(OperationContext* opCtx,
|
||||
"Collection [" + collNss.toStringForErrorMsg() + "] not found."};
|
||||
}
|
||||
|
||||
const auto& collectionPtr = collectionAcquisition->getCollectionPtr();
|
||||
|
||||
// We will parse all 'filterObj' into different groups of data to compute. This groups will be
|
||||
// marked and appended to the vector 'groupsToCompute'. In addition, if the filterObj doesn't
|
||||
// exist (filterObj == boost::none), we will retrieve all stats for all fields.
|
||||
@ -421,7 +406,7 @@ Status appendCollectionStorageStats(OperationContext* opCtx,
|
||||
serializationCtx,
|
||||
nss.isNamespaceAlwaysUntracked(),
|
||||
scale,
|
||||
isTimeseries,
|
||||
collectionPtr->isTimeseriesCollection(),
|
||||
result);
|
||||
break;
|
||||
case StorageStatsGroups::kRecordStoreField:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user