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 async fn index_root(&self, db: &str) -> Result<Option<DbRoot>, StoreError> {
34 Ok(self
35 .store
36 .get_root(&db_root_name(db))
37 .await?
38 .as_deref()
39 .and_then(DbRoot::decode))
40 }
41
42 pub async fn lease_holder_endpoint(&self, db: &str) -> Result<Option<String>, StoreError> {
50 Ok(self
51 .index_root(db)
52 .await?
53 .and_then(|root| (!root.owner_endpoint.is_empty()).then_some(root.owner_endpoint)))
54 }
55
56 pub async fn segment(
62 &self,
63 root: &DbRoot,
64 order: IndexOrder,
65 ) -> Result<Option<Arc<[u8]>>, StoreError> {
66 let Some(roots) = &root.roots else {
67 return Ok(None);
68 };
69 let slot = match order {
70 IndexOrder::Eavt => 0,
71 IndexOrder::Aevt => 1,
72 IndexOrder::Avet => 2,
73 IndexOrder::Vaet => 3,
74 };
75 self.cache
76 .get_or_load(self.store.as_ref(), &roots[slot])
77 .await
78 }
79
80 pub fn segment_keys(bytes: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
86 let mut keys = Vec::new();
87 let mut input = bytes;
88 while !input.is_empty() {
89 let (len_bytes, rest) = input
90 .split_at_checked(8)
91 .ok_or_else(|| StoreError::Io(std::io::Error::other("truncated segment")))?;
92 let len = usize::try_from(u64::from_be_bytes(len_bytes.try_into().unwrap_or_default()))
93 .map_err(|_| StoreError::Io(std::io::Error::other("segment key too large")))?;
94 let (key, rest) = rest
95 .split_at_checked(len)
96 .ok_or_else(|| StoreError::Io(std::io::Error::other("truncated segment key")))?;
97 keys.push(key.to_vec());
98 input = rest;
99 }
100 Ok(keys)
101 }
102}