Conversation
tamirms
added a commit
to stellar/stellar-rpc
that referenced
this pull request
Sep 12, 2026
eval narrowed a per-filter accumulator through the filter's groups one AndAny at a time, so every filter paid an 8 KiB accumulator on every slab even when its groups had nothing in common there, and a topic-count range paid its union on top. A filter now yields plans that are conjunctions of single terms, one per bucket of a range, since A and (b or c) is (A and b) or (A and c) and the union across plans keeps the or; the planner drops a plan that repeats an earlier one. The slab engine then holds one bitmap per term, runs one FastAnd over the slab's id range and the terms per plan, keeps its bounds as the searches return them, and counts each term's cardinality once. The slab bitmap is built once per slab and shared by every plan. With the pinned roaring, FastAnd intersects pairwise and the cost is unchanged or lower. With roaring's count-first intersections (RoaringBitmap/roaring#566 and the FastAnd follow-up built on it) an empty result allocates nothing, which is what bounds the slab walk on filter lists that match nothing; the version bump will add the contract test for that. roaring_contract_test.go now pins that FastAnd leaves its inputs untouched, returns fresh containers on the two- and many-input paths over whole and partial slab ranges, and agrees with the pairwise And chain for every subset of the container kinds; that a slab range built with AddRange is stored as run containers; and runs FastAnd in the concurrent-readers race gate. The AndAny pins go, since the engine no longer calls it. The shaped differential matrix gains a filter with a term and a count range, and a planner test covers the fan-out and the dedup. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M23ZvEkyrFjyUUbm7zLwob
tamirms
force-pushed
the
pr1-run-and-count-first
branch
from
September 14, 2026 20:47
0ffe5f3 to
2a85570
Compare
…ions
runContainer16.andBitmapContainer materialized the run as an 8 KiB bitmap
container and then intersected, so an empty or array-sized result paid
for a bitmap it never returned. It now counts the result with the existing
andBitmapContainerCardinality and builds only that: an empty array
container when the intersection is empty, an array of the right size when
it is small, and the bitmap only when the result is one. A run with more
than 64 intervals is ORed into a scratch bitmap on the stack, counted
there, and extracted in one pass instead.
bitmapContainer.iandRun16 did the same conversion on the argument side. It
now counts the same way, returns a small result as an array built from
the run's intervals, and otherwise clears the gaps between intervals in
place; past 64 intervals the run is built in stack scratch and ANDed in
one flat pass, since clearing gap by gap costs a call per interval.
runContainer16.intersects computed rc.and(a) and tested the result for
emptiness, allocating a container to answer a boolean; every mixed
pairing with a run reached it through the array and bitmap dispatchers.
It now walks the run's intervals against the other container, a masked
word scan for bitmaps, a galloping merge for arrays or a probe per value
when the array is much smaller than the interval list, an interval
overlap test for runs, each returning at the first shared value.
BenchmarkRunAndBitmap (added): And, in-place And and Intersects between a
run-optimized bitmap and a dense one over a single key. Xeon 8375C:
before after
And, empty result 3.0 µs 8328 B/op 4 allocs 594 ns 104 B/op 2 allocs
And, array result 8.3 µs 14504 B/op 8 allocs 4.6 µs 6280 B/op 6 allocs
And, bitmap result 4.6 µs 16560 B/op 8 allocs 3.6 µs 8336 B/op 6 allocs
And, 1024-interval run, array 11.9 µs 12456 B/op 8 allocs 10.0 µs 4232 B/op 6 allocs
And, 1024-interval run, bitmap 9.5 µs 16560 B/op 8 allocs 7.6 µs 8336 B/op 6 allocs
in-place And, bitmap result 2.4 µs 8224 B/op 2 allocs 290 ns 0 B/op 0 allocs
in-place And, 1024-interval run 7.3 µs 8224 B/op 2 allocs 4.6 µs 0 B/op 0 allocs
Intersects, disjoint 3.0 µs 8248 B/op 3 allocs 121 ns 0 B/op 0 allocs
Intersects, overlapping 8.3 µs 14392 B/op 4 allocs 8 ns 0 B/op 0 allocs
Intersects, few values, 1024 intervals 1.3 µs 32 B/op 2 allocs 62 ns 0 B/op 0 allocs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tamirms
force-pushed
the
pr1-run-and-count-first
branch
from
September 15, 2026 05:44
2a85570 to
3fe980c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Three run-container paths build an 8 KiB bitmap container before they know whether the result is empty, an array, or a bitmap. This counts or tests first, then allocates only what is returned.
Type of Change
Changes Made
What was changed?
runContainer16.andBitmapContainercounts the intersection with the existingandBitmapContainerCardinality, then builds an empty array container, an exact-size array, or a bitmap, whichever the count calls for.bitmapContainer.iandRun16counts the same way, returns a small result as an array built from the run's intervals, and otherwise clears the gaps between intervals in place.runContainer16.intersectswalks the run's intervals against the other container and returns at the first shared value, rather than building a container to answer a boolean.clearBitmapGapsandcontainerFromWordsfor the shared pieces, andrunbitmap_and_test.gowith tests andBenchmarkRunAndBitmap.Why was it changed?
andBitmapContainerconverted the run to a bitmap container and ANDed, so an empty or array-sized result paid for a bitmap it never returned.iandRun16did the same conversion on the argument side.intersectscomputedrc.and(a)and tested the result for emptiness, allocating a container to answer a boolean. Every mixed pairing with a run reaches it through the array and bitmap dispatchers, so this sits on the path of everyIntersectscall that touches a run.How was it changed?
bitmapContainer.andBitmap, which already does this.iandRun16also builds the run in stack scratch and ANDs in one flat pass, since clearing gap by gap costs a call per interval.intersectsuses a masked word scan for bitmaps, a galloping merge for arrays or a probe per value when the array is much smaller than the interval list, and an interval overlap test for runs.Testing
runbitmap_and_test.gochecks each path against its old definition,newBitmapContainerFromRun(rc).andBitmap(bc)and!rc.and(c).isEmpty(), over random container pairs and the edges: empty run, full run, intervals on word boundaries, results at the array and bitmap threshold, runs with hundreds of intervals, and a few values against many intervals. It also asserts that the empty and boolean paths allocate no container.All pass on linux/amd64 and darwin/arm64.
Formatting
gofmt -s -l .reports nothing.go vet ./...reports only the pre-existingReadFromsignature complaint on master.Fuzzing
The step above cannot be run as written: there is no
FuzzSmattarget on master.smat.gorefers to asmat_fuzz_test.gothat is not in the repository, sogo test -fuzz=FuzzSmatmatches nothing and simply runs the ordinary tests. What does run is the smat corpus, which passes:Performance Impact
BenchmarkRunAndBitmapis added:And, in-placeAndandIntersectsbetween a run-optimized bitmap and a dense one over a single key. Xeon 8375C.Performance Analysis
BenchmarkIntersection*,BenchmarkUnion*andBenchmarkAndAny/*do not reach these paths and are unchanged.Breaking Changes
None. No API change.
Related Issues
None.
Additional Notes
bitmapContainer.iandArrayhas the same conversion for arrays and is left for a separate change.🤖 Generated with Claude Code