Skip to main content

CachedBlockStore

Struct CachedBlockStore 

Source
pub struct CachedBlockStore<S: BlockStore> { /* private fields */ }
Expand description

Write-back LRU block cache.

Wraps an arbitrary BlockStore and serves reads from an in-memory LRU cache. Writes are marked dirty and batched to the inner store on sync(). If the cache is full and a dirty entry must be evicted, it is written-back to the inner store immediately.

Implementations§

Source§

impl<S: BlockStore> CachedBlockStore<S>

Source

pub fn new(inner: S, capacity: usize) -> Self

Create a new cache of capacity blocks in front of inner.

capacity is clamped to a minimum of 16.

Examples found in repository?
examples/network_mount.rs (line 82)
21fn main() {
22    let args: Vec<String> = std::env::args().collect();
23
24    let mut addr = "127.0.0.1:9100";
25    let mut server_name = "localhost";
26    let mut ca = "certs/ca.pem";
27    let mut master_key_hex = "";
28    let mut init = false;
29
30    let mut i = 1;
31    while i < args.len() {
32        match args[i].as_str() {
33            "--addr" => {
34                addr = &args[i + 1];
35                i += 2;
36            }
37            "--server-name" => {
38                server_name = &args[i + 1];
39                i += 2;
40            }
41            "--ca" => {
42                ca = &args[i + 1];
43                i += 2;
44            }
45            "--master-key" => {
46                master_key_hex = &args[i + 1];
47                i += 2;
48            }
49            "--init" => {
50                init = true;
51                i += 1;
52            }
53            other => {
54                eprintln!("unknown argument: {other}");
55                std::process::exit(1);
56            }
57        }
58    }
59
60    if master_key_hex.is_empty() || master_key_hex.len() != 64 {
61        eprintln!("--master-key must be a 64-character hex string (32 bytes)");
62        std::process::exit(1);
63    }
64
65    let master_key: Vec<u8> = (0..32)
66        .map(|i| u8::from_str_radix(&master_key_hex[i * 2..i * 2 + 2], 16).unwrap())
67        .collect();
68
69    // ── Connect ─────────────────────────────────────────────
70    println!("Connecting to {addr} (SNI: {server_name})...");
71    let net = NetworkBlockStore::connect(addr, server_name, Path::new(ca), &master_key)
72        .expect("failed to connect to server");
73
74    println!(
75        "Connected: {} blocks × {} bytes ({} MiB)",
76        net.total_blocks(),
77        net.block_size(),
78        net.total_blocks() as usize * net.block_size() / (1024 * 1024)
79    );
80
81    // ── Wrap with cache ─────────────────────────────────────
82    let store = Arc::new(CachedBlockStore::new(net, 1024));
83    let crypto = Arc::new(ChaChaEngine::new(&master_key).expect("invalid master key"));
84    let mut fs = FilesystemCore::new(store.clone(), crypto);
85
86    // ── Mount or init ───────────────────────────────────────
87    if init {
88        println!("Initializing new filesystem...");
89        fs.init_filesystem().expect("init_filesystem failed");
90    } else {
91        println!("Mounting existing filesystem...");
92        fs.open().expect("open failed");
93    }
94
95    // ── Demo operations ─────────────────────────────────────
96    println!("\nCreating file 'hello.txt'...");
97    match fs.create_file("hello.txt") {
98        Ok(()) => {}
99        Err(e) => println!("  (skipped: {e})"),
100    }
101
102    fs.write_file("hello.txt", 0, b"Hello from the network!")
103        .expect("write failed");
104
105    let data = fs.read_file("hello.txt", 0, 4096).expect("read failed");
106    println!("Read back: {:?}", String::from_utf8_lossy(&data));
107
108    println!("\nListing root directory:");
109    for entry in fs.list_directory("").expect("list failed") {
110        println!(
111            "  {:?}  {:>10} bytes  {}",
112            entry.kind, entry.size, entry.name
113        );
114    }
115
116    // ── Sync ────────────────────────────────────────────────
117    fs.sync().expect("sync failed");
118    println!("\nAll data synced to server.");
119}

Trait Implementations§

Source§

impl<S: BlockStore> BlockStore for CachedBlockStore<S>

Source§

fn block_size(&self) -> usize

Block size in bytes.
Source§

fn total_blocks(&self) -> u64

Total number of blocks in the store.
Source§

fn read_block(&self, block_id: u64) -> FsResult<Vec<u8>>

Read a full block. Returns exactly block_size() bytes.
Source§

fn write_block(&self, block_id: u64, data: &[u8]) -> FsResult<()>

Write a full block. data must be exactly block_size() bytes.
Source§

fn sync(&self) -> FsResult<()>

Sync / flush all writes. No-op for in-memory stores.
Source§

fn read_blocks(&self, block_ids: &[u64]) -> FsResult<Vec<Vec<u8>>>

Read multiple blocks in one call. Read more
Source§

fn write_blocks(&self, blocks: &[(u64, &[u8])]) -> FsResult<()>

Write multiple blocks in one call. Read more

Auto Trait Implementations§

§

impl<S> !Freeze for CachedBlockStore<S>

§

impl<S> RefUnwindSafe for CachedBlockStore<S>
where S: RefUnwindSafe,

§

impl<S> Send for CachedBlockStore<S>

§

impl<S> Sync for CachedBlockStore<S>

§

impl<S> Unpin for CachedBlockStore<S>
where S: Unpin,

§

impl<S> UnsafeUnpin for CachedBlockStore<S>
where S: UnsafeUnpin,

§

impl<S> UnwindSafe for CachedBlockStore<S>
where S: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V