pub struct Write<B: Blob> { /* private fields */ }Expand description
A writer that buffers the raw content of a Blob to optimize the performance of appending or updating data.
§Allocation Semantics
- Self::new starts with a detached tip buffer and allocates backing on first buffered write.
- Subsequent writes reuse that backing, copy-on-write allocation only occurs when buffered data is shared (for example, after handing out immutable views) or a merge needs more capacity.
- Sparse writes merged into tip extend logical length and zero-fill any gap in-buffer.
- Flush paths (Self::sync, Self::resize, overlap flushes in Self::write_at) hand drained bytes to the blob and leave the tip detached until the next buffered write.
§Example
use commonware_runtime::{Runner, BufferPooler, buffer::{Write, Read}, Blob, Error, Storage, deterministic};
use commonware_utils::NZUsize;
let executor = deterministic::Runner::default();
executor.start(|context| async move {
// Open a blob for writing
let (blob, size) = context.open("my_partition", b"my_data").await.expect("unable to open blob");
assert_eq!(size, 0);
// Create a buffered writer with 16-byte buffer
let mut blob = Write::from_pooler(&context, blob, 0, NZUsize!(16));
blob.write_at(0, b"hello").await.expect("write failed");
blob.sync().await.expect("sync failed");
// Write more data in multiple flushes
blob.write_at(5, b" world").await.expect("write failed");
blob.write_at(11, b"!").await.expect("write failed");
blob.sync().await.expect("sync failed");
// Read back the data to verify
let (blob, size) = context.open("my_partition", b"my_data").await.expect("unable to reopen blob");
let mut reader = Read::from_pooler(&context, blob, size, NZUsize!(8));
let buf = reader.read(size as usize).await.expect("read failed");
assert_eq!(buf.coalesce().as_ref(), b"hello world!");
});Implementations§
Source§impl<B: Blob> Write<B>
impl<B: Blob> Write<B>
Sourcepub fn new(blob: B, size: u64, capacity: NonZeroUsize, pool: BufferPool) -> Self
pub fn new(blob: B, size: u64, capacity: NonZeroUsize, pool: BufferPool) -> Self
Creates a new Write that buffers up to capacity bytes of data to be appended to the tip
of blob with the provided size.
Sourcepub fn from_pooler(
pooler: &impl BufferPooler,
blob: B,
size: u64,
capacity: NonZeroUsize,
) -> Self
pub fn from_pooler( pooler: &impl BufferPooler, blob: B, size: u64, capacity: NonZeroUsize, ) -> Self
Creates a new Write, extracting the storage BufferPool from a BufferPooler.
Sourcepub async fn size(&self) -> u64
pub async fn size(&self) -> u64
Returns the current logical size of the blob including any buffered data.
This represents the total size of data that would be present after flushing.
Sourcepub async fn read_at(&self, offset: u64, len: usize) -> Result<IoBufs, Error>
pub async fn read_at(&self, offset: u64, len: usize) -> Result<IoBufs, Error>
Read exactly len immutable bytes starting at offset.
Sourcepub async fn write_at(
&self,
offset: u64,
bufs: impl Into<IoBufs> + Send,
) -> Result<(), Error>
pub async fn write_at( &self, offset: u64, bufs: impl Into<IoBufs> + Send, ) -> Result<(), Error>
Write bytes from buf at offset.
Data is merged into the in-memory tip buffer when possible, otherwise buffered data may be flushed and chunks are written directly to the underlying blob.
Returns Error::OffsetOverflow when offset + bufs.len() overflows.
Trait Implementations§
Auto Trait Implementations§
impl<B> Freeze for Write<B>where
B: Freeze,
impl<B> !RefUnwindSafe for Write<B>
impl<B> Send for Write<B>
impl<B> Sync for Write<B>
impl<B> Unpin for Write<B>where
B: Unpin,
impl<B> UnsafeUnpin for Write<B>where
B: UnsafeUnpin,
impl<B> !UnwindSafe for Write<B>
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
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