Fix lazy queue memory preflight warnings

This commit is contained in:
Herbert Wolverson committed 2026-07-30 09:59:57 -05:00
1 parent b2a801aeb0
commit ddf78a0f16
8 files changed
+81 -11

No files matched your search

+4
View File
@@ -2860,6 +2860,10 @@ def refreshShapers():
},
"TC_QDISC_CAPACITY",
)
elif qdiscBudgetEstimate.get("memory_warning_only"):
preflightSummary = qdiscBudgetEstimate.get("summary") or ""
logging.warning(preflightSummary)
print("WARNING: " + preflightSummary)
# Save queuingStructure
queuingStructure = {}
+58 -4
View File
@@ -1693,6 +1693,8 @@ pub struct BakeryPreflightSnapshot {
pub memory_guard_min_available_bytes: u64,
/// Whether the memory preflight passed.
pub memory_ok: bool,
/// Whether the memory-only failure is an allowed lazy-queue warning.
pub memory_warning_only: bool,
/// Per-interface planned qdisc counts.
pub interfaces: Vec<BakeryCapacityInterfaceSnapshot>,
}
@@ -2459,18 +2461,27 @@ fn refresh_live_capacity_snapshot(config: &Config, force: bool) {
/// This function is not pure: it updates retained in-memory Bakery telemetry state.
pub fn record_qdisc_preflight_snapshot(snapshot: BakeryPreflightSnapshot) {
let ok = snapshot.ok;
let memory_warning_only = snapshot.memory_warning_only;
let summary = snapshot.message.clone();
{
let mut state = telemetry_state().write();
state.preflight = Some(snapshot);
}
push_bakery_event(
if ok {
if memory_warning_only {
"preflight_warning"
} else if ok {
"preflight_ok"
} else {
"preflight_blocked"
},
if ok { "info" } else { "warning" },
if memory_warning_only {
"warning"
} else if ok {
"info"
} else {
"warning"
},
summary,
);
}
@@ -2571,15 +2582,17 @@ pub struct QdiscBudgetEstimate {
pub memory_guard_min_available_bytes: u64,
/// Whether the memory preflight passed.
pub memory_ok: bool,
/// Whether lazy queue mode makes a memory-only preflight failure non-blocking.
pub memory_warning_only: bool,
}
impl QdiscBudgetEstimate {
/// Returns `true` when all planned per-interface counts fit within the safe budget.
/// Returns `true` when the qdisc count fits and memory preflight passes or is a lazy-queue warning.
pub fn ok(&self) -> bool {
self.interfaces
.values()
.all(|count| *count <= self.safe_budget)
&& self.memory_ok
&& (self.memory_ok || self.memory_warning_only)
}
}
@@ -2723,6 +2736,14 @@ pub fn estimate_full_reload_auto_qdisc_budget(
.saturating_sub(memory_guard_min_available_bytes)
>= estimated_total_memory_bytes
});
let qdisc_counts_fit = interfaces
.values()
.all(|count| *count <= SAFE_QDISC_BUDGET_PER_INTERFACE);
let memory_warning_only = lazy_queue_memory_preflight_is_warning(
config.queues.lazy_queues.as_ref(),
qdisc_counts_fit,
memory_ok,
);
QdiscBudgetEstimate {
interfaces,
@@ -2733,9 +2754,23 @@ pub fn estimate_full_reload_auto_qdisc_budget(
memory_snapshot,
memory_guard_min_available_bytes,
memory_ok,
memory_warning_only,
}
}
fn lazy_queue_memory_preflight_is_warning(
lazy_queue_mode: Option<&LazyQueueMode>,
qdisc_counts_fit: bool,
memory_ok: bool,
) -> bool {
qdisc_counts_fit
&& !memory_ok
&& matches!(
lazy_queue_mode,
Some(LazyQueueMode::Htb | LazyQueueMode::Full)
)
}
fn desired_shaping_tree_active(config: &Arc<Config>) -> bool {
!config.queues.queue_mode.is_observe()
}
@@ -14356,6 +14391,25 @@ mod tests {
);
}
#[test]
fn memory_warning_only_allows_preflight_to_continue() {
let mut estimate = QdiscBudgetEstimate {
interfaces: BTreeMap::from([("eth0".to_string(), 1)]),
interface_details: BTreeMap::new(),
safe_budget: SAFE_QDISC_BUDGET_PER_INTERFACE,
hard_limit: HARD_QDISC_HANDLE_LIMIT_PER_INTERFACE,
estimated_total_memory_bytes: 1,
memory_snapshot: None,
memory_guard_min_available_bytes: BAKERY_MEMORY_GUARD_MIN_AVAILABLE_BYTES,
memory_ok: false,
memory_warning_only: true,
};
assert!(estimate.ok());
estimate.memory_warning_only = false;
assert!(!estimate.ok());
}
#[test]
fn command_qdisc_memory_estimate_deduplicates_qdisc_identity() {
let commands = vec![
+10 -5
View File
@@ -3646,11 +3646,15 @@ impl Bakery {
.interfaces
.values()
.all(|count| *count <= estimate.safe_budget);
let preflight_status = match (qdisc_counts_fit, estimate.memory_ok) {
(true, true) => "fits preflight",
(false, true) => "exceeds qdisc-count preflight",
(true, false) => "passed qdisc-count preflight but failed memory preflight",
(false, false) => "exceeds qdisc-count preflight and failed memory preflight",
let preflight_status = if estimate.memory_warning_only {
"passed qdisc-count preflight; memory preflight is a non-blocking lazy-queue warning"
} else {
match (qdisc_counts_fit, estimate.memory_ok) {
(true, true) => "fits preflight",
(false, true) => "exceeds qdisc-count preflight",
(true, false) => "passed qdisc-count preflight but failed memory preflight",
(false, false) => "exceeds qdisc-count preflight and failed memory preflight",
}
};
let memory_summary = if let Some(snapshot) = estimate.memory_snapshot.as_ref() {
let required_available_bytes = estimate
@@ -3738,6 +3742,7 @@ impl Bakery {
estimate.estimated_total_memory_bytes,
)?;
result.set_item("memory_ok", estimate.memory_ok)?;
result.set_item("memory_warning_only", estimate.memory_warning_only)?;
result.set_item(
"memory_guard_min_available_bytes",
estimate.memory_guard_min_available_bytes,
+1
View File
@@ -907,6 +907,7 @@ fn handle_bus_requests(requests: &[BusRequest], responses: &mut Vec<BusResponse>
memory_available_bytes: *memory_available_bytes,
memory_guard_min_available_bytes: *memory_guard_min_available_bytes,
memory_ok: *memory_ok,
memory_warning_only: *ok && !*memory_ok,
interfaces: interfaces
.iter()
.map(|entry| lqos_bakery::BakeryCapacityInterfaceSnapshot {
@@ -99,6 +99,9 @@ function classifyEvent(entry) {
} else if (event === "preflight_ok") {
outcome = "Passed";
outcomeClass = "bg-success-subtle text-success border border-success-subtle";
} else if (event === "preflight_warning") {
outcome = "Memory Warning";
outcomeClass = "bg-warning-subtle text-warning border border-warning-subtle";
} else if (event === "preflight_blocked") {
outcome = "Blocked";
outcomeClass = "bg-warning-subtle text-warning border border-warning-subtle";
@@ -37,6 +37,9 @@ function bakeryMemoryBadge(preflight) {
if (preflight.memoryOk) {
return mkBadge("Memory OK", "bg-success-subtle text-success border border-success-subtle", preflight.message || "");
}
if (preflight.ok) {
return mkBadge("Memory Warning", "bg-warning-subtle text-warning border border-warning-subtle", preflight.message || "");
}
return mkBadge("Memory Guard", "bg-danger-subtle text-danger border border-danger-subtle", preflight.message || "");
}