Repository navigation
DDIR half join: consolidate each released window within itself - #1029
Open
frankmcsherry wants to merge 1 commit into
Open
frankmcsherry wants to merge 1 commit into
frankmcsherry wants to merge 1 commit into
Conversation
The half join's batcher releases arrivals the arrangement's frontier already allows without staging them, which for a one-off reading an import is every arrival. `Part::runs` sorted each released window by identifier only, so a stream that repeats a row, as converging paths do, met the arrangement once per copy and handed every copy downstream; the binary join's arrangement of its stream side merges them first. Each window is now sorted by (identifier, key, value, time) and its equal rows merged, dropping rows that cancel. The presented key leads with the identifier, so runs stay in identifier order, and it holds the real key, so keys sharing an identifier never merge. Only rows already released together merge: nothing waits longer and nothing is routed through the ladder. The half join is linear in its stream, so this is exact. `TimeChunk::form` uses the same routine. On a three-hop friend-of-friend expansion over a graph where paths converge (1,000 nodes, 50 friends each, read as a one-off), the third hop's physical rows went from 115,941 to 44,734 per read, the binary joins' count, and a read from 5.3-5.5 ms to 3.0-3.2 ms, against 2.7-2.8 ms with binary joins. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_019XsakwFGwtESwZ1gSYwG4o
Member
Author
|
Checked on the LDBC Interactive v2 harness (#1010): SF1, 4 workers, M4. Each read is a one-off, installed, answered and dropped. Answers are identical to the binary-join plans in every case.
Built from this PR's head (f5b6993) and compared with master-next 7eb7da8. 🤖 Generated with Claude Code |
This branch has not been deployed
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.
A profile of LDBC's IC reads found the half join cheaper per row than the binary join (44 against 55 ns), but producing 2.3× more physical rows on ic1's friend hops, and 1.9× on ic13's loop join.
The cause is the batcher's fast path.
HalfJoinBatcherreleases arrivals the arrangement's frontier already allows without staging them, and for a one-off reading an import that is every arrival.Part::runsthen sorted each released window by identifier only, so a stream that repeats a row, as converging paths do, met the arrangement once per copy and handed every copy downstream. The binary join's arrangement of its stream side merges them first.Each released window is now sorted by (identifier, key, value, time), with its equal rows merged and rows that cancel dropped.
TimeChunk::form, on the ladder path, uses the same consolidation.Measurement
A three-hop friend-of-friend expansion as a one-off over an imported graph where paths converge (1,000 nodes, 50 friends each). One worker, release, three alternated runs of 30 reads each, with the probe kept out of the tree:
Here hop 3's whole input arrives in one release, so all of the excess goes. ic13's in-loop excess repeats across rounds, at different iteration times, so some of it may span releases. That needs the LDBC harness to confirm.
Tests
a_release_is_consolidated_within_itselfchecks that equal rows within one release merge, that cancelling rows vanish, and that nothing unblocked is held back. A later repeat comes out in its own extraction.cargo test -p interactive -p ddir-server, 212 passed; dogs3's tests pass.delta,split,bind,reinstallwith late installs, and 1,000 with all oracles: all passed.cargo check --all-targets, and clippy shows nothing new.#1027's count stage uses the same batcher, so its stream is consolidated within each window too.
🤖 Generated with Claude Code
https://claude.ai/code/session_019XsakwFGwtESwZ1gSYwG4o