pub struct Tracker { /* private fields */ }Expand description
Bounded per-pid liveness ledger.
The slot table is a Vec<Slot> pre-allocated at construction to the
configured capacity; subsequent inserts push into that pre-allocated
space without reallocation. Lookups use a fixed-size [PidIndex] for
O(1) pid-to-index mapping — replaces the original HashMap so the hot
path is WCET-bounded (deterministic hash, bounded probe budget, no
rehashing on growth).
Implementations§
Source§impl Tracker
impl Tracker
Sourcepub fn new(
capacity: usize,
eviction_policy: EvictionPolicy,
eviction_scan_window: usize,
) -> Self
pub fn new( capacity: usize, eviction_policy: EvictionPolicy, eviction_scan_window: usize, ) -> Self
Create an empty tracker with capacity for capacity pids.
The slot table is pre-allocated to capacity entries; pushing
beyond that boundary yields Update::CapacityExceeded rather
than reallocating.
eviction_scan_window caps the number of slots inspected per
eviction attempt. Values outside
[MIN_EVICTION_SCAN_WINDOW, MAX_EVICTION_SCAN_WINDOW] are clamped
as defense in depth; the config layer rejects out-of-range values
loudly at startup.
Sourcepub fn record(
&mut self,
frame: &Frame,
now_ns: u64,
threshold_ns: u64,
origin: BeatOrigin,
peer_pid_ns_inode: Option<u64>,
) -> Update
pub fn record( &mut self, frame: &Frame, now_ns: u64, threshold_ns: u64, origin: BeatOrigin, peer_pid_ns_inode: Option<u64>, ) -> Update
Record a frame against the tracker.
Uses O(1) HashMap pid lookup to find the slot for frame.pid.
Returns Update::Inserted for a brand-new pid, Update::Refreshed
for an existing pid whose nonce moved forward, Update::OutOfOrder
if the nonce did not strictly increase, Update::CapacityExceeded
if the slot table is full (and no stale slot could be reclaimed) and
the pid is not yet tracked, or Update::OriginConflict if the
frame’s transport origin disagrees with the slot’s pinned origin.
origin is the transport-class classification surfaced by the
receiving listener (KernelAttested for UDS, NetworkUnverified for
any UDP variant). The first beat for a pid pins the slot’s origin;
subsequent beats from a different origin are dropped without
mutating the slot.
peer_pid_ns_inode is the kernel-attested PID-namespace inode of the
sending process (Linux only; None on non-Linux or when
/proc/<peer_pid>/ns/pid was unreadable). The first beat pins the
slot’s namespace inode; a later beat carrying a different Some(_)
inode for the same pid is rejected as Update::NamespaceConflict.
A None → Some(_) upgrade is permitted (peer became readable after a
transient failure); a Some(_) → None regression is treated as a
conflict.
Sourcepub fn take_evictions(&mut self) -> u64
pub fn take_evictions(&mut self) -> u64
Take and reset the eviction counter. Returns the number of slots reclaimed since the last call.
Sourcepub fn take_evicted_pid(&mut self) -> Option<u32>
pub fn take_evicted_pid(&mut self) -> Option<u32>
Return the pid of the most recently evicted slot, if any slots have been evicted since the last call.
Sourcepub fn take_nonce_wraps(&mut self) -> u64
pub fn take_nonce_wraps(&mut self) -> u64
Take and reset the nonce-wrap counter. Returns the number of nonce-space wraps detected since the last call.
Sourcepub fn take_capacity_exceeded(&mut self) -> u64
pub fn take_capacity_exceeded(&mut self) -> u64
Take and reset the capacity-exceeded counter. Returns the number of beats dropped due to a full tracker since the last call.
Sourcepub fn last_ns_of(&self, pid: u32) -> Option<u64>
pub fn last_ns_of(&self, pid: u32) -> Option<u64>
Return the last_ns timestamp for a tracked pid, if present.
Used by the observer for per-pid rate limiting without exposing
internal slot layout.
Sourcepub fn origin_of(&self, pid: u32) -> Option<BeatOrigin>
pub fn origin_of(&self, pid: u32) -> Option<BeatOrigin>
Return the pinned transport origin of a tracked pid, if present.
Used by the observer to populate Event::OriginConflict::slot_origin
before calling record (which may produce the conflict).
Sourcepub fn pid_ns_inode_of(&self, pid: u32) -> Option<Option<u64>>
pub fn pid_ns_inode_of(&self, pid: u32) -> Option<Option<u64>>
Return the pinned PID-namespace inode of a tracked pid, if present.
The outer Option is Some when the pid is tracked at all; the inner
Option is the inode (or None for non-Linux / unreadable). Used by
the observer to populate Event::NamespaceConflict::slot_ns_inode
without an extra slot lookup.
Sourcepub fn drain_stalled_slots(
&mut self,
now_ns: u64,
threshold_ns: u64,
cb: impl FnMut(u32, u64, u64, BeatOrigin, Option<u64>),
)
pub fn drain_stalled_slots( &mut self, now_ns: u64, threshold_ns: u64, cb: impl FnMut(u32, u64, u64, BeatOrigin, Option<u64>), )
Find newly-stalled slots and mark them emitted in one atomic pass.
A slot is “newly stalled” when its silence duration exceeds
threshold_ns and the observer has not yet surfaced a stall
event for the current silence run (stall_emitted == false).
Qualifying slots are marked stall_emitted = true and the callback
is invoked with (pid, last_nonce, last_ns, origin, pid_ns_inode) —
all within the same mutable borrow, closing the TOCTOU window that
existed between the former iter_stalled / mark_stall_emitted pair.
Sourcepub fn take_origin_conflicts(&mut self) -> u64
pub fn take_origin_conflicts(&mut self) -> u64
Take and reset the origin-conflict counter.
Surfaced as varta_origin_conflict_total by the Prometheus exporter;
non-zero values indicate that beats for a tracked pid arrived from a
transport other than the one that first claimed the pid — either a
misconfigured agent or an active spoofing attempt.
Sourcepub fn take_namespace_conflicts(&mut self) -> u64
pub fn take_namespace_conflicts(&mut self) -> u64
Take and reset the namespace-conflict counter.
Surfaced as varta_tracker_namespace_conflict_total by the Prometheus
exporter; non-zero values mean beats for a tracked pid arrived from a
different PID namespace than the one pinned by the slot’s first beat.
Linux-only signal; on non-Linux platforms this counter stays at 0.
Sourcepub fn take_eviction_scan_truncated(&mut self) -> u64
pub fn take_eviction_scan_truncated(&mut self) -> u64
Take and reset the bounded-window truncated-scan counter.
Surfaced as varta_tracker_eviction_scan_truncated_total by the
Prometheus exporter; non-zero values prove the window cap actually
engaged (i.e. the table was full and no victim was found within
EVICTION_SCAN_WINDOW slots).
Sourcepub fn take_invariant_violations(&mut self) -> u64
pub fn take_invariant_violations(&mut self) -> u64
Take and reset the invariant-violation counter.
Surfaced as varta_tracker_invariant_violations_total by the
Prometheus exporter. In correctly-operating code this counter stays
at 0 forever — non-zero values mean one of the defensive .get()
fall-throughs in the hot path triggered (e.g. a stale PidIndex
entry pointed at an out-of-range slot). The tracker recovers
without panicking; ops should still treat any non-zero value as a
bug worth investigating.
Sourcepub fn take_probe_exhausted(&mut self) -> u64
pub fn take_probe_exhausted(&mut self) -> u64
Take and reset the [PidIndex] probe-exhaustion counter.
Surfaced as varta_tracker_pid_index_probe_exhausted_total by the
Prometheus exporter. Non-zero values mean a pid lookup walked
[PidIndex::MAX_PROBE] slots without resolving — at load factor
≤ 0.5 this is effectively unreachable, so any non-zero value is a
red flag (pathological pid distribution, or an attempt to fill the
index past its safe load factor).