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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user