refactor(core): use linearizable lazy token bucket (#2421)

Replace periodic refill tasks with on-demand accounting to avoid waking
idle token buckets.

Keep balance, refill time, and fractional credit in one locked state so
concurrent consumers cannot observe partially published refills or
exceed the configured burst capacity. Track credit in nanoseconds and
discard excess credit at capacity to preserve precise limiter behavior.

Use a one-second default burst capacity to preserve the existing
limiter behavior while supporting explicit capacity configuration. Keep
limiter capacity and fill rate in a local config instead of an unused
protobuf message.

Charge only logical EasyTier data payload, unwrap foreign network
packets before accounting, and leave control traffic outside the
limiter. Reject forged payload lengths by accounting from actual packet
boundaries.

Split oversized blocking consumes into capacity-sized chunks and cover
concurrency, refill precision, burst caps, payload accounting, and
bandwidth integration behavior.
This commit is contained in:
Chenx Dust
2026-08-04 10:08:37 +08:00
committed by GitHub
parent 8d475dc3fc
commit df874b85be
9 changed files with 387 additions and 216 deletions
+16 -13
View File
@@ -2296,13 +2296,7 @@ pub async fn relay_bps_limit_test(#[values(100, 200, 400, 800)] bps_limit: u64)
println!("bps: {}", bps);
let bps = bps as u64 / 1024;
// allow 50kb jitter
assert!(
bps >= bps_limit - 50 && bps <= bps_limit + 50,
"bps: {}, bps_limit: {}",
bps,
bps_limit
);
assert_limited_payload_bps(bps, bps_limit);
drop_insts(insts).await;
}
@@ -2339,16 +2333,25 @@ pub async fn instance_recv_bps_limit_test(#[values(100, 800)] bps_limit: u64) {
println!("bps: {}", bps);
let bps = bps as u64 / 1024;
assert!(
bps >= bps_limit - 50 && bps <= bps_limit + 50,
"bps: {}, bps_limit: {}",
bps,
bps_limit
);
assert_limited_payload_bps(bps, bps_limit);
drop_insts(insts).await;
}
fn assert_limited_payload_bps(bps: u64, bps_limit: u64) {
// The benchmark measures TCP application payload while the limiter counts
// EasyTier data payload, including the inner IP and transport headers.
let min_bps = bps_limit.saturating_sub((bps_limit / 10).max(50));
let max_bps = bps_limit + 50;
assert!(
bps >= min_bps && bps <= max_bps,
"bps: {}, expected: {}..={}",
bps,
min_bps,
max_bps
);
}
async fn assert_peer_admission_blocked(inst: &Instance, url: url::Url) {
let ip = url
.host_str()