pub struct FsStore { /* private fields */ }Expand description
Filesystem-based storage for Heddle objects.
Layout:
.heddle/
objects/
blobs/
ab/
cdef1234...
trees/
ab/
cdef1234...
states/
<change_id>.state
actions/
<action_id>.action
packs/
<hash>.pack
<hash>.idxImplementations§
Source§impl FsStore
impl FsStore
Sourcepub fn new(root: impl AsRef<Path>) -> Self
pub fn new(root: impl AsRef<Path>) -> Self
Create a new filesystem store rooted at the given path.
The path should be the .heddle directory.
Sourcepub fn with_compression(
root: impl AsRef<Path>,
compression: CompressionConfig,
) -> Self
pub fn with_compression( root: impl AsRef<Path>, compression: CompressionConfig, ) -> Self
Create a new filesystem store with custom compression settings.
Sourcepub fn compression(&self) -> CompressionConfig
pub fn compression(&self) -> CompressionConfig
Get the compression configuration.
Sourcepub fn set_compression(&mut self, compression: CompressionConfig)
pub fn set_compression(&mut self, compression: CompressionConfig)
Set the compression configuration.
pub fn loose_object_write_mode(&self) -> LooseObjectWriteMode
pub fn set_loose_object_write_mode(&mut self, mode: LooseObjectWriteMode)
Sourcepub fn reload_packs(&self) -> Result<()>
pub fn reload_packs(&self) -> Result<()>
Reload pack files from disk.
Sourcepub fn pack_manager(&self) -> &RwLock<PackManager>
pub fn pack_manager(&self) -> &RwLock<PackManager>
Get the pack manager for pack operations.
pub fn clear_recent_object_caches(&self)
pub fn pack_ids(&self) -> Result<Vec<PackObjectId>>
Trait Implementations§
Source§impl ObjectStore for FsStore
impl ObjectStore for FsStore
Source§fn get_blob_bytes(&self, hash: &ContentHash) -> Result<Option<Bytes>>
fn get_blob_bytes(&self, hash: &ContentHash) -> Result<Option<Bytes>>
Zero-copy pack fast path. When the blob lives in a packfile
and is non-delta + uncompressed, returns a Bytes::slice
view of the pack’s mmap — no decompression, no allocation,
no memcpy. Compressed pack entries, delta entries, and
loose blobs fall back to get_blob and wrap the result in a
Bytes (the Vec → Bytes conversion is itself zero-copy).
Source§fn loose_blob_path(&self, hash: &ContentHash) -> Option<PathBuf>
fn loose_blob_path(&self, hash: &ContentHash) -> Option<PathBuf>
Loose blob path safe for clonefile/copy materialization.
Returns Some(path) only when the loose file exists, is
stored uncompressed, and its bytes hash to the expected
content hash. Compressed blobs and pack-only blobs fall
through to None; so do torn cache-mirror files (the
AtomicWriteMode::NoSync write side may leave one if the
host crashed during a previous promote). On the torn case
the caller re-promotes from the authoritative pack copy.
Verification is amortised: a hash that passes the check once
in this process is recorded in verified_loose_blobs and
subsequent calls skip the read+hash. So the cost on the
materialize hot path is at most one BLAKE3 over each unique
blob per process lifetime — negligible for tiny blobs,
bounded by working-set size for huge ones.
Source§fn promote_to_loose_uncompressed(&self, hash: &ContentHash) -> Result<bool>
fn promote_to_loose_uncompressed(&self, hash: &ContentHash) -> Result<bool>
Promote a blob to its uncompressed-loose canonical path so
loose_blob_path returns Some(path) and hardlink-first
materialization fires.
Three cases:
- Already loose+uncompressed: peek the header, no-op.
- Loose but compressed: read+decompress, atomically rewrite the canonical path with raw bytes.
- Pack-only: read out of the pack via
get_blob, atomically write to the canonical loose path. Pack copy is left in place — the next prune cycle will discard the loose mirror and a future materialize will re-promote.
Source§fn clear_recent_caches(&self)
fn clear_recent_caches(&self)
InMemoryStore is already the source of truth). Read morefn get_blob(&self, hash: &ContentHash) -> Result<Option<Blob>>
fn put_blob(&self, blob: &Blob) -> Result<ContentHash>
fn put_blob_with_hash( &self, blob: &Blob, hash: ContentHash, ) -> Result<ContentHash>
fn put_blob_bytes_with_hash( &self, data: &[u8], hash: ContentHash, ) -> Result<ContentHash>
fn has_blob(&self, hash: &ContentHash) -> Result<bool>
Source§fn blob_size(&self, hash: &ContentHash) -> Result<Option<u64>>
fn blob_size(&self, hash: &ContentHash) -> Result<Option<u64>>
hash, or Ok(None) when the blob is not in the store. Read morefn get_tree(&self, hash: &ContentHash) -> Result<Option<Tree>>
fn put_tree(&self, tree: &Tree) -> Result<ContentHash>
fn put_tree_serialized( &self, data: &[u8], hash: ContentHash, ) -> Result<ContentHash>
fn has_tree(&self, hash: &ContentHash) -> Result<bool>
fn get_state(&self, id: &ChangeId) -> Result<Option<State>>
fn put_state(&self, state: &State) -> Result<()>
fn put_state_serialized(&self, data: &[u8], id: ChangeId) -> Result<()>
fn has_state(&self, id: &ChangeId) -> Result<bool>
fn list_states(&self) -> Result<Vec<ChangeId>>
fn get_action(&self, id: &ActionId) -> Result<Option<Action>>
fn put_action(&self, action: &mut Action) -> Result<ActionId>
fn list_actions(&self) -> Result<Vec<ActionId>>
fn list_blobs(&self) -> Result<Vec<ContentHash>>
fn list_trees(&self) -> Result<Vec<ContentHash>>
fn pack_objects(&self, aggressive: bool) -> Result<(u64, u64)>
fn get_pack_object( &self, id: &PackObjectId, ) -> Result<Option<(ObjectType, Vec<u8>)>>
fn install_pack( &self, pack_data: &[u8], index_data: &[u8], ) -> Result<Vec<PackObjectId>>
Source§fn put_blobs_packed(&self, blobs: Vec<(ContentHash, Vec<u8>)>) -> Result<()>
fn put_blobs_packed(&self, blobs: Vec<(ContentHash, Vec<u8>)>) -> Result<()>
FsStore) override this to install one
packfile + index — two fsyncs total instead of N. Used by the
snapshot hot path so writing 1000 small files takes ~one fsync,
not 1000. Read moreSource§fn install_pack_streaming(
&self,
pack_path: &Path,
index_path: &Path,
) -> Result<Vec<PackObjectId>>
fn install_pack_streaming( &self, pack_path: &Path, index_path: &Path, ) -> Result<Vec<PackObjectId>>
StreamingPackBuilder). The default
impl reads both files fully and delegates to install_pack,
so any backend that doesn’t override this still works (at the
cost of giving back the bounded-memory promise). Real fs-
backed stores override this to rename(2) both files into the
pack directory without ever loading them. Read morefn prune_loose_objects(&self) -> Result<(u64, u64)>
fn begin_snapshot_write_batch(&self) -> Result<()>
fn flush_snapshot_write_batch(&self) -> Result<()>
fn abort_snapshot_write_batch(&self)
Source§fn has_redactions_for_blob(&self, blob: &ContentHash) -> Result<bool>
fn has_redactions_for_blob(&self, blob: &ContentHash) -> Result<bool>
Source§fn get_redactions_bytes_for_blob(
&self,
blob: &ContentHash,
) -> Result<Option<Vec<u8>>>
fn get_redactions_bytes_for_blob( &self, blob: &ContentHash, ) -> Result<Option<Vec<u8>>>
RedactionsBlob bytes for the given
blob, or Ok(None) if no redaction record exists. The bytes
are byte-identical to what was written by put_redactions_bytes_for_blob
(or by Repository::put_redaction); this is the wire-transfer
payload, not a re-serialized view. Read moreSource§fn put_redactions_bytes_for_blob(
&self,
blob: &ContentHash,
bytes: &[u8],
) -> Result<()>
fn put_redactions_bytes_for_blob( &self, blob: &ContentHash, bytes: &[u8], ) -> Result<()>
RedactionsBlob bytes for the given
blob. Receiver-side replay calls this after signature
verification so the bytes land in the same sidecar that the
sender’s Repository::put_redaction writes to. Read moreSource§fn list_blobs_with_redactions(&self) -> Result<Vec<ContentHash>>
fn list_blobs_with_redactions(&self) -> Result<Vec<ContentHash>>
Source§fn has_state_visibility_for_state(&self, state: &ChangeId) -> Result<bool>
fn has_state_visibility_for_state(&self, state: &ChangeId) -> Result<bool>
state. Read moreSource§fn get_state_visibility_bytes_for_state(
&self,
state: &ChangeId,
) -> Result<Option<Vec<u8>>>
fn get_state_visibility_bytes_for_state( &self, state: &ChangeId, ) -> Result<Option<Vec<u8>>>
StateVisibilityBlob bytes for state,
or Ok(None) if no sidecar exists. The bytes are the wire-transfer
payload for state visibility. Read moreSource§fn put_state_visibility_bytes_for_state(
&self,
state: &ChangeId,
bytes: &[u8],
) -> Result<()>
fn put_state_visibility_bytes_for_state( &self, state: &ChangeId, bytes: &[u8], ) -> Result<()>
Source§fn list_states_with_visibility(&self) -> Result<Vec<ChangeId>>
fn list_states_with_visibility(&self) -> Result<Vec<ChangeId>>
fn put_action_serialized(&self, data: &[u8], id: ActionId) -> Result<()>
Auto Trait Implementations§
impl !Freeze for FsStore
impl RefUnwindSafe for FsStore
impl Send for FsStore
impl Sync for FsStore
impl Unpin for FsStore
impl UnsafeUnpin for FsStore
impl UnwindSafe for FsStore
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> 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<S> ObjectSource for Swhere
S: ObjectStore + ?Sized,
impl<S> ObjectSource for Swhere
S: ObjectStore + ?Sized,
fn get_tree(&self, hash: &ContentHash) -> Result<Option<Tree>, HeddleError>
fn get_state(&self, id: &ChangeId) -> Result<Option<State>, HeddleError>
fn get_blob(&self, hash: &ContentHash) -> Result<Option<Blob>, HeddleError>
Source§fn get_blob_bytes(
&self,
hash: &ContentHash,
) -> Result<Option<Bytes>, HeddleError>
fn get_blob_bytes( &self, hash: &ContentHash, ) -> Result<Option<Bytes>, HeddleError>
get_blob.