refactor(cache): redesign cache system with structured keys and improved performance

- Add repo_path parameter to cached_response and cached_vec_response functions
- Implement structured cache key format with namespace, repo_path, and request proto
- Replace global cache with Moka in-memory cache using weight-based eviction
- Set 256MB memory cap with 10-minute TTL and 2-minute TTI policy
- Add metrics collection for cache operations and evictions
- Implement efficient repo-scoped invalidation using key structure
- Add detailed documentation comments explaining cache architecture
- Remove outdated dependencies and update dependency versions
- Add error handling for encoding failures in cache operations
- Optimize Vec responses with length-delimited encoding and pre-allocation
This commit is contained in:
zhenyi
2026-06-12 12:53:23 +08:00
parent a40da90ef9
commit 934858bebf
82 changed files with 1273 additions and 4969 deletions
+36 -35
View File
@@ -13,6 +13,8 @@ remote_client!(
"pack"
);
const MAX_INDEX_PACK_BUFFER_BYTES: usize = 512 * 1024 * 1024;
#[tonic::async_trait]
impl pack_service_server::PackService for GitksService {
type UploadPackStream = CancellableReceiverStream<Result<UploadPackResponse, tonic::Status>>;
@@ -276,43 +278,33 @@ impl pack_service_server::PackService for GitksService {
m.record("ok");
let (tx, rx) = tokio::sync::mpsc::channel(16);
tokio::spawn(async move {
let result = tokio::task::spawn_blocking(move || {
use std::io::Read;
let mut file = file;
let mut buf = vec![0u8; 65536];
let mut chunks = Vec::new();
loop {
match file.read(&mut buf) {
Ok(0) => break,
Ok(n) => chunks.push(Ok(PackfileChunk {
data: buf[..n].to_vec(),
})),
Err(e) => {
chunks.push(Err(tonic::Status::internal(format!(
use tokio::io::AsyncReadExt;
let mut file = tokio::fs::File::from_std(file);
let mut buf = vec![0u8; 65536];
loop {
match file.read(&mut buf).await {
Ok(0) => break,
Ok(n) => {
if tx
.send(Ok(PackfileChunk {
data: buf[..n].to_vec(),
}))
.await
.is_err()
{
break;
}
}
Err(e) => {
let _ = tx
.send(Err(tonic::Status::internal(format!(
"cache read error: {e}"
))));
break;
}
))))
.await;
break;
}
}
chunks
})
.await;
match result {
Ok(chunks) => {
for chunk in chunks {
if tx.send(chunk).await.is_err() {
break;
}
}
}
Err(e) => {
let _ = tx
.send(Err(tonic::Status::internal(format!(
"cache read task failed: {e}"
))))
.await;
}
}
});
return Ok(tonic::Response::new(ReceiverStream::new(rx)));
@@ -340,8 +332,17 @@ impl pack_service_server::PackService for GitksService {
let m = crate::metrics::RequestMetrics::new("gitks.PackService/IndexPack");
let mut stream = request.into_inner();
let mut inputs = Vec::new();
let mut total_bytes = 0usize;
while let Some(msg) = stream.next().await {
inputs.push(msg?);
let msg = msg?;
total_bytes = total_bytes.saturating_add(msg.data.len());
if total_bytes > MAX_INDEX_PACK_BUFFER_BYTES {
return Err(tonic::Status::resource_exhausted(format!(
"index-pack input too large (max {} bytes)",
MAX_INDEX_PACK_BUFFER_BYTES
)));
}
inputs.push(msg);
}
let _rate = self
.acquire_rate_limit(