1use std::sync::Arc;
9
10use corium_core::IndexOrder;
11use corium_store::{BlobStore, DbRoot, RootStore, SegmentCache, StoreError, db_root_name};
12
13pub struct SegmentSource<S> {
15 store: Arc<S>,
16 cache: SegmentCache,
17}
18
19impl<S: BlobStore + RootStore> SegmentSource<S> {
20 #[must_use]
22 pub fn new(store: Arc<S>) -> Self {
23 Self {
24 store,
25 cache: SegmentCache::default(),
26 }
27 }
28
29 pub fn index_root(&self, db: &str) -> Result<Option<DbRoot>, StoreError> {
34 Ok(self
35 .store
36 .get_root(&db_root_name(db))?
37 .as_deref()
38 .and_then(DbRoot::decode))
39 }
40
41 pub fn lease_holder_endpoint(&self, db: &str) -> Result<Option<String>, StoreError> {
49 Ok(self
50 .index_root(db)?
51 .and_then(|root| (!root.owner_endpoint.is_empty()).then_some(root.owner_endpoint)))
52 }
53
54 pub fn segment(
60 &self,
61 root: &DbRoot,
62 order: IndexOrder,
63 ) -> Result<Option<Arc<[u8]>>, StoreError> {
64 let Some(roots) = &root.roots else {
65 return Ok(None);
66 };
67 let slot = match order {
68 IndexOrder::Eavt => 0,
69 IndexOrder::Aevt => 1,
70 IndexOrder::Avet => 2,
71 IndexOrder::Vaet => 3,
72 };
73 self.cache.get_or_load(self.store.as_ref(), &roots[slot])
74 }
75
76 pub fn segment_keys(bytes: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
82 let mut keys = Vec::new();
83 let mut input = bytes;
84 while !input.is_empty() {
85 let (len_bytes, rest) = input
86 .split_at_checked(8)
87 .ok_or_else(|| StoreError::Io(std::io::Error::other("truncated segment")))?;
88 let len = usize::try_from(u64::from_be_bytes(len_bytes.try_into().unwrap_or_default()))
89 .map_err(|_| StoreError::Io(std::io::Error::other("segment key too large")))?;
90 let (key, rest) = rest
91 .split_at_checked(len)
92 .ok_or_else(|| StoreError::Io(std::io::Error::other("truncated segment key")))?;
93 keys.push(key.to_vec());
94 input = rest;
95 }
96 Ok(keys)
97 }
98}