MCPcopy Create free account
hub / github.com/clockworklabs/SpacetimeDB / alloc_for_obj_common

Method alloc_for_obj_common

crates/table/src/page.rs:675–726  ·  view source on GitHub ↗
(
        &mut self,
        obj_len: usize,
        chunks: impl Copy + FnOnce(usize) -> Cs,
    )

Source from the content-addressed store, hash-verified

673 /// before the granule's data is read from / assumed to be initialized.
674 #[expect(clippy::doc_overindented_list_items)]
675 fn alloc_for_obj_common<'chunk, Cs: Iterator<Item = (&'chunk [u8], usize)>>(
676 &mut self,
677 obj_len: usize,
678 chunks: impl Copy + FnOnce(usize) -> Cs,
679 ) -> Result<(VarLenRef, bool), Error> {
680 // Check that we have sufficient space to allocate `obj_len` bytes in var-len data.
681 let (req_granules, enough_space, in_blob) = self.has_enough_space_for(obj_len);
682 if !enough_space {
683 return Err(Error::InsufficientVarLenSpace {
684 need: req_granules.try_into().unwrap_or(u16::MAX),
685 have: self.num_granules_available().try_into().unwrap_or(u16::MAX),
686 });
687 }
688
689 // For large blob objects, only reserve a granule.
690 // The caller promised that they will initialize it with a blob hash.
691 if in_blob {
692 let vlr = self.alloc_blob_hash()?;
693 return Ok((vlr, true));
694 };
695
696 // Write each `chunk` to var-len storage.
697 // To do this, we allocate granules for and store the chunks in reverse,
698 // starting with the end first.
699 // The offset to the previous granule in the iteration is kept to
700 // link it in as the next pointer in the current iteration.
701 let mut next = PageOffset::VAR_LEN_NULL;
702 debug_assert_eq!(obj_len, chunks(req_granules).map(|(_, len)| len).sum::<usize>());
703 for (chunk, len) in chunks(req_granules) {
704 // This should never error, since we already checked for available space.
705 let granule = self.alloc_granule()?;
706 // SAFETY:
707 // 1. `granule` is properly aligned as it came from `alloc_granule`
708 // and so is `next` as it's either NULL or was the previous `granule`.
709 // This also ensures that both are in bounds
710 // of the page for `granule + granule + VarLenGranule::SIZE`.
711 //
712 // 2. `next` is either NULL or was initialized in the previous loop iteration.
713 //
714 // 3. `granule` points to an unused slot as the space was just allocated.
715 unsafe { self.write_chunk_to_granule(chunk, len, granule, next) };
716 next = granule;
717 }
718
719 Ok((
720 VarLenRef {
721 first_granule: next,
722 length_in_bytes: obj_len as u16,
723 },
724 false,
725 ))
726 }
727
728 /// Allocates a granule for a large blob object
729 /// and returns a [`VarLenRef`] pointing to that granule.

Callers 2

alloc_for_lenMethod · 0.80
alloc_for_sliceMethod · 0.80

Calls 9

has_enough_space_forMethod · 0.80
unwrap_orMethod · 0.80
try_intoMethod · 0.80
alloc_blob_hashMethod · 0.80
alloc_granuleMethod · 0.80
ErrFunction · 0.50
OkFunction · 0.50

Tested by

no test coverage detected