Repository navigation
fix(core): the schema-less API reads documents a typed collection stored in overflow pages (#301) - #319
Open
CaffeinatedCoder wants to merge 2 commits into
Open
fix(core): the schema-less API reads documents a typed collection stored in overflow pages (#301)#319CaffeinatedCoder wants to merge 2 commits into
CaffeinatedCoder wants to merge 2 commits into
Conversation
…red in overflow pages (EntglDb#301) A typed DocumentCollection stores a document larger than one page across overflow pages: the slot holds [length][first overflow page][first chunk]. DynamicCollection never checked SlotFlags.HasOverflow and handed the slot bytes to BsonSpanReader, which threw NotSupportedException "Skipping type … not supported at position 7". FindAllAsync, FindByIdAsync, ScanAsync, BLQL, BLite Studio and BLiteMigration all failed on the first large document. New internal OverflowChainReader (Storage/) reassembles such a document, sync and async, from the layout DocumentCollection writes, and lists the chain's pages. DynamicCollection uses it in ReadDocumentAt, ReadDocumentAtAsync and ScanAsync, and DeleteSlot frees the chain on commit (FreePageOnCommit, as DocumentCollection.FreeOverflowChain does) so a schema-less delete or relocating update of such a document leaks no pages. DynamicCollection still does not write overflow pages; the limit is now public as MaxDocumentSize and the rejection message names it. BLiteMigration copies into a DynamicCollection, so it refuses a document larger than MaxDocumentSize with a NotSupportedException naming the collection, _id and size, before writing it; on failure ToMultiFileAsync also removes the companion files (.idx, WAL directory, collection directory) it created, and ToSingleFileAsync removes a target it created. README notes the schema-less size limit. Tests: DynamicOverflowReadTests, 9 tests; 6 of the 8 that compile on upstream/main fail there (3 with the issue's exception). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mrdevrobot
requested changes
Oct 18, 2026
mrdevrobot
left a comment
Contributor
There was a problem hiding this comment.
Changes requested. Verified: the schema-less reads of overflow documents fail on 0450b97 and pass here. The PR adds an unrequested public DynamicCollection.MaxDocumentSize; make it internal (the tests see internals through InternalsVisibleTo) and drop the property name from the README note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Done in df2e66c: |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
A typed
DocumentCollectionstores a document larger than one page (about 16 KB with the default page size) across overflow pages. The schema-less API could not read such a collection:DynamicCollection.FindAllAsyncthrewNotSupportedException: Skipping type 69 not supported at position 7at the first large document, and so did everything built on it:FindByIdAsync,ScanAsync, BLQL, BLite Studio's collection view, andBLiteMigration.ToMultiFileAsync/ToSingleFileAsync, which copy every collection through the schema-less API (#301). The migration also left the empty multi-file layout (.idx,wal/,collections/) next to the source.Mechanism
A slot flagged
SlotFlags.HasOverflowholds[TotalLength (4)] [FirstOverflowPage (4)] [first chunk], and each overflow page holdsPageSize - SlottedPageHeader.Sizebytes after its header and names the next page inNextOverflowPage(DocumentCollection.InsertWithOverflow).DynamicCollectionnever checked the flag and handed the slot bytes toBsonSpanReaderas a document; byte 4 of the payload is a page id, not a BSON type.Fix
Storage/OverflowChainReader.cs(new, internal): reassembles the document from that layout, sync (Read) and async (ReadAsync, copying what it needs from the page buffer before the first await), returningnullrather than a partial document when a chain is inconsistent;ChainPageslists the chain's page ids and stops at a page that is not an overflow page. It is the same loopDocumentCollectionhas in three places (ReadRawBytesAt,ReadDocumentAt, its async twin); those are left as they are in this PR, so the typed hot path does not change.DynamicCollection:ReadDocumentAt,ReadDocumentAtAsyncandScanAsync(whose predicate now sees the whole document) use the reader. Every public read path goes through these three (FindAllAsync,FindByIdAsync,CountAsync,QueryIndexAsync, BLQL, the LINQ provider).DeleteSlotfrees the chain withFreePageOnCommit, asDocumentCollection.FreeOverflowChaindoes, so a schema-less delete, or an update that relocates the document (TryUpdateInPlacealready refuses a flagged slot), leaks no pages.DynamicCollectionstill does not write overflow pages. The limit is now public asDynamicCollection.MaxDocumentSize(page size minus header, slot and reserve), the rejection message names it, and the README's schema-less section says so. The write side is DynamicCollection cannot write a document larger than one page: no overflow on the schema-less write path #320; Moving from LiteDB: a guide, an API mapping and an import tool #297 (LiteDB import) will need it.BLiteMigration: before inserting a document into the targetDynamicCollection, a document larger thanMaxDocumentSizeis refused with aNotSupportedExceptionthat names the collection,_idand size and says the source is unchanged, instead of aBLiteValidationExceptionfrom insideInsertBulkAsync. On failureToMultiFileAsyncnow also removes the companion files it created (.idx, the WAL directory, the collection directory; ones that existed before the call are kept), andToSingleFileAsyncremoves a target file it created at another path.No format change. Overflow pages are read exactly as the typed API reads them; nothing is written differently.
Tests
DynamicOverflowReadTests, 9 tests. Each writes a small user and one with a 40,000-character name throughTestDbContext, then usesBLiteEngine:upstream/mainFindAllAsyncreturns both, the large one whole;CountAsyncis 2NotSupportedException: Skipping type 171FindByIdAsyncof the large oneEq,OrderByDescending, andGtethrough a new index onageScanAsyncpredicate sees all 40 KBMaxDocumentSizeis rejected naming the limitToMultiFileAsyncrefuses by collection and_id; source intact for both APIs; no.migrating,.idx, WAL or collection directory left.idx/wal//collections/remainFull suite
dotnet test tests/BLite.Tests(macOS, net10.0): 3101 passed, 0 failed, 4 skipped.BLite.Corealso builds fornetstandard2.1.Compatibility
Reads that threw now return the document.
DynamicCollection.MaxDocumentSizeis a new public property. The two rejection messages for an oversized write changed wording ("exceeds the N bytes a DynamicCollection document may occupy (one page)"); the exception type is unchanged.BLiteMigrationthrowsNotSupportedExceptionfor an oversized document where it threwNotSupportedExceptionfrom the BSON reader before.netstandard2.1and AOT are unaffected.Fixes #301
🤖 Generated with Claude Code