BLiteSession.Rollback() does not await the rollback: it returns while the transaction is still active, and failures go unobserved
Maintainers usually reply within 2 days
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 78/100
Research direction
Start with src/BLite.Core/BLiteSession.cs:107-116, then trace CurrentTransaction.RollbackAsync() through src/BLite.Core/Transactions/Transaction.cs:135-152 and the rollback handlers in DocumentCollection.cs and DynamicCollection.cs. Reproduce the concurrent rollback scenario and add coverage verifying that the transaction is Aborted when the operation returns and that WAL-write failures propagate; update the README session sample if the public API changes. Use the existing transaction and storage test structure to locate the appropriate tests.
Written by the indexing model from the issue text.
Description
BLiteSession.Rollback() starts CurrentTransaction.RollbackAsync() and returns without awaiting it. The session forgets the transaction at once, but the rollback finishes later: the abort record is written to the WAL, then the transaction becomes Aborted and its rollback handlers run, which restore the collection's free-space index. Any exception from that work is never observed.
The README's session sample uses exactly this call in its catch block.
Found while reviewing the public API for #296.
Repro
using var engine = new BLiteEngine("rb.db");
var col = engine.GetOrCreateCollection("orders");
// background load: another task inserting into a second collection in a loop
for (int i = 0; i < 300; i++)
{
using var session = engine.OpenSession();
var tx = session.BeginTransaction();
await session.InsertAsync("orders", doc);
session.Rollback();
if (tx.State != TransactionState.Aborted) stillActive++;
}
// stillActive: 59–85 of 300 across five runs; 0 of 200 without the background load
The rolled-back documents do not appear (the transaction's page images are dropped synchronously), so no data was lost in these runs. What is late is the rest of the rollback: the abort record, the state change and the free-space-index restore (_fsi.RollbackTransaction), which the next insert on that collection may read before it happens.
Expected: when Rollback() returns, the rollback is complete, and a failure is thrown to the caller.
Actual: under contention, about one rollback in four is still running when Rollback() returns, and its exceptions are lost.
Where in the code (0450b97)
BLiteSession.Rollback()(src/BLite.Core/BLiteSession.cs:107-116):try { CurrentTransaction.RollbackAsync(); } finally { CurrentTransaction = null; }, aValueTaskdropped withoutawait.Transaction.RollbackAsyncawaits_storage.RollbackTransactionAsync(WAL abort record) before it setsAbortedand runsOnRollback(src/BLite.Core/Transactions/Transaction.cs:135-152).- The handlers restore the free-space index (
src/BLite.Core/Collections/DocumentCollection.cs:4306,src/BLite.Core/DynamicCollection.cs:2709). - For comparison,
Transaction.Disposeblocks on the same call (RollbackAsync().GetAwaiter().GetResult(),Transaction.cs:189), andBLiteEngine.Rollback()is a documented no-op (src/BLite.Core/BLiteEngine.cs:432-438).
Suggested fix
- Add
BLiteSession.RollbackAsync(CancellationToken)that awaits, and makeRollback()either block on it (asTransaction.Disposedoes) or mark it[Obsolete]in favour of the async one; update the README sample toawait session.RollbackAsync(). - In v6, drop the synchronous
Rollback()and the no-opBLiteEngine.Rollback()/CommitAsync()(#296, public API). - Test: under concurrent commits, after
Rollback()(orRollbackAsync()) returns, the transaction isAborted; and a rollback whose WAL write throws surfaces the exception.
Related: #296.
- Dominant language
- C#
- Stars
- 66
- Forks
- 6
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 58
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from EntglDb/BLite
-
GdprMode.Strict warns that deleted documents are not zeroed, but every delete zero-fills themPossibly taken @CaffeinatedCoder claimed this 5 days ago. Openbug gdpr package/core severity/low
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
EntglDb/BLite#299 · 1 comment ·
Maintainers usually reply within 2 days
-
bug package/core severity/medium triage
Difficulty 4/5 3-5 days Newbie friendliness 54/100
Maintainers usually reply within 2 days
-
bug package/core severity/medium
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#322 · 1 comment ·
Maintainers usually reply within 2 days
-
enhancement package/core
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#320 · 1 comment ·
Maintainers usually reply within 2 days
-
area/indexing bug package/core severity/medium
Difficulty 4/5 3-5 days Newbie friendliness 55/100
EntglDb/BLite#305 · 1 comment ·
Maintainers usually reply within 2 days
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Nimblesite/SharpLsp#468 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
elastic/ecs-dotnet#575 ·
-
alerts bug effort:S P2
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
nightscout/nocturne#2511 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 2 days
-
Crash in v3.00Open
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
arkane-systems/mousejiggler#140 ·