Repository navigation
Optimize collection iteration with shard cursors - #854
DanielThomas wants to merge 6 commits into
Conversation
85a3df2 to
5d705e4
Compare
e34d514 to
6f8658e
Compare
6f8658e to
8bbd80d
Compare
8bbd80d to
95970e1
Compare
95970e1 to
f421028
Compare
f421028 to
0219f34
Compare
|
List iteration, bidirectional iteration and spliteration now share the captured ordinal read logic. Splits have independent validation state. Map and set iterators capture size and bucket bounds together, and empty Java list traversal uses the JDK empty adapters. Added coverage for cached and proxy-backed lists, refreshes, parallel resharding and empty traversal. |
20b602a to
000050e
Compare
000050e to
caa71cf
Compare
Suggested fix for the PR: make HollowList.iterator() use delegate.ordinalCursor(ordinal) and fall back to super.iterator() when it returns null, the same way listIterator() does. Also add the getClass() check to HollowPerfBackedList.iterator(). Streams, copies, toString() and hashCode() all go through iterator(), so that one change fixes all of them. Extending lookupSubclassRetainsItsGetBasedListIterator to cover iterator() and stream() would catch it. |
|
@Sunjeet Fixed both iterator paths as suggested, so they preserve custom |
04bae6a to
c87275d
Compare
|
Wired the iterator opt-in through |
c87275d to
617c0b0
Compare
Collection iteration previously resolved the shard and collection bounds for every element or bucket and performed two trailing read validations. Snapshot iterators capture the shard and bounds once, then validate each surfaced element against the captured shard. For mutable on-heap states, a concurrent update or reshard causes the current read to be discarded and the snapshot to be reacquired before iteration continues. Concrete read states use the snapshot implementations while proxy, missing, and historical data access retain the generic iterators. Add correctness and concurrent resharding tests for list, set, and map iteration, plus JMH benchmarks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Retain the existing iterator implementation types while using single-object shard snapshot iterators. Preserve sampling and empty collection behavior, and make immutable shard validation a no-op. Add HollowConsumer.Builder.withSnapshotCollectionIterators() as an experimental opt-in. Existing collection iterators remain the default. Route HollowList iteration through delegates so lookup-backed lists use the selected ordinal iterator while cached lists retain their cached contents. Extend the benchmarks to cover recycling and wasteful allocators.
Use the delegate cursor opt-out for forward HollowList iteration and retain get-based traversal for perf-list subclasses. Remove the now-unnecessary Java 8 spliterator workaround. Cover streams, copies, equality and hashing for custom lookup/cached delegates and perf-list subclasses.
617c0b0 to
d8beb2e
Compare
This picks up Michael Braun's work from #842, preserving his authorship, and reconciles it with the read-path invariants introduced by the preceding PRs.
When enabled, it adds snapshot iterators for list, set, and map reads. A snapshot iterator captures its holder, shard, and collection bounds once, then reads subsequent elements or buckets directly from that shard instead of resolving them for every operation:
This also means that #345 is no longer a problem.
Benchmarks
Representative JMH measurements on JDK 25 with ZGC on this x86-64 host, traversing 2,000 lists in ordinal order per operation:
Immutable shards (
WastefulRecycler)Recycling shards
The set and map benchmarks also improved on this host, though the recycling cases varied more.