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

Distinguish between a retryable write and a transaction when failing a command

    • Minor Change
    • v4.2, v4.0
    • Repl 2020-02-10, Repl 2020-02-24

      Currently, most txnNumber errors refer only to transactions, even if the error pertains to a retryable write. This can create a poor user experience for someone who is only using retryable writes.

      We should audit these types of errors on the server and determine whether the command was a part of a retryable write or a transaction. Depending on the answer, we can return one of the following errors:

      "Cannot start transaction X on session <UUID> because a newer transaction or retryable write with txnNumber Y has already started on this session."

      "Retryable write with txnNumber X is prohibited on session <UUID> because a newer transaction or retryable write with txnNumber Y has already started on this session."

      ORIGINAL POST:

      Code that reproduces the issue:

              private static async Task TestSingleSession(MongoClient client)
              {
                  var col = client.GetDatabase("_test").GetCollection<BsonDocument>("concurrent");                        
                  using (var session = await client.StartSessionAsync())
                  {
                      var ops = Enumerable.Range(0, 100)
                          .Select(async e =>
                          {
                              await col.ReplaceOneAsync(session, Builders<BsonDocument>.Filter.Eq("_id", e),
                                  new BsonDocument
                                  {
                                      { "_id", e },
                                      { "data", $"someData_{e}" },
                                  },
                                  new UpdateOptions { IsUpsert = true });
                          })
                          .ToArray();
                      await Task.WhenAll(ops);
                  }
              }
      

       

      When running above code I'm getting the exception:

      MongoCommandException: Command update failed: Cannot start transaction 1 on session c4fd4081-e0f0-40d6-84fc-cdfeccc74e3b - hf9LJrhq2lfp667gnURrBVE7MCUS1NJZYDmWlqfKWl0= because a newer transaction 3 has already started..

      This is misleading as there's no explicit transaction in progress.

      I know now that we should use either

      • ReplaceOneAsync overload without session
      • Create new session per call to ReplaceOneAsync with session

       

      background: I've encountered that issue in production code where one method is being used with and without transaction - our solution was to simply create a intermediate overloaded method that creates a session for you and passes it into method that accepts the session.

            Assignee:
            ali.mir@mongodb.com Ali Mir
            Reporter:
            marek.kresnicki@gmail.com Marek Kresnicki
            Votes:
            0 Vote for this issue
            Watchers:
            15 Start watching this issue

              Created:
              Updated:
              Resolved: