mongo/jstests/query_golden_sharding/sharded_find_with_collation.js

114 lines
4.3 KiB
JavaScript

/**
* Tests for the absence/presence of a shard filtering stage for queries which may/may not
* be single shard targeted.
* TODO SERVER-94611: Extend testing once sharding may have non-simple collation.
*/
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {code, outputShardedFindSummaryAndResults, section, subSection} from "jstests/libs/pretty_md.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
const st = new ShardingTest({shards: 2});
const db = st.getDB("test");
// Enable sharding.
const primaryShard = st.shard0.shardName;
assert.commandWorked(st.s0.adminCommand({enableSharding: db.getName(), primaryShard}));
const coll = db[jsTestName()];
const setupCollection = ({shardKey, splits}) => {
coll.drop();
let doc = {_id: "a", a: "a"};
let [shardField] = Object.keys(shardKey);
assert.commandWorked(db.createCollection(coll.getName()));
// Shard the collection on with the provided spec, implicitly creating an index with simple
// collation.
assert.commandWorked(db.adminCommand({shardCollection: coll.getFullName(), key: shardKey}));
// Split the collection. e.g.,
// shard0: [chunk 1] { <shardField> : { "$minKey" : 1 } } -->> { <shardField> : 0 }
// shard0: [chunk 2] { <shardField> : 0 } -->> { <shardField> : "b"}
// shard1: [chunk 3] { <shardField> : "b" } -->> { <shardField> : { "$maxKey" : 1 }}
// Chunk 2 will be moved between the shards.
for (let mid of splits) {
assert.commandWorked(db.adminCommand({split: coll.getFullName(), middle: mid}));
}
assert.commandWorked(
db.adminCommand({moveChunk: coll.getFullName(), find: {[shardField]: MinKey}, to: st.shard0.shardName}),
);
assert.commandWorked(
db.adminCommand({moveChunk: coll.getFullName(), find: {[shardField]: doc.a}, to: st.shard0.shardName}),
);
assert.commandWorked(
db.adminCommand({moveChunk: coll.getFullName(), find: {[shardField]: MaxKey}, to: st.shard1.shardName}),
);
// Put data on shard0, that will go into chunk 2.
assert.commandWorked(coll.insert(doc));
// Perform a chunk migration of chunk 2 from shard0 to shard1, but do not clean
// up orphans on shard0.
db.adminCommand({moveChunk: coll.getFullName(), find: doc, to: st.shard1.shardName});
};
const caseInsensitive = {
locale: "en_US",
strength: 2,
};
const doQueries = (withCollation) => {
let evalFn = (query) => {
let queryObj = coll.find(query);
if (withCollation) {
queryObj = queryObj.collation(caseInsensitive);
}
let results = outputShardedFindSummaryAndResults(queryObj);
// Only one document was inserted, and all queries should include it.
// Anything greater than one may indicate the query is not correctly shard
// filtering, and is seeing orphans.
assert.eq(1, results.length);
};
for (let fieldName of ["a", "_id"]) {
// Equality.
evalFn({[fieldName]: "a"});
// Ranges within a single chunk.
evalFn({[fieldName]: {"$lte": "a"}});
evalFn({[fieldName]: {"$gte": "a"}});
evalFn({[fieldName]: {"$gte": "a", "$lte": "a"}});
// These queries would return values from any chunk.
evalFn({[fieldName]: {"$gt": MinKey}});
evalFn({[fieldName]: {"$lt": MaxKey}});
evalFn({[fieldName]: {"$gt": MinKey, "$lt": MaxKey}});
}
};
let suspendRangeDeletionShard0;
for (let shardKey of [{a: 1}, {_id: 1}, {a: "hashed"}, {_id: "hashed"}]) {
let shardKeyJson = tojson(shardKey);
let key = Object.keys(shardKey)[0];
let splitPoints =
Object.values(shardKey)[0] == "hashed"
? [{[key]: convertShardKeyToHashed(0)}, {[key]: convertShardKeyToHashed("b")}]
: [{[key]: 0}, {[key]: "b"}];
suspendRangeDeletionShard0 = configureFailPoint(st.shard0, "suspendRangeDeletion");
setupCollection({shardKey: shardKey, splits: splitPoints});
section(`Find *without* collation on collection sharded on ${shardKeyJson}`);
doQueries(false);
// Since the query has non-simple collation we will have to broadcast to all shards (since
// the shard key is on a simple collation index), and should have a SHARD_FILTER stage.
section(`Find with collation on collection sharded on ${shardKeyJson}`);
doQueries(true);
suspendRangeDeletionShard0.off();
coll.drop();
}
st.stop();