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

Ban transaction snapshot reads on capped collections

    XMLWordPrintable

Details

    • Bug
    • Status: Closed
    • Major - P3
    • Resolution: Fixed
    • None
    • 4.7.0
    • Replication
    • None
    • Minor Change
    • Hide

      /* Tests capped collection reads with readConcern level snapshot.
       *
       * @tags: [requires_majority_read_concern, requires_fcv_46]
       */
      (function() {
      "use strict";
       
      const replSet = new ReplSetTest({nodes: 1});
       
      replSet.startSet();
      replSet.initiate();
       
      const collName = "coll";
      const primary = replSet.getPrimary();
      const primaryDB = primary.getDB('test');
       
      assert.commandWorked(primaryDB.createCollection(collName, {capped: true, size: 32, max: 1}));
       
      const insertTimestamp =
          assert
              .commandWorked(primaryDB.runCommand(
                  {insert: collName, documents: [{_id: 0}], writeConcern: {w: "majority"}}))
              .operationTime;
       
      // Perform an extra insert outside of the transaction to trigger capped collection cleanup.
      assert.commandWorked(
          primaryDB.runCommand({insert: collName, documents: [{_id: 1}], writeConcern: {w: "majority"}}));
       
      // Perform a local read outside of the transaction and it should only see {_id: 1}.
      let cmdRes = assert.commandWorked(primaryDB.runCommand({find: collName}));
      assert.sameMembers([{_id: 1}], cmdRes.cursor.firstBatch, tojson(cmdRes));
       
      // TODO(SERVER-47824): Also ban transaction snapshot reads on capped collections because reading
      // from a capped collection within a transaction with an atClusterTime could give wrong result.
      session = primary.startSession({causalConsistency: false});
      sessionDB = session.getDatabase('test');
      session.startTransaction({readConcern: {level: 'snapshot', atClusterTime: insertTimestamp}});
      cmdRes = assert.commandWorked(sessionDB.runCommand({find: collName}));
      assert.sameMembers([{_id: 0}], cmdRes.cursor.firstBatch, tojson(cmdRes));;  // This would FAIL!
       
      assert.commandWorked(session.abortTransaction_forTesting());
       
      replSet.stopSet();
      })();
      

      Show
      /* Tests capped collection reads with readConcern level snapshot. * * @tags: [requires_majority_read_concern, requires_fcv_46] */ (function() { "use strict";   const replSet = new ReplSetTest({nodes: 1});   replSet.startSet(); replSet.initiate();   const collName = "coll"; const primary = replSet.getPrimary(); const primaryDB = primary.getDB('test');   assert.commandWorked(primaryDB.createCollection(collName, {capped: true, size: 32, max: 1}));   const insertTimestamp = assert .commandWorked(primaryDB.runCommand( {insert: collName, documents: [{_id: 0}], writeConcern: {w: "majority"}})) .operationTime;   // Perform an extra insert outside of the transaction to trigger capped collection cleanup. assert.commandWorked( primaryDB.runCommand({insert: collName, documents: [{_id: 1}], writeConcern: {w: "majority"}}));   // Perform a local read outside of the transaction and it should only see {_id: 1}. let cmdRes = assert.commandWorked(primaryDB.runCommand({find: collName})); assert.sameMembers([{_id: 1}], cmdRes.cursor.firstBatch, tojson(cmdRes));   // TODO(SERVER-47824): Also ban transaction snapshot reads on capped collections because reading // from a capped collection within a transaction with an atClusterTime could give wrong result. session = primary.startSession({causalConsistency: false}); sessionDB = session.getDatabase('test'); session.startTransaction({readConcern: {level: 'snapshot', atClusterTime: insertTimestamp}}); cmdRes = assert.commandWorked(sessionDB.runCommand({find: collName})); assert.sameMembers([{_id: 0}], cmdRes.cursor.firstBatch, tojson(cmdRes));; // This would FAIL!   assert.commandWorked(session.abortTransaction_forTesting());   replSet.stopSet(); })();
    • Repl 2020-06-15, Repl 2020-07-27
    • 0

    Description

      Capped collections typically (always?) delete records with an unreplicated/untimestamped write. Those deletions will always become visible in a newer transaction. So if a transaction uses snapshot with an atClusterTime (e.g. coming from mongos), it may not see some deleted documents even if they existed at the point in time requested.

      Snapshot transactions without atClusterTime might still work if the snapshot is open before the deletions happen probably because they hold onto the WT txn and the snapshot. But I am not 100% sure. Either way, it seems that we will still have to ban transaction snapshot reads on capped collections unless we choose to timestamp the capped collection deletions.

      Attachments

        Issue Links

          Activity

            People

              ali.mir@mongodb.com Ali Mir
              lingzhi.deng@mongodb.com Lingzhi Deng
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: