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
+18 -4
View File
@@ -1,6 +1,6 @@
use crate::pb::*;
use super::{GitksService, into_status, into_stream};
use super::{GitksService, cache, into_status};
#[tonic::async_trait]
impl archive_service_server::ArchiveService for GitksService {
@@ -12,9 +12,13 @@ impl archive_service_server::ArchiveService for GitksService {
request: tonic::Request<ArchiveRequest>,
) -> Result<tonic::Response<Self::GetArchiveStream>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("archive.get_archive", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let chunks = gb.get_archive(inner).map_err(into_status)?;
Ok(tonic::Response::new(into_stream(chunks)))
let stream = gb.get_archive_stream(inner)?;
tracing::info!(%repo, "archive streaming started");
Ok(tonic::Response::new(stream))
}
async fn list_archive_entries(
@@ -22,8 +26,18 @@ impl archive_service_server::ArchiveService for GitksService {
request: tonic::Request<ListArchiveEntriesRequest>,
) -> Result<tonic::Response<ListArchiveEntriesResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("archive.list_archive_entries", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_archive_entries(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.treeish) {
cache::cached_response("archive.list_archive_entries", &inner, || {
gb.list_archive_entries(inner.clone()).map_err(into_status)
})?
} else {
gb.list_archive_entries(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.entries.len(), "list_archive_entries done");
Ok(tonic::Response::new(resp))
}
}
+24 -3
View File
@@ -1,6 +1,6 @@
use crate::pb::*;
use super::{GitksService, into_status, into_stream};
use super::{GitksService, cache, into_status, into_stream};
#[tonic::async_trait]
impl blame_service_server::BlameService for GitksService {
@@ -12,8 +12,19 @@ impl blame_service_server::BlameService for GitksService {
request: tonic::Request<BlameRequest>,
) -> Result<tonic::Response<BlameResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let path = inner.path.clone();
let span = tracing::info_span!("blame.blame", %repo, %path);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.blame(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("blame.blame", &inner, || {
gb.blame(inner.clone()).map_err(into_status)
})?
} else {
gb.blame(inner).map_err(into_status)?
};
tracing::info!(%repo, %path, hunks = resp.hunks.len(), "blame done");
Ok(tonic::Response::new(resp))
}
@@ -22,8 +33,18 @@ impl blame_service_server::BlameService for GitksService {
request: tonic::Request<BlameRequest>,
) -> Result<tonic::Response<Self::StreamBlameStream>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let path = inner.path.clone();
let span = tracing::info_span!("blame.stream_blame", %repo, %path);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.blame(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("blame.blame", &inner, || {
gb.blame(inner.clone()).map_err(into_status)
})?
} else {
gb.blame(inner).map_err(into_status)?
};
Ok(tonic::Response::new(into_stream(resp.hunks)))
}
}
+40
View File
@@ -9,8 +9,12 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<ListBranchesRequest>,
) -> Result<tonic::Response<ListBranchesResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("branch.list_branches", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_branches(inner).map_err(into_status)?;
tracing::info!(%repo, count = resp.branches.len(), "list_branches done");
Ok(tonic::Response::new(resp))
}
@@ -19,6 +23,10 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<GetBranchRequest>,
) -> Result<tonic::Response<Branch>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("branch.get_branch", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_branch(inner).map_err(into_status)?;
Ok(tonic::Response::new(resp))
@@ -29,8 +37,13 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<CreateBranchRequest>,
) -> Result<tonic::Response<Branch>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("branch.create_branch", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.create_branch(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "branch created");
Ok(tonic::Response::new(resp))
}
@@ -39,8 +52,13 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<DeleteBranchRequest>,
) -> Result<tonic::Response<()>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("branch.delete_branch", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
gb.delete_branch(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "branch deleted");
Ok(tonic::Response::new(()))
}
@@ -49,8 +67,14 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<RenameBranchRequest>,
) -> Result<tonic::Response<Branch>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let old = inner.old_name.clone();
let new = inner.new_name.clone();
let span = tracing::info_span!("branch.rename_branch", %repo, %old, %new);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.rename_branch(inner).map_err(into_status)?;
tracing::info!(%repo, old = %old, new = %new, "branch renamed");
Ok(tonic::Response::new(resp))
}
@@ -59,8 +83,13 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<UpdateBranchTargetRequest>,
) -> Result<tonic::Response<Branch>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("branch.update_branch_target", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.update_branch_target(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "branch target updated");
Ok(tonic::Response::new(resp))
}
@@ -69,8 +98,13 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<SetBranchUpstreamRequest>,
) -> Result<tonic::Response<Branch>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("branch.set_branch_upstream", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.set_branch_upstream(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "branch upstream set");
Ok(tonic::Response::new(resp))
}
@@ -79,8 +113,14 @@ impl branch_service_server::BranchService for GitksService {
request: tonic::Request<CompareBranchRequest>,
) -> Result<tonic::Response<CompareBranchResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let source = inner.source_branch.clone();
let target = inner.target_branch.clone();
let span = tracing::info_span!("branch.compare_branch", %repo, %source, %target);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.compare_branch(inner).map_err(into_status)?;
tracing::info!(%repo, %source, %target, ahead = resp.ahead_by, behind = resp.behind_by, "branch compared");
Ok(tonic::Response::new(resp))
}
}
+62 -5
View File
@@ -1,6 +1,6 @@
use crate::pb::*;
use super::{GitksService, into_status};
use super::{GitksService, cache, into_status};
#[tonic::async_trait]
impl commit_service_server::CommitService for GitksService {
@@ -9,8 +9,18 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<ListCommitsRequest>,
) -> Result<tonic::Response<ListCommitsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("commit.list_commits", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_commits(inner).map_err(into_status)?;
let resp = if !inner.all && cache::selector_is_oid(&inner.revision) {
cache::cached_response("commit.list_commits", &inner, || {
gb.list_commits(inner.clone()).map_err(into_status)
})?
} else {
gb.list_commits(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.commits.len(), total = resp.page_info.as_ref().map(|p| p.total_count).unwrap_or(0), "list_commits done");
Ok(tonic::Response::new(resp))
}
@@ -19,8 +29,17 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<GetCommitRequest>,
) -> Result<tonic::Response<Commit>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("commit.get_commit", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_commit(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("commit.get_commit", &inner, || {
gb.get_commit(inner.clone()).map_err(into_status)
})?
} else {
gb.get_commit(inner).map_err(into_status)?
};
Ok(tonic::Response::new(resp))
}
@@ -29,8 +48,18 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<GetCommitAncestorsRequest>,
) -> Result<tonic::Response<GetCommitAncestorsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("commit.get_commit_ancestors", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_commit_ancestors(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("commit.get_commit_ancestors", &inner, || {
gb.get_commit_ancestors(inner.clone()).map_err(into_status)
})?
} else {
gb.get_commit_ancestors(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.commits.len(), "get_commit_ancestors done");
Ok(tonic::Response::new(resp))
}
@@ -39,8 +68,16 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<CreateCommitRequest>,
) -> Result<tonic::Response<CreateCommitResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let branch = inner.branch.clone();
let span = tracing::info_span!("commit.create_commit", %repo, %branch);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.create_commit(inner).map_err(into_status)?;
let commit_hex = resp.commit.as_ref()
.and_then(|c| c.oid.as_ref().map(|o| o.hex.as_str()).or(Some("?")))
.unwrap_or("?");
tracing::info!(%repo, %branch, %commit_hex, "commit created");
Ok(tonic::Response::new(resp))
}
@@ -49,8 +86,13 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<RevertCommitRequest>,
) -> Result<tonic::Response<CreateCommitResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let branch = inner.branch.clone();
let span = tracing::info_span!("commit.revert_commit", %repo, %branch);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.revert_commit(inner).map_err(into_status)?;
tracing::info!(%repo, %branch, "commit reverted");
Ok(tonic::Response::new(resp))
}
@@ -59,8 +101,13 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<CherryPickCommitRequest>,
) -> Result<tonic::Response<CreateCommitResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let branch = inner.branch.clone();
let span = tracing::info_span!("commit.cherry_pick_commit", %repo, %branch);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.cherry_pick_commit(inner).map_err(into_status)?;
tracing::info!(%repo, %branch, "commit cherry-picked");
Ok(tonic::Response::new(resp))
}
@@ -69,8 +116,18 @@ impl commit_service_server::CommitService for GitksService {
request: tonic::Request<CompareCommitsRequest>,
) -> Result<tonic::Response<CompareCommitsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("commit.compare_commits", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.compare_commits(inner).map_err(into_status)?;
let resp = if cache::selectors_are_oid(&inner.base, &inner.head) {
cache::cached_response("commit.compare_commits", &inner, || {
gb.compare_commits(inner.clone()).map_err(into_status)
})?
} else {
gb.compare_commits(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.commits.len(), "compare_commits done");
Ok(tonic::Response::new(resp))
}
}
+43 -5
View File
@@ -1,6 +1,6 @@
use crate::pb::*;
use super::{GitksService, into_status, into_stream};
use super::{GitksService, cache, into_status, into_stream};
#[tonic::async_trait]
impl diff_service_server::DiffService for GitksService {
@@ -12,8 +12,18 @@ impl diff_service_server::DiffService for GitksService {
request: tonic::Request<GetDiffRequest>,
) -> Result<tonic::Response<GetDiffResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("diff.get_diff", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_diff(inner).map_err(into_status)?;
let resp = if cache::selectors_are_oid(&inner.base, &inner.head) {
cache::cached_response("diff.get_diff", &inner, || {
gb.get_diff(inner.clone()).map_err(into_status)
})?
} else {
gb.get_diff(inner).map_err(into_status)?
};
tracing::info!(%repo, files = resp.files.len(), overflow = resp.overflow, "get_diff done");
Ok(tonic::Response::new(resp))
}
@@ -22,8 +32,18 @@ impl diff_service_server::DiffService for GitksService {
request: tonic::Request<GetCommitDiffRequest>,
) -> Result<tonic::Response<GetDiffResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("diff.get_commit_diff", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_commit_diff(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.commit) {
cache::cached_response("diff.get_commit_diff", &inner, || {
gb.get_commit_diff(inner.clone()).map_err(into_status)
})?
} else {
gb.get_commit_diff(inner).map_err(into_status)?
};
tracing::info!(%repo, files = resp.files.len(), "get_commit_diff done");
Ok(tonic::Response::new(resp))
}
@@ -32,8 +52,17 @@ impl diff_service_server::DiffService for GitksService {
request: tonic::Request<GetPatchRequest>,
) -> Result<tonic::Response<Self::GetPatchStream>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("diff.get_patch", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let items = gb.get_patch(inner).map_err(into_status)?;
let items = if cache::selectors_are_oid(&inner.base, &inner.head) {
cache::cached_vec_response("diff.get_patch", &inner, || {
gb.get_patch(inner.clone()).map_err(into_status)
})?
} else {
gb.get_patch(inner).map_err(into_status)?
};
Ok(tonic::Response::new(into_stream(items)))
}
@@ -42,8 +71,17 @@ impl diff_service_server::DiffService for GitksService {
request: tonic::Request<GetDiffStatsRequest>,
) -> Result<tonic::Response<DiffStats>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("diff.get_diff_stats", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_diff_stats(inner).map_err(into_status)?;
let resp = if cache::selectors_are_oid(&inner.base, &inner.head) {
cache::cached_response("diff.get_diff_stats", &inner, || {
gb.get_diff_stats(inner.clone()).map_err(into_status)
})?
} else {
gb.get_diff_stats(inner).map_err(into_status)?
};
Ok(tonic::Response::new(resp))
}
}
+23
View File
@@ -9,8 +9,12 @@ impl merge_service_server::MergeService for GitksService {
request: tonic::Request<CheckMergeRequest>,
) -> Result<tonic::Response<MergeResult>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("merge.check_merge", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.check_merge(inner).map_err(into_status)?;
tracing::info!(%repo, status = resp.status, "check_merge done");
Ok(tonic::Response::new(resp))
}
@@ -19,8 +23,13 @@ impl merge_service_server::MergeService for GitksService {
request: tonic::Request<MergeRequest>,
) -> Result<tonic::Response<MergeResult>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let target = inner.target_branch.clone();
let span = tracing::info_span!("merge.merge", %repo, %target);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.merge(inner).map_err(into_status)?;
tracing::info!(%repo, %target, status = resp.status, "merge done");
Ok(tonic::Response::new(resp))
}
@@ -29,8 +38,12 @@ impl merge_service_server::MergeService for GitksService {
request: tonic::Request<ListMergeConflictsRequest>,
) -> Result<tonic::Response<ListMergeConflictsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("merge.list_merge_conflicts", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_merge_conflicts(inner).map_err(into_status)?;
tracing::info!(%repo, conflicts = resp.conflicts.len(), "list_merge_conflicts done");
Ok(tonic::Response::new(resp))
}
@@ -39,8 +52,13 @@ impl merge_service_server::MergeService for GitksService {
request: tonic::Request<ResolveMergeConflictsRequest>,
) -> Result<tonic::Response<MergeResult>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let target = inner.target_branch.clone();
let span = tracing::info_span!("merge.resolve_merge_conflicts", %repo, %target);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.resolve_merge_conflicts(inner).map_err(into_status)?;
tracing::info!(%repo, %target, status = resp.status, "merge conflicts resolved");
Ok(tonic::Response::new(resp))
}
@@ -49,8 +67,13 @@ impl merge_service_server::MergeService for GitksService {
request: tonic::Request<RebaseRequest>,
) -> Result<tonic::Response<RebaseResult>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let branch = inner.branch.clone();
let span = tracing::info_span!("merge.rebase", %repo, %branch);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.rebase(inner).map_err(into_status)?;
tracing::info!(%repo, %branch, status = resp.status, "rebase done");
Ok(tonic::Response::new(resp))
}
}
+61 -17
View File
@@ -1,6 +1,7 @@
mod archive;
mod blame;
mod branch;
mod cache;
mod commit;
mod diff;
mod merge;
@@ -23,11 +24,23 @@ use crate::pb::{
#[derive(Clone)]
pub struct GitksService {
/// 所有仓库的根路径前缀
pub(crate) repo_prefix: PathBuf,
/// Root prefix path for all repositories
pub repo_prefix: PathBuf,
}
impl GitksService {
fn repo_label(&self, header: Option<&crate::pb::RepositoryHeader>) -> String {
header
.and_then(|h| {
if h.relative_path.is_empty() {
None
} else {
Some(h.relative_path.clone())
}
})
.unwrap_or_else(|| "unknown".into())
}
pub(crate) fn resolve(
&self,
header: Option<&crate::pb::RepositoryHeader>,
@@ -35,7 +48,12 @@ impl GitksService {
let header =
header.ok_or_else(|| tonic::Status::invalid_argument("repository is required"))?;
let header = self.prefixed_header(header);
GitBare::from_repository_header(&header).map_err(into_status)
let gb = GitBare::from_repository_header(&header).map_err(into_status)?;
tracing::debug!(
repo = %gb.bare_dir.display(),
"resolved repository"
);
Ok(gb)
}
pub(crate) fn resolve_for_init(
@@ -49,7 +67,7 @@ impl GitksService {
return Err(tonic::Status::invalid_argument("relative_path is required"));
}
let candidate = self.repo_prefix.join(relative_path);
// 路径穿越检查
// Path traversal check
let canonical = candidate
.canonicalize()
.unwrap_or_else(|_| candidate.clone());
@@ -65,11 +83,8 @@ impl GitksService {
Ok(canonical)
}
/// 将客户端传入的 header 注入 repo_prefix 作为 storage_path
fn prefixed_header(
&self,
header: &crate::pb::RepositoryHeader,
) -> crate::pb::RepositoryHeader {
/// Inject repo_prefix as storage_path into the client-provided header
fn prefixed_header(&self, header: &crate::pb::RepositoryHeader) -> crate::pb::RepositoryHeader {
crate::pb::RepositoryHeader {
storage_path: self.repo_prefix.to_string_lossy().into_owned(),
relative_path: header.relative_path.clone(),
@@ -115,20 +130,49 @@ pub(crate) fn git_cmd(gb: &GitBare, args: &[&str]) -> Result<std::process::Outpu
gb.bare_dir.to_string_lossy().into_owned(),
];
full_args.extend(args.iter().map(|s| s.to_string()));
std::process::Command::new("git")
tracing::debug!(
repo = %gb.bare_dir.display(),
args = %full_args.iter().skip(2).cloned().collect::<Vec<_>>().join(" "),
"spawning git subprocess"
);
let result = std::process::Command::new("git")
.args(&full_args)
.output()
.map_err(|e| tonic::Status::internal(e.to_string()))
.map_err(|e| {
tracing::error!(
repo = %gb.bare_dir.display(),
error = %e,
"failed to spawn git subprocess"
);
tonic::Status::internal(e.to_string())
})?;
if !result.status.success() {
let stderr = String::from_utf8_lossy(&result.stderr);
tracing::warn!(
repo = %gb.bare_dir.display(),
status = ?result.status.code(),
stderr = %stderr.trim(),
"git subprocess exited with non-zero status"
);
}
Ok(result)
}
pub async fn serve(
addr: std::net::SocketAddr,
repo_prefix: PathBuf,
) -> Result<(), tonic::transport::Error> {
let span = tracing::info_span!("gitks.server", %addr);
let _enter = span.enter();
let svc = GitksService { repo_prefix };
tonic::transport::Server::builder()
.add_service(repository_service_server::RepositoryServiceServer::new(svc.clone()))
.add_service(archive_service_server::ArchiveServiceServer::new(svc.clone()))
tracing::info!("registering gRPC services");
let server = tonic::transport::Server::builder()
.add_service(repository_service_server::RepositoryServiceServer::new(
svc.clone(),
))
.add_service(archive_service_server::ArchiveServiceServer::new(
svc.clone(),
))
.add_service(blame_service_server::BlameServiceServer::new(svc.clone()))
.add_service(branch_service_server::BranchServiceServer::new(svc.clone()))
.add_service(commit_service_server::CommitServiceServer::new(svc.clone()))
@@ -136,7 +180,7 @@ pub async fn serve(
.add_service(merge_service_server::MergeServiceServer::new(svc.clone()))
.add_service(pack_service_server::PackServiceServer::new(svc.clone()))
.add_service(tag_service_server::TagServiceServer::new(svc.clone()))
.add_service(tree_service_server::TreeServiceServer::new(svc))
.serve(addr)
.await
.add_service(tree_service_server::TreeServiceServer::new(svc));
tracing::info!("server ready, starting to accept connections");
server.serve(addr).await
}
+28
View File
@@ -16,8 +16,12 @@ impl pack_service_server::PackService for GitksService {
request: tonic::Request<AdvertiseRefsRequest>,
) -> Result<tonic::Response<AdvertiseRefsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("pack.advertise_refs", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.advertise_refs(inner).map_err(into_status)?;
tracing::info!(%repo, refs = resp.references.len(), "advertise_refs done");
Ok(tonic::Response::new(resp))
}
@@ -30,6 +34,10 @@ impl pack_service_server::PackService for GitksService {
.next()
.await
.ok_or_else(|| tonic::Status::invalid_argument("empty upload-pack stream"))??;
let repo = self.repo_label(first.repository.as_ref());
let span = tracing::info_span!("pack.upload_pack", %repo);
let _enter = span.enter();
tracing::info!(%repo, "upload-pack streaming started");
let gb = self.resolve(first.repository.as_ref())?;
let (tx, rx) = tokio::sync::mpsc::channel(16);
@@ -57,6 +65,10 @@ impl pack_service_server::PackService for GitksService {
.next()
.await
.ok_or_else(|| tonic::Status::invalid_argument("empty receive-pack stream"))??;
let repo = self.repo_label(first.repository.as_ref());
let span = tracing::info_span!("pack.receive_pack", %repo);
let _enter = span.enter();
tracing::info!(%repo, "receive-pack streaming started");
let gb = self.resolve(first.repository.as_ref())?;
let (tx, rx) = tokio::sync::mpsc::channel(16);
@@ -80,8 +92,12 @@ impl pack_service_server::PackService for GitksService {
request: tonic::Request<PackObjectsRequest>,
) -> Result<tonic::Response<Self::PackObjectsStream>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("pack.pack_objects", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let stream = gb.pack_objects(inner).await?;
tracing::info!(%repo, "pack-objects streaming started");
Ok(tonic::Response::new(stream))
}
@@ -94,8 +110,12 @@ impl pack_service_server::PackService for GitksService {
while let Some(msg) = stream.next().await {
inputs.push(msg?);
}
let repo = self.repo_label(inputs.first().and_then(|r| r.repository.as_ref()));
let span = tracing::info_span!("pack.index_pack", %repo);
let _enter = span.enter();
let gb = self.resolve(inputs.first().and_then(|r| r.repository.as_ref()))?;
let resp = gb.index_pack(inputs).map_err(into_status)?;
tracing::info!(%repo, objects = resp.object_count, "index_pack done");
Ok(tonic::Response::new(resp))
}
@@ -104,8 +124,12 @@ impl pack_service_server::PackService for GitksService {
request: tonic::Request<ListPackfilesRequest>,
) -> Result<tonic::Response<ListPackfilesResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("pack.list_packfiles", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_packfiles(inner).map_err(into_status)?;
tracing::info!(%repo, count = resp.packfiles.len(), "list_packfiles done");
Ok(tonic::Response::new(resp))
}
@@ -114,8 +138,12 @@ impl pack_service_server::PackService for GitksService {
request: tonic::Request<FsckRequest>,
) -> Result<tonic::Response<FsckResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("pack.fsck", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.fsck(inner).map_err(into_status)?;
tracing::info!(%repo, ok = resp.ok, errors = resp.errors.len(), warnings = resp.warnings.len(), "fsck done");
Ok(tonic::Response::new(resp))
}
}
+61 -15
View File
@@ -21,6 +21,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<GetRepositoryRequest>,
) -> Result<tonic::Response<Repository>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.get_repository", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let bare = gb.bare_dir.join("HEAD").exists();
let object_format = gb.object_format();
@@ -38,9 +41,13 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<InitRepositoryRequest>,
) -> Result<tonic::Response<Repository>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.init_repository", %repo);
let _enter = span.enter();
let bare_dir = self.resolve_for_init(inner.repository.as_ref())?;
let gb = crate::bare::GitBare { bare_dir };
let gb = crate::bare::GitBare::new(bare_dir);
gb.init_repository(inner.bare).map_err(into_status)?;
tracing::info!(%repo, bare = inner.bare, "repository initialized");
Ok(tonic::Response::new(Repository {
header: inner.repository,
bare: inner.bare,
@@ -53,8 +60,13 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<DeleteRepositoryRequest>,
) -> Result<tonic::Response<()>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.delete_repository", %repo);
let _enter = span.enter();
let bare_dir = self.resolve_for_init(inner.repository.as_ref())?;
tracing::warn!(%repo, path = %bare_dir.display(), "deleting repository");
std::fs::remove_dir_all(&bare_dir).map_err(|e| tonic::Status::internal(e.to_string()))?;
tracing::info!(%repo, "repository deleted");
Ok(tonic::Response::new(()))
}
@@ -63,6 +75,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<RepositoryExistsRequest>,
) -> Result<tonic::Response<RepositoryExistsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.repository_exists", %repo);
let _enter = span.enter();
let bare_dir = self.resolve_for_init(inner.repository.as_ref())?;
let exists = bare_dir.exists() && bare_dir.is_dir() && bare_dir.join("HEAD").exists();
Ok(tonic::Response::new(RepositoryExistsResponse { exists }))
@@ -73,6 +88,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<RepositoryObjectFormatRequest>,
) -> Result<tonic::Response<RepositoryObjectFormatResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.get_object_format", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(RepositoryObjectFormatResponse {
object_format: gb.object_format() as i32,
@@ -84,6 +102,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<GetDefaultBranchRequest>,
) -> Result<tonic::Response<GetDefaultBranchResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.get_default_branch", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(GetDefaultBranchResponse {
name: default_branch_name(&gb),
@@ -95,6 +116,10 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<SetDefaultBranchRequest>,
) -> Result<tonic::Response<()>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("repo.set_default_branch", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let refname = format!("refs/heads/{}", inner.name);
let out = git_cmd(&gb, &["symbolic-ref", "HEAD", &refname])?;
@@ -103,6 +128,7 @@ impl repository_service_server::RepositoryService for GitksService {
String::from_utf8_lossy(&out.stderr).trim().to_string(),
));
}
tracing::info!(%repo, %name, "default branch set");
Ok(tonic::Response::new(()))
}
@@ -111,6 +137,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<GetRepositoryConfigRequest>,
) -> Result<tonic::Response<GetRepositoryConfigResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.get_repository_config", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let mut entries = Vec::new();
if inner.keys.is_empty() {
@@ -156,6 +185,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<SetRepositoryConfigRequest>,
) -> Result<tonic::Response<()>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.set_repository_config", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
for entry in &inner.entries {
if entry.values.is_empty() {
@@ -178,6 +210,9 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<RepositoryStatisticsRequest>,
) -> Result<tonic::Response<RepositoryStatistics>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.get_repository_statistics", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(repository_maint::get_statistics(&gb)))
}
@@ -187,11 +222,13 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<RepositoryHealthRequest>,
) -> Result<tonic::Response<RepositoryHealthResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.check_repository_health", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(repository_maint::check_health(
&gb,
inner.connectivity_only,
)?))
let resp = repository_maint::check_health(&gb, inner.connectivity_only)?;
tracing::info!(%repo, ok = resp.ok, errors = resp.errors.len(), warnings = resp.warnings.len(), "health check done");
Ok(tonic::Response::new(resp))
}
async fn garbage_collect(
@@ -199,12 +236,13 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<GarbageCollectRequest>,
) -> Result<tonic::Response<RepositoryMaintenanceResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.garbage_collect", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(repository_maint::run_gc(
&gb,
inner.prune,
inner.aggressive,
)?))
let resp = repository_maint::run_gc(&gb, inner.prune, inner.aggressive)?;
tracing::info!(%repo, ok = resp.ok, "gc done");
Ok(tonic::Response::new(resp))
}
async fn repack(
@@ -212,13 +250,18 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<RepackRequest>,
) -> Result<tonic::Response<RepositoryMaintenanceResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.repack", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(repository_maint::run_repack(
let resp = repository_maint::run_repack(
&gb,
inner.full,
inner.write_bitmaps,
inner.write_multi_pack_index,
)?))
)?;
tracing::info!(%repo, ok = resp.ok, "repack done");
Ok(tonic::Response::new(resp))
}
async fn write_commit_graph(
@@ -226,9 +269,12 @@ impl repository_service_server::RepositoryService for GitksService {
request: tonic::Request<WriteCommitGraphRequest>,
) -> Result<tonic::Response<RepositoryMaintenanceResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("repo.write_commit_graph", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
Ok(tonic::Response::new(
repository_maint::run_commit_graph_write(&gb, inner.split, inner.replace)?,
))
let resp = repository_maint::run_commit_graph_write(&gb, inner.split, inner.replace)?;
tracing::info!(%repo, ok = resp.ok, "commit-graph write done");
Ok(tonic::Response::new(resp))
}
}
+49 -12
View File
@@ -10,19 +10,32 @@ pub(crate) fn maintenance_response(out: std::process::Output) -> RepositoryMaint
}
}
fn dir_size(path: &std::path::Path) -> u64 {
let mut total = 0u64;
if let Ok(entries) = std::fs::read_dir(path) {
for entry in entries.flatten() {
let p = entry.path();
if p.is_file() {
total += entry.metadata().map(|m| m.len()).unwrap_or(0);
} else if p.is_dir() {
total += dir_size(&p);
}
/// Get approximate repository size using git count-objects instead of
/// recursively scanning the filesystem (which is O(n) and very slow for large repos).
fn dir_size(gb: &crate::bare::GitBare) -> u64 {
let out = git_cmd(gb, &["count-objects", "-v"]).ok();
let text = out
.as_ref()
.map(|o| String::from_utf8_lossy(&o.stdout).into_owned())
.unwrap_or_default();
let mut loose_size_kb = 0u64;
let mut pack_size_kb = 0u64;
let mut garbage_size_kb = 0u64;
for line in text.lines() {
let line = line.trim();
if let Some(val) = line.strip_prefix("size: ") {
loose_size_kb = val.trim().parse().unwrap_or(0);
} else if let Some(val) = line.strip_prefix("size-pack: ") {
pack_size_kb = val.trim().parse().unwrap_or(0);
} else if let Some(val) = line.strip_prefix("size-garbage: ") {
garbage_size_kb = val.trim().parse().unwrap_or(0);
}
}
total
// count-objects reports sizes in KiB; convert to bytes
(loose_size_kb + pack_size_kb + garbage_size_kb) * 1024
}
fn count_refs(gb: &crate::bare::GitBare) -> u64 {
@@ -44,7 +57,7 @@ fn file_len(path: &std::path::Path) -> u64 {
}
pub(crate) fn get_statistics(gb: &crate::bare::GitBare) -> RepositoryStatistics {
let size_bytes = dir_size(&gb.bare_dir);
let size_bytes = dir_size(gb);
let mut loose_object_count: u64 = 0;
let mut packed_object_count: u64 = 0;
@@ -81,6 +94,11 @@ pub(crate) fn check_health(
gb: &crate::bare::GitBare,
connectivity_only: bool,
) -> Result<RepositoryHealthResponse, tonic::Status> {
tracing::info!(
repo = %gb.bare_dir.display(),
connectivity_only = connectivity_only,
"running health check"
);
let mut args: Vec<&str> = vec!["fsck"];
if connectivity_only {
args.push("--connectivity-only");
@@ -109,6 +127,12 @@ pub(crate) fn run_gc(
prune: bool,
aggressive: bool,
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
tracing::info!(
repo = %gb.bare_dir.display(),
prune = prune,
aggressive = aggressive,
"running garbage collection"
);
let mut args: Vec<&str> = vec!["gc"];
if prune {
args.push("--prune=now");
@@ -126,6 +150,13 @@ pub(crate) fn run_repack(
write_bitmaps: bool,
write_multi_pack_index: bool,
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
tracing::info!(
repo = %gb.bare_dir.display(),
full = full,
write_bitmaps = write_bitmaps,
write_multi_pack_index = write_multi_pack_index,
"running repack"
);
let mut args: Vec<&str> = vec!["repack", "-d"];
if full {
args.push("-a");
@@ -145,6 +176,12 @@ pub(crate) fn run_commit_graph_write(
split: bool,
replace: bool,
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
tracing::info!(
repo = %gb.bare_dir.display(),
split = split,
replace = replace,
"writing commit-graph"
);
let mut args: Vec<&str> = vec!["commit-graph", "write"];
if split {
args.push("--split");
+23
View File
@@ -9,8 +9,12 @@ impl tag_service_server::TagService for GitksService {
request: tonic::Request<ListTagsRequest>,
) -> Result<tonic::Response<ListTagsResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tag.list_tags", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_tags(inner).map_err(into_status)?;
tracing::info!(%repo, count = resp.tags.len(), "list_tags done");
Ok(tonic::Response::new(resp))
}
@@ -19,6 +23,10 @@ impl tag_service_server::TagService for GitksService {
request: tonic::Request<GetTagRequest>,
) -> Result<tonic::Response<Tag>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("tag.get_tag", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_tag(inner).map_err(into_status)?;
Ok(tonic::Response::new(resp))
@@ -29,8 +37,13 @@ impl tag_service_server::TagService for GitksService {
request: tonic::Request<CreateTagRequest>,
) -> Result<tonic::Response<Tag>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("tag.create_tag", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.create_tag(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "tag created");
Ok(tonic::Response::new(resp))
}
@@ -39,8 +52,13 @@ impl tag_service_server::TagService for GitksService {
request: tonic::Request<DeleteTagRequest>,
) -> Result<tonic::Response<()>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("tag.delete_tag", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
gb.delete_tag(inner).map_err(into_status)?;
tracing::info!(%repo, %name, "tag deleted");
Ok(tonic::Response::new(()))
}
@@ -49,8 +67,13 @@ impl tag_service_server::TagService for GitksService {
request: tonic::Request<VerifyTagRequest>,
) -> Result<tonic::Response<VerifiedSignature>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let name = inner.name.clone();
let span = tracing::info_span!("tag.verify_tag", %repo, %name);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.verify_tag(inner).map_err(into_status)?;
tracing::info!(%repo, %name, verified = resp.verified, "tag verified");
Ok(tonic::Response::new(resp))
}
}
+68 -7
View File
@@ -1,6 +1,6 @@
use crate::pb::*;
use super::{GitksService, into_status, into_stream};
use super::{GitksService, cache, into_status, into_stream};
#[tonic::async_trait]
impl tree_service_server::TreeService for GitksService {
@@ -12,8 +12,18 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<ListTreeRequest>,
) -> Result<tonic::Response<ListTreeResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tree.list_tree", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_tree(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("tree.list_tree", &inner, || {
gb.list_tree(inner.clone()).map_err(into_status)
})?
} else {
gb.list_tree(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.entries.len(), "list_tree done");
Ok(tonic::Response::new(resp))
}
@@ -22,8 +32,17 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<GetTreeRequest>,
) -> Result<tonic::Response<Tree>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tree.get_tree", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_tree(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("tree.get_tree", &inner, || {
gb.get_tree(inner.clone()).map_err(into_status)
})?
} else {
gb.get_tree(inner).map_err(into_status)?
};
Ok(tonic::Response::new(resp))
}
@@ -32,8 +51,18 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<GetBlobRequest>,
) -> Result<tonic::Response<Blob>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let path = inner.path.clone();
let span = tracing::info_span!("tree.get_blob", %repo, %path);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_blob(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("tree.get_blob", &inner, || {
gb.get_blob(inner.clone()).map_err(into_status)
})?
} else {
gb.get_blob(inner).map_err(into_status)?
};
Ok(tonic::Response::new(resp))
}
@@ -42,8 +71,21 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<GetRawBlobRequest>,
) -> Result<tonic::Response<Self::GetRawBlobStream>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tree.get_raw_blob", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let items = gb.get_raw_blob(inner).map_err(into_status)?;
let items = if inner.oid.is_some() {
cache::cached_vec_response("tree.get_raw_blob", &inner, || {
gb.get_raw_blob(inner.clone()).map_err(into_status)
})?
} else if cache::selector_is_oid(&inner.revision) {
cache::cached_vec_response("tree.get_raw_blob", &inner, || {
gb.get_raw_blob(inner.clone()).map_err(into_status)
})?
} else {
gb.get_raw_blob(inner).map_err(into_status)?
};
Ok(tonic::Response::new(into_stream(items)))
}
@@ -52,8 +94,17 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<GetFileMetadataRequest>,
) -> Result<tonic::Response<FileMetadata>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tree.get_file_metadata", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_file_metadata(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("tree.get_file_metadata", &inner, || {
gb.get_file_metadata(inner.clone()).map_err(into_status)
})?
} else {
gb.get_file_metadata(inner).map_err(into_status)?
};
Ok(tonic::Response::new(resp))
}
@@ -62,8 +113,18 @@ impl tree_service_server::TreeService for GitksService {
request: tonic::Request<FindFilesRequest>,
) -> Result<tonic::Response<FindFilesResponse>, tonic::Status> {
let inner = request.into_inner();
let repo = self.repo_label(inner.repository.as_ref());
let span = tracing::info_span!("tree.find_files", %repo);
let _enter = span.enter();
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_files(inner).map_err(into_status)?;
let resp = if cache::selector_is_oid(&inner.revision) {
cache::cached_response("tree.find_files", &inner, || {
gb.find_files(inner.clone()).map_err(into_status)
})?
} else {
gb.find_files(inner).map_err(into_status)?
};
tracing::info!(%repo, count = resp.files.len(), "find_files done");
Ok(tonic::Response::new(resp))
}
}