Skip to content

perf(shared): class-based BTree iterators#5607

Draft
Karavil wants to merge 1 commit intorocicorp:mainfrom
goblinshq:perf/btree-iterators
Draft

perf(shared): class-based BTree iterators#5607
Karavil wants to merge 1 commit intorocicorp:mainfrom
goblinshq:perf/btree-iterators

Conversation

@Karavil
Copy link
Contributor

@Karavil Karavil commented Feb 25, 2026

Note: This PR was generated by Claude (Anthropic) and has not been
reviewed by @Karavil. It is part of an upstream contribution effort from
the Goblins team.

Summary

Replace closure-based BTree iterators with class-based BTreeForwardIterator and BTreeReverseIterator.

Motivation

BTree iterators are on the hot path for every index scan in the IVM pipeline. In a workload with 135 IVM pipelines each scanning ~200 rows, these iterators are instantiated and advanced thousands of times per page render.

The current implementation uses closures (iterator(() => {...})) which capture mutable state in closure variables. V8 optimizes property access on class instances better than captured closure variables, particularly for hot iteration paths where the JIT compiler can inline property access more effectively.

Changes

  • Add BTreeForwardIterator<K> class implementing IterableIterator<K> with traversal state (_nodeQueue, _nodeIndex, _leaf, _i) as instance properties
  • Add BTreeReverseIterator<K> class implementing IterableIterator<K> with the same pattern
  • Modify valuesFrom() to return a class instance instead of a closure-based iterator
  • Modify valuesFromReversed() to return a class instance
  • Keep the iterator() helper for the empty-tree edge case (where findPath returns undefined)

Expected Performance Impact

Each BTree scan creates one iterator and calls .next() for every row visited. With class-based iterators, V8 can create a hidden class for the iterator and optimize property access into direct memory offsets, whereas closure variable access goes through the scope chain. The improvement is per-.next() call, compounding across thousands of iterations per page render.

Testing

  • All 22 existing btree-set tests pass
  • New tests for: forward/reverse equivalence (100 elements), empty tree iterator, single element, [Symbol.iterator] returns self

Class-based iterators (BTreeForwardIterator/BTreeReverseIterator) store
traversal state in instance properties instead of closure variables,
which V8 optimizes better for hot iteration paths.

Part of IVM pipeline perf optimizations that reduced page freeze from
~7.7s to <1s in a production app.

* Add BTreeForwardIterator<K> class with next() and [Symbol.iterator]()
* Add BTreeReverseIterator<K> class with next() and [Symbol.iterator]()
* Modify valuesFrom() to return BTreeForwardIterator
* Modify valuesFromReversed() to return BTreeReverseIterator
* Keep iterator() helper for empty-tree case
@vercel
Copy link

vercel bot commented Feb 25, 2026

Someone is attempting to deploy a commit to the Rocicorp Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant