pub mod aligned;
#[cfg(any(test, all(target_os = "linux", feature = "io-uring")))]
mod buffer_pool;
pub mod file;
pub mod memory;
pub use aligned::AlignedBlobBuf;
#[cfg(all(target_os = "linux", feature = "io-uring"))]
pub(crate) use buffer_pool::BlobBufPool;
pub use file::FileBlobStore;
pub use memory::MemoryBlobStore;
use crate::api::errors::Result;
use crate::layout::BlobGuid;
#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ColdBlobLookup {
Unknown,
Found {
value: Vec<u8>,
seq: u64,
},
Crossing {
child_guid: BlobGuid,
child_depth: usize,
},
NotFound,
}
pub trait BlobStore: Send + Sync {
fn alloc_blob_buf_zeroed(&self) -> AlignedBlobBuf {
AlignedBlobBuf::zeroed()
}
fn read_blob(&self, guid: BlobGuid, dst: &mut AlignedBlobBuf) -> Result<()>;
fn read_blobs(&self, guids: &[BlobGuid], dsts: &mut [AlignedBlobBuf]) -> Vec<Result<()>> {
debug_assert_eq!(guids.len(), dsts.len());
guids
.iter()
.zip(dsts.iter_mut())
.map(|(guid, dst)| self.read_blob(*guid, dst))
.collect()
}
fn read_blob_range(&self, guid: BlobGuid, byte_offset: u64, dst: &mut [u8]) -> Result<()> {
let mut full = self.alloc_blob_buf_zeroed();
self.read_blob(guid, &mut full)?;
let start = byte_offset as usize;
dst.copy_from_slice(&full.as_slice()[start..start + dst.len()]);
Ok(())
}
fn write_blob(&self, guid: BlobGuid, src: &AlignedBlobBuf) -> Result<()>;
fn write_blobs(&self, writes: &[(BlobGuid, &AlignedBlobBuf)]) -> Result<()> {
for (guid, src) in writes {
self.write_blob(*guid, src)?;
}
Ok(())
}
fn write_blobs_with_data_sync(&self, writes: &[(BlobGuid, &AlignedBlobBuf)]) -> Result<()> {
self.write_blobs(writes)
}
fn delete_blob(&self, guid: BlobGuid) -> Result<()>;
fn list_blobs(&self) -> Result<Vec<BlobGuid>>;
fn flush(&self) -> Result<()>;
fn needs_flush(&self) -> bool {
true
}
fn has_blob(&self, guid: BlobGuid) -> Result<bool> {
self.list_blobs().map(|v| v.contains(&guid))
}
}