use serde_json::{Map, Value as JsonValue};
use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::server::response_shape::types::{DdlColType, ShapedRows};
use crate::control::state::SharedState;
use super::super::super::result::{DdlError, DdlResult};
use super::support::ddl_err;
pub fn rebalance(
state: &SharedState,
identity: &AuthenticatedIdentity,
) -> Result<Vec<DdlResult>, DdlError> {
if !identity.is_superuser {
return Err(ddl_err(
"42501",
"permission denied: only superuser can rebalance",
));
}
let routing = match &state.cluster_routing {
Some(r) => r,
None => {
return Err(ddl_err(
"55000",
"cluster mode not enabled (single-node instance)",
));
}
};
let topo = match &state.cluster_topology {
Some(t) => t,
None => {
return Err(ddl_err("55000", "cluster topology not available"));
}
};
let routing = routing.read().unwrap_or_else(|p| p.into_inner());
let topo = topo.read().unwrap_or_else(|p| p.into_inner());
let plan = nodedb_cluster::compute_plan(&routing, &topo)
.map_err(|e| ddl_err("XX000", format!("rebalance planning failed: {e}")))?;
if plan.is_empty() {
let mut row = Map::new();
row.insert(
"status".to_string(),
JsonValue::String("cluster is balanced — no moves needed".to_string()),
);
return Ok(vec![DdlResult::Rows(ShapedRows {
columns: vec!["status".to_string()],
column_types: vec![DdlColType::Text],
rows: vec![row],
notice: None,
})]);
}
let columns = vec![
"vshard_id".to_string(),
"source_node".to_string(),
"target_node".to_string(),
"source_group".to_string(),
];
let column_types = vec![
DdlColType::Int8,
DdlColType::Int8,
DdlColType::Int8,
DdlColType::Int8,
];
let mut rows = Vec::new();
for m in &plan.moves {
let mut row = Map::new();
row.insert(
"vshard_id".to_string(),
JsonValue::String((m.vshard_id as i64).to_string()),
);
row.insert(
"source_node".to_string(),
JsonValue::String((m.source_node as i64).to_string()),
);
row.insert(
"target_node".to_string(),
JsonValue::String((m.target_node as i64).to_string()),
);
row.insert(
"source_group".to_string(),
JsonValue::String((m.source_group as i64).to_string()),
);
rows.push(row);
}
Ok(vec![DdlResult::Rows(ShapedRows {
columns,
column_types,
rows,
notice: None,
})])
}