[][src]Struct pagecache::PageCache

pub struct PageCache<P> where
    P: Materializer
{ /* fields omitted */ }

A lock-free pagecache which supports fragmented pages for dramatically improving write throughput.

Working with the PageCache

use {
    pagecache::{pin, Config, Materializer},
    serde::{Deserialize, Serialize},
};

#[derive(
    Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Serialize, Deserialize,
)]
pub struct TestState(String);

impl Materializer for TestState {
    // Used to merge chains of partial pages into a form
    // that is useful for the `PageCache` owner.
    fn merge(&mut self, other: &TestState) {
        self.0.push_str(&other.0);
    }
}

fn main() {
    let config = pagecache::ConfigBuilder::new().temporary(true).build();
    let pc: pagecache::PageCache<TestState> =
        pagecache::PageCache::start(config).unwrap();
    {
        // We begin by initiating a new transaction, which
        // will prevent any witnessable memory from being
        // reclaimed before we drop this object.
        let guard = pin();

        // The first item in a page should be set using allocate,
        // which signals that this is the beginning of a new
        // page history.
        let (id, mut key) =
            pc.allocate(TestState("a".to_owned()), &guard).unwrap();

        // Subsequent atomic updates should be added with link.
        key = pc
            .link(id, key, TestState("b".to_owned()), &guard)
            .unwrap()
            .unwrap();
        key = pc
            .link(id, key, TestState("c".to_owned()), &guard)
            .unwrap()
            .unwrap();

        // When getting a page, the provided `Materializer` is
        // used to merge all pages together.
        let (mut key, page, size_on_disk) =
            pc.get(id, &guard).unwrap().unwrap();

        assert_eq!(page.0, "abc".to_owned());

        // You can completely rewrite a page by using `replace`:
        key = pc
            .replace(id, key, TestState("d".into()), &guard)
            .unwrap()
            .unwrap();

        let (key, page, size_on_disk) =
            pc.get(id, &guard).unwrap().unwrap();

        assert_eq!(page.0, "d".to_owned());
    }
}

Methods

impl<P> PageCache<P> where
    P: Materializer
[src]

pub fn start(config: Config) -> Result<Self>[src]

Instantiate a new PageCache.

pub fn flush(&self) -> Result<usize>[src]

Flushes any pending IO buffers to disk to ensure durability. Returns the number of bytes written during this call.

pub fn allocate<'g>(
    &self,
    new: P,
    guard: &'g Guard
) -> Result<(PageId, PagePtr<'g, P>)>
[src]

Create a new page, trying to reuse old freed pages if possible to maximize underlying PageTable pointer density. Returns the page ID and its pointer for use in future atomic replace and link operations.

pub fn attempt_gc(&self) -> Result<bool>[src]

Attempt to opportunistically rewrite data from a Draining segment of the file to help with space amplification. Returns Ok(true) if we had the opportunity to attempt to move a page. Returns Ok(false) if there were no pages to GC. Returns an Err if we encountered an IO problem while performing this GC.

pub fn pin_log(&self) -> Result<RecoveryGuard>[src]

Initiate an atomic sequence of writes to the underlying log. Returns a RecoveryGuard which, when dropped, will record the current max reserved LSN into an earlier log reservation. During recovery, when we hit this early atomic LSN marker, if the specified LSN is beyond the contiguous tip of the log, we immediately halt recovery, preventing the recovery of partial transactions or write batches. This is a relatively low-level primitive that can be used to facilitate transactions and write batches when combined with a concurrency control system in another component.

pub fn free<'g>(
    &self,
    pid: PageId,
    old: PagePtr<'g, P>,
    guard: &'g Guard
) -> Result<CasResult<'g, P, ()>>
[src]

Free a particular page.

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.

pub fn replace<'g>(
    &self,
    pid: PageId,
    old: PagePtr<'g, P>,
    new: P,
    guard: &'g Guard
) -> Result<CasResult<'g, P, P>>
[src]

Replace an existing page with a different set of PageFrags. 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.

pub fn get<'g>(
    &self,
    pid: PageId,
    guard: &'g Guard
) -> Result<Option<(PagePtr<'g, P>, &'g P, u64)>>
[src]

Try to retrieve a page by its logical ID.

pub fn stable_lsn(&self) -> Lsn[src]

The highest known stable Lsn on disk.

pub fn make_stable(&self, lsn: Lsn) -> Result<usize>[src]

Blocks until the provided Lsn is stable on disk, triggering necessary flushes in the process. Returns the number of bytes written during this call.

pub fn was_recovered(&self) -> bool[src]

Returns true if the database was recovered from a previous process. Note that database state is only guaranteed to be present up to the last call to flush! Otherwise state is synced to disk periodically if the sync_every_ms configuration option is set to Some(number_of_ms_between_syncs) or if the IO buffer gets filled to capacity before being rotated.

pub fn generate_id(&self) -> Result<u64>[src]

Generate a monotonic ID. Not guaranteed to be contiguous. Written to disk every idgen_persist_interval operations, followed by a blocking flush. During recovery, we take the last recovered generated ID and add 2x the idgen_persist_interval to it. While persisting, if the previous persisted counter wasn't synced to disk yet, we will do a blocking flush to fsync the latest counter, ensuring that we will never give out the same counter twice.

pub fn meta<'a>(&self, guard: &'a Guard) -> Result<&'a Meta>[src]

Returns the current Meta map, which contains a convenient mapping from identifiers to PageId's that the PageCache owner may use for storing metadata about their higher-level collections.

pub fn meta_pid_for_name(&self, name: &[u8], guard: &Guard) -> Result<PageId>[src]

Look up a PageId for a given identifier in the Meta mapping. This is pretty cheap, but in some cases you may prefer to maintain your own atomic references to collection roots instead of relying on this. See sled's Tree root tracking for an example of avoiding this in a lock-free way that handles various race conditions.

pub fn cas_root_in_meta<'g>(
    &self,
    name: &[u8],
    old: Option<PageId>,
    new: Option<PageId>,
    guard: &'g Guard
) -> Result<Result<(), Option<PageId>>>
[src]

Compare-and-swap the Meta mapping for a given identifier.

Trait Implementations

impl<P> Sync for PageCache<P> where
    P: Materializer
[src]

impl<P> Send for PageCache<P> where
    P: Materializer
[src]

impl<P> Debug for PageCache<P> where
    P: Materializer
[src]

Auto Trait Implementations

impl<P> Unpin for PageCache<P>

impl<P> !UnwindSafe for PageCache<P>

impl<P> !RefUnwindSafe for PageCache<P>

Blanket Implementations

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> From<T> for T[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> Any for T where
    T: 'static + ?Sized
[src]