diff options
-rw-r--r-- | jstests/sharding/timeseries_sharded_query.js | 162 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/create_collection_coordinator.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/s/shardsvr_create_collection_command.cpp | 8 |
4 files changed, 23 insertions, 156 deletions
diff --git a/jstests/sharding/timeseries_sharded_query.js b/jstests/sharding/timeseries_sharded_query.js index f9845c87687..4324d2c1dc9 100644 --- a/jstests/sharding/timeseries_sharded_query.js +++ b/jstests/sharding/timeseries_sharded_query.js @@ -25,8 +25,9 @@ if (!TimeseriesTest.timeseriesCollectionsEnabled(st.shard0)) { return; } -// Simple shard key on the metadata field. -(function metaShardKey() { +(function timeseriesCollectionsCannotBeSharded() { + assert.commandWorked(st.s.adminCommand({enableSharding: dbName})); + assert.commandWorked( sDB.createCollection('ts', {timeseries: {timeField: 'time', metaField: 'hostId'}})); @@ -50,160 +51,13 @@ if (!TimeseriesTest.timeseriesCollectionsEnabled(st.shard0)) { // This index gets created as {meta: 1} on the buckets collection. assert.commandWorked(tsColl.createIndex({hostId: 1})); - st.shardColl('system.buckets.ts', - {meta: 1} /* Shard key */, - {meta: 10} /* Split at */, - {meta: 10} /* Move the chunk containing {meta: 10} to its own shard */, - dbName, /* dbName */ - false /* Wait until documents orphaned by the move get deleted */); - - let counts = st.chunkCounts('system.buckets.ts', 'test'); - assert.eq(1, counts[st.shard0.shardName]); - assert.eq(1, counts[st.shard1.shardName]); - - // Query with shard key - assert.docEq([docs[0]], sDB.ts.find({hostId: 0}).toArray()); - assert.docEq([docs[numDocs - 1]], sDB.ts.find({hostId: (numDocs - 1)}).toArray()); - - // Query without shard key - assert.docEq(docs, sDB.ts.find().sort({time: 1}).toArray()); - - assert.commandWorked(sDB.dropDatabase()); -})(); - -// Create a time-series collection with a non-default collation, but an index with the simple -// collation, which makes it eligible as a shard key. -(function metaShardKeyCollation() { - // TODO (SERVER-55653): Re-enable this test when querying by non-default view collation works. - if (true) { - return; - } - - assert.commandWorked(sDB.createCollection('ts', { - timeseries: {timeField: 'time', metaField: 'hostName'}, - collation: {locale: 'en', strength: 1, numericOrdering: true} - })); - - // Insert directly on the primary shard because mongos does not know how to insert into a TS - // collection. - st.ensurePrimaryShard(dbName, st.shard0.shardName); - const tsColl = st.shard0.getDB(dbName).ts; - - const numDocs = 20; - let docs = []; - for (let i = 0; i < numDocs; i++) { - const doc = { - time: ISODate(), - hostName: 'host_' + i, - _id: i, - data: Random.rand(), - }; - docs.push(doc); - assert.commandWorked(tsColl.insert(doc)); - } - - // This index gets created as {meta: 1} on the buckets collection. - assert.commandWorked(tsColl.createIndex({hostName: 1}, {collation: {locale: 'simple'}})); - - assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); - assert.commandWorked(st.s.adminCommand({ - shardCollection: 'test.system.buckets.ts', - key: {meta: 1}, - collation: {locale: 'simple'}, - })); - - assert.commandWorked( - st.s.adminCommand({split: 'test.system.buckets.ts', middle: {meta: 'host_10'}})); - - let otherShard = st.getOther(st.getPrimaryShard(dbName)).name; - assert.commandWorked(st.s.adminCommand({ - movechunk: 'test.system.buckets.ts', - find: {meta: 'host_10'}, - to: otherShard, - _waitForDelete: false - })); - - let counts = st.chunkCounts('system.buckets.ts', 'test'); - assert.eq(1, counts[st.shard0.shardName]); - assert.eq(1, counts[st.shard1.shardName]); - - // Query with shard key - assert.docEq([docs[0]], - sDB.ts.find({hostName: 'host_0'}).collation({locale: 'simple'}).toArray()); - assert.docEq( - [docs[numDocs - 1]], - sDB.ts.find({hostName: 'host_' + (numDocs - 1)}).collation({locale: 'simple'}).toArray()); - - // Query without shard key - assert.docEq(docs, sDB.ts.find().sort({time: 1}).toArray()); - assert.commandWorked(sDB.dropDatabase()); -})(); - -// Create a time-series collection with a shard key compounded with a metadata subfield and time. -(function compoundShardKey() { - assert.commandWorked( - sDB.createCollection('ts', {timeseries: {timeField: 'time', metaField: 'meta'}})); - - // Insert directly on the primary shard because mongos does not know how to insert into a TS - // collection. - st.ensurePrimaryShard(dbName, st.shard0.shardName); - - const tsColl = st.shard0.getDB(dbName).ts; - const numDocs = 20; - let docs = []; - for (let i = 0; i < numDocs; i++) { - const doc = { - time: ISODate(), - meta: {id: i}, - _id: i, - data: Random.rand(), - }; - docs.push(doc); - assert.commandWorked(tsColl.insert(doc)); - } - - // This index gets created as {meta.id: 1, control.min.time: 1, control.max.time: 1} on the - // buckets collection. - assert.commandWorked(tsColl.createIndex({'meta.id': 'hashed', time: 1})); - - assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); - assert.commandWorked(st.s.adminCommand({ - shardCollection: 'test.system.buckets.ts', - key: {'meta.id': 'hashed', 'control.min.time': 1, 'control.max.time': 1} - })); - - let counts = st.chunkCounts('system.buckets.ts', 'test'); - assert.eq(1, counts[st.shard0.shardName], counts); - assert.eq(0, counts[st.shard1.shardName], counts); - - // Split the chunk based on 'bounds' and verify total chunks increased by one. - const lowestChunk = findChunksUtil.findChunksByNs(configDB, 'test.system.buckets.ts') - .sort({min: 1}) - .limit(1) - .next(); - assert(lowestChunk); - - assert.commandWorked(st.s.adminCommand( - {split: 'test.system.buckets.ts', bounds: [lowestChunk.min, lowestChunk.max]})); - - let otherShard = st.getOther(st.getPrimaryShard(dbName)).name; - assert.commandWorked(st.s.adminCommand({ - movechunk: 'test.system.buckets.ts', - find: {'meta.id': 10, 'control.min.time': 0, 'control.max.time': 0}, - to: otherShard, - _waitForDelete: false - })); - - counts = st.chunkCounts('system.buckets.ts', 'test'); - assert.eq(1, counts[st.shard0.shardName], counts); - assert.eq(1, counts[st.shard1.shardName], counts); + // Trying to shard a time-series collection -> error + assert.commandFailed(st.s.adminCommand({shardCollection: 'test.ts', key: {hostId: 1}})); - // Query with shard key - assert.docEq([docs[0]], sDB.ts.find({'meta.id': 0}).toArray()); - assert.docEq([docs[numDocs - 1]], sDB.ts.find({'meta.id': (numDocs - 1)}).toArray()); + // Trying to shard the buckets collection -> error + assert.commandFailed( + st.s.adminCommand({shardCollection: 'test.system.buckets.ts', key: {meta: 1}})); - // Query without shard key - assert.docEq(docs, sDB.ts.find().sort({time: 1}).toArray()); assert.commandWorked(sDB.dropDatabase()); })(); diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index ec1dac6b245..7e8fe61b88c 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -401,6 +401,7 @@ env.Library( '$BUILD_DIR/mongo/db/repl/primary_only_service', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/repl/replica_set_messages', + '$BUILD_DIR/mongo/db/timeseries/timeseries_lookup', '$BUILD_DIR/mongo/s/commands/shared_cluster_commands', '$BUILD_DIR/mongo/s/sharding_initialization', '$BUILD_DIR/mongo/s/sharding_router_api', diff --git a/src/mongo/db/s/create_collection_coordinator.cpp b/src/mongo/db/s/create_collection_coordinator.cpp index 0aa339016fb..ea95b3678d9 100644 --- a/src/mongo/db/s/create_collection_coordinator.cpp +++ b/src/mongo/db/s/create_collection_coordinator.cpp @@ -42,6 +42,7 @@ #include "mongo/db/s/sharding_ddl_util.h" #include "mongo/db/s/sharding_logging.h" #include "mongo/db/s/sharding_state.h" +#include "mongo/db/timeseries/timeseries_lookup.h" #include "mongo/logv2/log.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/cluster_commands_helpers.h" @@ -572,11 +573,16 @@ void CreateCollectionCoordinator::_checkCommandArguments(OperationContext* opCtx "the hashed field by declaring an additional (non-hashed) unique index on the field.", !_shardKeyPattern->isHashedPattern() || !_doc.getUnique().value_or(false)); + // Ensure that a time-series collection cannot be sharded + uassert(ErrorCodes::IllegalOperation, + str::stream() << "can't shard time-series collection " << nss(), + !timeseries::getTimeseriesOptions(opCtx, nss())); + // Ensure the namespace is valid. uassert(ErrorCodes::IllegalOperation, "can't shard system namespaces", !nss().isSystem() || nss() == NamespaceString::kLogicalSessionsNamespace || - nss().isTemporaryReshardingCollection() || nss().isTimeseriesBucketsCollection()); + nss().isTemporaryReshardingCollection()); if (_doc.getNumInitialChunks()) { // Ensure numInitialChunks is within valid bounds. diff --git a/src/mongo/db/s/shardsvr_create_collection_command.cpp b/src/mongo/db/s/shardsvr_create_collection_command.cpp index 5300e89713b..641d3e52079 100644 --- a/src/mongo/db/s/shardsvr_create_collection_command.cpp +++ b/src/mongo/db/s/shardsvr_create_collection_command.cpp @@ -42,6 +42,7 @@ #include "mongo/db/s/shard_collection_legacy.h" #include "mongo/db/s/sharding_ddl_coordinator_service.h" #include "mongo/db/s/sharding_state.h" +#include "mongo/db/timeseries/timeseries_lookup.h" #include "mongo/logv2/log.h" #include "mongo/s/grid.h" #include "mongo/s/request_types/shard_collection_gen.h" @@ -119,11 +120,16 @@ CreateCollectionResponse createCollectionLegacy(OperationContext* opCtx, !shardKeyPattern.isHashedPattern() || !(request.getUnique() && request.getUnique().value())); + // Ensure that a time-series collection cannot be sharded + uassert(ErrorCodes::IllegalOperation, + str::stream() << "can't shard time-series collection " << nss, + !timeseries::getTimeseriesOptions(opCtx, nss)); + // Ensure the namespace is valid. uassert(ErrorCodes::IllegalOperation, "can't shard system namespaces", !nss.isSystem() || nss == NamespaceString::kLogicalSessionsNamespace || - nss.isTemporaryReshardingCollection() || nss.isTimeseriesBucketsCollection()); + nss.isTemporaryReshardingCollection()); auto optNumInitialChunks = request.getNumInitialChunks(); if (optNumInitialChunks) { |