Skip to main content

SchemaCleanCache

Struct SchemaCleanCache 

pub struct SchemaCleanCache { /* private fields */ }
Expand description

Bounded memo of SchemaCleanr::clean_shared results, keyed by source schema identity and strategy.

Cleaning is a pure function of (schema, strategy), but tool schemas that need rewriting ($ref/$defs, const, unions — pervasive in generated MCP schemas) would otherwise be deep-copied on every provider request. Providers that clean per request embed one of these so each distinct schema is cleaned once per strategy for as long as it stays registered. This holds no canonical state: entries are derived values, keyed by the identity of the canonical Arc the tool registry owns, and the memoized result is byte-stable across requests (which also keeps provider-side prompt caching stable).

Retired sources are pruned whenever a dirty schema uses the cache, so a replaced MCP schema does not wait for capacity pressure before its cleaned tree can be released. Completed entries are additionally bounded per provider by both count and estimated heap bytes. When a new result would exceed either bound, admission is declined for that result instead of evicting the established working set. In-flight single-flight cells are never evicted; concurrent callers participating in one cold miss still share exactly one computation.

Only rewritten results are cached. A no-op clean is returned straight from the pre-scan and never inserted: such an entry’s cleaned field would be the very allocation its source Weak watches, pinning it forever (the dead-entry prune could never fire), and ephemeral per-call Arcs — the default Tool::spec() builds a fresh one every iteration — would flood the map until the overflow clear evicted the live memos this cache exists to keep.

A hit requires upgrading the stored Weak and Arc::ptr_eq with the candidate. Stale hits are impossible twice over: while an entry lives, its Weak keeps the source ArcInner allocation reserved, so no new schema can occupy that address; and once the source is dropped the Weak permanently refuses to upgrade, so the entry can only miss.

Implementations§

Source§

impl SchemaCleanCache

Source

pub fn new() -> Self

Source

pub fn clean_shared( &self, schema: &Arc<Value>, strategy: CleaningStrategy, ) -> Arc<Value>

Memoized SchemaCleanr::clean_shared: returns the shared source Arc when cleaning is a no-op, and otherwise the cleaned tree — deep-computed at most once per retained (live schema, strategy) pair, even when multiple threads race a cold miss on the same key together.

Single-flight: the first miss for a (schema, strategy) key installs a shared OnceLock cell in the map before the lock is released. Any other thread that misses on the same key (i.e. it upgrades to the same live source) finds that cell already installed, reuses it, and blocks in get_or_init instead of starting its own deep clone — so only the winner’s closure ever runs, and every caller, winner and waiters alike, ends up with the one resulting Arc. Misses on different keys install independent cells and clean fully concurrently; the map lock is never held while a clean itself runs. Capacity enforcement can decline admission only for the just-completed cell, so it cannot split an in-flight computation into competing cells or discard the established working set.

Trait Implementations§

Source§

impl Default for SchemaCleanCache

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.