Skip to main content

DedupCache

Struct DedupCache 

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

Haematite-backed idempotency-key cache for the lightweight dedup contract.

Clones share one in-flight index (dedup/in_flight.rs). The index assumes it is the only one kept for its namespace in the process, as the store assumes one writing process: a second cache built over the same namespace is a second process’s view, as a restart would be.

Implementations§

Source§

impl DedupCache

Source

pub async fn in_flight_claims( &self, ) -> Result<Vec<InFlightClaim>, DurabilityError>

The claims in flight in this namespace, each with its claim time and the evidence it carries, in key order, read from the in-flight index and never by walking the namespace (except once, on the first start over a store written before the index existed).

§Errors

Refuses an unreadable index or key stream, or a malformed record; never answers a partial list.

Source

pub async fn record_empty_start(&self) -> Result<(), DurabilityError>

Records the start of an index begun empty (a cache opened with DedupCache::new_empty) whose start is not yet recorded: one compare-and-set of the index start key from 0 to 1, after which a later process opening the namespace with DedupCache::new reads the index and never walks the namespace. The first claim calls this before it writes; the start that created the store calls it earlier (DUR-023), so a namespace nothing is ever claimed in is not mistaken at its next start for a store written before the index existed and walked, shard by shard, to find nothing.

Makes no store call for a cache opened with DedupCache::new, for an index whose start is already recorded, or on a second call. Another join or another start recording the same start first counts as recorded.

§Errors

Propagates a store error from the compare-and-set other than the cursor regression that says it was recorded first.

Source§

impl DedupCache

Source

pub async fn claim_with_evidence( &self, key: &str, evidence: ClaimEvidence, timestamp_millis: u64, ) -> Result<DedupDecision, DurabilityError>

Claim a producer key and persist where its row would be in one append.

The key is first named in the namespace’s in-flight index (dedup/in_flight.rs), so a start finds the claim without walking the namespace; a crash between the two writes leaves an index row that the next start drops, never a claim the index does not name.

§Errors

Propagates storage and codec failures; conflicting keys retain the normal dedup collision refusal. A failed write must be resolved before publishing.

Source§

impl DedupCache

Source

pub fn new(store: Arc<dyn DurableStore>, namespace: impl Into<String>) -> Self

Creates a dedup cache over the given durable store and namespace prefix.

Source

pub fn new_empty( store: Arc<dyn DurableStore>, namespace: impl Into<String>, ) -> Self

Creates a dedup cache over a namespace nothing has written to: one in a store this process created, or one no earlier process used.

Its in-flight index starts empty without reading the store, so Self::in_flight_claims reads nothing and no claim walks the namespace. Self::record_empty_start, or failing that the first claim, records the index start before anything is written, so a later process opening the namespace with Self::new reads the index and never walks it. A namespace that may hold claims is opened with Self::new.

Source

pub fn namespace(&self) -> &str

Returns the configured dedup namespace.

Source

pub fn stream_key_for(&self, idempotency_key: &str) -> String

Formats the haematite stream key for an idempotency key.

Source

pub async fn lookup( &self, idempotency_key: &str, ) -> Result<Option<DedupDecision>, DurabilityError>

Looks up an existing key without appending a record. A stream of fewer than one page of records is read in one page, as before DUR-008 A12; a longer one is read from its verified recorded head, and one whose head was never recorded is walked once and its head recorded.

§Errors

Propagates store read errors and returns DurabilityError::DedupCollision when the hashed stream contains a different original idempotency key.

Source

pub async fn claim_or_get( &self, idempotency_key: &str, timestamp_millis: u64, ) -> Result<DedupDecision, DurabilityError>

Claims a new key or returns the existing completed/in-flight decision.

Callers must only deliver the message when this returns DedupDecision::Claimed.

§Errors

Propagates store errors and serialization errors. A concurrent first claim that wins the append race is converted into the duplicate completed/in-flight decision.

Source

pub async fn complete_receipt( &self, idempotency_key: &str, receipt: ProcessingReceipt, ) -> Result<(), DurabilityError>

Stores a processing receipt by appending a completed entry for an existing key.

§Errors

Returns DurabilityError::ConfigError when the current system time cannot be encoded. Returns DurabilityError::DedupCollision when the key is missing or collides with another original key, and propagates serialization/store append errors.

Source

pub async fn release_claim( &self, idempotency_key: &str, ) -> Result<(), DurabilityError>

Releases an in-flight claim so the key becomes re-claimable.

Callers use this on the publish failure path: a key was claimed (DedupDecision::Claimed) but the downstream delivery failed before a receipt could be recorded, leaving the key dangling DedupDecision::InFlight forever and permanently suppressing every re-publish. Releasing appends a tombstone so the next claim succeeds.

This NEVER clobbers a stored receipt: an already-completed key (receipt present) and an absent key are both no-ops, preserving the at-most-once guarantee. Only a current in-flight entry (active, no receipt) is tombstoned.

§Errors

Propagates store read/append and serialization errors. A DurabilityError::SequenceConflict on the tombstone append is re-checked: if the latest state is now completed or already a tombstone the release is treated as successful, otherwise the conflict is propagated.

Trait Implementations§

Source§

impl Clone for DedupCache

Source§

fn clone(&self) -> Self

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 DedupCache

Source§

fn fmt(&self, formatter: &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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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> 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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, !>

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<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