@@ -292,11 +292,13 @@ extension DiskPersistence.Datastore.Index {
292292 /// - Parameters:
293293 /// - proposedEntry: The entry to use in comparison with other persisted entries.
294294 /// - pages: A collection of pages to check against.
295+ /// - pageBuilder: A closure that provides a cached Page object for the loaded page.
295296 /// - comparator: A comparator to determine order and equality between the proposed entry and a persisted one.
296297 /// - Returns: The index within the pages collection where the entry would reside.
297298 func pageIndex< T> (
298299 for proposedEntry: T ,
299- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
300+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
301+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
300302 comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
301303 ) async throws -> Int ? {
302304 var slice = pages [ ... ]
@@ -316,41 +318,45 @@ extension DiskPersistence.Datastore.Index {
316318 var firstEntryOfPage : DatastorePageEntry ?
317319
318320 /// Start checking the page at the middle index, continuing to scan until we build up enough of an entry to compare to.
319- pageIterator: for page in pages [ middle... ] {
320- guard let page else { continue }
321- let blocks = try await page. value. blocks
322-
323- /// Start scanning the page block-by-block, continuing to scan until we build up enough of an entry to compare to.
324- for try await block in blocks {
325- switch block {
326- case . complete( let bytes) :
327- /// We have a complete entry, lets use it and stop scanning
328- firstEntryOfPage = try DatastorePageEntry ( bytes: bytes, isPartial: false )
329- break pageIterator
330- case . head( let bytes) :
331- /// We are starting an entry, but will need to go to the next page.
332- bytesForFirstEntry = bytes
333- case . slice( let bytes) :
334- /// In the first position, lets skip it.
335- guard bytesForFirstEntry != nil else { continue }
336- /// In the final position, lets save and continue.
337- bytesForFirstEntry? . append ( contentsOf: bytes)
338- case . tail( let bytes) :
339- /// In the first position, lets skip it.
340- guard bytesForFirstEntry != nil else { continue }
341- /// In the final position, lets save and stop.
342- bytesForFirstEntry? . append ( contentsOf: bytes)
343- firstEntryOfPage = try DatastorePageEntry ( bytes: bytesForFirstEntry!, isPartial: false )
344- break pageIterator
345- }
321+ pageIterator: for pageInfo in pages [ middle... ] {
322+ switch pageInfo {
323+ case . removed: break
324+ case . added( let pageID) , . existing( let pageID) :
325+ let page = await pageBuilder ( pageID)
326+ let blocks = try await page. blocks
346327
347- /// If we have some bytes, attempt to decode them into an entry.
348- if let bytesForFirstEntry {
349- firstEntryOfPage = try ? DatastorePageEntry ( bytes: bytesForFirstEntry, isPartial: false )
328+ /// Start scanning the page block-by-block, continuing to scan until we build up enough of an entry to compare to.
329+ for try await block in blocks {
330+ switch block {
331+ case . complete( let bytes) :
332+ /// We have a complete entry, lets use it and stop scanning
333+ firstEntryOfPage = try DatastorePageEntry ( bytes: bytes, isPartial: false )
334+ break pageIterator
335+ case . head( let bytes) :
336+ /// We are starting an entry, but will need to go to the next page.
337+ bytesForFirstEntry = bytes
338+ case . slice( let bytes) :
339+ /// In the first position, lets skip it.
340+ guard bytesForFirstEntry != nil else { continue }
341+ /// In the final position, lets save and continue.
342+ bytesForFirstEntry? . append ( contentsOf: bytes)
343+ case . tail( let bytes) :
344+ /// In the first position, lets skip it.
345+ guard bytesForFirstEntry != nil else { continue }
346+ /// In the final position, lets save and stop.
347+ bytesForFirstEntry? . append ( contentsOf: bytes)
348+ firstEntryOfPage = try DatastorePageEntry ( bytes: bytesForFirstEntry!, isPartial: false )
349+ break pageIterator
350+ }
351+
352+ /// If we have some bytes, attempt to decode them into an entry.
353+ if let bytesForFirstEntry {
354+ firstEntryOfPage = try ? DatastorePageEntry ( bytes: bytesForFirstEntry, isPartial: false )
355+ }
356+
357+ /// If we have an entry, stop scanning as we can go ahead and operate on it.
358+ if firstEntryOfPage != nil { break pageIterator }
350359 }
351-
352- /// If we have an entry, stop scanning as we can go ahead and operate on it.
353- if firstEntryOfPage != nil { break pageIterator }
354360 }
355361
356362 /// If we had to advance a page and didn't yet start accumulating data, move our middle since it would be pointless to check that page again if the proposed entry was ordered after the persisted one we found.
@@ -390,30 +396,48 @@ extension DiskPersistence.Datastore.Index {
390396 cursor: DiskPersistence . InstanceCursor ,
391397 entry: DatastorePageEntry
392398 ) {
393- try await entry ( for: proposedEntry, in: try await orderedPages, comparator: comparator)
399+ try await entry (
400+ for: proposedEntry,
401+ in: try await manifest. orderedPages,
402+ pageBuilder: { await datastore. page ( for: . init( index: self . id, page: $0) ) } ,
403+ comparator: comparator
404+ )
394405 }
395406
396407 func entry< T> (
397408 for proposedEntry: T ,
398- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
409+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
410+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
399411 comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
400412 ) async throws -> (
401413 cursor: DiskPersistence . InstanceCursor ,
402414 entry: DatastorePageEntry
403415 ) {
404416 /// Get the page the entry should reside on
405- guard let startingPageIndex = try await pageIndex ( for: proposedEntry, in: pages, comparator: comparator)
417+ guard
418+ let startingPageIndex = try await pageIndex (
419+ for: proposedEntry,
420+ in: pages,
421+ pageBuilder: pageBuilder,
422+ comparator: comparator
423+ )
406424 else { throw DatastoreInterfaceError . instanceNotFound }
407425
408426 var bytesForEntry : Bytes ?
409427 var isEntryComplete = false
410428 var blocksForEntry : [ DiskPersistence . CursorBlock ] = [ ]
411429 var pageIndex = startingPageIndex
412430
413- pageIterator: for lazyPage in pages [ startingPageIndex... ] {
431+ pageIterator: for pageInfo in pages [ startingPageIndex... ] {
414432 defer { pageIndex += 1 }
415- guard let lazyPage else { continue }
416- let page = await lazyPage. value
433+
434+ let page : DiskPersistence . Datastore . Page
435+ switch pageInfo {
436+ case . removed: continue
437+ case . existing( let pageID) , . added( let pageID) :
438+ page = await pageBuilder ( pageID)
439+ }
440+
417441 let blocks = try await page. blocks
418442 var blockIndex = 0
419443
@@ -484,16 +508,28 @@ extension DiskPersistence.Datastore.Index {
484508 for proposedEntry: T ,
485509 comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
486510 ) async throws -> DiskPersistence . InsertionCursor {
487- try await insertionCursor ( for: proposedEntry, in: try await orderedPages, comparator: comparator)
511+ try await insertionCursor (
512+ for: proposedEntry,
513+ in: try await manifest. orderedPages,
514+ pageBuilder: { await datastore. page ( for: . init( index: self . id, page: $0) ) } ,
515+ comparator: comparator
516+ )
488517 }
489518
490519 func insertionCursor< T> (
491520 for proposedEntry: T ,
492- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
521+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
522+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
493523 comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
494524 ) async throws -> DiskPersistence . InsertionCursor {
495525 /// Get the page the entry should reside on
496- guard let startingPageIndex = try await pageIndex ( for: proposedEntry, in: pages, comparator: comparator)
526+ guard
527+ let startingPageIndex = try await pageIndex (
528+ for: proposedEntry,
529+ in: pages,
530+ pageBuilder: pageBuilder,
531+ comparator: comparator
532+ )
497533 else {
498534 return DiskPersistence . InsertionCursor (
499535 persistence: datastore. snapshot. persistence,
@@ -509,10 +545,16 @@ extension DiskPersistence.Datastore.Index {
509545 var currentBlock : DiskPersistence . CursorBlock ? = nil
510546 var pageIndex = startingPageIndex
511547
512- pageIterator: for lazyPage in pages [ startingPageIndex... ] {
548+ pageIterator: for pageInfo in pages [ startingPageIndex... ] {
513549 defer { pageIndex += 1 }
514- guard let lazyPage else { continue }
515- let page = await lazyPage. value
550+
551+ let page : DiskPersistence . Datastore . Page
552+ switch pageInfo {
553+ case . removed: continue
554+ case . existing( let pageID) , . added( let pageID) :
555+ page = await pageBuilder ( pageID)
556+ }
557+
516558 let blocks = try await page. blocks
517559 var blockIndex = 0
518560
0 commit comments