Skip to main content

Log

Struct Log 

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

Caller-owned heap history with fixed limits and monotonic append watermarks.

Implementations§

Source§

impl Log

Source

pub const fn new(limits: Limits) -> Self

Construct an empty log without preallocating the configured maximum.

Examples found in repository?
examples/worker.rs (lines 7-11)
6fn main() {
7    let mut log = Log::new(Limits {
8        max_entries: NonZeroUsize::new(8).expect("positive capacity"),
9        max_message_bytes: 32,
10        max_label_bytes: 16,
11    });
12    for (created_at_secs, level, message) in [
13        (10, Level::Info, "delivery accepted"),
14        (
15            11,
16            Level::Warn,
17            "provider reply is still unknown; reconcile before retry",
18        ),
19        (12, Level::Ok, "original delivery reconciled"),
20    ] {
21        log.append(EntryInput {
22            created_at_secs,
23            level,
24            source: "worker",
25            topic: Some("delivery"),
26            message,
27        })
28        .expect("valid bounded entry");
29    }
30    let page = log.page(
31        Filter::default(),
32        PageRequest {
33            before: None,
34            max_results: NonZeroUsize::new(8).expect("positive results"),
35            max_scanned: NonZeroUsize::new(8).expect("positive scan"),
36        },
37    );
38    for entry in page.entries {
39        println!("{} {:?}: {}", entry.sequence, entry.level, entry.message);
40    }
41    let batch = log.prune_expired(16, 5, 1);
42    assert_eq!(batch.removed, 1);
43    assert_eq!(log.next_expiry_secs(5), Some(17));
44}
Source

pub const fn limits(&self) -> Limits

Return the fixed bounds without copying retained messages.

Source

pub fn snapshot(&self) -> LogSnapshot

Copy all retained rows and both append watermarks for explicit checkpointing. Work and allocation scale with retained history, not a cursor-page limit.

Source

pub fn restore(snapshot: LogSnapshot) -> Result<Self, RestoreError>

Admit a complete checkpoint without replaying entries or reissuing identities.

Empty retained history preserves its original append watermarks. Admission proves internal consistency, not source authenticity or host continuity. Byte decoders must bound allocation before constructing the checkpoint.

§Errors

Rejects bounds, row ordering, watermarks and truncation states that cannot result from this engine’s append/retention operations.

Source

pub fn len(&self) -> usize

Return the retained row count.

Source

pub fn is_empty(&self) -> bool

Whether this log currently has no retained rows.

Source

pub fn append(&mut self, input: EntryInput<'_>) -> Result<u64, AppendError>

Admit one row and evict the oldest if the count ceiling is reached.

§Errors

Returns a typed refusal for oversized labels, regressed time or exhausted sequence identities. Validation completes before any eviction or mutation.

Examples found in repository?
examples/worker.rs (lines 21-27)
6fn main() {
7    let mut log = Log::new(Limits {
8        max_entries: NonZeroUsize::new(8).expect("positive capacity"),
9        max_message_bytes: 32,
10        max_label_bytes: 16,
11    });
12    for (created_at_secs, level, message) in [
13        (10, Level::Info, "delivery accepted"),
14        (
15            11,
16            Level::Warn,
17            "provider reply is still unknown; reconcile before retry",
18        ),
19        (12, Level::Ok, "original delivery reconciled"),
20    ] {
21        log.append(EntryInput {
22            created_at_secs,
23            level,
24            source: "worker",
25            topic: Some("delivery"),
26            message,
27        })
28        .expect("valid bounded entry");
29    }
30    let page = log.page(
31        Filter::default(),
32        PageRequest {
33            before: None,
34            max_results: NonZeroUsize::new(8).expect("positive results"),
35            max_scanned: NonZeroUsize::new(8).expect("positive scan"),
36        },
37    );
38    for entry in page.entries {
39        println!("{} {:?}: {}", entry.sequence, entry.level, entry.message);
40    }
41    let batch = log.prune_expired(16, 5, 1);
42    assert_eq!(batch.removed, 1);
43    assert_eq!(log.next_expiry_secs(5), Some(17));
44}
Source

pub fn prune_expired( &mut self, now_secs: u64, max_age_secs: u64, max_remove: usize, ) -> RetentionBatch

Remove at most max_remove entries strictly older than the age cutoff. An entry remains available through its full configured age second.

Examples found in repository?
examples/worker.rs (line 41)
6fn main() {
7    let mut log = Log::new(Limits {
8        max_entries: NonZeroUsize::new(8).expect("positive capacity"),
9        max_message_bytes: 32,
10        max_label_bytes: 16,
11    });
12    for (created_at_secs, level, message) in [
13        (10, Level::Info, "delivery accepted"),
14        (
15            11,
16            Level::Warn,
17            "provider reply is still unknown; reconcile before retry",
18        ),
19        (12, Level::Ok, "original delivery reconciled"),
20    ] {
21        log.append(EntryInput {
22            created_at_secs,
23            level,
24            source: "worker",
25            topic: Some("delivery"),
26            message,
27        })
28        .expect("valid bounded entry");
29    }
30    let page = log.page(
31        Filter::default(),
32        PageRequest {
33            before: None,
34            max_results: NonZeroUsize::new(8).expect("positive results"),
35            max_scanned: NonZeroUsize::new(8).expect("positive scan"),
36        },
37    );
38    for entry in page.entries {
39        println!("{} {:?}: {}", entry.sequence, entry.level, entry.message);
40    }
41    let batch = log.prune_expired(16, 5, 1);
42    assert_eq!(batch.removed, 1);
43    assert_eq!(log.next_expiry_secs(5), Some(17));
44}
Source

pub fn next_expiry_secs(&self, max_age_secs: u64) -> Option<u64>

First second at which the oldest row expires; None for empty history or overflow.

Examples found in repository?
examples/worker.rs (line 43)
6fn main() {
7    let mut log = Log::new(Limits {
8        max_entries: NonZeroUsize::new(8).expect("positive capacity"),
9        max_message_bytes: 32,
10        max_label_bytes: 16,
11    });
12    for (created_at_secs, level, message) in [
13        (10, Level::Info, "delivery accepted"),
14        (
15            11,
16            Level::Warn,
17            "provider reply is still unknown; reconcile before retry",
18        ),
19        (12, Level::Ok, "original delivery reconciled"),
20    ] {
21        log.append(EntryInput {
22            created_at_secs,
23            level,
24            source: "worker",
25            topic: Some("delivery"),
26            message,
27        })
28        .expect("valid bounded entry");
29    }
30    let page = log.page(
31        Filter::default(),
32        PageRequest {
33            before: None,
34            max_results: NonZeroUsize::new(8).expect("positive results"),
35            max_scanned: NonZeroUsize::new(8).expect("positive scan"),
36        },
37    );
38    for entry in page.entries {
39        println!("{} {:?}: {}", entry.sequence, entry.level, entry.message);
40    }
41    let batch = log.prune_expired(16, 5, 1);
42    assert_eq!(batch.removed, 1);
43    assert_eq!(log.next_expiry_secs(5), Some(17));
44}
Source

pub fn page(&self, filter: Filter<'_>, request: PageRequest) -> Page<'_>

Scan newest-first without cloning retained messages or counting every match. Follow next_before with the same filters, including after an empty page.

Examples found in repository?
examples/worker.rs (lines 30-37)
6fn main() {
7    let mut log = Log::new(Limits {
8        max_entries: NonZeroUsize::new(8).expect("positive capacity"),
9        max_message_bytes: 32,
10        max_label_bytes: 16,
11    });
12    for (created_at_secs, level, message) in [
13        (10, Level::Info, "delivery accepted"),
14        (
15            11,
16            Level::Warn,
17            "provider reply is still unknown; reconcile before retry",
18        ),
19        (12, Level::Ok, "original delivery reconciled"),
20    ] {
21        log.append(EntryInput {
22            created_at_secs,
23            level,
24            source: "worker",
25            topic: Some("delivery"),
26            message,
27        })
28        .expect("valid bounded entry");
29    }
30    let page = log.page(
31        Filter::default(),
32        PageRequest {
33            before: None,
34            max_results: NonZeroUsize::new(8).expect("positive results"),
35            max_scanned: NonZeroUsize::new(8).expect("positive scan"),
36        },
37    );
38    for entry in page.entries {
39        println!("{} {:?}: {}", entry.sequence, entry.level, entry.message);
40    }
41    let batch = log.prune_expired(16, 5, 1);
42    assert_eq!(batch.removed, 1);
43    assert_eq!(log.next_expiry_secs(5), Some(17));
44}

Trait Implementations§

Source§

impl Debug for Log

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Log

§

impl RefUnwindSafe for Log

§

impl Send for Log

§

impl Sync for Log

§

impl Unpin for Log

§

impl UnsafeUnpin for Log

§

impl UnwindSafe for Log

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

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.