Struct spacetimedb_table::page::Page
source · #[repr(C, align(64))]pub struct Page { /* private fields */ }
Expand description
A page of row data with an associated header
and the raw row_data
itself.
As a rough summary, the strategy employed by this page is:
-
The fixed-len parts of rows grows left-to-right and starts from the beginning of the
row_data
until its high water mark (fixed HWM), i.e.,self.header.fixed.last
. -
The var-len parts of rows grows right-to-left and starts from the end of the
row_data
until its high water mark (variable HWM), i.e.,self.header.var.first
.Each var-len object is stored in terms of a linked-list of chunks. Each chunk in this case is a
VarLenGranule
taking up 64 bytes where:- 6 bits = length, 10 bits = next-cell-pointer
- 62 bytes = the bytes of the object
-
As new rows are added, the HWMs move appropriately. When the fixed and variable HWMs meet, the page is full.
-
When rows are freed, a freelist strategy is used both for the fixed parts and each
VarLenGranule
. These freelists are then used first before using space from the gap. The head of these freelists are stored innext_free
in the fixed and variable headers respectively. -
As the fixed parts of rows may store pointers into the var-length section, to ensure that these pointers aren’t dangling, the page uses pointer fixups when adding to, deleting from, and copying the page. These fixups are handled by having callers provide
VarLenMembers
to find the var-len reference slots in the fixed parts.
Implementations§
source§impl Page
impl Page
sourcepub fn new(fixed_row_size: Size) -> Box<Self>
pub fn new(fixed_row_size: Size) -> Box<Self>
Returns a new page allocated on the heap.
The new page supports fixed rows of size fixed_row_size
.
sourcepub fn get_row_data(&self, row: PageOffset, size: Size) -> &Bytes
pub fn get_row_data(&self, row: PageOffset, size: Size) -> &Bytes
Returns the range of row data starting at offset
and lasting size
bytes.
sourcepub fn has_row_offset(&self, fixed_row_size: Size, offset: PageOffset) -> bool
pub fn has_row_offset(&self, fixed_row_size: Size, offset: PageOffset) -> bool
Returns whether the row at offset
is present or not.
sourcepub fn split_fixed_var_mut(&mut self) -> (FixedView<'_>, VarView<'_>)
pub fn split_fixed_var_mut(&mut self) -> (FixedView<'_>, VarView<'_>)
Returns split mutable views of this page over the fixed and variable sections.
sourcepub fn total_granules_required_for_objects(
objects: &[impl AsRef<[u8]>]
) -> usize
pub fn total_granules_required_for_objects( objects: &[impl AsRef<[u8]>] ) -> usize
Return the total required var-len granules to store objects
.
sourcepub fn has_space_for_row_with_objects(
&self,
fixed_row_size: Size,
var_len_objects: &[impl AsRef<[u8]>]
) -> bool
pub fn has_space_for_row_with_objects( &self, fixed_row_size: Size, var_len_objects: &[impl AsRef<[u8]>] ) -> bool
Does the page have space to store a row,
where the fixed size part is fixed_row_size
bytes large,
and the row has the given var_len_objects
?
sourcepub fn has_space_for_row(
&self,
fixed_row_size: Size,
num_granules: usize
) -> bool
pub fn has_space_for_row( &self, fixed_row_size: Size, num_granules: usize ) -> bool
Does the page have space to store a row,
where the fixed size part is fixed_row_size
bytes large,
and the variable part requires num_granules
.
sourcepub fn is_full(&self, fixed_row_size: Size) -> bool
pub fn is_full(&self, fixed_row_size: Size) -> bool
Returns whether the row is full with respect to storing a fixed row with fixed_row_size
and no variable component.
sourcepub unsafe fn insert_row(
&mut self,
fixed_row: &Bytes,
var_len_objects: &[impl AsRef<[u8]>],
var_len_visitor: &impl VarLenMembers,
blob_store: &mut dyn BlobStore
) -> Result<PageOffset, Error>
pub unsafe fn insert_row( &mut self, fixed_row: &Bytes, var_len_objects: &[impl AsRef<[u8]>], var_len_visitor: &impl VarLenMembers, blob_store: &mut dyn BlobStore ) -> Result<PageOffset, Error>
Will leave partially-allocated chunks if fails prematurely,
so always check Self::has_space_for_row
before calling.
This method is provided for testing the page store directly;
higher-level codepaths are expected to use [crate::bflatn::ser::write_av_to_page
],
which performs similar operations to this method,
but handles rollback on failure appropriately.
This function will never fail if Self::has_space_for_row
has returned true.
§Safety
-
var_len_visitor
is suitable for visiting var-len refs infixed_row
. -
fixed_row.len()
must be consistent withvar_len_visitor
andself
. That is,VarLenMembers
must be specialized for a row type with that length, and all past, present, and future fixed-length rows stored in thisPage
must also be of that length.
sourcepub unsafe fn alloc_fixed_len(
&mut self,
fixed_row_size: Size
) -> Result<PageOffset, Error>
pub unsafe fn alloc_fixed_len( &mut self, fixed_row_size: Size ) -> Result<PageOffset, Error>
Allocates space for a fixed size row of fixed_row_size
bytes.
§Safety
fixed_row_size
must be equal to the value passed
to all other methods ever invoked on self
.
sourcepub fn iter_fixed_len(&self, fixed_row_size: Size) -> FixedLenRowsIter<'_> ⓘ
pub fn iter_fixed_len(&self, fixed_row_size: Size) -> FixedLenRowsIter<'_> ⓘ
Returns an iterator over all the PageOffset
s of the fixed rows in this page.
The rows are assumed to be fixed_row_size
bytes long.
NOTE: This method is not unsafe
as it cannot trigger UB.
However, when provided with garbage input, it will return garbage back.
It is the caller’s responsibility to ensure that PageOffset
s derived from
this iterator are valid when used to do anything unsafe
.
sourcepub unsafe fn iter_var_len_object(
&self,
first_granule: PageOffset
) -> impl Clone + Iterator<Item = &VarLenGranule>
pub unsafe fn iter_var_len_object( &self, first_granule: PageOffset ) -> impl Clone + Iterator<Item = &VarLenGranule>
Returns an iterator over all the VarLenGranule
s of the var-len object
that has its first granule at offset first_granule
.
An empty iterator will be returned when first_granule
is NULL
.
§Safety
first_granule
must be an offset to a valid granule or NULL
.
sourcepub unsafe fn iter_vlo_data(
&self,
first_granule: PageOffset
) -> impl '_ + Clone + Iterator<Item = &[u8]>
pub unsafe fn iter_vlo_data( &self, first_granule: PageOffset ) -> impl '_ + Clone + Iterator<Item = &[u8]>
Returns an iterator over the data of all the VarLenGranule
s of the var-len object
that has its first granule at offset first_granule
.
An empty iterator will be returned when first_granule
is NULL
.
§Safety
first_granule
must be an offset to a valid granule or NULL
.
sourcepub unsafe fn delete_row(
&mut self,
fixed_row: PageOffset,
fixed_row_size: Size,
var_len_visitor: &impl VarLenMembers,
blob_store: &mut dyn BlobStore
)
pub unsafe fn delete_row( &mut self, fixed_row: PageOffset, fixed_row_size: Size, var_len_visitor: &impl VarLenMembers, blob_store: &mut dyn BlobStore )
Free a row, marking its fixed-len and var-len storage granules as available for re-use.
§Safety
-
fixed_row
must point to a valid row in this page. -
fixed_row_size
must be the size in bytes of the fixed part of all past, present, and future rows in this page and future rows in this page. -
The
var_len_visitor
must visit the same set ofVarLenRef
s in the row as the visitor provided toinsert_row
.
sourcepub unsafe fn row_total_granules(
&self,
fixed_row_offset: PageOffset,
fixed_row_size: Size,
var_len_visitor: &impl VarLenMembers
) -> usize
pub unsafe fn row_total_granules( &self, fixed_row_offset: PageOffset, fixed_row_size: Size, var_len_visitor: &impl VarLenMembers ) -> usize
Returns the total number of granules used by the fixed row at fixed_row_offset
and lasting fixed_row_size
bytes where var_len_visitor
is used to find
the VarLenRef
s in the fixed row.
§Safety
-
fixed_row_offset
must refer to a previously-allocated and initialized row inself
, and must not have been de-allocated. In other words, the fixed row must be valid. -
fixed_row_size
andvar_len_visitor
must be consistent with each other and with all other calls to any methods onself
.
sourcepub unsafe fn copy_filter_into(
&self,
starting_from: PageOffset,
dst: &mut Page,
fixed_row_size: Size,
var_len_visitor: &impl VarLenMembers,
blob_store: &mut dyn BlobStore,
filter: impl FnMut(&Page, PageOffset) -> bool
) -> ControlFlow<(), PageOffset>
pub unsafe fn copy_filter_into( &self, starting_from: PageOffset, dst: &mut Page, fixed_row_size: Size, var_len_visitor: &impl VarLenMembers, blob_store: &mut dyn BlobStore, filter: impl FnMut(&Page, PageOffset) -> bool ) -> ControlFlow<(), PageOffset>
Copy as many rows from self
for which filter
returns true
into dst
as will fit,
starting from starting_from
.
If less than the entirety of self
could be processed, return Continue(resume_point)
,
where resume_point
is the starting_from
argument of a subsequent call to copy_filter_into
that will complete the iteration.
dst
should be assumed to be full in this case,
as it does not contain enough free space to store the row of self
at resume_point
.
If the entirety of self
is processed, return Break
.
dst
may or may not be full in this case, but is likely not full.
§Safety
The var_len_visitor
must visit the same set of VarLenRef
s in the row
as the visitor provided to all other methods on self
and dst
.
The fixed_row_size
must be consistent with the var_len_visitor
,
and be equal to the value provided to all other methods on self
and dst
.
The starting_from
offset must point to a valid starting offset
consistent with fixed_row_size
.
That is, it must not point into the middle of a row.
Auto Trait Implementations§
impl Freeze for Page
impl RefUnwindSafe for Page
impl Send for Page
impl Sync for Page
impl Unpin for Page
impl UnwindSafe for Page
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more