SERVER-121533 Fix MaxKey range inclusion for migration_destination_manager (#51012)
GitOrigin-RevId: 9c14094e37cb0470cbb5abe293a0919792ded2a0
This commit is contained in:
parent
6f5d11312b
commit
722b13eef2
@ -202,4 +202,33 @@ function assertMigrationComplete(dbName, ns, coll, shard0DB, expectedCount) {
|
||||
st.s.getDB(dbName).coll.drop();
|
||||
}
|
||||
|
||||
// Test 8: Recipient pre-cloning check detects MaxKey orphans with wider-than-shard-key index.
|
||||
// checkForExistingDocumentsInRange must extend bounds to the index width so that a MaxKey
|
||||
// document already present on the recipient is detected even when the index is wider than
|
||||
// the shard key.
|
||||
{
|
||||
const {dbName, ns, coll, shard0DB} = setupCollection("recipient_wider_idx", {x: 1});
|
||||
assert.commandWorked(coll.createIndex({x: 1, y: 1}));
|
||||
assert.commandWorked(coll.dropIndex({x: 1}));
|
||||
|
||||
assert.commandWorked(coll.insert({_id: "normal", x: 5}));
|
||||
|
||||
// Directly insert a MaxKey orphan on shard1 (bypassing mongos to simulate an orphan from
|
||||
// a prior buggy migration that left it behind). The wider index {x:1, y:1} means the scan
|
||||
// must use extendRangeBound to pad bounds to match the index width.
|
||||
assert.commandWorked(st.shard1.getDB(dbName).coll.insert({_id: "orphan_maxkey", x: MaxKey(), y: 42}));
|
||||
|
||||
// Migrate the chunk [MinKey, MaxKey) from shard0 to shard1. The recipient's pre-cloning
|
||||
// check should detect the orphaned MaxKey document and abort the migration. Without the
|
||||
// extendRangeBound fix, the wider index scan would use {x: MaxKey, y: MinKey} as the
|
||||
// upper bound, missing the orphan at {x: MaxKey, y: 42}.
|
||||
const result = st.s.adminCommand({moveChunk: ns, find: {x: 0}, to: st.shard1.shardName, _waitForDelete: true});
|
||||
|
||||
assert.commandFailed(result);
|
||||
|
||||
// Clean up the orphan directly on shard1.
|
||||
assert.commandWorked(st.shard1.getDB(dbName).coll.remove({_id: "orphan_maxkey"}));
|
||||
coll.drop();
|
||||
}
|
||||
|
||||
st.stop();
|
||||
|
||||
@ -232,7 +232,7 @@ std::string stateToString(MigrationDestinationManager::State state) {
|
||||
* Checks if an upsert of a remote document will override a local document with the same _id but in
|
||||
* a different range on this shard. Must be in WriteContext to avoid races and DBHelper errors.
|
||||
*
|
||||
* TODO: Could optimize this check out if sharding on _id.
|
||||
* TODO SERVER-123300: Could optimize this check out if sharding on _id.
|
||||
*/
|
||||
bool willOverrideLocalId(OperationContext* opCtx,
|
||||
const NamespaceString& nss,
|
||||
@ -2234,13 +2234,22 @@ boost::optional<BSONObj> MigrationDestinationManager::checkForExistingDocumentsI
|
||||
<< " on collection " << nss.toStringForErrorMsg(),
|
||||
shardKeyIdx);
|
||||
|
||||
// Use InternalPlanner to scan the shard key index within the range.
|
||||
// Extend bounds to match the index width and strip field names for the index scan.
|
||||
// When the range max is the global max (all fields MaxKey), use makeUpperInclusive=true
|
||||
// so trailing fields are padded with MaxKey instead of MinKey, and use inclusive upper
|
||||
// bound so the scan detects documents whose shard key is exactly MaxKey. See SERVER-121533.
|
||||
const KeyPattern kp(shardKeyIdx->keyPattern());
|
||||
const bool isMaxGlobal = kp.isGlobalMax(max);
|
||||
const auto extendedMin = Helpers::toKeyFormat(kp.extendRangeBound(min, false));
|
||||
const auto extendedMax = Helpers::toKeyFormat(kp.extendRangeBound(max, isMaxGlobal));
|
||||
const auto boundInclusion = isMaxGlobal ? BoundInclusion::kIncludeBothStartAndEndKeys
|
||||
: BoundInclusion::kIncludeStartKeyOnly;
|
||||
auto exec = InternalPlanner::shardKeyIndexScan(opCtx,
|
||||
collection,
|
||||
*shardKeyIdx,
|
||||
min,
|
||||
max,
|
||||
BoundInclusion::kIncludeStartKeyOnly,
|
||||
extendedMin,
|
||||
extendedMax,
|
||||
boundInclusion,
|
||||
PlanYieldPolicy::YieldPolicy::YIELD_AUTO,
|
||||
InternalPlanner::FORWARD);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user