feat(admin): add MinIO-compatible diagnostics endpoints (#4333)

feat(admin): add MinIO-compatible diagnostics and service-control endpoints

Register and implement MinIO admin API compatibility routes:
- POST /v3/service: restart/stop trigger the existing graceful-shutdown
  path; freeze/unfreeze record advisory state (request admission is not
  yet gated, surfaced honestly via effective=false)
- profiling/trace and healthinfo/obdinfo/log diagnostics endpoints
- GET /v3/top/locks and POST /v3/force-unlock, backed by new
  FastObjectLockManager::list_locks()/force_unlock() introspection
- speedtest routes where feasible

Refs rustfs/backlog#604 #606 #607 #615
This commit is contained in:
Zhengchao An
2026-07-07 04:46:42 +08:00
committed by GitHub
parent 68f048b8fe
commit 3420f28c17
9 changed files with 1755 additions and 10 deletions
+81
View File
@@ -508,6 +508,87 @@ impl LockShard {
None
}
/// Enumerate every currently held lock in this shard.
///
/// Exclusive locks yield a single entry; shared locks yield one entry per
/// distinct owner so administrative "top locks" views can attribute every
/// holder. Entries for objects that are tracked but not currently locked
/// (e.g. pooled-but-idle state) are skipped.
pub fn list_locks(&self) -> Vec<crate::fast_lock::types::ObjectLockInfo> {
let objects = self.objects.read();
let mut infos = Vec::new();
for (key, state) in objects.iter() {
let Some(mode) = state.current_mode() else {
continue;
};
let priority = *state.priority.read();
match mode {
LockMode::Exclusive => {
if let Some(info) = state.current_owner.read().clone() {
let expires_at = info
.acquired_at
.checked_add(info.lock_timeout)
.unwrap_or_else(|| info.acquired_at + crate::fast_lock::DEFAULT_LOCK_TIMEOUT);
infos.push(crate::fast_lock::types::ObjectLockInfo {
key: key.clone(),
mode,
owner: info.owner,
acquired_at: info.acquired_at,
expires_at,
priority,
});
}
}
LockMode::Shared => {
for entry in state.shared_owners.read().iter() {
let expires_at = entry
.acquired_at
.checked_add(entry.lock_timeout)
.unwrap_or_else(|| entry.acquired_at + crate::fast_lock::DEFAULT_LOCK_TIMEOUT);
infos.push(crate::fast_lock::types::ObjectLockInfo {
key: key.clone(),
mode,
owner: entry.owner.clone(),
acquired_at: entry.acquired_at,
expires_at,
priority,
});
}
}
}
}
infos
}
/// Force-release every holder of a lock on `key`, regardless of owner.
///
/// Returns the number of owners that were released. Used by the admin
/// force-unlock path to clear a stuck resource.
pub fn force_release_all(&self, key: &ObjectKey) -> usize {
let owners_modes: Vec<(Arc<str>, LockMode)> = {
let objects = self.objects.read();
let Some(state) = objects.get(key) else {
return 0;
};
let mut pairs = Vec::new();
if let Some(info) = state.current_owner.read().clone() {
pairs.push((info.owner, LockMode::Exclusive));
}
for entry in state.shared_owners.read().iter() {
pairs.push((entry.owner.clone(), LockMode::Shared));
}
pairs
};
let mut released = 0;
for (owner, mode) in owners_modes {
if self.release_lock(key, &owner, mode) {
released += 1;
}
}
released
}
/// Get current load factor of the shard
pub fn current_load_factor(&self) -> f64 {
let objects = self.objects.read();