refactor(actor): implement replica sync and ref update notification system
- Add is_write parameter to remote clients for read/write routing distinction - Introduce RepoEntry struct with role tracking (primary/replica) for repositories - Replace HashSet with HashMap for repository storage with role metadata - Add ROLE_PRIMARY and ROLE_REPLICA constants for node role identification - Implement FindPrimary and FindReplica RPC methods for role-based routing - Add RefUpdateEvent message type for propagating reference updates - Create sync module with BundleApplicator for handling replica synchronization - Implement notify_ref_update calls after branch/tag/commit operations - Add broadcast_ref_update function to propagate events across cluster nodes - Modify route_repository to prioritize primary for writes and replicas for reads - Update actor message handling to support role-based repository discovery - Implement sync_from_primary function using pack protocol for incremental updates
This commit is contained in:
+47
-1
@@ -13,6 +13,9 @@ impl BytesConvertable for RepositoryHeader {
|
||||
}
|
||||
}
|
||||
|
||||
pub const ROLE_PRIMARY: &str = "primary";
|
||||
pub const ROLE_REPLICA: &str = "replica";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RouteDecision {
|
||||
pub found: bool,
|
||||
@@ -20,6 +23,7 @@ pub struct RouteDecision {
|
||||
pub relative_path: String,
|
||||
pub actor_name: String,
|
||||
pub grpc_addr: String,
|
||||
pub role: String,
|
||||
}
|
||||
|
||||
impl BytesConvertable for RouteDecision {
|
||||
@@ -30,6 +34,7 @@ impl BytesConvertable for RouteDecision {
|
||||
self.relative_path,
|
||||
self.actor_name,
|
||||
self.grpc_addr,
|
||||
self.role,
|
||||
])
|
||||
}
|
||||
|
||||
@@ -41,6 +46,7 @@ impl BytesConvertable for RouteDecision {
|
||||
relative_path: values.get(2).cloned().unwrap_or_default(),
|
||||
actor_name: values.get(3).cloned().unwrap_or_default(),
|
||||
grpc_addr: values.get(4).cloned().unwrap_or_default(),
|
||||
role: values.get(5).cloned().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +80,41 @@ impl BytesConvertable for NodeHealth {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RefUpdateEvent {
|
||||
pub relative_path: String,
|
||||
pub ref_name: String,
|
||||
pub old_oid: String,
|
||||
pub new_oid: String,
|
||||
pub primary_grpc_addr: String,
|
||||
pub primary_storage_name: String,
|
||||
}
|
||||
|
||||
impl BytesConvertable for RefUpdateEvent {
|
||||
fn into_bytes(self) -> Vec<u8> {
|
||||
encode_strings(&[
|
||||
self.relative_path,
|
||||
self.ref_name,
|
||||
self.old_oid,
|
||||
self.new_oid,
|
||||
self.primary_grpc_addr,
|
||||
self.primary_storage_name,
|
||||
])
|
||||
}
|
||||
|
||||
fn from_bytes(bytes: Vec<u8>) -> Self {
|
||||
let values = decode_strings(bytes);
|
||||
Self {
|
||||
relative_path: values.first().cloned().unwrap_or_default(),
|
||||
ref_name: values.get(1).cloned().unwrap_or_default(),
|
||||
old_oid: values.get(2).cloned().unwrap_or_default(),
|
||||
new_oid: values.get(3).cloned().unwrap_or_default(),
|
||||
primary_grpc_addr: values.get(4).cloned().unwrap_or_default(),
|
||||
primary_storage_name: values.get(5).cloned().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RactorClusterMessage)]
|
||||
pub enum GitNodeMessage {
|
||||
ScanAndRegister,
|
||||
@@ -82,8 +123,13 @@ pub enum GitNodeMessage {
|
||||
|
||||
RemoveRepository(RepositoryHeader),
|
||||
|
||||
RefUpdated(RefUpdateEvent),
|
||||
|
||||
#[rpc]
|
||||
RouteRepository(RepositoryHeader, RpcReplyPort<RouteDecision>),
|
||||
FindPrimary(RepositoryHeader, RpcReplyPort<RouteDecision>),
|
||||
|
||||
#[rpc]
|
||||
FindReplica(RepositoryHeader, RpcReplyPort<RouteDecision>),
|
||||
|
||||
#[rpc]
|
||||
ListRepositoryPaths(RpcReplyPort<String>),
|
||||
|
||||
Reference in New Issue
Block a user