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

Bumping txnNumber does not clear stashed transaction resources

    XMLWordPrintableJSON

Details

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: Major - P3 Major - P3
    • None
    • None
    • Storage
    • None
    • ALL
    • Hide

      (function() {
          const rst = new ReplSetTest({nodes: 1});
          rst.startSet();
          rst.initiate();
          const session = rst.getPrimary().getDB("test").getMongo().startSession();
          const db1 = session.getDatabase("test1");
          const db2 = session.getDatabase("test2");
       
          // Populate two collections in different databases.
          for (let i = 0; i < 4; i++) {
              assert.commandWorked(db1.coll.insert({_id: i}, {writeConcern: {w: "majority"}}));
              assert.commandWorked(db2.coll.insert({_id: i}, {writeConcern: {w: "majority"}}));
          }
       
          // Open a snapshot read cursor on db1.coll.
          let res = assert.commandWorked(db1.runCommand(
              {find: "coll", batchSize: 2, readConcern: {level: "snapshot"}, txnNumber: NumberLong(0)}));
       
          // Open a snapshot read cursor on db2.coll.
          res = assert.commandWorked(db2.runCommand(
              {find: "coll", batchSize: 2, readConcern: {level: "snapshot"}, txnNumber: NumberLong(1)}));
       
          // db2.coll is not locked, so this drop succeeds, when it should fail.
          db2.coll.drop();
          rst.stopSet();
      }());
      

      Show
      (function() { const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); const session = rst.getPrimary().getDB("test").getMongo().startSession(); const db1 = session.getDatabase("test1"); const db2 = session.getDatabase("test2");   // Populate two collections in different databases. for (let i = 0; i < 4; i++) { assert.commandWorked(db1.coll.insert({_id: i}, {writeConcern: {w: "majority"}})); assert.commandWorked(db2.coll.insert({_id: i}, {writeConcern: {w: "majority"}})); }   // Open a snapshot read cursor on db1.coll. let res = assert.commandWorked(db1.runCommand( {find: "coll", batchSize: 2, readConcern: {level: "snapshot"}, txnNumber: NumberLong(0)}));   // Open a snapshot read cursor on db2.coll. res = assert.commandWorked(db2.runCommand( {find: "coll", batchSize: 2, readConcern: {level: "snapshot"}, txnNumber: NumberLong(1)}));   // db2.coll is not locked, so this drop succeeds, when it should fail. db2.coll.drop(); rst.stopSet(); }());
    • Storage NYC 2018-03-26

    Description

      This is what happens in the repro. First we open a snapshot cursor on db1.coll. The next operation has a higher txnNumber, so we set _isSnapshotTxn to false. Then we unstash resources from the previous operation onto our OperationContext, since we have not cleared stashed resources. Then at the end of the operation, since _isSnapshotTxn is false, we do not stash resources. This allows us to drop db2.coll.

      I did not demonstrate this in the repro, but the second read is also holding the locks from the first read while it is running.

      Attachments

        Activity

          People

            tess.avitabile@mongodb.com Tess Avitabile (Inactive)
            tess.avitabile@mongodb.com Tess Avitabile (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: