diff options
author | Enrico Golfieri <enrico.golfieri@mongodb.com> | 2022-09-07 14:28:24 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-12 09:31:21 +0000 |
commit | 80e78ce7159c4adf6a0332eda578c8d770a76ba0 (patch) | |
tree | a954a201a4b6d727f6737ceae6fc564bde705c3a | |
parent | 3bf0d522db3017a344e5f093706539e97659897b (diff) | |
download | mongo-80e78ce7159c4adf6a0332eda578c8d770a76ba0.tar.gz |
SERVER-69220 refineCollectionShardKey permits toggling current shard key fields between range-based and hashed, leading to data inconsistency
-rw-r--r-- | src/mongo/s/shard_key_pattern.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/shard_key_pattern_test.cpp | 78 |
2 files changed, 80 insertions, 1 deletions
diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index c8fb1b7a84c..7bfb9c88237 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -33,6 +33,7 @@ #include <vector> +#include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/db/field_ref.h" #include "mongo/db/field_ref_set.h" #include "mongo/db/hasher.h" @@ -288,7 +289,7 @@ bool ShardKeyPattern::isShardKey(const BSONObj& shardKey) const { } bool ShardKeyPattern::isExtendedBy(const ShardKeyPattern& newShardKeyPattern) const { - return toBSON().isFieldNamePrefixOf(newShardKeyPattern.toBSON()); + return toBSON().isPrefixOf(newShardKeyPattern.toBSON(), SimpleBSONElementComparator::kInstance); } BSONObj ShardKeyPattern::normalizeShardKey(const BSONObj& shardKey) const { diff --git a/src/mongo/s/shard_key_pattern_test.cpp b/src/mongo/s/shard_key_pattern_test.cpp index 2965b5d6222..b7c2a3e24b1 100644 --- a/src/mongo/s/shard_key_pattern_test.cpp +++ b/src/mongo/s/shard_key_pattern_test.cpp @@ -1016,5 +1016,83 @@ TEST_F(ShardKeyPatternTest, ExtractShardKeyFromDocumentKey_Hashed) { BSONObj()); } +TEST_F(ShardKeyPatternTest, IsExtendedBy) { + + // NumberOfFields + ShardKeyPattern shardKeyPattern1(BSON("a" << 1)); + ShardKeyPattern shardKeyPattern2(BSON("a" << 1 << "b" << 1)); + ShardKeyPattern shardKeyPattern3(BSON("a" << 1 << "b" << 1 << "c" << 1)); + + // NumberOfFields_PositionOfHash + ShardKeyPattern shardKeyPatternHashed1_0(BSON("a" + << "hashed")); + ShardKeyPattern shardKeyPatternHashed2_0(BSON("a" + << "hashed" + << "b" << 1)); + ShardKeyPattern shardKeyPatternHashed2_1(BSON("a" << 1 << "b" + << "hashed")); + ShardKeyPattern shardKeyPatternHashed3_0(BSON("a" + << "hashed" + << "b" << 1 << "c" << 1)); + ShardKeyPattern shardKeyPatternHashed3_1(BSON("a" << 1 << "b" + << "hashed" + << "c" << 1)); + ShardKeyPattern shardKeyPatternHashed3_2(BSON("a" << 1 << "b" << 1 << "c" + << "hashed")); + + // same pattern, always true + ASSERT_TRUE(shardKeyPattern1.isExtendedBy(shardKeyPattern1)); + ASSERT_TRUE(shardKeyPattern2.isExtendedBy(shardKeyPattern2)); + ASSERT_TRUE(shardKeyPattern3.isExtendedBy(shardKeyPattern3)); + ASSERT_TRUE(shardKeyPatternHashed1_0.isExtendedBy(shardKeyPatternHashed1_0)); + ASSERT_TRUE(shardKeyPatternHashed2_0.isExtendedBy(shardKeyPatternHashed2_0)); + ASSERT_TRUE(shardKeyPatternHashed2_1.isExtendedBy(shardKeyPatternHashed2_1)); + ASSERT_TRUE(shardKeyPatternHashed3_0.isExtendedBy(shardKeyPatternHashed3_0)); + ASSERT_TRUE(shardKeyPatternHashed3_1.isExtendedBy(shardKeyPatternHashed3_1)); + ASSERT_TRUE(shardKeyPatternHashed3_2.isExtendedBy(shardKeyPatternHashed3_2)); + + // different number of fields, same values + ASSERT_TRUE(shardKeyPattern1.isExtendedBy(shardKeyPattern2)); + ASSERT_TRUE(shardKeyPattern2.isExtendedBy(shardKeyPattern3)); + ASSERT_TRUE(shardKeyPattern1.isExtendedBy(shardKeyPattern3)); + + ASSERT_FALSE(shardKeyPattern2.isExtendedBy(shardKeyPattern1)); + ASSERT_FALSE(shardKeyPattern3.isExtendedBy(shardKeyPattern2)); + ASSERT_FALSE(shardKeyPattern3.isExtendedBy(shardKeyPattern1)); + + // different number of fields, different values + // { a : 1 } is not extended by { a : "hashed" } and viceversa + ASSERT_FALSE(shardKeyPattern1.isExtendedBy(shardKeyPatternHashed1_0)); + ASSERT_FALSE(shardKeyPatternHashed1_0.isExtendedBy(shardKeyPattern1)); + + // { a : 1, b : 1 } is not extended by { a : 1, b : "hashed" } and viceversa + ASSERT_FALSE(shardKeyPattern2.isExtendedBy(shardKeyPatternHashed2_1)); + ASSERT_FALSE(shardKeyPatternHashed2_1.isExtendedBy(shardKeyPattern2)); + + // { a : 1 } is extended by { a : 1, b : "hashed" } but not viceversa + ASSERT_TRUE(shardKeyPattern1.isExtendedBy(shardKeyPatternHashed2_1)); + ASSERT_FALSE(shardKeyPatternHashed2_1.isExtendedBy(shardKeyPattern1)); + + // { a : 1, b : 1 } is extended by { a : 1, b : 1, c : "hashed" } but not viceversa + ASSERT_TRUE(shardKeyPattern2.isExtendedBy(shardKeyPatternHashed3_2)); + ASSERT_FALSE(shardKeyPatternHashed3_2.isExtendedBy(shardKeyPattern2)); + + // { a : 1, b : 1, c : 1 } is not extended by { a : 1, b : 1, c : "hashed" } and viceversa + ASSERT_FALSE(shardKeyPattern3.isExtendedBy(shardKeyPatternHashed3_2)); + ASSERT_FALSE(shardKeyPatternHashed3_2.isExtendedBy(shardKeyPattern3)); + + // { a: "hashed", b : 1 } is not extended by { a : 1, b : 1, c : "hashed" } and viceversa + ASSERT_FALSE(shardKeyPatternHashed2_1.isExtendedBy(shardKeyPatternHashed3_2)); + ASSERT_FALSE(shardKeyPatternHashed3_2.isExtendedBy(shardKeyPatternHashed2_1)); + + // { a : "hashed", b : 1 } is extended by { a : "hashed", b : 1, c : "1" } but not viceversa + ASSERT_TRUE(shardKeyPatternHashed2_0.isExtendedBy(shardKeyPatternHashed3_0)); + ASSERT_FALSE(shardKeyPatternHashed3_0.isExtendedBy(shardKeyPatternHashed2_0)); + + // { a : 1, b : "hashed " } is extended by { a : 1, b : "hashed", c : "1" } but not viceversa + ASSERT_TRUE(shardKeyPatternHashed2_1.isExtendedBy(shardKeyPatternHashed3_1)); + ASSERT_FALSE(shardKeyPatternHashed3_1.isExtendedBy(shardKeyPatternHashed2_1)); +} + } // namespace } // namespace mongo |