pagesift_store/items.rs
1//! Explicit item identity for incremental collectors. Callers supply a stable
2//! source/item key and a version token (or empty bytes for identity-only mode).
3//! Commit AFTER successful delivery. This is not a lease or an atomic reservation:
4//! concurrent consumers still need coordination or an idempotent destination.
5use crate::engine::{group_key, ns};
6use crate::{Result, Store, to_ms};
7use std::time::SystemTime;
8
9pub struct Items<'a> {
10 store: &'a Store,
11}
12
13impl<'a> Items<'a> {
14 pub(crate) fn new(store: &'a Store) -> Self {
15 Self { store }
16 }
17
18 /// Whether this exact source/item revision was successfully committed.
19 /// URLs are deliberately not part of the key. No missing-page deletion is
20 /// inferred: absence from a listing is not proof an item was deleted.
21 pub fn matches(&self, source: &[u8], item: &[u8], revision: &[u8]) -> Result<bool> {
22 Ok(self
23 .store
24 .get(ns::ITEM, &group_key(source, item)?)?
25 .is_some_and(|(_, value)| value == revision))
26 }
27
28 /// Save completion in a single CRC-protected record. Durability follows the
29 /// Store's SyncPolicy; process termination and power loss are different risks.
30 pub fn commit(&self, source: &[u8], item: &[u8], revision: &[u8]) -> Result<()> {
31 self.store
32 .put(
33 ns::ITEM,
34 &group_key(source, item)?,
35 revision,
36 to_ms(SystemTime::now()),
37 )
38 .map(drop)
39 }
40
41 /// Explicitly forget a completed identity so it will be processed again.
42 pub fn forget(&self, source: &[u8], item: &[u8]) -> Result<bool> {
43 self.store.delete(ns::ITEM, &group_key(source, item)?)
44 }
45}