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

rollback makes config.transactions fastcount inaccurate

    • Type: Icon: Bug Bug
    • Resolution: Won't Fix
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Replication
    • Replication
    • ALL
    • Hide
      (function() {
          "use strict";
      
          load("jstests/replsets/libs/rollback_test.js");
      
          const testName = "rollback_transactions_count";
          const dbName = testName;
      
          let replSet = new ReplSetTest({name: testName, nodes: 3, useBridge: true});
          replSet.startSet();
      
          const nodes = replSet.nodeList();
          replSet.initiate({
              _id: testName,
              members: [
                  {_id: 0, host: nodes[0]},
                  {_id: 1, host: nodes[1]},
                  {_id: 2, host: nodes[2], arbiterOnly: true}
              ]
          });
      
          // Set up Rollback Test.
          let rollbackTest = new RollbackTest(testName, replSet);
          let primary = rollbackTest.getPrimary();
          assert.commandWorked(primary.setLogLevel(3, 'storage.recovery'));
          let testDb = primary.getDB(dbName);
      
          const txnName = "txnCollName";
      
          const session1 = primary.startSession();
          const sessionDb1 = session1.getDatabase(dbName);
          const sessionColl1 = sessionDb1[txnName];
          assert.commandWorked(sessionColl1.insert({a: 1}));
          session1.startTransaction();
          assert.commandWorked(sessionColl1.insert({b: 1}));
          session1.commitTransaction();
      
          replSet.awaitLastOpCommitted();
          assert.commandWorked(
              primary.adminCommand({configureFailPoint: 'disableSnapshotting', mode: 'alwaysOn'}));
      
          const session2 = primary.startSession();
          const sessionDb2 = session2.getDatabase(dbName);
          const sessionColl2 = sessionDb2[txnName];
          session2.startTransaction();
          assert.commandWorked(sessionColl2.insert({c: 1}));
          session2.commitTransaction();
      
          rollbackTest.transitionToRollbackOperations();
      
          session2.startTransaction();
          assert.commandWorked(sessionColl2.insert({d: 1}));
          session2.commitTransaction();
      
          const session3 = primary.startSession();
          const sessionDb3 = session3.getDatabase(dbName);
          const sessionColl3 = sessionDb3[txnName];
          session3.startTransaction();
          assert.commandWorked(sessionColl3.insert({e: 1}));
          session3.commitTransaction();
      
          rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
          rollbackTest.transitionToSyncSourceOperationsDuringRollback();
          try {
              rollbackTest.transitionToSteadyStateOperations();
          } finally {
              assert.commandWorked(
                  primary.adminCommand({configureFailPoint: 'disableSnapshotting', mode: 'off'}));
          }
      
          rollbackTest.stop();
      })();
      
      Show
      (function() { "use strict"; load("jstests/replsets/libs/rollback_test.js"); const testName = "rollback_transactions_count"; const dbName = testName; let replSet = new ReplSetTest({name: testName, nodes: 3, useBridge: true}); replSet.startSet(); const nodes = replSet.nodeList(); replSet.initiate({ _id: testName, members: [ {_id: 0, host: nodes[0]}, {_id: 1, host: nodes[1]}, {_id: 2, host: nodes[2], arbiterOnly: true} ] }); // Set up Rollback Test. let rollbackTest = new RollbackTest(testName, replSet); let primary = rollbackTest.getPrimary(); assert.commandWorked(primary.setLogLevel(3, 'storage.recovery')); let testDb = primary.getDB(dbName); const txnName = "txnCollName"; const session1 = primary.startSession(); const sessionDb1 = session1.getDatabase(dbName); const sessionColl1 = sessionDb1[txnName]; assert.commandWorked(sessionColl1.insert({a: 1})); session1.startTransaction(); assert.commandWorked(sessionColl1.insert({b: 1})); session1.commitTransaction(); replSet.awaitLastOpCommitted(); assert.commandWorked( primary.adminCommand({configureFailPoint: 'disableSnapshotting', mode: 'alwaysOn'})); const session2 = primary.startSession(); const sessionDb2 = session2.getDatabase(dbName); const sessionColl2 = sessionDb2[txnName]; session2.startTransaction(); assert.commandWorked(sessionColl2.insert({c: 1})); session2.commitTransaction(); rollbackTest.transitionToRollbackOperations(); session2.startTransaction(); assert.commandWorked(sessionColl2.insert({d: 1})); session2.commitTransaction(); const session3 = primary.startSession(); const sessionDb3 = session3.getDatabase(dbName); const sessionColl3 = sessionDb3[txnName]; session3.startTransaction(); assert.commandWorked(sessionColl3.insert({e: 1})); session3.commitTransaction(); rollbackTest.transitionToSyncSourceOperationsBeforeRollback(); rollbackTest.transitionToSyncSourceOperationsDuringRollback(); try { rollbackTest.transitionToSteadyStateOperations(); } finally { assert.commandWorked( primary.adminCommand({configureFailPoint: 'disableSnapshotting', mode: 'off'})); } rollbackTest.stop(); })();

      When an applyOps entry causes a record to be upserted into the config.transactions table, it's impossible to know whether the entry changed the count of the collection or not. If it's a new session it will change the count, but if it's an existing session it won't. We would need to actually inspect the table for the existence of the session to correct this.

            Assignee:
            backlog-server-repl [DO NOT USE] Backlog - Replication Team
            Reporter:
            judah.schvimer@mongodb.com Judah Schvimer
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: