Skip to content

Commit

Permalink
chore: Write documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
matheus23 committed Aug 31, 2023
1 parent 7d0148a commit 2ee11bb
Showing 1 changed file with 44 additions and 2 deletions.
46 changes: 44 additions & 2 deletions car-mirror/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,32 @@ use async_trait::async_trait;
use libipld::{Cid, IpldCodec};
use wnfs_common::BlockStore;

/// This trait abstracts caches used by the car mirror implementation.
/// An efficient cache implementation can significantly reduce the amount
/// of lookups into the blockstore.
///
/// At the moment, all caches are conceptually memoization tables, so you don't
/// necessarily need to think about being careful about cache eviction.
///
/// See `InMemoryCache` for a `quick_cache`-based implementation, and
/// `NoCache` for disabling the cache.
#[async_trait(?Send)]
pub trait Cache {
/// This returns further references from the block referenced by given CID,
/// if the cache is hit.
/// Returns `None` if it's a cache miss.
///
/// This isn't meant to be called directly, instead use `Cache::references`.
async fn get_references_cached(&self, cid: Cid) -> Result<Option<Vec<Cid>>>;

/// Populates the references cache for given CID with given references.
async fn put_references_cached(&self, cid: Cid, references: Vec<Cid>) -> Result<()>;

/// Find out any CIDs that are linked to from the block with given CID.
///
/// This makes use of the cache via `get_references_cached`, if possible.
/// If the cache is missed, then it will fetch the block, compute the references
/// and automatically populate the cache using `put_references_cached`.
async fn references(&self, cid: Cid, store: &impl BlockStore) -> Result<Vec<Cid>> {
// raw blocks don't have further links
let raw_codec: u64 = IpldCodec::Raw.into();
Expand All @@ -28,12 +48,33 @@ pub trait Cache {
}
}

/// A [quick-cache]-based implementation of a car mirror cache.
///
/// [quick-cache]: https://github.com/arthurprs/quick-cache/
#[derive(Debug)]
pub struct InMemoryCache {
references: quick_cache::sync::Cache<Cid, Vec<Cid>>,
}

impl InMemoryCache {
/// Create a new in-memory cache that approximately holds
/// cached references for `approx_capacity` CIDs.
///
/// Computing the expected memory requirements isn't easy.
/// A block in theory have up to thousands of references.
/// [UnixFS] chunked files will reference up to 174 chunks
/// at a time.
/// Each CID takes up 96 bytes of memory.
/// In the UnixFS worst case of 175 CIDs per cache entry,
/// you need to reserve up to `175 * 96B = 16.8KB` of space
/// per entry. Thus, if you want your cache to not outgrow
/// ~100MB (ignoring the internal cache structure space
/// requirements), you can store up to `100MB / 16.8KB = 5952`
/// entries.
///
/// In practice, the fanout average will be much lower than 174.
///
/// [UnixFS]: https://github.com/ipfs/specs/blob/main/UNIXFS.md#layout
pub fn new(approx_capacity: usize) -> Self {
Self {
references: quick_cache::sync::Cache::new(approx_capacity),
Expand All @@ -53,16 +94,17 @@ impl Cache for InMemoryCache {
}
}

/// An implementation of `Cache` that doesn't cache at all.
#[derive(Debug)]
pub struct NoCache();

#[async_trait(?Send)]
impl Cache for NoCache {
async fn get_references_cached(&self, cid: Cid) -> Result<Option<Vec<Cid>>> {
async fn get_references_cached(&self, _: Cid) -> Result<Option<Vec<Cid>>> {
Ok(None)
}

async fn put_references_cached(&self, cid: Cid, references: Vec<Cid>) -> Result<()> {
async fn put_references_cached(&self, _: Cid, _: Vec<Cid>) -> Result<()> {
Ok(())
}
}

0 comments on commit 2ee11bb

Please sign in to comment.