kvstore
A key/value store that survives being interrupted.
Nothing in FlintOS outlives a reboot today. Calibration constants, a device identity, a Wi-Fi credential later — all of it needs somewhere to live, and that somewhere is flash, which has two awkward properties: you can only clear bits by erasing a whole sector, and the power can go away in the middle of a write.
Append-only, because that is what makes power loss survivable
Section titled “Append-only, because that is what makes power loss survivable”Writing a key does not modify the old one. It appends a new entry and the newest wins. A write interrupted halfway leaves a torn entry at the end of the log, whose checksum fails, and the scan stops there — every key written before it is exactly as it was. There is no window in which a completed earlier write can be lost, because nothing ever overwrites it.
The cost is space: the log fills with superseded entries and eventually
needs compacting. [Store::used] and [Error::Full] make that the
caller’s decision rather than a surprise.
No storage here
Section titled “No storage here”This crate is lib/: no registers, no chip. It talks to a [Storage],
which a driver implements over real flash. That is what lets the whole of
the interesting behaviour — tearing, corruption, exhaustion — be tested
against a fake, at every byte offset, which no on-target test could do.
Structs
Section titled “Structs”struct Store<S> { /* private fields */ }The log, over some [Storage].
enum Error { Full, BadKey, BadValue, NotFound, BufferTooSmall, Io,}What went wrong.
Implements: Clone, Copy, Debug, Eq, PartialEq, StructuralPartialEq
Traits
Section titled “Traits”Storage
Section titled “Storage”trait Storage { fn capacity(&self) -> u32 fn read(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> fn erase_all(&mut self) -> Result<(), Error>}Flash, as this store needs to see it.
Deliberately small. Everything about wear levelling, cache disabling and which core is stalled belongs to the implementation, not here.
Functions
Section titled “Functions”entry_len
Section titled “entry_len”const fn entry_len(key_len: usize, value_len: usize) -> u32Bytes one entry occupies, header and padding included.
Constants
Section titled “Constants”MAX_KEY_LEN
Section titled “MAX_KEY_LEN”const MAX_KEY_LEN: usize;Longest key. One byte holds the length.
MAX_VALUE_LEN
Section titled “MAX_VALUE_LEN”const MAX_VALUE_LEN: usize;Longest value.