use std::collections::HashMap;
use crate::control::state::SharedState;
use crate::types::VShardId;
pub(in crate::control::server::graph_dispatch) struct ShardTarget {
pub(in crate::control::server::graph_dispatch) node_id: u64,
pub(in crate::control::server::graph_dispatch) is_local: bool,
pub(in crate::control::server::graph_dispatch) owned_vshards: Vec<u32>,
}
impl ShardTarget {
pub(in crate::control::server::graph_dispatch) fn route_vshard(&self) -> u32 {
self.owned_vshards.first().copied().unwrap_or(0)
}
}
pub(in crate::control::server::graph_dispatch) struct Enumeration {
pub(in crate::control::server::graph_dispatch) targets: Vec<ShardTarget>,
pub(in crate::control::server::graph_dispatch) vshard_owner: HashMap<u32, u64>,
}
pub(in crate::control::server::graph_dispatch) fn enumerate_shards(
state: &SharedState,
) -> crate::Result<Enumeration> {
let Some(routing_lock) = state.cluster_routing.as_ref() else {
return Ok(Enumeration {
targets: Vec::new(),
vshard_owner: HashMap::new(),
});
};
let routing = routing_lock.read().unwrap_or_else(|p| p.into_inner());
let raft_snapshot: Vec<nodedb_cluster::GroupStatus> =
state.raft_status_fn.get().map(|f| f()).unwrap_or_default();
let live_leader = |group_id: u64| -> u64 {
raft_snapshot
.iter()
.find(|gs| gs.group_id == group_id)
.map(|gs| gs.leader_id)
.unwrap_or(0)
};
let mut owned_by_node: HashMap<u64, Vec<u32>> = HashMap::new();
let mut node_order: Vec<u64> = Vec::new();
let mut vshard_owner: HashMap<u32, u64> = HashMap::new();
for group_id in routing.group_ids() {
if group_id == 0 {
continue;
}
let vshards = routing.vshards_for_group(group_id);
if vshards.is_empty() {
continue;
}
let mut leader = live_leader(group_id);
if leader == 0 {
leader = routing.group_info(group_id).map(|g| g.leader).unwrap_or(0);
}
if leader == 0 {
let first = vshards.first().copied().unwrap_or(0);
return Err(crate::Error::NotLeader {
vshard_id: VShardId::new(first),
leader_node: 0,
leader_addr: String::new(),
});
}
if !owned_by_node.contains_key(&leader) {
node_order.push(leader);
}
let entry = owned_by_node.entry(leader).or_default();
for vs in vshards {
vshard_owner.insert(vs, leader);
entry.push(vs);
}
}
let targets = node_order
.into_iter()
.map(|node_id| {
let mut owned_vshards = owned_by_node.remove(&node_id).unwrap_or_default();
owned_vshards.sort_unstable();
ShardTarget {
node_id,
is_local: node_id == state.node_id,
owned_vshards,
}
})
.collect();
Ok(Enumeration {
targets,
vshard_owner,
})
}