[Router] Add bucket-aware policy domains and native cache indexing (#38108)

Signed-off-by: Vincent Gao <vincentbo@linux.alibaba.com>
Co-authored-by: inkcherry <mingzhi.liu@amd.com>
Co-authored-by: yangbodong22011 <13137470+yangbodong22011@users.noreply.github.com>
This commit is contained in:
Vincent Gao
2026-09-06 19:47:51 +08:00
committed by GitHub
co-authored by inkcherry yangbodong22011
parent a176ba2f7b
commit 5bebe7a033
76 changed files with 5842 additions and 3639 deletions
@@ -34,7 +34,7 @@ use sgl_kv_indexer::{
PrefixIndex, PrefixIndexConfig, MAX_GRPC_DECODING_MESSAGE_SIZE,
};
use test_id::nanos;
use test_kv::{action, apply_request, hbm};
use test_kv::{action, action_with_parent, apply_request, hbm};
use test_net::free_addr;
async fn start_backend(
@@ -211,6 +211,27 @@ fn apply_report(
)
}
fn apply_report_with_parent(
worker: &str,
addr: &str,
seq: u64,
tier: i32,
parent_block_hash: Option<i64>,
hashes: &[i64],
) -> ApplyExternalKvBatchRequest {
apply_request(
worker,
addr,
seq,
vec![action_with_parent(
ExternalKvActionType::ActionReport,
tier,
parent_block_hash,
hashes,
)],
)
}
#[tokio::test]
async fn multiple_workers_share_one_indexer_server() {
let mut indexer = start().await;
@@ -225,7 +246,7 @@ async fn multiple_workers_share_one_indexer_server() {
"10.0.0.1:9000",
1,
hbm(),
&[hash_0, shared_hash],
&[shared_hash, hash_0],
))
.await
.expect("apply worker-0");
@@ -235,7 +256,7 @@ async fn multiple_workers_share_one_indexer_server() {
"10.0.0.2:9000",
1,
hbm(),
&[hash_1, shared_hash],
&[shared_hash, hash_1],
))
.await
.expect("apply worker-1");
@@ -309,6 +330,7 @@ async fn validation_errors_map_to_invalid_argument_over_grpc() {
hashes: vec![1],
component_masks: Vec::new(),
block_sizes: Vec::new(),
parent_block_hash: None,
}],
};
let err = c
@@ -318,6 +340,76 @@ async fn validation_errors_map_to_invalid_argument_over_grpc() {
assert_eq!(err.code(), Code::InvalidArgument);
}
#[tokio::test]
async fn rejected_batch_is_atomic_over_grpc() {
let mut c = start().await;
c.apply_external_kv_batch(apply_report("w", "old-address", 1, hbm(), &[1, 2]))
.await
.expect("seed chain");
let err = c
.apply_external_kv_batch(apply_request(
"w",
"new-address",
2,
vec![
action(ExternalKvActionType::ActionReport, hbm(), &[3]),
action_with_parent(ExternalKvActionType::ActionReport, hbm(), Some(9), &[2]),
],
))
.await
.expect_err("conflicting parent must reject the whole batch");
assert_eq!(err.code(), Code::InvalidArgument);
let old = c
.match_external_kv(MatchExternalKvRequest {
hashes: vec![1],
count_as_hit: false,
})
.await
.expect("query original state")
.into_inner();
assert_eq!(old.matches.len(), 1);
assert_eq!(old.matches[0].address, "old-address");
let leaked = c
.match_external_kv(MatchExternalKvRequest {
hashes: vec![3],
count_as_hit: false,
})
.await
.expect("query rejected action")
.into_inner();
assert!(leaked.matches.is_empty());
}
#[tokio::test]
async fn cyclic_report_is_rejected_over_grpc() {
let mut c = start().await;
let err = c
.apply_external_kv_batch(apply_report_with_parent(
"w",
"address",
1,
hbm(),
Some(2),
&[1, 2],
))
.await
.expect_err("cyclic report must be rejected");
assert_eq!(err.code(), Code::InvalidArgument);
let response = c
.match_external_kv(MatchExternalKvRequest {
hashes: vec![1, 2],
count_as_hit: false,
})
.await
.expect("query rejected report")
.into_inner();
assert!(response.matches.is_empty());
}
#[tokio::test]
async fn match_prefix_over_grpc() {
let mut c = start().await;
@@ -358,12 +450,14 @@ async fn prefix_query_scans_more_than_one_apply_chunk_over_grpc() {
let mut indexer = start().await;
let hashes: Vec<i64> = (0..=APPLY_CHUNK_SIZE as i64).collect();
for (seq, chunk) in hashes.chunks(APPLY_CHUNK_SIZE).enumerate() {
let parent_block_hash = (seq > 0).then_some(chunk[0] - 1);
indexer
.apply_external_kv_batch(apply_report(
.apply_external_kv_batch(apply_report_with_parent(
"large-prefix-worker",
"10.0.0.1:9000",
seq as u64,
hbm(),
parent_block_hash,
chunk,
))
.await
@@ -487,7 +581,7 @@ async fn start_recording_deadlines(
/// the only thing letting the indexer shed a query whose caller gave up.
#[tokio::test]
async fn router_client_publishes_its_deadline_on_the_wire() {
let (index, seen) = start_recording_deadlines(Duration::from_millis(250)).await;
let (index, seen) = start_recording_deadlines(Duration::from_secs(2)).await;
index
.match_prefix(vec![1, 2, 3])