pub struct LimitsSpec {
pub memory: Option<u64>,
pub fuel: Option<u64>,
pub wall_clock: Option<Duration>,
pub cpu: Option<u32>,
}Expand description
Per-process limits. All fields optional — None = unbounded for that axis.
Fields§
§memory: Option<u64>Max linear memory in bytes. Authored as a byte-size string
("64MiB", "1GiB", "512KB"). Round-trips back to the same
canonical string on serialize.
fuel: Option<u64>Max wasm instructions per outermost call (wasmtime fuel).
Plain integer; None = unbounded.
wall_clock: Option<Duration>Wall-clock cap per outermost call. Authored as a duration
string ("30s", "500ms", "2m").
cpu: Option<u32>Soft CPU share. Authored as a Kubernetes-style millicore string
("500m" for half a core, "2" or "2000m" for two cores).
Stored as millicores (u32).
Implementations§
Source§impl LimitsSpec
impl LimitsSpec
Sourcepub const fn memory(&self) -> Option<u64>
pub const fn memory(&self) -> Option<u64>
Substrate-canonical per-:limits :memory Lunatic-per-process
wasm32-linear-memory byte-cap scalar accessor every consumer of
the Servico’s wasmtime::StoreLimits::memory_size propagation
keys off — returns the author-declared :limits :memory typed
byte-cap verbatim as an Option<u64>, copied out of the typed
slot’s own Option<u64> storage (Option<u64> is Copy, so
the accessor returns by value; no borrow of &self past the
call). None when the slot is absent (the “no memory cap
declared — engine-default applies, today the pre-M2 unbounded-
linear-memory shape” arm the module-level docstring names on
LimitsSpec::memory itself — LimitsSpec::is_empty’s
memory().is_none() arm reads this predicate too, so an
authored-but-unset :limits (:memory ()) round-trips to a
servico_m2_overlay emission structurally identical to one
that omits the slot entirely).
The :limits :memory slot carries the “per-process wasm32
linear-memory byte-cap” Lunatic-shaped sandboxing contract
(theory/INSPIRATIONS.md §III.1) — the typed slot’s
Option<u64> accept-set (zero-floor rejected through
LimitsError::MemoryZero, wasm32-page-floor rejected through
LimitsError::MemoryBelowWasm32Page, upper-bounded by
LIMITS_MEMORY_WASM32_MAX_BYTES, authored as a byte-size
string that round-trips back to the canonical form through
[ser_byte_size] / [de_byte_size]) maps onto the wasmtime
Store::limiter-side memory_size projection the wasm-engine
M2 wires and, via crate::render::servico_m2_overlay, onto
the pleme-computeunit Helm-library-chart values sub-block’s
limits.memory key that lands as the ComputeUnit CR’s
spec.limits.memory field.
Prior to this lift the .memory field was accessed inline at
four sites inside impl LimitsSpec — LimitsSpec::is_empty’s
self.memory.is_none() arm and three LimitsSpec::validate
arms (the numeric zero-floor arm at line 397, the wasm32-page
structural floor arm at line 427, and the wasm32 upper-cap
arm at line 449) — four open-coded field-accesses that
expressed no compile-time link back to the typed slot. A
future extension of the :limits :memory axis to a richer
author surface — a per-instance memory-declaration override
the operator pins through a future ComputeUnit CR-side
spec.limits.memory overlay, a split of the single u64
byte-cap into a {min, max} pair once wasm32’s (memory M N)
two-arg form promotes past its current single-max typed
bound, a wasm64 promotion once the wasm-engine grows past the
wasm32 4 GiB structural ceiling — would have had to be
threaded through every open-coded copy in lockstep or the
emptiness predicate and the validate call would silently
disagree on which cap a given LimitsSpec resolves to.
Lifting the resolution to a typed method on the substrate
primitive means every downstream consumer of the Servico’s
per-:limits byte-cap surface reaches for exactly one typed
dispatch — the resolver’s accept-set migrates as a unit on any
future axis addition.
First Option<Copy-T>-return accessor on the M2 slot family
(peer of the sibling per-:politicas crate::MeshPolicy::mtls_required
c0110f1 Option<bool> accessor, per-:politicas
crate::MeshPolicy::retries bdfb399 Option<u32> accessor,
and per-:politicas crate::MeshPolicy::timeout 7073d0f
Option<Duration> accessor on the M3 mesh-slot family — same
“one typed dispatch on the substrate primitive, thin
projections at each consumer” discipline extended onto the
peer per-:limits typed-u64 optional-scalar axis; opens the
“optional per-slot Copy-T scalar” projection pattern the
sibling per-:limits :fuel (Option:wall-clock
(Option:cpu (Optionmemory() to match the storage field’s name; the
accessor’s identity maps onto the canonical Lunatic-shaped
theory/INSPIRATIONS.md §III.1 vocabulary the slot’s docstring
already carries.
Sourcepub const fn fuel(&self) -> Option<u64>
pub const fn fuel(&self) -> Option<u64>
Substrate-canonical per-:limits :fuel wasmtime-per-call
wasm-instruction budget scalar accessor every consumer of the
Servico’s wasmtime::Store::set_fuel propagation keys off —
returns the author-declared :limits :fuel typed
wasm-instruction budget verbatim as an Option<u64>, copied
out of the typed slot’s own Option<u64> storage
(Option<u64> is Copy, so the accessor returns by value; no
borrow of &self past the call). None when the slot is
absent (the “no fuel budget declared — engine-default applies,
today the pre-M2 unbounded-fuel-counter shape” arm the
module-level docstring names on LimitsSpec::fuel itself —
LimitsSpec::is_empty’s fuel().is_none() arm reads this
predicate too, so an authored-but-unset :limits (:fuel ())
round-trips to a servico_m2_overlay emission structurally
identical to one that omits the slot entirely).
The :limits :fuel slot carries the “per-call wasm-instruction
budget” wasmtime-shaped sandboxing contract
(theory/INSPIRATIONS.md §III.1 — Lunatic’s supervised
wasm-Store-per-process fuel accounting, translated onto
pleme-io’s typed :limits slot) — the typed slot’s
Option<u64> accept-set (zero-floor rejected through
LimitsError::FuelZero because wasmtime traps the first
instruction at fuel=0, upper-bounded by LIMITS_FUEL_MAX
(10¹² wasm instructions — the operationally-reachable
per-call budget within the sibling LIMITS_WALL_CLOCK_MAX
1h ceiling)) maps onto the wasmtime Store::set_fuel call
the M2.5 wasm-engine wires per outermost call and, via
crate::render::servico_m2_overlay, onto the
pleme-computeunit Helm-library-chart values sub-block’s
limits.fuel key that lands as the ComputeUnit CR’s
spec.limits.fuel field.
Prior to this lift the .fuel field was accessed inline at
two sites inside impl LimitsSpec — LimitsSpec::is_empty’s
self.fuel.is_none() arm and LimitsSpec::validate’s
if let Some(f) = self.fuel { … } zero-floor + upper-cap
bracket arm — two open-coded field-accesses that expressed no
compile-time link back to the typed slot. A future extension
of the :limits :fuel axis to a richer author surface — a
per-instance ComputeUnit CR-side spec.limits.fuel overlay
the operator pins per-cluster, a wasm-instruction-count →
wasmtime-fuel-unit rescale once the fuel-tracking backend
switches from Cranelift’s implicit 1:1 count to a
per-opcode-weighted budget, a split of the single
per-outermost-call u64 budget into a {per_call, per_second}
pair once the wasm-engine grows a sustained-throughput cap —
would have had to be threaded through every open-coded copy in
lockstep or the emptiness predicate and the validate call
would silently disagree on which fuel budget a given
LimitsSpec resolves to. Lifting the resolution to a typed
method on the substrate primitive means every downstream
consumer of the Servico’s per-:limits fuel-budget surface
reaches for exactly one typed dispatch — the resolver’s
accept-set migrates as a unit on any future axis addition.
Second Option<Copy-T>-return accessor on the M2 slot family
(peer of the sibling per-:limits LimitsSpec::memory
(620c067) Option<u64> accessor — same typed-u64
optional-scalar shape, extended to the peer per-:limits
wasm-instruction-budget axis; sibling to
crate::MeshPolicy::mtls_required (c0110f1) / crate::MeshPolicy::retries
(bdfb399) / crate::MeshPolicy::timeout (7073d0f) on the
closed M3 mesh-slot Option<Copy-T> accessor family). The
pair (memory(), fuel()) jointly projects the two Option<u64>
axes every M2 :limits consumer that fans on
wasm-linear-memory-cap + wasm-fuel-budget keys off. Two of the
four :limits axes now route through a typed dispatch on the
substrate primitive; the two remaining (wall_clock: Option<Duration>, cpu: Option<u32>) fold on the same
one-line accessor + is_empty-arm-route + validate-arm-route +
three-test pattern. Named fuel() to match the storage field’s
name; the accessor’s identity maps onto the canonical
wasmtime-Store::set_fuel-shaped vocabulary the slot’s
docstring already carries.
Sourcepub const fn wall_clock(&self) -> Option<Duration>
pub const fn wall_clock(&self) -> Option<Duration>
Substrate-canonical per-:limits :wall-clock wasmtime-per-call
wall-clock deadline scalar accessor every consumer of the
Servico’s wasmtime::Store::epoch_deadline_* / wasi:clocks
propagation keys off — returns the author-declared :limits :wall-clock typed Duration verbatim as an Option<Duration>,
copied out of the typed slot’s own Option<Duration> storage
(Duration is Copy, so Option<Duration> is Copy and the
accessor returns by value; no borrow of &self past the call).
None when the slot is absent (the “no wall-clock deadline
declared — engine-default applies, today the pre-M2
unbounded-wall-clock shape” arm the module-level docstring names
on LimitsSpec::wall_clock itself — LimitsSpec::is_empty’s
wall_clock().is_none() arm reads this predicate too, so an
authored-but-unset :limits (:wall-clock ()) round-trips to a
servico_m2_overlay emission structurally identical to one that
omits the slot entirely).
The :limits :wall-clock slot carries the “per-outermost-call
wall-clock deadline” wasmtime-shaped sandboxing contract
(theory/INSPIRATIONS.md §III.1 — Lunatic’s supervised
wasm-Store-per-process epoch-deadline accounting, translated
onto pleme-io’s typed :limits slot) — the typed slot’s
Option<Duration> accept-set (zero-floor rejected through
LimitsError::WallClockZero because a zero deadline traps the
first instruction; integer-millisecond granularity enforced
through LimitsError::WallClockNotCanonical because the
duration codec’s canonical form emits "1500ms" not "1.5s"
and the operator’s wall-clock scheduler quantizes at
milliseconds; upper-bounded by LIMITS_WALL_CLOCK_MAX (1h —
the coarsest per-call deadline any operationally-reachable
Servico can honor without spanning multiple scheduler epochs))
maps onto the wasmtime Store::epoch_deadline_* call the M2.5
wasm-engine wires per outermost call and, via
crate::render::servico_m2_overlay, onto the
pleme-computeunit Helm-library-chart values sub-block’s
limits.wallClock key that lands as the ComputeUnit CR’s
spec.limits.wallClock field.
Prior to this lift the .wall_clock field was accessed inline at
two sites inside impl LimitsSpec — LimitsSpec::is_empty’s
self.wall_clock.is_none() arm and LimitsSpec::validate’s
if let Some(w) = self.wall_clock { … } zero-floor +
canonical-form + upper-cap bracket arm — two open-coded
field-accesses that expressed no compile-time link back to the
typed slot. A future extension of the :limits :wall-clock axis
to a richer author surface — a per-instance ComputeUnit
CR-side spec.limits.wallClock overlay the operator pins
per-cluster, a wall-clock-vs-monotonic-clock discriminator once
the wasm-engine grows a :limits (:wall-clock (:kind monotonic …)) axis, a split of the single per-outermost-call Duration
budget into a {deadline, warn_at} pair once the wasm-engine
grows a soft-deadline warning surface — would have had to be
threaded through every open-coded copy in lockstep or the
emptiness predicate and the validate call would silently
disagree on which deadline a given LimitsSpec resolves to.
Lifting the resolution to a typed method on the substrate
primitive means every downstream consumer of the Servico’s
per-:limits wall-clock-deadline surface reaches for exactly
one typed dispatch — the resolver’s accept-set migrates as a
unit on any future axis addition.
Third Option<Copy-T>-return accessor on the M2 slot family
(peer of the sibling per-:limits LimitsSpec::memory
(620c067) Option<u64> accessor and per-:limits
LimitsSpec::fuel (795dee7) Option<u64> accessor — same
typed-optional-scalar shape extended to the peer per-:limits
wall-clock-deadline axis; sibling to crate::MeshPolicy::timeout
(7073d0f) on the closed M3 mesh-slot Option<Duration> accessor
axis — same typed-Duration shape extended from the M3
per-call-timeout to the M2 per-outermost-call deadline). The
triple (memory(), fuel(), wall_clock()) jointly projects three
of the four Option<Copy-T> axes every M2 :limits consumer
that fans on wasm-linear-memory-cap + wasm-fuel-budget +
wall-clock-deadline keys off. Three of the four :limits axes
now route through a typed dispatch on the substrate primitive;
the one remaining (cpu: Option<u32>) folds on the same
one-line accessor + is_empty-arm-route + validate-arm-route +
three-test pattern in the next run, closing the M2 :limits
slot family’s Option<Copy-T> accessor axis. Named wall_clock()
to match the storage field’s name; the accessor’s identity maps
onto the canonical wasmtime-Store::epoch_deadline_*-shaped
vocabulary the slot’s docstring already carries.
Sourcepub const fn cpu(&self) -> Option<u32>
pub const fn cpu(&self) -> Option<u32>
Substrate-canonical per-:limits :cpu Kubernetes-millicore
soft cgroup-share scalar accessor every consumer of the Servico’s
pod-spec resources.requests.cpu propagation keys off — returns
the author-declared :limits :cpu typed millicore magnitude
verbatim as an Option<u32>, copied out of the typed slot’s own
Option<u32> storage (Option<u32> is Copy, so the accessor
returns by value; no borrow of &self past the call). None
when the slot is absent (the “no cpu share declared —
scheduler-default applies, today the pre-M2 unbounded-cpu-share
shape” arm the module-level docstring names on
LimitsSpec::cpu itself — LimitsSpec::is_empty’s
cpu().is_none() arm reads this predicate too, so an
authored-but-unset :limits (:cpu ()) round-trips to a
servico_m2_overlay emission structurally identical to one that
omits the slot entirely).
The :limits :cpu slot carries the “per-process soft cgroup-v2
CPU share” Kubernetes-scheduler-shaped sandboxing hint
(theory/INSPIRATIONS.md §III.1 — Lunatic’s supervised
wasm-Store-per-process host-runtime CPU accounting, translated
onto pleme-io’s typed :limits slot as a scheduler-facing
millicore request the pod’s kubelet propagates to the container’s
cgroup) — the typed slot’s Option<u32> accept-set (zero-floor
rejected through LimitsError::CpuZero because a zero cgroup
share starves the process; upper-bounded by
LIMITS_CPU_MILLICORES_MAX (128 cores — the largest commercially-
common non-metal cloud Kubernetes node vCPU count on managed GKE
/ EKS / AKS general-purpose SKUs)) maps onto the K8s pod spec’s
spec.containers[].resources.requests.cpu field the
M2.5 wasm-engine host-runtime lands on the ComputeUnit CR-side
pod template and, via crate::render::servico_m2_overlay, onto
the pleme-computeunit Helm-library-chart values sub-block’s
limits.cpu key that lands as the ComputeUnit CR’s
spec.limits.cpu field.
Prior to this lift the .cpu field was accessed inline at two
sites inside impl LimitsSpec — LimitsSpec::is_empty’s
self.cpu.is_none() arm and LimitsSpec::validate’s
if let Some(m) = self.cpu { … } zero-floor + upper-cap bracket
arm — two open-coded field-accesses that expressed no
compile-time link back to the typed slot. A future extension of
the :limits :cpu axis to a richer author surface — a
per-instance ComputeUnit CR-side spec.limits.cpu overlay the
operator pins per-cluster, a split of the single u32 millicore
request into a {request, limit} pair once the pod spec’s
resources.requests.cpu / resources.limits.cpu distinction
promotes past its current single-request author surface, a
millicore → cgroup-v2 cpu.weight rescale once the operator’s
scheduler-facing translation lands past its current kubelet
passthrough — would have had to be threaded through every
open-coded copy in lockstep or the emptiness predicate and the
validate call would silently disagree on which cgroup share a
given LimitsSpec resolves to. Lifting the resolution to a
typed method on the substrate primitive means every downstream
consumer of the Servico’s per-:limits cpu-share surface reaches
for exactly one typed dispatch — the resolver’s accept-set
migrates as a unit on any future axis addition.
Fourth and final Option<Copy-T>-return accessor on the M2 slot
family (peer of the sibling per-:limits LimitsSpec::memory
(620c067) Option<u64> accessor, per-:limits
LimitsSpec::fuel (795dee7) Option<u64> accessor, and
per-:limits LimitsSpec::wall_clock (8cb717b)
Option<Duration> accessor — same typed-optional-scalar shape
extended to the peer per-:limits cgroup-cpu-share axis; sibling
to crate::MeshPolicy::mtls_required (c0110f1) /
crate::MeshPolicy::retries (bdfb399) /
crate::MeshPolicy::timeout (7073d0f) on the closed M3
mesh-slot Option<Copy-T> accessor family). The four-tuple
(memory(), fuel(), wall_clock(), cpu()) jointly projects every
Option<Copy-T> axis on the M2 :limits slot every consumer
that fans on wasm-linear-memory-cap + wasm-fuel-budget +
wall-clock-deadline + cgroup-cpu-share keys off — closes the M2
:limits slot family’s Option<Copy-T> accessor axis (the
last unlifted :limits field-access site on the M2 slot family;
every axis now routes through a typed dispatch on the substrate
primitive, with no open-coded field access anywhere on the impl).
Named cpu() to match the storage field’s name; the accessor’s
identity maps onto the canonical Kubernetes-resources.requests.cpu-
shaped vocabulary the slot’s docstring already carries.
Sourcepub fn validate(&self) -> Result<(), LimitsError>
pub fn validate(&self) -> Result<(), LimitsError>
Reject operationally-meaningless zero values on every declared axis. Each axis remains optional — omitting a field expresses “no bound on this axis”; the bug being closed is carrying a zero value, which the wasm-engine consumes as “trap the first instruction” / “instantiation refused” / “immediate timeout” rather than the author’s intended “an unspecified bound”.
Mirrors the discipline applied to :politicas axes in
AplicacaoSpec::validate and to SupervisorSpec::max_restarts
— every typed value carried by a slot is either absent or
meaningfully non-zero.
Trait Implementations§
Source§impl Clone for LimitsSpec
impl Clone for LimitsSpec
Source§fn clone(&self) -> LimitsSpec
fn clone(&self) -> LimitsSpec
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for LimitsSpec
Source§impl Debug for LimitsSpec
impl Debug for LimitsSpec
Source§impl Default for LimitsSpec
impl Default for LimitsSpec
Source§fn default() -> LimitsSpec
fn default() -> LimitsSpec
Source§impl<'de> Deserialize<'de> for LimitsSpec
impl<'de> Deserialize<'de> for LimitsSpec
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for LimitsSpec
Source§impl PartialEq for LimitsSpec
impl PartialEq for LimitsSpec
Source§impl Serialize for LimitsSpec
impl Serialize for LimitsSpec
impl StructuralPartialEq for LimitsSpec
Auto Trait Implementations§
impl Freeze for LimitsSpec
impl RefUnwindSafe for LimitsSpec
impl Send for LimitsSpec
impl Sync for LimitsSpec
impl Unpin for LimitsSpec
impl UnsafeUnpin for LimitsSpec
impl UnwindSafe for LimitsSpec
Blanket Implementations§
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.