Skip to main content

ipld_blockstore/
lib.rs

1// Copyright 2020 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4#[cfg(feature = "buffered")]
5mod buffered;
6#[cfg(feature = "resolve")]
7pub mod resolve;
8#[cfg(feature = "sled")]
9mod sled;
10#[cfg(feature = "tracking")]
11mod tracking;
12
13#[cfg(feature = "buffered")]
14pub use self::buffered::BufferedBlockStore;
15
16#[cfg(feature = "tracking")]
17pub use self::tracking::{BSStats, TrackingBlockStore};
18
19use cid::{Cid, Code};
20use db::{MemoryDB, Store};
21use encoding::{de::DeserializeOwned, from_slice, ser::Serialize, to_vec};
22use std::error::Error as StdError;
23
24#[cfg(feature = "rocksdb")]
25use db::rocks::{RocksDb, WriteBatch};
26
27/// Wrapper for database to handle inserting and retrieving ipld data with Cids
28pub trait BlockStore: Store {
29    /// Get bytes from block store by Cid.
30    fn get_bytes(&self, cid: &Cid) -> Result<Option<Vec<u8>>, Box<dyn StdError>> {
31        Ok(self.read(cid.to_bytes())?)
32    }
33
34    /// Get typed object from block store by Cid.
35    fn get<T>(&self, cid: &Cid) -> Result<Option<T>, Box<dyn StdError>>
36    where
37        T: DeserializeOwned,
38    {
39        match self.get_bytes(cid)? {
40            Some(bz) => Ok(Some(from_slice(&bz)?)),
41            None => Ok(None),
42        }
43    }
44
45    /// Put an object in the block store and return the Cid identifier.
46    fn put<S>(&self, obj: &S, code: Code) -> Result<Cid, Box<dyn StdError>>
47    where
48        S: Serialize,
49    {
50        let bytes = to_vec(obj)?;
51        self.put_raw(bytes, code)
52    }
53
54    /// Put raw bytes in the block store and return the Cid identifier.
55    fn put_raw(&self, bytes: Vec<u8>, code: Code) -> Result<Cid, Box<dyn StdError>> {
56        let cid = cid::new_from_cbor(&bytes, code);
57        self.write(cid.to_bytes(), bytes)?;
58        Ok(cid)
59    }
60
61    /// Batch put cbor objects into blockstore and returns vector of Cids
62    fn bulk_put<'a, S, V>(&self, values: V, code: Code) -> Result<Vec<Cid>, Box<dyn StdError>>
63    where
64        S: Serialize + 'a,
65        V: IntoIterator<Item = &'a S>,
66    {
67        values
68            .into_iter()
69            .map(|value| self.put(value, code))
70            .collect()
71    }
72}
73
74impl BlockStore for MemoryDB {}
75
76#[cfg(feature = "rocksdb")]
77impl BlockStore for RocksDb {
78    fn bulk_put<'a, S, V>(&self, values: V, code: Code) -> Result<Vec<Cid>, Box<dyn StdError>>
79    where
80        S: Serialize + 'a,
81        V: IntoIterator<Item = &'a S>,
82    {
83        let mut batch = WriteBatch::default();
84        let cids: Vec<Cid> = values
85            .into_iter()
86            .map(|v| {
87                let bz = to_vec(v)?;
88                let cid = cid::new_from_cbor(&bz, code);
89                batch.put(cid.to_bytes(), bz);
90                Ok(cid)
91            })
92            .collect::<Result<_, Box<dyn StdError>>>()?;
93        self.db.write(batch)?;
94
95        Ok(cids)
96    }
97}