forceps/
lib.rs

1//! `forceps` is a crate that provides a simple and easy-to-use on-disk cache/database.
2//!
3//! **This crate is intended to be used with the [`tokio`](tokio) runtime.**
4//!
5//! `forceps` is made to be an easy-to-use, thread-safe, performant, and asynchronous disk cache
6//! that has easy reading and manipulation of data. It levereges tokio's async `fs` APIs
7//! and fast task schedulers to perform IO operations, and `sled` as a fast metadata database.
8//!
9//! It was originally designed to be used in [`scalpel`](https://github.com/blockba5her/scalpel),
10//! the MD@Home implementation for the Rust language.
11//!
12//! ## Features
13//!
14//! - Asynchronous APIs
15//! - Fast and reliable reading/writing
16//! - Optional memory-cache layer
17//! - Tuned for large-file databases
18//! - Included cache eviction (LRU/FIFO)
19//! - Easily accessible value metadata
20//! - Optimized for cache `HIT`s
21//! - Easy error handling
22//! - `bytes` crate support (non-optional)
23//!
24//! ## Database and Meta-database
25//!
26//! This database solution easily separates data into two databases: the LFS (large-file-storage)
27//! database, and the metadata database. The LFS database is powered using Tokio's async filesystem
28//! operations, whereas the metadata database is powered using [`sled`](sled).
29//!
30//! The advantage of splitting these two up is simple: Accessing metadata (for things like database
31//! eviction) is realatively cheap and efficient, with the only downside being that `async` is not
32//! present.
33//!
34//! # Examples
35//!
36//! ```rust,no_run
37//! use std::error::Error;
38//! use forceps::Cache;
39//!
40//! #[tokio::main]
41//! async fn main() -> Result<(), Box<dyn Error>> {
42//!     let cache = Cache::new("./cache")
43//!         .build()
44//!         .await?;
45//!
46//!     cache.write(b"MY_KEY", b"Hello World").await?;
47//!     let data = cache.read(b"MY_KEY").await?;
48//!     assert_eq!(data.as_ref(), b"Hello World");
49//!
50//!     Ok(())
51//! }
52//! ```
53
54#![warn(missing_docs)]
55#![warn(rustdoc::broken_intra_doc_links)]
56
57use std::error;
58use std::io;
59
60/// Global error type for the `forceps` crate, which is used in the `Result` types of all calls to
61/// forcep APIs.
62#[derive(Debug)]
63pub enum ForcepError {
64    /// An I/O operation error. This can occur on reads, writes, or builds.
65    Io(io::Error),
66    /// Error deserialization metadata information (most likely corrupted)
67    MetaDe(bson::de::Error),
68    /// Error serializing metadata information
69    MetaSer(bson::ser::Error),
70    /// Error with metadata sled database operation
71    MetaDb(sled::Error),
72    /// The entry was found successfully, but the metadata was strangely not present
73    MetaNotFound,
74    /// The entry for the specified key is not found
75    NotFound,
76}
77/// Re-export of [`ForcepError`]
78pub type Error = ForcepError;
79/// Result that is returned by all error-bound operations of `forceps`.
80pub type Result<T> = std::result::Result<T, ForcepError>;
81
82impl std::fmt::Display for ForcepError {
83    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        match self {
85            Self::Io(e) => write!(fmt, "an I/O error occurred: {}", e),
86            Self::MetaDe(e) => write!(fmt, "there was a problem deserializing metadata: {}", e),
87            Self::MetaSer(e) => write!(fmt, "there was a problem serializing metadata: {}", e),
88            Self::MetaDb(e) => write!(fmt, "an error with the metadata database occurred: {}", e),
89            Self::MetaNotFound => write!(fmt, "the entry for the key provided was found, but the metadata was strangely not present"),
90            Self::NotFound => write!(fmt, "the entry for the key provided was not found"),
91        }
92    }
93}
94impl error::Error for ForcepError {
95    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
96        match self {
97            Self::Io(e) => Some(e),
98            Self::MetaDe(e) => Some(e),
99            Self::MetaSer(e) => Some(e),
100            Self::MetaDb(e) => Some(e),
101            Self::MetaNotFound => None,
102            Self::NotFound => None,
103        }
104    }
105}
106
107mod mem_cache;
108mod tmp;
109
110mod builder;
111pub use builder::CacheBuilder;
112
113mod cache;
114pub use cache::Cache;
115
116mod metadata;
117pub(crate) use metadata::MetaDb;
118pub use metadata::{Md5Bytes, Metadata};
119
120/// A collection of [`Cache`] eviction algorithms and generics
121///
122/// This module contains the [`Evictor`] trait, which is used to signify a structure or enum that
123/// is used to evict items out of a cache, as well as some implementations of that trait.
124///
125/// [`Evictor`]: crate::evictors::Evictor
126pub mod evictors;