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

Ban transaction snapshot reads on capped collections

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 4.7.0
    • Component/s: Replication
    • Labels:
      None
    • Backwards Compatibility:
      Minor Change
    • Steps To Reproduce:
      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(); })();
    • Sprint:
      Repl 2020-06-15, Repl 2020-07-27
    • Linked BF Score:
      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

              Assignee:
              ali.mir Ali Mir
              Reporter:
              lingzhi.deng Lingzhi Deng
              Participants:
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: