···33use std::collections::VecDeque;
44use std::error::Error;
5566-use crate::disk_walk::{Trip, Walker};
66+use crate::disk_walk::{Trip, Walker, RkeyError};
77use crate::mst::Commit;
8899use ipld_core::cid::Cid;
···4141 Tripped(#[from] Trip),
4242}
43434444+#[derive(Debug, thiserror::Error)]
4545+pub enum BlockStoreError {
4646+ #[error("Error from the storage backend: {0}")]
4747+ StorageBackend(Box<dyn Error + Send>),
4848+4949+ #[error(transparent)]
5050+ RkeyError(#[from] RkeyError),
5151+5252+ // this should probably not be up here
5353+ #[error("Failed to join tokio task: {0}")]
5454+ JoinError(tokio::task::JoinError),
5555+5656+ #[error("Could not find block: {0}")]
5757+ MissingBlock(Cid),
5858+}
5959+4460/// Storage backend for caching large-repo blocks
4561///
4662/// Since
4763pub trait BlockStore<MPB: Serialize + DeserializeOwned> {
4848- fn put_batch(&self, blocks: Vec<(Cid, MPB)>) -> impl Future<Output = ()> + Send; // unwraps for now
6464+ fn put_batch(&self, blocks: Vec<(Cid, MPB)>) -> impl Future<Output = Result<(), BlockStoreError>>; // unwraps for now
4965 fn walk_batch(
5066 &self,
5167 walker: Walker,
5268 n: usize,
5353- ) -> impl Future<Output = Result<(Walker, Vec<(String, MPB)>), String>>; // boo string error for now because
6969+ ) -> impl Future<Output = Result<(Walker, Vec<(String, MPB)>), BlockStoreError>>; // boo string error for now because
5470}
55715672type CarBlock<E> = Result<(Cid, Vec<u8>), E>;
···127143 to_insert.push((cid, data));
128144 }
129145 }
130130- block_store.put_batch(to_insert).await;
146146+ block_store
147147+ .put_batch(to_insert)
148148+ .await
149149+ .map_err(|e| DriveError::Boooooo(format!("boooOOOOO! {e}")))?; // TODO
131150 }
132151133152 log::warn!("init: got commit?");
···155174 .block_store
156175 .walk_batch(walker, n)
157176 .await
158158- .map_err(DriveError::Boooooo)?;
177177+ .map_err(|e| DriveError::Boooooo(format!("booo! {e}")))?; // TODO
159178 self.walker = walker;
160179161180 let processed = batch
+26-19
src/disk_redb.rs
···11-use crate::disk_drive::BlockStore;
11+use crate::disk_drive::{BlockStore, BlockStoreError};
22use crate::disk_walk::{Need, Walker};
33use ipld_core::cid::Cid;
44use redb::{Database, Durability, Error, ReadableDatabase, TableDefinition};
···2323 }
2424}
25252626+// TODO: ship off to a blocking thread
2627impl Drop for RedbStore {
2728 fn drop(&mut self) {
2829 let mut tx = self.db.begin_write().unwrap();
···3233 }
3334}
34353636+impl<E: Into<Error>> From<E> for BlockStoreError {
3737+ fn from(e: E) -> BlockStoreError {
3838+ let e = Into::<Error>::into(e);
3939+ BlockStoreError::StorageBackend(Box::new(e))
4040+ }
4141+}
4242+3543impl BlockStore<Vec<u8>> for RedbStore {
3636- async fn put_batch(&self, blocks: Vec<(Cid, Vec<u8>)>) {
4444+ async fn put_batch(&self, blocks: Vec<(Cid, Vec<u8>)>) -> Result<(), BlockStoreError> {
3745 let db = self.db.clone();
3838- tokio::task::spawn_blocking(move || {
3939- let mut tx = db.begin_write().unwrap();
4040- tx.set_durability(Durability::None).unwrap();
4646+ tokio::task::spawn_blocking(move || -> Result<(), BlockStoreError> {
4747+ let mut tx = db.begin_write()?;
4848+ tx.set_durability(Durability::None)?;
41494250 {
4343- let mut table = tx.open_table(TABLE).unwrap();
5151+ let mut table = tx.open_table(TABLE)?;
4452 for (cid, t) in blocks {
4553 let key_bytes = cid.to_bytes();
4646- table.insert(&*key_bytes, &*t).unwrap();
5454+ table.insert(&*key_bytes, &*t)?;
4755 }
4856 }
49575050- tx.commit().unwrap();
5858+ Ok(tx.commit()?)
5159 })
5260 .await
5353- .unwrap();
6161+ .map_err(BlockStoreError::JoinError)?
5462 }
55635664 async fn walk_batch(
5765 &self,
5866 mut walker: Walker,
5967 n: usize,
6060- ) -> Result<(Walker, Vec<(String, Vec<u8>)>), String> {
6868+ ) -> Result<(Walker, Vec<(String, Vec<u8>)>), BlockStoreError> {
6169 let db = self.db.clone();
6262- tokio::task::spawn_blocking(move || {
6363- let tx = db.begin_read().unwrap();
6464- let table = tx.open_table(TABLE).unwrap();
7070+ tokio::task::spawn_blocking(move || -> Result<_, BlockStoreError> {
7171+ let tx = db.begin_read()?;
7272+ let table = tx.open_table(TABLE)?;
65736674 let mut out = Vec::with_capacity(n);
6775 loop {
6868- let Some(need) = walker.next_needed() else {
7676+ let Some(need) = walker.next_needed()? else {
6977 break;
7078 };
7179 let cid = need.cid();
7272- let Some(res) = table.get(&*cid.to_bytes()).unwrap() else {
7373- return Err(format!("missing block: {cid:?}"));
8080+ let Some(res) = table.get(&*cid.to_bytes())? else {
8181+ return Err(BlockStoreError::MissingBlock(cid));
7482 };
7583 let block = res.value();
76847785 match need {
7886 Need::Node(_) => walker
7979- .handle_node(block)
8080- .map_err(|e| format!("failed to handle mst node: {e}"))?,
8787+ .handle_node(block)?,
8188 Need::Record { rkey, .. } => {
8289 out.push((rkey, block.to_vec()));
8390 if out.len() >= n {
···8996 Ok((walker, out))
9097 })
9198 .await
9292- .unwrap() // tokio join
9999+ .map_err(BlockStoreError::JoinError)?
93100 }
94101}
+19-17
src/disk_walk.rs
···1717 RkeyError(#[from] RkeyError),
1818 #[error("Process failed: {0}")]
1919 ProcessFailed(String),
2020- #[error("Encountered an rkey out of order while walking the MST")]
2121- RkeyOutOfOrder,
2220}
23212422/// Errors from invalid Rkeys
···2826 EntryPrefixOutOfbounds,
2927 #[error("RKey was not utf-8")]
3028 EntryRkeyNotUtf8(#[from] std::string::FromUtf8Error),
2929+ #[error("Encountered an rkey out of order while walking the MST")]
3030+ RkeyOutOfOrder,
3131+ #[error("Failed to decode commit block: {0}")]
3232+ BlockDecodeError(#[from] serde_ipld_dagcbor::DecodeError<Infallible>),
3133}
32343335/// Walker outputs
···110112 }
111113 }
112114113113- pub fn next_needed(&mut self) -> Option<Need> {
114114- self.stack.pop()
115115- // TODO:
116116- // let need = self.stack.pop()?;
117117- // if let Need::Record { ref rkey, .. } = need {
118118- // // rkeys *must* be in order or else the tree is invalid (or
119119- // // we have a bug)
120120- // if *rkey <= self.prev {
121121- // return Err(Trip::RkeyOutOfOrder);
122122- // }
123123- // self.prev = rkey.clone();
124124- // }
125125- // Some(need)
115115+ pub fn next_needed(&mut self) -> Result<Option<Need>, RkeyError> {
116116+ let Some(need) = self.stack.pop() else {
117117+ return Ok(None);
118118+ };
119119+ if let Need::Record { ref rkey, .. } = need {
120120+ // rkeys *must* be in order or else the tree is invalid (or
121121+ // we have a bug)
122122+ if *rkey <= self.prev {
123123+ return Err(RkeyError::RkeyOutOfOrder);
124124+ }
125125+ self.prev = rkey.clone();
126126+ }
127127+ Ok(Some(need))
126128 }
127129128130 /// hacky: this must be called after next_needed if it was a node
129129- pub fn handle_node(&mut self, block: &[u8]) -> Result<(), Trip> {
130130- let node = serde_ipld_dagcbor::from_slice::<Node>(block).map_err(Trip::BadCommit)?;
131131+ pub fn handle_node(&mut self, block: &[u8]) -> Result<(), RkeyError> {
132132+ let node = serde_ipld_dagcbor::from_slice::<Node>(block)?;
131133 push_from_node(&mut self.stack, &node)?;
132134 Ok(())
133135 }