page_db/store.rs
1//! The [`PageStore`] trait: the storage seam the buffer pool sits on.
2
3use crate::error::PageResult;
4use crate::page::{Page, PageId};
5
6/// A backing store of fixed-size pages addressed by [`PageId`].
7///
8/// This is the extension seam between the buffer pool and what holds the pages.
9/// [`PageFile`](crate::PageFile) is the implementation that matters — pages on
10/// disk through Direct I/O — but the pool is written against this trait so it
11/// can be driven by an in-memory store in tests, or by an alternative backend
12/// later, without change.
13///
14/// A store does not cache, pin, or track dirtiness; those are the pool's job. A
15/// store only has to read a page by id, write a page to an id, allocate a blank
16/// page of the right size, and flush to durability.
17///
18/// # Examples
19///
20/// A [`PageFile`](crate::PageFile) is a `PageStore`, so it can back a pool:
21///
22/// ```
23/// use page_db::{BufferPool, PageFile, PageId, DEFAULT_PAGE_SIZE};
24///
25/// # let dir = tempfile::tempdir().unwrap();
26/// # let path = dir.path().join("data.pages");
27/// let file = PageFile::open(&path, DEFAULT_PAGE_SIZE)?;
28/// let pool = BufferPool::new(file, 64); // 64 frames over the file
29/// let _ = pool.new_page(PageId::new(0))?;
30/// # Ok::<(), page_db::PageError>(())
31/// ```
32pub trait PageStore: Send + Sync {
33 /// The fixed page size of this store, in bytes.
34 fn page_size(&self) -> usize;
35
36 /// Allocate a blank page sized for this store. The page is in memory only.
37 fn allocate_page(&self) -> Page;
38
39 /// Read the page at `id` into `page`, verifying it.
40 ///
41 /// Reusing the caller's buffer is what lets the pool recycle a frame on a
42 /// miss without allocating.
43 ///
44 /// # Errors
45 ///
46 /// Implementation-defined; for a file this is a short read past end-of-file
47 /// or a failed integrity check.
48 fn read_into(&self, id: PageId, page: &mut Page) -> PageResult<()>;
49
50 /// Write `page` to slot `id`. The page's header is stamped (id + checksum)
51 /// as part of the write.
52 ///
53 /// # Errors
54 ///
55 /// Implementation-defined; for a file this is an I/O failure or a page-size
56 /// mismatch.
57 fn write_page(&self, id: PageId, page: &mut Page) -> PageResult<()>;
58
59 /// Flush all written pages to stable storage.
60 ///
61 /// # Errors
62 ///
63 /// Implementation-defined; for a file this is an I/O failure.
64 fn sync(&self) -> PageResult<()>;
65}
66
67impl PageStore for crate::file::PageFile {
68 #[inline]
69 fn page_size(&self) -> usize {
70 crate::file::PageFile::page_size(self)
71 }
72
73 #[inline]
74 fn allocate_page(&self) -> Page {
75 crate::file::PageFile::allocate_page(self)
76 }
77
78 #[inline]
79 fn read_into(&self, id: PageId, page: &mut Page) -> PageResult<()> {
80 crate::file::PageFile::read_into(self, id, page)
81 }
82
83 #[inline]
84 fn write_page(&self, id: PageId, page: &mut Page) -> PageResult<()> {
85 crate::file::PageFile::write_page(self, id, page)
86 }
87
88 #[inline]
89 fn sync(&self) -> PageResult<()> {
90 crate::file::PageFile::sync(self)
91 }
92}