refactor(build): reformat code and add tonic health dependency

- Reformatted build script with proper indentation and line breaks
- Added tonic-health dependency to Cargo.toml and updated lock file
- Improved error handling in disk cache with concurrent deletion checks
- Refactored conditional chains using && and let expressions
- Reformatted struct initialization and function parameter lists
- Added proper spacing and alignment in language stats processing
- Improved assertion formatting in test cases
- Reorganized import statements and code layout in multiple files
- Updated metrics functions with better parameter handling and formatting
This commit is contained in:
zhenyi
2026-06-11 13:56:15 +08:00
parent c32a7cad2f
commit a40da90ef9
31 changed files with 696 additions and 417 deletions
+51 -35
View File
@@ -1,7 +1,7 @@
use crate::actor::message::{
AppendEntriesRequest, AppendEntriesResponse, ElectionRequest, ElectionResult, GitNodeMessage,
NodeHealth, ReadIndexResponse, RefUpdateEvent, RoleChangedEvent, RouteDecision,
ROLE_PRIMARY, ROLE_REPLICA, RAFT_MSG_VERSION,
NodeHealth, RAFT_MSG_VERSION, ROLE_PRIMARY, ROLE_REPLICA, ReadIndexResponse, RefUpdateEvent,
RoleChangedEvent, RouteDecision,
};
use crate::actor::raft_log::RaftLog;
use crate::pb::RepositoryHeader;
@@ -94,9 +94,8 @@ impl Actor for GitNodeActor {
// Initialize Raft log with disk persistence
let raft_data_dir = args.data_dir.join("raft");
let raft_log = RaftLog::new(&raft_data_dir).map_err(|e| {
ActorProcessingErr::from(format!("failed to init raft log: {e}"))
})?;
let raft_log = RaftLog::new(&raft_data_dir)
.map_err(|e| ActorProcessingErr::from(format!("failed to init raft log: {e}")))?;
tracing::info!(
storage_name = %args.storage_name,
entries = raft_log.len(),
@@ -451,9 +450,7 @@ fn should_accept_election(request: &ElectionRequest, state: &GitNodeState) -> bo
);
return false;
}
if request.last_log_term == my_last_term
&& request.last_log_index < my_last_index
{
if request.last_log_term == my_last_term && request.last_log_index < my_last_index {
tracing::warn!(
candidate_index = request.last_log_index,
my_index = my_last_index,
@@ -796,20 +793,19 @@ fn handle_append_entries(
};
}
}
if state.raft_log.term_at(entry.index) == 0 {
if let Some(raft_entry) = entry.to_entry()
&& let Err(e) = state.raft_log.append_reserved(raft_entry)
{
tracing::error!(error = %e, "failed to append raft entry");
return AppendEntriesResponse {
version: RAFT_MSG_VERSION,
term: state.current_term,
success: false,
match_index: state.raft_log.last_index(),
conflict_index: 0,
conflict_term: 0,
};
}
if state.raft_log.term_at(entry.index) == 0
&& let Some(raft_entry) = entry.to_entry()
&& let Err(e) = state.raft_log.append_reserved(raft_entry)
{
tracing::error!(error = %e, "failed to append raft entry");
return AppendEntriesResponse {
version: RAFT_MSG_VERSION,
term: state.current_term,
success: false,
match_index: state.raft_log.last_index(),
conflict_index: 0,
conflict_term: 0,
};
}
}
@@ -858,7 +854,10 @@ fn handle_read_index(state: &GitNodeState) -> ReadIndexResponse {
ReadIndexResponse {
commit_index: state.raft_log.commit_index(),
leader_term: state.current_term,
is_leader: state.is_primary && state.leader_lease_deadline.is_some_and(|d| d > Instant::now()),
is_leader: state.is_primary
&& state
.leader_lease_deadline
.is_some_and(|d| d > Instant::now()),
}
}
@@ -902,8 +901,12 @@ pub async fn broadcast_append_entries(
match ractor::call_t!(actor_ref, GitNodeMessage::AppendEntries, 5000, request) {
Ok(response) if response.success => {
success_count += 1;
state.match_index.insert(follower_id.clone(), response.match_index);
state.next_index.insert(follower_id, response.match_index + 1);
state
.match_index
.insert(follower_id.clone(), response.match_index);
state
.next_index
.insert(follower_id, response.match_index + 1);
}
Ok(response) => {
// Follower rejected — update next_index for retry
@@ -916,7 +919,9 @@ pub async fn broadcast_append_entries(
// Decrement next_index (optimization: use conflict info)
let next = state.next_index.get(&follower_id).copied().unwrap_or(1);
if response.conflict_index > 0 && response.conflict_index < next {
state.next_index.insert(follower_id, response.conflict_index);
state
.next_index
.insert(follower_id, response.conflict_index);
} else if next > 1 {
state.next_index.insert(follower_id, next - 1);
}
@@ -933,7 +938,9 @@ pub async fn broadcast_append_entries(
/// Check if Leader lease is still valid.
pub fn is_leader_lease_valid(state: &GitNodeState) -> bool {
state.is_primary
&& state.leader_lease_deadline.is_some_and(|d| d > Instant::now())
&& state
.leader_lease_deadline
.is_some_and(|d| d > Instant::now())
}
/// Update Leader lease after successful majority replication.
@@ -1006,8 +1013,12 @@ async fn handle_raft_write(
match ractor::call_t!(actor_ref, GitNodeMessage::AppendEntries, 5000, request) {
Ok(response) if response.success => {
success_count += 1;
state.match_index.insert(follower_id.clone(), response.match_index);
state.next_index.insert(follower_id, response.match_index + 1);
state
.match_index
.insert(follower_id.clone(), response.match_index);
state
.next_index
.insert(follower_id, response.match_index + 1);
}
Ok(response) => {
tracing::debug!(
@@ -1083,11 +1094,14 @@ fn apply_raft_command(state: &mut GitNodeState, command: &crate::actor::raft_log
storage_name = %storage_name,
"applying RegisterRepo from Raft log"
);
state.repos.entry(relative_path.clone()).or_insert_with(|| RepoEntry {
role: ROLE_REPLICA.to_string(),
last_commit: String::new(),
read_only: false,
});
state
.repos
.entry(relative_path.clone())
.or_insert_with(|| RepoEntry {
role: ROLE_REPLICA.to_string(),
last_commit: String::new(),
read_only: false,
});
}
crate::actor::raft_log::Command::RemoveRepo { relative_path } => {
tracing::info!(
@@ -1121,5 +1135,7 @@ fn apply_raft_command(state: &mut GitNodeState, command: &crate::actor::raft_log
}
// Advance last_applied
state.raft_log.advance_last_applied(state.raft_log.commit_index());
state
.raft_log
.advance_last_applied(state.raft_log.commit_index());
}
+23 -4
View File
@@ -159,7 +159,6 @@ pub enum GitNodeMessage {
TriggerElection,
// ── Raft consensus messages ──────────────────────────────
/// AppendEntries RPC: Leader → Follower log replication.
#[rpc]
AppendEntries(AppendEntriesRequest, RpcReplyPort<AppendEntriesResponse>),
@@ -418,7 +417,16 @@ impl BytesConvertable for AppendEntriesRequest {
});
}
let leader_commit = read_u64(&bytes, &mut offset);
Self { version, term, leader_id, leader_grpc_addr, prev_log_index, prev_log_term, entries, leader_commit }
Self {
version,
term,
leader_id,
leader_grpc_addr,
prev_log_index,
prev_log_term,
entries,
leader_commit,
}
}
}
@@ -457,7 +465,14 @@ impl BytesConvertable for AppendEntriesResponse {
let match_index = read_u64(&bytes, &mut offset);
let conflict_index = read_u64(&bytes, &mut offset);
let conflict_term = read_u64(&bytes, &mut offset);
Self { version, term, success, match_index, conflict_index, conflict_term }
Self {
version,
term,
success,
match_index,
conflict_index,
conflict_term,
}
}
}
@@ -502,7 +517,11 @@ impl BytesConvertable for ReadIndexResponse {
let commit_index = read_u64(&bytes, &mut offset);
let leader_term = read_u64(&bytes, &mut offset);
let is_leader = bytes.get(offset).copied().unwrap_or(0) == 1;
Self { commit_index, leader_term, is_leader }
Self {
commit_index,
leader_term,
is_leader,
}
}
}
+6 -7
View File
@@ -7,15 +7,14 @@ pub mod sync;
pub use handler::find_primary_in_cluster;
pub use handler::{
broadcast_append_entries, broadcast_ref_update, broadcast_role_changed,
get_category_members, get_cluster_nodes, is_leader_lease_valid, list_all_groups,
renew_leader_lease, route_group_for, start_node_actor, GitNodeActor, GitNodeArgs, RepoEntry,
GitNodeActor, GitNodeArgs, RepoEntry, broadcast_append_entries, broadcast_ref_update,
broadcast_role_changed, get_category_members, get_cluster_nodes, is_leader_lease_valid,
list_all_groups, renew_leader_lease, route_group_for, start_node_actor,
};
pub use message::{
AppendEntriesRequest, AppendEntriesResponse, ElectionRequest, ElectionResult,
GitNodeMessage, NodeHealth, ReadIndexRequest, ReadIndexResponse, RefUpdateEvent,
RepoActorMessage, RoleChangedEvent, RouteDecision, SerializedRaftEntry,
ROLE_PRIMARY, ROLE_REPLICA, RAFT_MSG_VERSION,
AppendEntriesRequest, AppendEntriesResponse, ElectionRequest, ElectionResult, GitNodeMessage,
NodeHealth, RAFT_MSG_VERSION, ROLE_PRIMARY, ROLE_REPLICA, ReadIndexRequest, ReadIndexResponse,
RefUpdateEvent, RepoActorMessage, RoleChangedEvent, RouteDecision, SerializedRaftEntry,
};
pub use raft_log::{Command as RaftCommand, LogEntry as RaftLogEntry, RaftLog};
pub use server::init_actor_cluster;
+55 -24
View File
@@ -13,9 +13,9 @@ use std::sync::atomic::{AtomicU64, Ordering};
use ractor_cluster::BytesConvertable;
use crate::error::{GitError, GitResult};
use crate::actor::snapshot::{RaftSnapshot, SnapshotStorage};
use crate::actor::handler::RepoEntry;
use crate::actor::snapshot::{RaftSnapshot, SnapshotStorage};
use crate::error::{GitError, GitResult};
use std::collections::HashMap;
/// Protocol version for forward/backward compatibility.
@@ -56,11 +56,19 @@ impl Command {
pub fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
match self {
Command::RefUpdate { relative_path, ref_name, old_oid, new_oid } => {
Command::RefUpdate {
relative_path,
ref_name,
old_oid,
new_oid,
} => {
buf.push(0); // tag
encode_strings(&mut buf, &[relative_path, ref_name, old_oid, new_oid]);
}
Command::RegisterRepo { relative_path, storage_name } => {
Command::RegisterRepo {
relative_path,
storage_name,
} => {
buf.push(1);
encode_strings(&mut buf, &[relative_path, storage_name]);
}
@@ -68,7 +76,10 @@ impl Command {
buf.push(2);
encode_strings(&mut buf, &[relative_path]);
}
Command::SetPrimary { storage_name, relative_paths } => {
Command::SetPrimary {
storage_name,
relative_paths,
} => {
buf.push(3);
encode_string(&mut buf, storage_name);
buf.extend((relative_paths.len() as u32).to_be_bytes());
@@ -192,7 +203,12 @@ pub struct LogEntry {
impl LogEntry {
pub fn new(term: u64, index: u64, command: Command) -> Self {
let checksum = Self::compute_checksum(term, index, &command);
Self { term, index, command, checksum }
Self {
term,
index,
command,
checksum,
}
}
fn compute_checksum(term: u64, index: u64, command: &Command) -> u32 {
@@ -243,7 +259,12 @@ impl LogEntry {
return None;
}
Some(LogEntry { term, index, command, checksum })
Some(LogEntry {
term,
index,
command,
checksum,
})
}
}
@@ -320,7 +341,9 @@ impl RaftStorage {
.append(true)
.open(&self.index_path)
.map_err(GitError::Io)?;
index_file.write_all(&index_entry.encode()).map_err(GitError::Io)?;
index_file
.write_all(&index_entry.encode())
.map_err(GitError::Io)?;
index_file.flush().map_err(GitError::Io)?;
Ok(entry.index)
@@ -383,7 +406,12 @@ impl RaftStorage {
);
break;
}
entries.push(LogEntry { term, index, command, checksum });
entries.push(LogEntry {
term,
index,
command,
checksum,
});
}
None => {
tracing::warn!(index, "failed to decode command during recovery, stopping");
@@ -478,7 +506,10 @@ impl RaftLog {
let entries = storage.load_all()?;
let next_index = entries.last().map(|e| e.index + 1).unwrap_or(snapshot_index + 1);
let next_index = entries
.last()
.map(|e| e.index + 1)
.unwrap_or(snapshot_index + 1);
let last_applied = entries.last().map(|e| e.index).unwrap_or(snapshot_index);
Ok(Self {
@@ -610,7 +641,9 @@ impl RaftLog {
return Ok(()); // Nothing to compact
}
let keep: Vec<LogEntry> = self.entries.iter()
let keep: Vec<LogEntry> = self
.entries
.iter()
.filter(|e| e.index >= from_index)
.cloned()
.collect();
@@ -622,11 +655,7 @@ impl RaftLog {
self.storage.truncate_and_rebuild(&keep)?;
self.entries = keep;
tracing::info!(
from_index,
kept = self.entries.len(),
"raft log compacted"
);
tracing::info!(from_index, kept = self.entries.len(), "raft log compacted");
Ok(())
}
@@ -635,7 +664,9 @@ impl RaftLog {
/// when a follower detects a term mismatch, it must delete the conflicting entry
/// and all entries that follow.
pub fn truncate_from(&mut self, from_index: u64) -> GitResult<()> {
let keep: Vec<LogEntry> = self.entries.iter()
let keep: Vec<LogEntry> = self
.entries
.iter()
.filter(|e| e.index < from_index)
.cloned()
.collect();
@@ -677,11 +708,7 @@ impl RaftLog {
/// Create a snapshot of the current state and compact the log.
pub fn create_snapshot(&mut self, repos: HashMap<String, RepoEntry>) -> GitResult<()> {
let snapshot = RaftSnapshot::new(
self.last_applied,
self.term_at(self.last_applied),
repos,
);
let snapshot = RaftSnapshot::new(self.last_applied, self.term_at(self.last_applied), repos);
self.snapshot_storage.save(&snapshot)?;
self.snapshot_index = snapshot.last_included_index;
@@ -701,12 +728,16 @@ impl RaftLog {
}
/// Restore state from a snapshot.
pub fn restore_snapshot(&mut self, snapshot: RaftSnapshot) -> GitResult<HashMap<String, RepoEntry>> {
pub fn restore_snapshot(
&mut self,
snapshot: RaftSnapshot,
) -> GitResult<HashMap<String, RepoEntry>> {
self.snapshot_index = snapshot.last_included_index;
self.snapshot_term = snapshot.last_included_term;
self.commit_index = snapshot.last_included_index;
self.last_applied = snapshot.last_included_index;
self.next_index.store(snapshot.last_included_index + 1, Ordering::SeqCst);
self.next_index
.store(snapshot.last_included_index + 1, Ordering::SeqCst);
// Clear all entries (they're covered by the snapshot)
self.entries.clear();
+8 -5
View File
@@ -79,11 +79,14 @@ impl RaftSnapshot {
let last_commit = read_string(data, &mut offset)?;
let read_only = data.get(offset).copied().unwrap_or(0) == 1;
offset += 1;
repos.insert(path, RepoEntry {
role,
last_commit,
read_only,
});
repos.insert(
path,
RepoEntry {
role,
last_commit,
read_only,
},
);
}
Some(Self {
+4 -5
View File
@@ -219,7 +219,9 @@ async fn sync_via_pack_service_to_file(
temp_dir: &Path,
) -> Result<Option<PathBuf>, String> {
use crate::pb::pack_service_client::PackServiceClient;
use crate::pb::{AdvertiseRefsRequest, PackObjectsOptions, PackObjectsRequest, RepositoryHeader};
use crate::pb::{
AdvertiseRefsRequest, PackObjectsOptions, PackObjectsRequest, RepositoryHeader,
};
use tokio::io::AsyncWriteExt;
use tokio_stream::StreamExt;
@@ -358,10 +360,7 @@ fn update_local_ref(repo_path: &Path, ref_name: &str, new_oid: &str) {
/// Apply a committed Raft command to the local git repository.
/// This is called on followers when they receive committed entries from the leader.
pub fn apply_raft_command_to_repo(
repo_prefix: &Path,
command: &crate::actor::raft_log::Command,
) {
pub fn apply_raft_command_to_repo(repo_prefix: &Path, command: &crate::actor::raft_log::Command) {
match command {
crate::actor::raft_log::Command::RefUpdate {
relative_path,