Skip to content

fix(kvblock): early-stop lookup on missing key or empty filtered pods - #2713

Open
quangh33 wants to merge 4 commits into
llm-d:mainfrom
quangh33:fix-kvblock-lookup-early-stop
Open

fix(kvblock): early-stop lookup on missing key or empty filtered pods#2713
quangh33 wants to merge 4 commits into
llm-d:mainfrom
quangh33:fix-kvblock-lookup-early-stop

Conversation

@quangh33

@quangh33 quangh33 commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?
/kind bug

What this PR does / why we need it:
In-memory and cost-aware memory index implementations (InMemoryIndex and CostAwareMemoryIndex) did not early-stop when a key in requestKeys was not found (!found) or when filtering against podIdentifierSet resulted in an empty pod list. Instead, they logged a message and continued traversing remaining keys. This is inconsistent with the behavior in RedisIndex.

Because Index.Lookup represents a contiguous prefix-cache lookup (longest prefix match), breaking the prefix chain at any key invalidates subsequent keys and must terminate traversal immediately, matching the behavior of RedisIndex.

This PR:

  • Adds early return (return podsPerKey, nil) on missing keys and empty filtered pod slices in InMemoryIndex.Lookup and CostAwareMemoryIndex.Lookup.
  • Adds EarlyStopOnMiss and EarlyStopOnFilteredEmpty test cases to testCommonIndexBehavior in index_test.go to enforce prefix-break early-stop semantics across all Index backends.
  • Updates TestInMemoryIndexSize and TestCostAwareIndexSize to query evicted keys and remaining cached keys independently, respecting prefix lookup semantics.

Which issue(s) this PR fixes:
Fixes #

Release note (write NONE if no user-facing change):
NONE

@github-actions github-actions Bot added area/kvcache size/L Denotes a PR that changes 100-499 lines, ignoring generated files. kind/bug Categorizes issue or PR as related to a bug. labels Sep 6, 2026
@quangh33
quangh33 marked this pull request as ready for review September 6, 2026 07:44
@github-actions github-actions Bot added kind/bug Categorizes issue or PR as related to a bug. and removed kind/bug Categorizes issue or PR as related to a bug. labels Sep 6, 2026
@vMaroon vMaroon self-assigned this Sep 6, 2026
@yankay

yankay commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

I found one telemetry issue: early termination changes blocks_found and block_hit_ratio for [hit, miss, hit]. Could you add a regression test? I found no other correctness issues or performance regressions. Do you have benchmark data quantifying the improvement?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The updated cost-aware size test asserts a specific eviction outcome for a Ristretto-backed cache, which is not guaranteed and risks test flakiness.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR aligns the in-memory KV-block index backends (InMemoryIndex and CostAwareMemoryIndex) with the prefix-chain semantics already used by RedisIndex.Lookup, ensuring lookups early-stop when the prefix breaks (missing key or filter produces no matching pods).

Changes:

  • Early-return from Lookup on missing keys and on empty filtered pod results in InMemoryIndex and CostAwareMemoryIndex.
  • Add common behavior tests to enforce early-stop semantics across all Index implementations.
  • Update in-memory and cost-aware size/eviction tests to avoid multi-key lookups that violate prefix lookup semantics.
File summaries
File Description
pkg/kvcache/kvblock/index_test.go Adds common tests for early-stop behavior on misses and filter-empty results.
pkg/kvcache/kvblock/in_memory.go Implements early-stop on missing key and empty filtered pod list during prefix lookup.
pkg/kvcache/kvblock/in_memory_test.go Adjusts eviction test to query evicted and remaining keys in separate lookups.
pkg/kvcache/kvblock/cost_aware_memory.go Implements early-stop on missing key and empty filtered pod list during prefix lookup.
pkg/kvcache/kvblock/cost_aware_memory_test.go Updates eviction test to use separate lookups consistent with prefix semantics.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/kvcache/kvblock/cost_aware_memory_test.go Outdated
@quangh33

quangh33 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

I found one telemetry issue: early termination changes blocks_found and block_hit_ratio for [hit, miss, hit]. Could you add a regression test? I found no other correctness issues or performance regressions. Do you have benchmark data quantifying the improvement?

@yankay I added TestScoreTokensBlockHitTelemetryEarlyTermination in pkg/kvcache/indexer_trace_test.go to verify the tememetry.

@yankay

yankay commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Thanks! Since #2680 changed this lookup path, could you rebase onto the latest main and check whether this PR is still needed? It may now be superseded by #2680.

In-memory and cost-aware memory index implementations continued traversing
subsequent request keys when a key was not found or when filtering by pod
identifiers yielded no matches. Because KV block lookup represents a
contiguous prefix match, breaking the prefix chain invalidates subsequent
keys and must terminate the search immediately, matching RedisIndex.

Signed-off-by: quangh33 <quanghd.95vn@gmail.com>
…rly termination

Early termination in Index.Lookup cuts the block search at the first
missing key. Verify that keys after the miss do not count towards
blocks_found and block_hit_ratio for a [hit, miss, hit] sequence.

Signed-off-by: quangh33 <quanghd.95vn@gmail.com>
CostAwareMemoryIndex uses Ristretto TinyLFU admission and sampled eviction,
which can reject incoming keys rather than strictly evicting earlier keys
in LRU order. Assert total retained key count instead of specific key
presence.

Signed-off-by: quangh33 <quanghd.95vn@gmail.com>
@quangh33
quangh33 force-pushed the fix-kvblock-lookup-early-stop branch from f1522da to abefe4a Compare September 11, 2026 12:19
@quangh33

Copy link
Copy Markdown
Contributor Author

Thanks! Since #2680 changed this lookup path, could you rebase onto the latest main and check whether this PR is still needed? It may now be superseded by #2680.

@yankay this PR is still needed because #2680 only implemented KeyWalker for InMemoryIndex.

traceLogger.Info("no pods found for key, cutting search", "key", requestKey)
}
continue
return podsPerKey, nil // early stop since prefix-chain breaks here

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for rebasing this. The new missing-key return bypasses the final ctx.Err() check. Cancellation after the last checkpoint can therefore return partial results with nil, while the filtered-empty path below returns the cancellation error. Could we use the same check here and cover cancellation between a checkpoint and a miss?

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

Labels

area/kvcache kind/bug Categorizes issue or PR as related to a bug. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants