Skip to content

InsertAsync / InsertBulkAsync / UpsertAsync roll back the caller's explicit transaction on any exception #185

Closed

Description

@CaffeinatedCoder

DocumentCollection.InsertAsync, InsertBulkAsync and UpsertAsync roll back the transaction in their catch blocks even when the caller passed it in (DocumentCollection.cs ~L2028, ~L2084, ~L2961 on the #182 branch). UpdateAsync only rolls back a transaction it created itself (if (autoCommit)).

So any exception inside an explicit transaction aborts the whole transaction: a unique-index violation (#176), a serialization error, etc. The caller can't catch the error and carry on, and the next CommitAsync fails with "state Aborted".

Repro

await people.CreateIndexAsync(p => p.Name, "idx_name", unique: true);
using var tx = await db.BeginTransactionAsync();
await people.InsertAsync(new Person { Name = "a" }, tx);
try { await people.InsertAsync(new Person { Name = "a" }, tx); }
catch (InvalidOperationException) { /* expected duplicate */ }
await tx.CommitAsync(); // throws: transaction is Aborted; the first insert is lost

Expected: these methods behave like UpdateAsync. They roll back only a transaction they own; otherwise they rethrow and leave the caller's transaction as it was. With #182, a rejected write leaves no pages behind, because the unique check runs before any write.

Whether a failed operation should poison a caller-owned transaction is a design choice, but it should be the same for Insert, Update and Upsert.

Raised in the review of #182.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions