Skip to content

Fix concurrent LiteDB access crash with lock() serialization#784

Merged
dangershony merged 4 commits intomainfrom
copilot/fix-lite-db-collection-modification-error
Apr 29, 2026
Merged

Fix concurrent LiteDB access crash with lock() serialization#784
dangershony merged 4 commits intomainfrom
copilot/fix-lite-db-collection-modification-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 24, 2026

A single LiteDatabase instance was shared across all LiteDbDocumentCollection wrappers with no synchronization, causing InvalidOperationException: Collection was modified; enumeration operation may not execute when concurrent reads/writes triggered mid-enumeration deserialization in LiteDB's BsonMapper.

Changes

LiteDbDocumentDatabase

  • Adds a shared object _lock = new() field passed to every LiteDbDocumentCollection wrapper
  • No disposal needed — plain lock objects are GC-managed

LiteDbDocumentCollection

  • Accepts a shared object syncLock in the constructor
  • Every method touching _collection (Insert, Update, Upsert, Delete, DeleteAll, FindById, Exists, Find, FindAll, Count) wraps the LiteDB call with a lock statement
  • UpsertAsync holds the lock across the full exists-check + insert/update sequence — eliminating the TOCTOU race
  • Methods are no longer async since all LiteDB operations are synchronous; they return Task.FromResult(...) directly
lock (_lock)
{
    var exists = _collection.Exists(Query.EQ("_id", new BsonValue(document.Id)));
    if (exists)
        return Task.FromResult(Result.Success(_collection.Update(document)));
    else
        return Task.FromResult(Result.Success(_collection.Insert(document) != null));
}

Comment thread src/sdk/Angor.Data.Documents.LiteDb/LiteDbDocumentCollection.cs
Copilot AI changed the title Fix concurrent LiteDB access crash with SemaphoreSlim serialization Fix concurrent LiteDB access crash with lock() serialization Apr 24, 2026
Copilot AI requested a review from dangershony April 24, 2026 22:57
Comment thread src/sdk/Angor.Data.Documents.LiteDb/LiteDbDocumentCollection.cs Outdated
DavidGershony and others added 2 commits April 29, 2026 15:01
The global lock caused unnecessary contention across unrelated collection
types. The BsonMapper concurrency bug only affects concurrent deserialization
of the same type, so a lock per collection type is sufficient.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…thread

Replace lock() with SemaphoreSlim.WaitAsync() so the UI thread yields
while waiting for the semaphore instead of blocking. Each collection type
gets its own SemaphoreSlim via ConcurrentDictionary to avoid cross-type
contention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dangershony dangershony marked this pull request as ready for review April 29, 2026 15:13
@dangershony dangershony merged commit 145a720 into main Apr 29, 2026
3 checks passed
@dangershony dangershony deleted the copilot/fix-lite-db-collection-modification-error branch April 29, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants