The MigrationSourceManager object should be released before the ActiveMigrationsRegistry is released

XMLWordPrintableJSON

    • Catalog and Routing
    • Fully Compatible
    • ALL
    • Hide
      import {configureFailPoint} from "jstests/libs/fail_point_util.js";
      import {funWithArgs} from "jstests/libs/parallel_shell_helpers.js";
      import {ShardingTest} from "jstests/libs/shardingtest.js";
      
      const st = new ShardingTest({shards: 2, rs: {nodes: 1}, other:{enableBalancer: false}});
      
      function moveRangeFunc(ns, min, max, toShard) {
          assert.commandWorked(db.adminCommand(\{moveRange: ns, min: min, max: max, toShard: toShard}));
      }
      
      const dbName = "test";
      const collName = "move_range_msm_cleanup";
      const ns = dbName + "." + collName;
      
      const mongos = st.s0;
      const donorShard = st.shard0.shardName;
      const recipientShard = st.shard1.shardName;
      
      assert.commandWorked(mongos.adminCommand({enableSharding: dbName, primaryShard: donorShard}));
      assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {x: 1}}));
      
      // 1. Set failpoint to pause the first coordinator after releasing its locks
      const donorPrimary = st.rs0.getPrimary();
      const fp = configureFailPoint(donorPrimary, "hangAfterReleasingMoveRangeCoordinatorLocks");
      
      // 2. Start a chunk migration
      const moveA = startParallelShell(
          funWithArgs(moveRangeFunc, ns, {x: 0}, {x: 10}, recipientShard),
          mongos.port,
      );
      fp.wait();
      
      
      // 3. Start a second chunk migration
      const moveB = startParallelShell(
          funWithArgs(moveRangeFunc, ns, {x: 10}, {x: 20}, recipientShard),
          mongos.port,
      );
      
      // Give the second migration a chance to start and hit the invariant if it is going to.
      sleep(2000);
      
      fp.off();
      moveA();
      moveB();
      assert.commandWorked(donorPrimary.adminCommand({ping: 1}));
      
      st.stop();
      

       

      Show
      import {configureFailPoint} from "jstests/libs/fail_point_util.js" ; import {funWithArgs} from "jstests/libs/parallel_shell_helpers.js" ; import {ShardingTest} from "jstests/libs/shardingtest.js" ; const st = new ShardingTest({shards: 2, rs: {nodes: 1}, other:{enableBalancer: false }}); function moveRangeFunc(ns, min, max, toShard) {     assert .commandWorked(db.adminCommand(\{moveRange: ns, min: min, max: max, toShard: toShard})); } const dbName = "test" ; const collName = "move_range_msm_cleanup" ; const ns = dbName + "." + collName; const mongos = st.s0; const donorShard = st.shard0.shardName; const recipientShard = st.shard1.shardName; assert .commandWorked(mongos.adminCommand({enableSharding: dbName, primaryShard: donorShard})); assert .commandWorked(mongos.adminCommand({shardCollection: ns, key: {x: 1}})); // 1. Set failpoint to pause the first coordinator after releasing its locks const donorPrimary = st.rs0.getPrimary(); const fp = configureFailPoint(donorPrimary, "hangAfterReleasingMoveRangeCoordinatorLocks" ); // 2. Start a chunk migration const moveA = startParallelShell(     funWithArgs(moveRangeFunc, ns, {x: 0}, {x: 10}, recipientShard),     mongos.port, ); fp.wait(); // 3. Start a second chunk migration const moveB = startParallelShell(     funWithArgs(moveRangeFunc, ns, {x: 10}, {x: 20}, recipientShard),     mongos.port, ); // Give the second migration a chance to start and hit the invariant if it is going to. sleep(2000); fp.off(); moveA(); moveB(); assert .commandWorked(donorPrimary.adminCommand({ping: 1})); st.stop();  
    • CAR Team 2026-06-22
    • 200
    • 🟥 DDL
    • None
    • None
    • None
    • None
    • None
    • None

      MoveRangeCoordinator first acquires a slot in the ActiveMigrationsRegistry and then emplaces a MigrationSourceManager. When the operation completes, however, teardown happens in the opposite order: the ActiveMigrationsRegistry entry is released first, and only afterward is the MigrationSourceManager destroyed.

      MigrationSourceManager enforces an invariant that only one instance can exist at a time.
      As a result, if a second migration attempts to emplace a MigrationSourceManager before the previous one has been destroyed, we hit this invariant.

       

            Assignee:
            Silvia Surroca
            Reporter:
            Silvia Surroca
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: