Expand description
A lock-free pagecache which supports fragmented pages for dramatically improving write throughput.
Working with the PageCache
extern crate pagecache;
use pagecache::{pin, Materializer};
pub struct TestMaterializer;
impl Materializer for TestMaterializer {
// The possibly fragmented page, written to log storage sequentially, and
// read in parallel from multiple locations on disk when serving
// a request to read the page. These will be merged to a single version
// at read time, and possibly cached.
type PageFrag = String;
// The state returned by a call to `PageCache::recover`, as
// described by `Materializer::recover`
type Recovery = ();
// Create a new `Materializer` with the previously recovered
// state if any existed.
fn new(config: pagecache::Config, last_recovery: &Option<Self::Recovery>) -> Self {
TestMaterializer
}
// Used to merge chains of partial pages into a form
// that is useful for the `PageCache` owner.
fn merge(&self, frags: &[&Self::PageFrag]) -> Self::PageFrag {
let mut consolidated = String::new();
for frag in frags.into_iter() {
consolidated.push_str(&*frag);
}
consolidated
}
// Used to feed custom recovery information back to a higher-level abstraction
// during startup. For example, a B-Link tree must know what the current
// root node is before it can start serving requests.
fn recover(&self, _: &Self::PageFrag) -> Option<Self::Recovery> {
None
}
// Used to determine the resident size for this item in cache.
fn size_in_bytes(&self, frag: &String) -> usize {
std::mem::size_of::<String>() + frag.as_bytes().len()
}
}
fn main() {
let config = pagecache::ConfigBuilder::new().temporary(true).build();
let pc: pagecache::PageCache<TestMaterializer, _, _> =
pagecache::PageCache::start(config).unwrap();
{
let guard = pin();
let id = pc.allocate(&guard).unwrap();
let mut key = pagecache::PagePtr::allocated();
// The first item in a page should be set using replace,
// which signals that this is the beginning of a new
// page history, and that any previous items associated
// with this page should be forgotten.
key = pc.replace(id, key, "a".to_owned(), &guard).unwrap();
// Subsequent atomic updates should be added with link.
key = pc.link(id, key, "b".to_owned(), &guard).unwrap();
key = pc.link(id, key, "c".to_owned(), &guard).unwrap();
// When getting a page, the provided `Materializer` is
// used to merge all pages together.
let (consolidated, key) = pc.get(id, &guard).unwrap().unwrap();
assert_eq!(*consolidated, "abc".to_owned());
}
}
Implementations
sourceimpl<PM, P, R> PageCache<PM, P, R>where
PM: Materializer<PageFrag = P, Recovery = R>,
PM: 'static + Send + Sync,
P: 'static + Debug + Clone + Serialize + DeserializeOwned + Send + Sync,
R: Debug + Clone + Serialize + DeserializeOwned + Send + Sync,
impl<PM, P, R> PageCache<PM, P, R>where
PM: Materializer<PageFrag = P, Recovery = R>,
PM: 'static + Send + Sync,
P: 'static + Debug + Clone + Serialize + DeserializeOwned + Send + Sync,
R: Debug + Clone + Serialize + DeserializeOwned + Send + Sync,
sourcepub fn flush(&self) -> Result<(), ()>
pub fn flush(&self) -> Result<(), ()>
Flushes any pending IO buffers to disk to ensure durability.
sourcepub fn recovered_state(&self) -> Option<R>
pub fn recovered_state(&self) -> Option<R>
Return the recovered state from the snapshot
sourcepub fn allocate<'g>(&self, guard: &'g Guard) -> Result<PageId, ()>
pub fn allocate<'g>(&self, guard: &'g Guard) -> Result<PageId, ()>
Create a new page, trying to reuse old freed pages if possible
to maximize underlying Radix
pointer density.
sourcepub fn free<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
guard: &'g Guard
) -> Result<(), Option<PagePtr<'g, P>>>
pub fn free<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
guard: &'g Guard
) -> Result<(), Option<PagePtr<'g, P>>>
Free a particular page.
sourcepub fn link<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
new: P,
guard: &'g Guard
) -> Result<PagePtr<'g, P>, Option<PagePtr<'g, P>>>
pub fn link<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
new: P,
guard: &'g Guard
) -> Result<PagePtr<'g, P>, Option<PagePtr<'g, P>>>
Try to atomically add a PageFrag
to the page.
Returns Ok(new_key)
if the operation was successful. Returns
Err(None)
if the page no longer exists. Returns Err(Some(actual_key))
if the atomic append fails.
sourcepub fn replace<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
new: P,
guard: &'g Guard
) -> Result<PagePtr<'g, P>, Option<PagePtr<'g, P>>>
pub fn replace<'g>(
&self,
pid: PageId,
old: PagePtr<'g, P>,
new: P,
guard: &'g Guard
) -> Result<PagePtr<'g, P>, Option<PagePtr<'g, P>>>
Replace an existing page with a different set of PageFrag
s.
Returns Ok(new_key)
if the operation was successful. Returns
Err(None)
if the page no longer exists. Returns Err(Some(actual_key))
if the atomic swap fails.