Skip to main content

ArticleCache

Struct ArticleCache 

Source
pub struct ArticleCache { /* private fields */ }
Expand description

Article cache using LRU eviction with TTL

Uses Arc<str> (message ID content without brackets) as key for zero-allocation lookups. Arc<str> implements Borrow<str>, allowing cache.get(&str) without allocation.

Supports tier-aware TTL: entries from higher tier backends get longer TTLs. Formula: effective_ttl = base_ttl * (2 ^ tier)

Implementations§

Source§

impl ArticleCache

Source

pub fn new(max_capacity: u64, ttl: Duration) -> Self

Create a new article cache

§Arguments
  • max_capacity - Maximum cache size in bytes (uses weighted entries)
  • ttl - Time-to-live for cached articles
Source

pub async fn get(&self, message_id: &MessageId<'_>) -> Option<CachedArticle>

Get an article from the cache

Accepts any lifetime MessageId and uses the string content (without brackets) as key.

Zero-allocation: without_brackets() returns &str, which moka accepts directly for Arc<str> keys via the Borrow<str> trait. This avoids allocating a new Arc<str> for every cache lookup. See test_arc_str_borrow_lookup test for verification.

Tier-aware TTL: Even if moka hasn’t expired the entry yet, we check if the entry is expired based on tier-aware TTL. Higher tier entries get longer TTLs.

Source

pub async fn upsert_ingest( &self, message_id: MessageId<'_>, buffer: impl Into<CacheIngestResponse>, backend: BackendId, tier: CacheTier, )

Upsert cache entry (insert or update) - ATOMIC OPERATION

Uses moka’s entry().and_upsert_with() for atomic get-modify-store. This eliminates the race condition of separate get() + insert() calls and provides key-level locking for concurrent operations.

If entry exists: updates the entry while preserving authoritative missing facts If entry doesn’t exist: inserts new entry

The tier is stored with the entry for tier-aware TTL calculation.

CRITICAL: Always re-insert to refresh TTL while preserving negative availability.

Source

pub async fn record_backend_has_status( &self, message_id: MessageId<'_>, status_code: StatusCode, backend: BackendId, tier: CacheTier, )

Record successful backend availability without storing response payload bytes.

Source

pub async fn record_backend_missing( &self, message_id: MessageId<'_>, backend_id: BackendId, )

Record that a backend returned 430 for this article - ATOMIC OPERATION

Uses moka’s entry().and_upsert_with() for atomic get-modify-store. This eliminates the race condition of separate get() + insert() calls and provides key-level locking for concurrent operations.

If the article is already cached, updates the availability bitset. If not cached, creates a typed missing cache entry. This prevents repeated queries to backends that don’t have the article.

Note: We don’t store the actual backend 430 response because:

  1. We always send a standardized 430 to clients, never the backend’s response
  2. The only info we need is the availability bitset (which backends returned 430)
Source

pub fn stats(&self) -> CacheStats

Get cache statistics

Source

pub const fn capacity(&self) -> u64

Get maximum cache capacity

Source

pub fn entry_count(&self) -> u64

Get current number of cached entries (synchronous)

Source

pub fn weighted_size(&self) -> u64

Get current weighted size in bytes (synchronous)

Source

pub fn hit_rate(&self) -> f64

Get cache hit rate as percentage (0.0 to 100.0)

Source

pub async fn sync(&self)

Run pending background tasks (for testing)

Moka performs maintenance tasks (eviction, expiration) asynchronously. This method ensures all pending tasks complete, useful for deterministic testing.

Trait Implementations§

Source§

impl CacheStatsProvider for ArticleCache

Source§

fn display_stats(&self) -> CacheDisplayStats

Get statistics for TUI display
Source§

impl Clone for ArticleCache

Source§

fn clone(&self) -> ArticleCache

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ArticleCache

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Scope for T

Source§

fn with<F, R>(self, f: F) -> R
where Self: Sized, F: FnOnce(Self) -> R,

Scoped with ownership.
Source§

fn with_ref<F, R>(&self, f: F) -> R
where F: FnOnce(&Self) -> R,

Scoped with reference.
Source§

fn with_mut<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut Self) -> R,

Scoped with mutable reference.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = !

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> Value for T
where T: Send + Sync + 'static,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more