Skip to content

Commit f54712c

Browse files
Added fast paths for scanning from the beginning or end of an index
1 parent e4d8f32 commit f54712c

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,52 @@ extension DiskPersistence.Datastore.Index {
491491
throw DatastoreInterfaceError.instanceNotFound
492492
}
493493

494+
var firstInsertionCursor: DiskPersistence.InsertionCursor {
495+
get {
496+
DiskPersistence.InsertionCursor(
497+
persistence: datastore.snapshot.persistence,
498+
datastore: datastore,
499+
index: self,
500+
insertAfter: nil
501+
)
502+
}
503+
}
504+
505+
var lastInsertionCursor: DiskPersistence.InsertionCursor {
506+
get async throws {
507+
let pages = try await manifest.orderedPages
508+
var pageIndex = pages.count - 1
509+
510+
for pageInfo in pages.reversed() {
511+
defer { pageIndex -= 1 }
512+
513+
let page: DiskPersistence.Datastore.Page
514+
switch pageInfo {
515+
case .removed: continue
516+
case .existing(let pageID), .added(let pageID):
517+
page = await datastore.page(for: .init(index: self.id, page: pageID))
518+
}
519+
520+
let blocks = try await page.blocks.reduce(into: []) { $0.append($1) }
521+
guard !blocks.isEmpty else { throw DiskPersistenceError.invalidPageFormat }
522+
523+
return DiskPersistence.InsertionCursor(
524+
persistence: datastore.snapshot.persistence,
525+
datastore: datastore,
526+
index: self,
527+
insertAfter: DiskPersistence.CursorBlock(
528+
pageIndex: pageIndex,
529+
page: page,
530+
blockIndex: blocks.count - 1
531+
)
532+
)
533+
}
534+
535+
/// Couldn't find a last page, so the cursor is the same as the first insertion cursor.
536+
return firstInsertionCursor
537+
}
538+
}
539+
494540
func insertionCursor<T>(
495541
for proposedEntry: T,
496542
comparator: (_ lhs: T, _ rhs: DatastorePageEntry) throws -> SortOrder

Sources/CodableDatastore/Persistence/Disk Persistence/Transaction/Transaction.swift

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -658,10 +658,15 @@ extension DiskPersistence.Transaction {
658658

659659
switch range.order {
660660
case .ascending:
661-
let startCursor = try await index.insertionCursor(
662-
for: (range.lowerBoundExpression, range.order),
663-
comparator: primaryIndexBoundComparator
664-
)
661+
let startCursor: DiskPersistence.InsertionCursor
662+
if range.lowerBoundExpression == .extent {
663+
startCursor = await index.firstInsertionCursor
664+
} else {
665+
startCursor = try await index.insertionCursor(
666+
for: (range.lowerBoundExpression, range.order),
667+
comparator: primaryIndexBoundComparator
668+
)
669+
}
665670

666671
try await index.forwardScanEntries(after: startCursor) { entry in
667672
guard case .descending = try primaryIndexBoundComparator(
@@ -677,10 +682,15 @@ extension DiskPersistence.Transaction {
677682
return true
678683
}
679684
case .descending:
680-
let startCursor = try await index.insertionCursor(
681-
for: (range.upperBoundExpression, range.order),
682-
comparator: primaryIndexBoundComparator
683-
)
685+
let startCursor: DiskPersistence.InsertionCursor
686+
if range.upperBoundExpression == .extent {
687+
startCursor = try await index.lastInsertionCursor
688+
} else {
689+
startCursor = try await index.insertionCursor(
690+
for: (range.upperBoundExpression, range.order),
691+
comparator: primaryIndexBoundComparator
692+
)
693+
}
684694

685695
try await index.backwardScanEntries(before: startCursor) { entry in
686696
guard case .ascending = try primaryIndexBoundComparator(

0 commit comments

Comments
 (0)