Fix: release file handles on DocumentDbContext constructor failure#130
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses a resource-leak bug where DocumentDbContext constructor failures (notably during encrypted store open) could leave the underlying database file locked due to undisposed storage/file handles, preventing in-process delete/replace flows.
Changes:
- Added exception handling in
DocumentDbContextconstructors to dispose acquired resources when initialization fails. - Added a regression test ensuring a failed open with the wrong encryption password does not leave the DB file locked.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/BLite.Core/DocumentDbContext.cs | Wraps model/collection initialization in try/catch and disposes storage/CDC (and owned encryption coordinator where applicable) on constructor failure. |
| tests/BLite.Tests/EncryptionTests.cs | Adds a regression test for issue #129 asserting the database file can be deleted after a constructor failure caused by wrong encryption credentials. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try | ||
| { | ||
| var modelBuilder = new ModelBuilder(); | ||
| OnModelCreating(modelBuilder); | ||
| _model = modelBuilder.GetEntityBuilders(); |
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
|
[xUnit.net 00:00:30.30] BLite.Tests.ConcurrencyPressureTests.FindConcurrencyBreakingPoint_ServerLayout [SKIP] |
Fixed in 5719af4. The lock was coming from |
When
DocumentDbContextthrows during construction (e.g. wrong encryption password →AuthenticationTagMismatchExceptioninsideInitializeCollections()), theStorageEngine/PageFileand memory-mapped handles were never disposed, leaving the database file locked for the lifetime of the process.Changes
src/BLite.Core/DocumentDbContext.csInitializeCollections()+DropOrphanCollections()+ GDPR-validation sequence in atry/catchin all three "real" constructors_storage.Dispose(),_cdc.Dispose(),_ownedCoordinator?.Dispose()(zeros key material),_disposed = true, then rethrowStorageEngine storageoverload skips disposing_storageon failure — it is caller-ownedtests/BLite.Tests/EncryptionTests.csDocumentDbContext_ConstructorFailure_WrongPassword_FileNotLocked: creates an encrypted DB, checkpoints it, then opens it with the wrong password → asserts the constructor throws → assertsFile.Deletesucceeds in the same process without GC interventionDocumentDbContextconstructor failure #129