@@ -292,11 +292,13 @@ extension DiskPersistence.Datastore.Index {
292
292
/// - Parameters:
293
293
/// - proposedEntry: The entry to use in comparison with other persisted entries.
294
294
/// - pages: A collection of pages to check against.
295
+ /// - pageBuilder: A closure that provides a cached Page object for the loaded page.
295
296
/// - comparator: A comparator to determine order and equality between the proposed entry and a persisted one.
296
297
/// - Returns: The index within the pages collection where the entry would reside.
297
298
func pageIndex< T> (
298
299
for proposedEntry: T ,
299
- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
300
+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
301
+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
300
302
comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
301
303
) async throws -> Int ? {
302
304
var slice = pages [ ... ]
@@ -316,41 +318,45 @@ extension DiskPersistence.Datastore.Index {
316
318
var firstEntryOfPage : DatastorePageEntry ?
317
319
318
320
/// 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
346
327
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 }
350
359
}
351
-
352
- /// If we have an entry, stop scanning as we can go ahead and operate on it.
353
- if firstEntryOfPage != nil { break pageIterator }
354
360
}
355
361
356
362
/// 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 {
390
396
cursor: DiskPersistence . InstanceCursor ,
391
397
entry: DatastorePageEntry
392
398
) {
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
+ )
394
405
}
395
406
396
407
func entry< T> (
397
408
for proposedEntry: T ,
398
- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
409
+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
410
+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
399
411
comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
400
412
) async throws -> (
401
413
cursor: DiskPersistence . InstanceCursor ,
402
414
entry: DatastorePageEntry
403
415
) {
404
416
/// 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
+ )
406
424
else { throw DatastoreInterfaceError . instanceNotFound }
407
425
408
426
var bytesForEntry : Bytes ?
409
427
var isEntryComplete = false
410
428
var blocksForEntry : [ DiskPersistence . CursorBlock ] = [ ]
411
429
var pageIndex = startingPageIndex
412
430
413
- pageIterator: for lazyPage in pages [ startingPageIndex... ] {
431
+ pageIterator: for pageInfo in pages [ startingPageIndex... ] {
414
432
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
+
417
441
let blocks = try await page. blocks
418
442
var blockIndex = 0
419
443
@@ -484,16 +508,28 @@ extension DiskPersistence.Datastore.Index {
484
508
for proposedEntry: T ,
485
509
comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
486
510
) 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
+ )
488
517
}
489
518
490
519
func insertionCursor< T> (
491
520
for proposedEntry: T ,
492
- in pages: [ LazyTask < DiskPersistence . Datastore . Page > ? ] ,
521
+ in pages: [ DatastoreIndexManifest . PageInfo ] ,
522
+ pageBuilder: ( _ pageID: DatastorePageIdentifier ) async -> DiskPersistence . Datastore . Page ,
493
523
comparator: ( _ lhs: T , _ rhs: DatastorePageEntry ) throws -> SortOrder
494
524
) async throws -> DiskPersistence . InsertionCursor {
495
525
/// 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
+ )
497
533
else {
498
534
return DiskPersistence . InsertionCursor (
499
535
persistence: datastore. snapshot. persistence,
@@ -509,10 +545,16 @@ extension DiskPersistence.Datastore.Index {
509
545
var currentBlock : DiskPersistence . CursorBlock ? = nil
510
546
var pageIndex = startingPageIndex
511
547
512
- pageIterator: for lazyPage in pages [ startingPageIndex... ] {
548
+ pageIterator: for pageInfo in pages [ startingPageIndex... ] {
513
549
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
+
516
558
let blocks = try await page. blocks
517
559
var blockIndex = 0
518
560
0 commit comments