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
+26 -5
View File
@@ -2,23 +2,29 @@ use crate::bare::GitBare;
use crate::error::GitResult;
use crate::pb::*;
const MAX_SEARCH_RESULTS: u32 = 1000;
impl GitBare {
/// Search file contents with a regex pattern.
pub fn search_files_by_content(
&self,
request: SearchFilesByContentRequest,
) -> GitResult<SearchFilesByContentResponse> {
crate::sanitize::validate_revision(&request.revision)?;
let revision = if request.revision.is_empty() {
"HEAD"
} else {
&request.revision
};
crate::sanitize::validate_revision(revision)?;
if request.query.is_empty() {
return Err(crate::error::GitError::InvalidArgument(
"search query cannot be empty".into(),
));
}
let max_results = if request.max_results == 0 {
100
} else {
request.max_results
request.max_results.min(MAX_SEARCH_RESULTS)
};
let mut args = vec![
@@ -51,6 +57,12 @@ impl GitBare {
})?;
// git grep returns exit code 1 when no matches found — that's not an error
if !output.status.success() && output.status.code() != Some(1) {
return Err(crate::error::GitError::CommandFailed {
status_code: output.status.code(),
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
});
}
let stdout = String::from_utf8_lossy(&output.stdout);
let mut results = Vec::new();
@@ -59,13 +71,16 @@ impl GitBare {
if let Some((path_and_rest, matched)) = line.rsplit_once(':') {
let prefix_parts: Vec<&str> = path_and_rest.rsplitn(3, ':').collect();
if prefix_parts.len() >= 3
&& let Ok(line_num) = prefix_parts[0].parse::<u32>()
&& let Ok(line_num) = prefix_parts[1].parse::<u32>()
{
results.push(SearchResult {
path: prefix_parts[2].to_string(),
line: line_num,
matched_text: matched.to_string(),
});
if results.len() >= max_results as usize {
break;
}
}
}
}
@@ -88,7 +103,7 @@ impl GitBare {
let max_results = if request.max_results == 0 {
100
} else {
request.max_results
request.max_results.min(MAX_SEARCH_RESULTS)
};
let mut args = vec![
@@ -113,6 +128,12 @@ impl GitBare {
status_code: None,
stderr: e.to_string(),
})?;
if !output.status.success() {
return Err(crate::error::GitError::CommandFailed {
status_code: output.status.code(),
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
});
}
let stdout = String::from_utf8_lossy(&output.stdout);
let mut results = Vec::new();