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:
+51
-35
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user