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

Writing an oplog entry for prepare should not push the lastApplied timestamp

    • Fully Compatible
    • ALL
    • Hide

      commit: 8c5002b06fd737f75941a73785ce75e3ca7f5ce1
      1. Put a 5 second sleep between (1) and (2) to increase the chance that another transaction starts in between.

      Unable to find source-code formatter for language: c++. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
            opObserver->onTransactionPrepare(opCtx);                                    
            lk.lock();                                                                  
            _checkIsActiveTransaction(lk, *opCtx->getTxnNumber(), true);                
            invariant(_txnState == MultiDocumentTransactionState::kPrepared);           
      +     sleep(5);                                                                   
                                                                                        
            opCtx->getWriteUnitOfWork()->prepare(); 
       

      2. repro.js:

      Unable to find source-code formatter for language: cpp. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      const session = db.getMongo().startSession({causalConsistency: false});            
      const sessionDB = session.getDatabase('test');                                     
      sessionDB.a.insert({x: 1});                                                        
      session.startTransaction({readConcern: {level: "snapshot"}});                      
      assert.commandWorked(sessionDB.runCommand({                                        
          update: 'a',                                                                   
          updates: [{q: {x: 1}, u: {$inc: {x: 1}}}],                                     
      }));                                                                               
                                                                                         
      let awaitShell = startParallelShell(function() {                                   
          const session = db.getMongo().startSession({causalConsistency: false});        
          const sessionDB = session.getDatabase('test');                                 
          while (1) {                                                                    
              session.startTransaction({readConcern: {level: "snapshot"}});              
              sessionDB.a.find().toArray();                                              
              session.abortTransaction();                                                
          }                                                                              
      });                                                                                
                                                                                         
      assert.commandWorked(sessionDB.adminCommand({prepareTransaction: 1}));             
      session.abortTransaction();                                                        
                                                                                         
      awaitShell(); 
      
      Show
      commit: 8c5002b06fd737f75941a73785ce75e3ca7f5ce1 1. Put a 5 second sleep between (1) and (2) to increase the chance that another transaction starts in between. Unable to find source-code formatter for language: c++. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml opObserver->onTransactionPrepare(opCtx); lk.lock(); _checkIsActiveTransaction(lk, *opCtx->getTxnNumber(), true ); invariant(_txnState == MultiDocumentTransactionState::kPrepared); + sleep(5); opCtx->getWriteUnitOfWork()->prepare(); 2. repro.js: Unable to find source-code formatter for language: cpp. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml const session = db.getMongo().startSession({causalConsistency: false }); const sessionDB = session.getDatabase( 'test' ); sessionDB.a.insert({x: 1}); session.startTransaction({readConcern: {level: "snapshot" }}); assert .commandWorked(sessionDB.runCommand({ update: 'a' , updates: [{q: {x: 1}, u: {$inc: {x: 1}}}], })); let awaitShell = startParallelShell(function() { const session = db.getMongo().startSession({causalConsistency: false }); const sessionDB = session.getDatabase( 'test' ); while (1) { session.startTransaction({readConcern: {level: "snapshot" }}); sessionDB.a.find().toArray(); session.abortTransaction(); } }); assert .commandWorked(sessionDB.adminCommand({prepareTransaction: 1})); session.abortTransaction(); awaitShell();
    • Repl 2018-07-16, Repl 2018-07-30, Repl 2018-08-13
    • 70

      Our current prepareTransaction() logic might need some changes: currently, (1) we first log the prepare and get a timestamp T. And then (2) use this timestamp T to set the prepare timestamp in WiredTiger. Since (1) pushes the lastApplied timestamp to T and another transaction could start between (1) and (2), with lastApplied T as the read timestamp, it breaks the rule that prepare timestamp should be greater than any active read timestamp.

       

      Here is what happened in BF-9432:
      1. A started a transaction, did the insertion, and tried to prepare.
      2. A called prepareTransaction() in session.cpp. It first logged the prepare and got a timestamp T. This operation also pushed the lastApplied timestamp to T.
      3. B started a transaction with a read, the read timestamp is set to the lastApplied which is T.
      4. A now tried to set the prepare timestamp to T in WiredTiger. It will cause a WiredTiger error that prepare timestamp being equal to an active read timestamp.

            Assignee:
            judah.schvimer@mongodb.com Judah Schvimer
            Reporter:
            xiangyu.yao@mongodb.com Xiangyu Yao (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: