pub struct MonitorCore { /* private fields */ }Expand description
The monitor’s shareable core: ingest on one side, events + snapshots on
the other. Session wiring lives in Monitor; the core is pure and
deterministically testable.
Implementations§
Source§impl MonitorCore
impl MonitorCore
pub fn new(capacity: usize) -> Arc<MonitorCore> ⓘ
Sourcepub fn bounded(capacity: usize, max_keys: usize) -> Arc<MonitorCore> ⓘ
pub fn bounded(capacity: usize, max_keys: usize) -> Arc<MonitorCore> ⓘ
A core whose statistics table is bounded at max_keys distinct keys.
Sourcepub fn ingest(&self, view: SampleView, sn: Option<u32>)
pub fn ingest(&self, view: SampleView, sn: Option<u32>)
Ingest one sample: stats update + retention + broadcast. Hot path — two short locks, no tree work (that happens on the tick).
Sourcepub fn ingest_at(
&self,
view: Arc<SampleView>,
sn: Option<u32>,
now: Instant,
wall: SystemTime,
)
pub fn ingest_at( &self, view: Arc<SampleView>, sn: Option<u32>, now: Instant, wall: SystemTime, )
MonitorCore::ingest with both clocks injected (#217).
Replay rebuilds feed this with the capture clock — the row’s t
offset from the load epoch, on both axes: now for the monotonic
fold, wall for the skewed-latency subtraction — rather than the
live clocks, which is what makes a rebuild deterministic down to the
EWMA rates and the latency window: the same rows at the same instants
fold to bit-identical statistics, however fast the rebuild loop runs.
(Before wall was threaded, the latency read the live wall clock
even under an injected now, so a rebuild folded arrival-time
garbage — deep-review D2.)
pub fn node_event(&self, key: String, up: bool)
Sourcepub fn tick(&self)
pub fn tick(&self)
Rebuild the snapshot from the stats and announce it.
Two phases, and the split is the whole point (#330). The stats
mutex is the one ingest takes on zenoh’s network
callback thread, so whatever this holds it for, the network layer
waits for. It therefore holds it for the O(keys) row copy
(StatsTable::rows) and folds the tree — O(keys × chunks) of
BTreeMap descents, a String per new node, ~300 000 map operations
at the 50 000-key bound — after releasing it. Four times a second the
old shape held the lock for the whole rebuild, which made
Monitor::watch’s promise that a slow UI cannot exert backpressure
into the network layer false four times a second.
The fold still runs on the calling thread here. The periodic tick
takes tick_off_runtime instead, which puts
it on the blocking pool where that much CPU belongs.
Sourcepub async fn tick_off_runtime(&self)
pub async fn tick_off_runtime(&self)
tick with the fold on the blocking pool (#330): the
copy is taken here, the CPU is spent on a blocking thread, and the
runtime’s workers stay free for the drains they exist for. Used by the
stats-tick task; tick remains the synchronous form for the paths
that publish a snapshot as part of another operation (a seed boundary,
an unwatch).
Sourcepub fn tree(&self) -> Arc<KeyTreeSnapshot> ⓘ
pub fn tree(&self) -> Arc<KeyTreeSnapshot> ⓘ
The latest immutable snapshot (lock-free pull).
Sourcepub fn with_stats<R>(&self, f: impl FnOnce(&StatsTable) -> R) -> R
pub fn with_stats<R>(&self, f: impl FnOnce(&StatsTable) -> R) -> R
Read access to the raw stats (hz/bw commands).
Sourcepub fn with_stats_mut<R>(&self, f: impl FnOnce(&mut StatsTable) -> R) -> R
pub fn with_stats_mut<R>(&self, f: impl FnOnce(&mut StatsTable) -> R) -> R
Mutable access — watch retirement and tests.
Sourcepub fn keys_unwatched(&self) -> u64
pub fn keys_unwatched(&self) -> u64
Keys retired from the table because their watch was released
(RFC 09 §5.1 O6 — see crate::model::stats::StatsTable::unwatched).
Sourcepub fn keys_evicted(&self) -> u64
pub fn keys_evicted(&self) -> u64
Distinct keys dropped from the statistics table to stay within its bound. Non-zero means the key set on display is partial — report it rather than letting a shrinking tree read as a quieting bus (RFC 09 §5.1).
Sourcepub fn retained(&self) -> Arc<[Arc<SampleView>]> ⓘ
pub fn retained(&self) -> Arc<[Arc<SampleView>]> ⓘ
The retained window, oldest first (#217): Arc clones of every
sample still inside both retention budgets. This is what the GUI’s
retained scrub rebuilds panes from, and what “save window as .zrec”
writes — the same rows either way.
Covers only watched keys by construction: the ring sits on the ingest path, and nothing unwatched is ever ingested. A consumer that presents this window MUST say so (RFC 09 §5.1 O5 — a retained window over three watches is not a retained window over the bus).
What this read costs the network thread (#331): the retain mutex
is ingest’s, taken on zenoh’s callback thread, so a
read that walked the window blocked the network layer for as long as
the window was long — 64 MiB of 256-byte samples is ~260 000 refcount
atomics, and zengui calls this from update(). The ring is chunked
instead (crate::model::retain): under the lock this clones the
sealed chunks’ pointers and the open tail — bounded by
window / 1024 + 1024, independent of payload — and the flatten into
the returned slice happens after the guard is dropped. The result
is an Arc<[_]> so passing the window on costs nothing again.
Sourcepub fn retention(&self) -> RetentionStats
pub fn retention(&self) -> RetentionStats
The retained window’s account of itself: budget in force, what it
holds, and what each bound cost — evicted (byte budget) apart from
expired (age), both apart from MonitorCore::dropped,
MonitorCore::keys_evicted and MonitorCore::keys_unwatched
(RFC 09 §5.1 O6; v1.18 R1 forbids folding the kinds).
Sourcepub fn set_retention_budget(&self, budget: RetentionBudget)
pub fn set_retention_budget(&self, budget: RetentionBudget)
Change the retention budget in force; applied from the next push or
read. The default (RetentionBudget::default) is 64 MiB / 2 min.
Sourcepub fn events(self: &Arc<Self>) -> EventStream
pub fn events(self: &Arc<Self>) -> EventStream
Subscribe to the event stream.
Auto Trait Implementations§
impl !Freeze for MonitorCore
impl !RefUnwindSafe for MonitorCore
impl !UnwindSafe for MonitorCore
impl Send for MonitorCore
impl Sync for MonitorCore
impl Unpin for MonitorCore
impl UnsafeUnpin for MonitorCore
Blanket Implementations§
Source§impl<Source> AccessAs for Source
impl<Source> AccessAs for Source
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more