resource_limits: read the override map once per SSE scan
`container_view::build_all` renders every container on every scan, and each agent's row resolved its limits through `effective()`, which reads and parses `resource-limits.json` from disk. That is one file read per agent per scan of a file that is identical for all of them. Split the resolution in two: `effective_from` takes an already-loaded map, and `effective` keeps the read-then-resolve shape for the single-agent callers (`write_dropins`, which runs once per spawn and rebuild and has no map to hand). `build_all` now loads the map once at the top — the same treatment `topology::read()` already gets there — and calls `effective_from` per agent. No behaviour change: the fallback matrix lives in `resolve`, which both paths still go through, and its tests are untouched. The now-redundant `limits_for` is gone; `effective_from` covers its one caller.
This commit is contained in:
parent
a6dc980700
commit
c149963917
2 changed files with 28 additions and 9 deletions
|
|
@ -70,20 +70,34 @@ pub fn read() -> BTreeMap<String, AgentLimits> {
|
||||||
serde_json::from_str(&raw).unwrap_or_default()
|
serde_json::from_str(&raw).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look up one agent's overrides. Returns the all-`None` default when
|
|
||||||
/// the agent has no entry.
|
|
||||||
#[must_use]
|
|
||||||
pub fn limits_for(name: &str) -> AgentLimits {
|
|
||||||
read().get(name).cloned().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolve the effective values for an agent, filling each unset field
|
/// Resolve the effective values for an agent, filling each unset field
|
||||||
/// from the hive-wide default. This is the single place the fallback
|
/// from the hive-wide default. This is the single place the fallback
|
||||||
/// rule lives; `write_dropins` calls it and passes the result straight
|
/// rule lives; `write_dropins` calls it and passes the result straight
|
||||||
/// to systemd.
|
/// to systemd.
|
||||||
|
///
|
||||||
|
/// Reads the override file. Use [`effective_from`] when resolving more
|
||||||
|
/// than one agent in a row.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn effective(name: &str, hive_cpu_quota: &str, hive_memory_max: &str) -> (String, String) {
|
pub fn effective(name: &str, hive_cpu_quota: &str, hive_memory_max: &str) -> (String, String) {
|
||||||
resolve(&limits_for(name), hive_cpu_quota, hive_memory_max)
|
effective_from(&read(), name, hive_cpu_quota, hive_memory_max)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`effective`] against an already-loaded map — the multi-agent form.
|
||||||
|
///
|
||||||
|
/// `container_view::build_all` renders every agent on each SSE scan, so
|
||||||
|
/// it loads the map once and calls this per agent rather than re-reading
|
||||||
|
/// the same small file N times per scan.
|
||||||
|
#[must_use]
|
||||||
|
pub fn effective_from(
|
||||||
|
limits: &BTreeMap<String, AgentLimits>,
|
||||||
|
name: &str,
|
||||||
|
hive_cpu_quota: &str,
|
||||||
|
hive_memory_max: &str,
|
||||||
|
) -> (String, String) {
|
||||||
|
match limits.get(name) {
|
||||||
|
Some(l) => resolve(l, hive_cpu_quota, hive_memory_max),
|
||||||
|
None => (hive_cpu_quota.to_owned(), hive_memory_max.to_owned()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pure core of [`effective`], split out so the fallback matrix is
|
/// Pure core of [`effective`], split out so the fallback matrix is
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,10 @@ pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> Vec<ContainerView>
|
||||||
// Empty / absent topology.json → every agent root-level (safe
|
// Empty / absent topology.json → every agent root-level (safe
|
||||||
// degradation for fresh installs that haven't run sync_agents yet).
|
// degradation for fresh installs that haven't run sync_agents yet).
|
||||||
let topology = crate::topology::read();
|
let topology = crate::topology::read();
|
||||||
|
// Same once-per-scan treatment as the topology map: the override file
|
||||||
|
// is read here and resolved per agent below, rather than re-read for
|
||||||
|
// every container on every SSE scan.
|
||||||
|
let limits = crate::resource_limits::read();
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for c in &raw {
|
for c in &raw {
|
||||||
let Some(logical) = c.strip_prefix(AGENT_PREFIX) else {
|
let Some(logical) = c.strip_prefix(AGENT_PREFIX) else {
|
||||||
|
|
@ -123,7 +127,8 @@ pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> Vec<ContainerView>
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let paused = Coordinator::is_paused(&logical);
|
let paused = Coordinator::is_paused(&logical);
|
||||||
let (cpu_quota, memory_max) = crate::resource_limits::effective(
|
let (cpu_quota, memory_max) = crate::resource_limits::effective_from(
|
||||||
|
&limits,
|
||||||
logical.as_str(),
|
logical.as_str(),
|
||||||
&hive.agent_cpu_quota,
|
&hive.agent_cpu_quota,
|
||||||
&hive.agent_memory_max,
|
&hive.agent_memory_max,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue