Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-20407

findAndModify on mongoS upserts to the wrong shard

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Fixed
    • Affects Version/s: 3.0.6, 3.1.8
    • Fix Version/s: 3.0.8, 3.1.9
    • Component/s: Querying, Sharding
    • Labels:
      None
    • Backwards Compatibility:
      Fully Compatible
    • Operating System:
      ALL
    • Backport Completed:
    • Steps To Reproduce:
      Hide

      This is simplified jstests/sharding/find_and_modify_after_multi_write.js

          var st = new ShardingTest({ shards: 2, mongos: 2 });
       
          var testDB = st.s.getDB('test');
          testDB.dropDatabase();
       
          testDB.adminCommand({ enableSharding: 'test' });
          st.ensurePrimaryShard('test', 'shard0000');
          testDB.adminCommand({ shardCollection: 'test.user', key: { x: 1 }});
          testDB.adminCommand({ split: 'test.user', middle: { x: 0 }});
          testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0001' });
       
          var testDB2 = st.s1.getDB('test');
          testDB2.user.insert({ x: 123456 });
       
          // Move chunk to bump version on a different mongos.
          testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0000' });
       
          testDB2.user.update({}, { $inc: { y: 987654 }}, false, true);
       
          // Issue a targetted findAndModify and check that it was upserted to the right shard.
          testDB2.runCommand({ findAndModify: 'user', query: { x: 100 }, update: { $set: { y: 1 }}, upsert: true });
       
          st.d0.getDB('test').user.findOne({ x: 100 });
      

      The last line should return a record, but it does not because findAndModify updates the wrong shard. The query

          st.d1.getDB('test').user.findOne({ x: 100 });
      

      finds the record.

      Show
      This is simplified jstests/sharding/find_and_modify_after_multi_write.js var st = new ShardingTest({ shards: 2, mongos: 2 });   var testDB = st.s.getDB('test'); testDB.dropDatabase();   testDB.adminCommand({ enableSharding: 'test' }); st.ensurePrimaryShard('test', 'shard0000'); testDB.adminCommand({ shardCollection: 'test.user', key: { x: 1 }}); testDB.adminCommand({ split: 'test.user', middle: { x: 0 }}); testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0001' });   var testDB2 = st.s1.getDB('test'); testDB2.user.insert({ x: 123456 });   // Move chunk to bump version on a different mongos. testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0000' });   testDB2.user.update({}, { $inc: { y: 987654 }}, false, true);   // Issue a targetted findAndModify and check that it was upserted to the right shard. testDB2.runCommand({ findAndModify: 'user', query: { x: 100 }, update: { $set: { y: 1 }}, upsert: true });   st.d0.getDB('test').user.findOne({ x: 100 }); The last line should return a record, but it does not because findAndModify updates the wrong shard. The query st.d1.getDB('test').user.findOne({ x: 100 }); finds the record.

      Description

      findAndModify command is not able to detect stale shard version and as a result can update the wrong shard if the chunk on the shard that it has cached has been moved via a moveChunk command from different mongoS.
      Current test jstests/sharding/find_and_modify_after_multi_write.js masks the issue by executing findOne just before calling findAndModify. findOne updates the ssv on the connection.
      The new ClusterClientCursor code path does not set ssv per connection and hence will invalidate the existing workaround.

        Attachments

          Issue Links

            Activity

              People

              • Votes:
                0 Vote for this issue
                Watchers:
                9 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: