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

findAndModify on mongoS upserts to the wrong shard

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 3.0.8, 3.1.9
    • Affects Version/s: 3.0.6, 3.1.8
    • Component/s: Querying, Sharding
    • Labels:
      None
    • Fully Compatible
    • ALL
    • 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.

      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.

            Assignee:
            kaloian.manassiev@mongodb.com Kaloian Manassiev
            Reporter:
            misha.tyulenev@mongodb.com Misha Tyulenev
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: