feat(server): add tracing spans and caching to archive and blame services

- Add tracing spans with repo labels for archive and blame operations
- Implement caching for archive list entries when using OID selectors
- Implement caching for blame operations when using OID selectors
- Add detailed
This commit is contained in:
zhenyi
2026-06-04 15:33:16 +08:00
parent 729604f13b
commit cc202d6d1f
41 changed files with 2400 additions and 1067 deletions
+22 -19
View File
@@ -8,15 +8,27 @@ impl GitBare {
/// Index a pack file from streamed input.
///
/// Client-streaming → unary response.
/// Collects all input chunks into a single pack, then runs `git index-pack`.
/// Writes each chunk directly to a temp file to avoid buffering
/// the entire pack in memory.
pub fn index_pack(&self, inputs: Vec<IndexPackRequest>) -> GitResult<IndexPackResponse> {
// Reassemble all chunks into a single pack data buffer
let mut pack_data = Vec::new();
let mut strict = false;
let mut keep = false;
let mut has_data = false;
let pack_dir = self.bare_dir.join("objects").join("pack");
std::fs::create_dir_all(&pack_dir).map_err(GitError::Io)?;
// Stream pack data to a temp file instead of accumulating in memory
let mut tmp_file = tempfile::Builder::new()
.prefix("tmp_index_pack_")
.tempfile_in(&pack_dir)
.map_err(GitError::Io)?;
for input in &inputs {
pack_data.extend_from_slice(&input.data);
if !input.data.is_empty() {
tmp_file.write_all(&input.data).map_err(GitError::Io)?;
has_data = true;
}
if input.strict {
strict = true;
}
@@ -25,25 +37,18 @@ impl GitBare {
}
}
if pack_data.is_empty() {
if !has_data {
return Err(GitError::InvalidArgument("empty pack data".into()));
}
let pack_dir = self.bare_dir.join("objects").join("pack");
std::fs::create_dir_all(&pack_dir).map_err(GitError::Io)?;
// Write pack data to a unique temp file in the pack directory.
let mut tmp_file = tempfile::Builder::new()
.prefix("tmp_index_pack_")
.tempfile_in(&pack_dir)
.map_err(GitError::Io)?;
tmp_file.write_all(&pack_data).map_err(GitError::Io)?;
// Flush and get the path before we pass it to git
tmp_file.flush().map_err(GitError::Io)?;
let tmp_path = tmp_file.path().to_path_buf();
let mut args = vec![
"--git-dir".to_string(),
self.bare_dir.to_string_lossy().into_owned(),
"index-pack".to_string(),
"index-pack".into(),
];
if strict {
args.push("--strict".into());
@@ -59,6 +64,7 @@ impl GitBare {
.unchecked()
.run()?;
// Drop the temp file handle — git index-pack has processed it
drop(tmp_file);
if !result.status.success() {
@@ -73,12 +79,9 @@ impl GitBare {
let stderr = String::from_utf8_lossy(&result.stderr);
let all_output = format!("{output}\n{stderr}");
// git index-pack outputs the .idx and .pack filenames
// e.g. "... pack-<hex>.pack ... pack-<hex>.idx"
let pack_hash = all_output
.lines()
.filter_map(|line| {
// Look for the hash after "pack-" and before ".idx" or ".pack"
let trimmed = line.trim();
if let Some(idx) = trimmed.find("pack-") {
let rest = &trimmed[idx + 5..];
@@ -96,7 +99,7 @@ impl GitBare {
// Try to get object count from .idx if it exists
let mut object_count = 0u64;
if let Some(ref hash) = pack_hash {
let idx_path = pack_dir.join(format!("pack-{}.idx", hash));
let idx_path = pack_dir.join(format!("pack-{hash}.idx"));
if idx_path.exists() {
let verify = duct::cmd(
"git",