Skip to content

Batch consecutive same-RPC recipes via BatchVisit RPC#6983

Merged
jkschneider merged 8 commits intomainfrom
defer-getobject-consecutive-rpc-recipes
Mar 15, 2026
Merged

Batch consecutive same-RPC recipes via BatchVisit RPC#6983
jkschneider merged 8 commits intomainfrom
defer-getobject-consecutive-rpc-recipes

Conversation

@jkschneider
Copy link
Member

@jkschneider jkschneider commented Mar 13, 2026

Summary

When a composite recipe has consecutive sub-recipes that all run on the same RPC peer, the scheduler now batches them into a single BatchVisit RPC call instead of sending individual Visit + GetObject round-trips for each one.

  • New BatchVisit RPC method runs N visitors in sequence on the remote and returns per-visitor metadata (modified, deleted, searchResultIds)
  • Host accumulates BatchVisitItem entries for consecutive same-RPC recipes and sends one BatchVisit at the batch boundary
  • For edits: one GetObject fetches the final tree state at the end of the batch
  • For scans: no GetObject needed (scan results are discarded)
  • SearchResult attribution uses marker ID diffing on the remote — each result entry reports which SearchResult UUIDs were added by that visitor

For N consecutive same-RPC recipes, this reduces N Visit RPCs + N GetObject RPCs down to 1 BatchVisit RPC + 1 GetObject RPC.

Changes

New files:

  • BatchVisit.java — request class with BatchVisitItem, plus Handler that runs visitors in sequence and diffs SearchResult marker IDs
  • BatchVisitResponse.java — per-visitor result with modified, deleted, hasNewMessages, searchResultIds
  • batch-visit.ts — TypeScript BatchVisit handler

Core changes:

  • RewriteRpc.javabatchVisit() method, register "BatchVisit" handler
  • RpcRecipe.java@Getter on rpc, editVisitor, scanVisitor fields (needed to build batch items without triggering individual Visit RPCs)
  • RecipeRunCycle.javaBatchState for edit and scan phases; flushBatch() sends one BatchVisit + one GetObject and builds per-recipe attribution from response; flushScanBatch() for scan phase
  • RecipeStack.javanextRecipe lookahead (used for batch boundary detection)

Remote handlers (~50 lines each):

  • Python server.pyhandle_batch_visit() + _collect_search_result_ids()
  • C# RewriteRpcServer.cs[JsonRpcMethod("BatchVisit")] handler + CollectSearchResultIds()

Test plan

  • consecutiveSameRpcRecipesAreBatchedAndProduceCorrectResult — two consecutive same-RPC recipes
  • threeConsecutiveSameRpcRecipes — three consecutive same-RPC recipes
  • sameRpcBatchFollowedByNonRpcRecipe — batch flush at RPC/non-RPC boundary
  • singleRpcRecipeNoBatch — single RPC recipe uses normal Visit path
  • Full rewrite-core test suite passes

When a composite recipe has consecutive RPC-based recipes (e.g., all C#),
skip the host-side getObject() call between them, letting the remote keep
the modified tree in localObjects. The tree is fetched once at the end of
the batch, saving 2N-2 GetObject round-trips per source file for N
consecutive same-RPC recipes.

Key changes:
- Add `deleted` field to VisitResponse across all languages
- Add SearchResult recipe attribution via recipeName RPC field
- Add deferral logic to RewriteRpc (deferGetObject, fetchDeferredResult)
- Add batch detection and flush logic to RecipeRunCycle
- Add nextRecipe lookahead to RecipeStack
- Update C#/Python/JS Visit handlers to check localObjects first
- Add integration tests for deferral scenarios
Instead of deferring GetObject calls between individual Visit RPCs for
consecutive same-RPC recipes (which required 6 mutable fields, recipeName
on SearchResult in 3 languages, and RpcReceiveQueue interception), use a
single BatchVisit RPC that runs N visitors in sequence on the remote and
returns per-visitor metadata (modified, deleted, newSearchResultIds).

The host accumulates BatchVisitItem entries and sends one BatchVisit at
the batch boundary. For edits, one getObject fetches the final tree.
For scans, no getObject is needed. SearchResult attribution comes from
diffing marker IDs before/after each visitor on the remote side.
@jkschneider jkschneider changed the title Defer GetObject for consecutive same-RPC recipes Replace deferred GetObject with BatchVisit RPC Mar 15, 2026
Collect SearchResult IDs once before the loop and maintain a running
set, avoiding redundant full-tree walks on each iteration.
@jkschneider jkschneider changed the title Replace deferred GetObject with BatchVisit RPC Batch consecutive same-RPC recipes via BatchVisit RPC Mar 15, 2026
Port the Java visitor's prefix and marker visitation to C#:
- Add VisitSpace, VisitMarkers, and VisitMarker virtual methods to JavaVisitor<P>
- Wire VisitSpace and VisitMarkers into all visit methods in JavaVisitor and CSharpVisitor
- Revert SearchResultCollector to use VisitMarker override (no longer needs Accept workaround)
Remove externs/attributeLists visiting from CompilationUnit and
NamespaceDeclaration (those fields don't exist on main yet).
Keep prefix/markers visiting for all methods.
@jkschneider jkschneider merged commit 4026a11 into main Mar 15, 2026
0 of 2 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in OpenRewrite Mar 15, 2026
@jkschneider jkschneider deleted the defer-getobject-consecutive-rpc-recipes branch March 15, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant