budgeted agent containers get no swap; export oom kills and swap use
This commit is contained in:
parent
a5470d82ae
commit
4eb27046a0
1 changed files with 131 additions and 16 deletions
|
|
@ -225,6 +225,10 @@ const RESTART_SEC: u32 = 5;
|
|||
/// weights. A weight of `None` means "not configured" and omits its line
|
||||
/// entirely, so a request from a hive-c0re built before the weights
|
||||
/// existed — or one whose nix option is `null` — renders no weight lines.
|
||||
///
|
||||
/// A finite `MemoryMax=` comes with `MemorySwapMax=0`: at the budget the
|
||||
/// kernel kills inside the container instead of paging it out to host swap.
|
||||
/// `MemoryMax=infinity` is no budget and leaves swap alone.
|
||||
fn limits_dropin_body(
|
||||
runtime_dir: &str,
|
||||
rootfs_check: &str,
|
||||
|
|
@ -238,6 +242,11 @@ fn limits_dropin_body(
|
|||
// `format_push_string`, and a `write!` would need an unwrap.
|
||||
let cpu_weight_line = cpu_weight.map_or_else(String::new, |w| format!("CPUWeight={w}\n"));
|
||||
let io_weight_line = io_weight.map_or_else(String::new, |w| format!("IOWeight={w}\n"));
|
||||
let swap_line = if memory_max == "infinity" {
|
||||
""
|
||||
} else {
|
||||
"MemorySwapMax=0\n"
|
||||
};
|
||||
format!(
|
||||
"[Unit]\n\
|
||||
ConditionPathIsDirectory={runtime_dir}\n\
|
||||
|
|
@ -248,6 +257,7 @@ fn limits_dropin_body(
|
|||
ExecStartPre={rootfs_check}\n\
|
||||
RestartSec={RESTART_SEC}\n\
|
||||
MemoryMax={memory_max}\n\
|
||||
{swap_line}\
|
||||
CPUQuota={cpu_quota}\n\
|
||||
{cpu_weight_line}{io_weight_line}"
|
||||
)
|
||||
|
|
@ -893,6 +903,7 @@ mod tests {
|
|||
ExecStartPre=/store/hive-priv/bin/hive-priv check-rootfs h-iris\n\
|
||||
RestartSec=5\n\
|
||||
MemoryMax=4G\n\
|
||||
MemorySwapMax=0\n\
|
||||
CPUQuota=200%\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -924,6 +935,25 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// A budgeted container gets no swap; an unbudgeted one keeps it. The
|
||||
/// finite arm is the presence control for the infinity arm's absence.
|
||||
#[test]
|
||||
fn swap_is_off_exactly_when_the_memory_is_budgeted() {
|
||||
for mem in ["4G", "512M", "50%", "8589934592"] {
|
||||
let body = limits_dropin_body("/rt/x", CHECK, mem, "200%", None, None);
|
||||
assert!(
|
||||
body.contains(&format!("\nMemoryMax={mem}\nMemorySwapMax=0\n")),
|
||||
"no swap line under a budget of {mem}: {body}"
|
||||
);
|
||||
assert_eq!(body.matches("MemorySwapMax=").count(), 1, "{body}");
|
||||
}
|
||||
let unbudgeted = limits_dropin_body("/rt/x", CHECK, "infinity", "200%", None, None);
|
||||
assert!(
|
||||
unbudgeted.contains("\nMemoryMax=infinity\n"),
|
||||
"{unbudgeted}"
|
||||
);
|
||||
assert!(!unbudgeted.contains("MemorySwapMax"), "{unbudgeted}");
|
||||
}
|
||||
/// Weights are appended to the `[Service]` section, each omitted
|
||||
/// independently when `None`.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue