summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergi Mateo Bellido <sergi.mateo-bellido@mongodb.com>2021-04-08 11:42:55 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-12 06:28:44 +0000
commitfaa1f8247ce659bde4115326d5ba1e14b3d52d9e (patch)
treec6714f3816906e38e54d8755f94070f22f01b809
parentcd9151050f4f37960da917909263458aebfa2c9f (diff)
downloadmongo-faa1f8247ce659bde4115326d5ba1e14b3d52d9e.tar.gz
SERVER-55809 Disallow sharding a time-series collection or a buckets collection
-rw-r--r--jstests/sharding/timeseries_sharded_query.js162
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/create_collection_coordinator.cpp8
-rw-r--r--src/mongo/db/s/shardsvr_create_collection_command.cpp8
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) {