feat: enhance quota user lock management and testing

- Adjusted QUOTA_USER_LOCKS_MAX based on test and non-test configurations to improve flexibility.
- Implemented logic to retain existing locks when the maximum quota is reached, ensuring efficient memory usage.
- Added comprehensive tests for quota user lock functionality, including cache reuse, saturation behavior, and race conditions.
- Enhanced StatsIo struct to manage wake scheduling for read and write operations, preventing unnecessary self-wakes.
- Introduced separate replay checker domains for handshake and TLS to ensure isolation and prevent cross-pollution of keys.
- Added security tests for replay checker to validate domain separation and window clamping behavior.
This commit is contained in:
David Osipov
2026-03-18 23:55:08 +04:00
parent 20e205189c
commit c7cf37898b
18 changed files with 1896 additions and 49 deletions

View File

@@ -208,6 +208,8 @@ struct StatsIo<S> {
user: String,
quota_limit: Option<u64>,
quota_exceeded: Arc<AtomicBool>,
quota_read_wake_scheduled: bool,
quota_write_wake_scheduled: bool,
epoch: Instant,
}
@@ -230,6 +232,8 @@ impl<S> StatsIo<S> {
user,
quota_limit,
quota_exceeded,
quota_read_wake_scheduled: false,
quota_write_wake_scheduled: false,
epoch,
}
}
@@ -293,9 +297,19 @@ impl<S: AsyncRead + Unpin> AsyncRead for StatsIo<S> {
.then(|| quota_user_lock(&this.user));
let _quota_guard = if let Some(lock) = quota_lock.as_ref() {
match lock.try_lock() {
Ok(guard) => Some(guard),
Ok(guard) => {
this.quota_read_wake_scheduled = false;
Some(guard)
}
Err(_) => {
cx.waker().wake_by_ref();
if !this.quota_read_wake_scheduled {
this.quota_read_wake_scheduled = true;
let waker = cx.waker().clone();
tokio::task::spawn(async move {
tokio::task::yield_now().await;
waker.wake();
});
}
return Poll::Pending;
}
}
@@ -356,9 +370,19 @@ impl<S: AsyncWrite + Unpin> AsyncWrite for StatsIo<S> {
.then(|| quota_user_lock(&this.user));
let _quota_guard = if let Some(lock) = quota_lock.as_ref() {
match lock.try_lock() {
Ok(guard) => Some(guard),
Ok(guard) => {
this.quota_write_wake_scheduled = false;
Some(guard)
}
Err(_) => {
cx.waker().wake_by_ref();
if !this.quota_write_wake_scheduled {
this.quota_write_wake_scheduled = true;
let waker = cx.waker().clone();
tokio::task::spawn(async move {
tokio::task::yield_now().await;
waker.wake();
});
}
return Poll::Pending;
}
}