ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_cache_store.h File Reference

Persistent key(CRC32)->blob cache for compiled .rabook containers,built on the vendored, HIL-validated LevelX NOR wear-levelling layer (#201). More...

#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_cache_store.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_cache_store_entry_t
 One RAM index slot: key -> {header sector, run length, payload len}. More...
struct  ra8_cache_store_t
 Caller-owned store handle. More...
struct  ra8_cache_store_reader_t
 Handle to an open entry that streams through ra8_cache_store_read. More...
struct  ra8_cache_store_cfg_t
 Injected dependencies + geometry for ra8_cache_store_init. More...

Typedefs

typedef unsigned int(* ra8_cache_store_nor_init_fn) (struct LX_NOR_FLASH_STRUCT *nor_flash)
 LevelX NOR driver-initialise seam (the injected physical-flash bind).

Enumerations

enum  ra8_cache_store_geom_t : uint16_t {
  k_ra8_cache_store_sector_bytes = 512U ,
  k_ra8_cache_store_min_sectors = 8U ,
  k_ra8_cache_store_overprov_pct = 20U ,
  k_ra8_cache_store_max_overprov = 90U
}
 Fixed geometry + tuning constants for the store. More...
enum  ra8_cache_store_flag_t : uint8_t {
  k_ra8_cache_store_flag_none = 0U ,
  k_ra8_cache_store_flag_in_use = 1U << 0 ,
  k_ra8_cache_store_flag_pinned = 1U << 1
}
 Per-entry index-slot flag bits. More...

Functions

ra8_err_t ra8_cache_store_init (ra8_cache_store_t *store, const ra8_cache_store_cfg_t *cfg)
 Bind a LevelX NOR flash instance and mount (or format) the store.
ra8_err_t ra8_cache_store_put (ra8_cache_store_t *store, uint32_t key, const uint8_t *data, uint32_t len)
 Seal a new entry once: append data under key, atomically.
ra8_err_t ra8_cache_store_get (const ra8_cache_store_t *store, uint32_t key, ra8_cache_store_reader_t *out_reader)
 Open a sealed entry for random reads through ra8_cache_store_read.
ra8_err_t ra8_cache_store_read (void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
 ra8_vsource_read_fn-shaped random read over an open entry.
ra8_err_t ra8_cache_store_evict (ra8_cache_store_t *store, uint32_t key)
 Drop an entry and reclaim its sectors (no write-back).
ra8_err_t ra8_cache_store_pin (ra8_cache_store_t *store, uint32_t key, bool pin)
 Pin or unpin an entry (pinned entries are never evicted).
ra8_err_t ra8_cache_store_sync (ra8_cache_store_t *store)
 Checkpoint the index to flash (directory + clean marker not set).
ra8_err_t ra8_cache_store_close (ra8_cache_store_t *store)
 Checkpoint, set the clean-shutdown marker, and close the store.

Detailed Description

Persistent key(CRC32)->blob cache for compiled .rabook containers,

built on the vendored, HIL-validated LevelX NOR wear-levelling layer (#201).

ra8_cache_store is the persistent-cache tier from the multi-GB book-streaming design (Decision 2): a small, flat put / get / evict store keyed by the source CRC-32, log-structured, living on the OSPI/NAND tier – NOT a second ra8_fs mount. It is the on-flash backing for a compiled .rabook so the reader can page a book straight out of NOR flash without touching the SD card (fast resume + a power-savings win on a battery handheld).

Not bespoke wear-levelling – LevelX underneath

The wear-levelling / block-remapping / power-safe-sector-write machinery is the already-vendored Azure RTOS LevelX (libs/third_party/levelx/), run in standalone mode (LX_STANDALONE_ENABLE, no ThreadX). This module is only the thin key -> LevelX-logical-sector index + log/checkpoint bookkeeping on top of lx_nor_flash_sector_write / _read / _release. See issue #201 and recon/reports/disk-cache-design-review.md for the full rationale.

Dependency-inversion seam (host-testable)

The bind to a physical flash is the injected ra8_cache_store_nor_init_fn driver-initialise callback – lx_nor_driver_ra8_xspi_initialize on the EK-RA8D2 Octo-SPI flash, or a RAM NOR fake under the host tests. This header therefore never includes lx_api.h; the LX_NOR_FLASH control block is passed as an opaque, forward-declared pointer the caller owns.

Zero heap (NASA P10 Rule 3)

The caller supplies all storage: the LX_NOR_FLASH control block, this ra8_cache_store_t handle, the ra8_cache_store_entry_t index array, and a one-sector (>= k_ra8_cache_store_sector_bytes) staging buffer. The module allocates nothing.

Streaming a hit (feeds ra8_vsource)

ra8_cache_store_get fills a ra8_cache_store_reader_t and the caller wires ra8_cache_store_read (an ra8_vsource_read_fn-shaped read(ctx,off,buf,len)) into ra8_vsource_add_paged, so a cached .rabook demand-pages through the #204/#205 paged path – full residency is never required.

Write-once invariant

An entry is sealed by a single ra8_cache_store_put; there is deliberately no in-place-update call (the Liskov-clean shape). Because every cached blob is re-derivable from its SD source, eviction never writes anything back – it only releases sectors. GC is internal to LevelX plus this module's sector accounting.

Note
Not thread-safe: one reader core, callers serialise access.
See also
ra8_cache_store_put Seal a new entry.
ra8_cache_store_get Open an entry for streaming reads.
ra8_cache_store_evict Drop an entry and reclaim its sectors.
Since
0.1.0
Tag
[Ring 4 / Storage] {World: NS}

Definition in file ra8_cache_store.h.

Typedef Documentation

◆ ra8_cache_store_nor_init_fn

typedef unsigned int(* ra8_cache_store_nor_init_fn) (struct LX_NOR_FLASH_STRUCT *nor_flash)

LevelX NOR driver-initialise seam (the injected physical-flash bind).

Passed straight to lx_nor_flash_open() / lx_nor_flash_format(). Production binds lx_nor_driver_ra8_xspi_initialize; host tests bind a RAM NOR fake. The unsigned int return mirrors LevelX's UINT (LX_SUCCESS == 0) without needing the LevelX typedefs here.

Parameters
[in,out]nor_flashLevelX control block to populate (geometry + driver callbacks + sector buffer).
Returns
0 (LX_SUCCESS) on success; any non-zero LevelX status on failure.
Since
0.1.0

Definition at line 95 of file ra8_cache_store.h.

Enumeration Type Documentation

◆ ra8_cache_store_flag_t

enum ra8_cache_store_flag_t : uint8_t

Per-entry index-slot flag bits.

Since
0.1.0
Enumerator
k_ra8_cache_store_flag_none 

Empty slot.

k_ra8_cache_store_flag_in_use 

Slot holds a live entry.

k_ra8_cache_store_flag_pinned 

Never-evict (open book / metadata).

Definition at line 117 of file ra8_cache_store.h.

◆ ra8_cache_store_geom_t

enum ra8_cache_store_geom_t : uint16_t

Fixed geometry + tuning constants for the store.

k_ra8_cache_store_sector_bytes is the LevelX logical-sector size the module reads/writes a sector at a time; the staging buffer and every media record are sized against it.

Since
0.1.0
Enumerator
k_ra8_cache_store_sector_bytes 

LevelX logical-sector size (bytes).

k_ra8_cache_store_min_sectors 

Minimum usable logical-sector span.

k_ra8_cache_store_overprov_pct 

Default GC headroom margin (%).

k_ra8_cache_store_max_overprov 

Reject nonsensical margins above.

Definition at line 105 of file ra8_cache_store.h.

Function Documentation

◆ ra8_cache_store_close()

ra8_err_t ra8_cache_store_close ( ra8_cache_store_t * store)
nodiscard

Checkpoint, set the clean-shutdown marker, and close the store.

Writes the directory checkpoint and stamps the clean marker so the next ra8_cache_store_init takes the fast (no-scan) mount path, then closes the LevelX partition. After this the handle must be re-init'd before reuse.

Parameters
[in,out]storeInitialised store.
Returns
Error code.
Return values
k_ra8_okStore checkpointed, marked clean, and closed.
k_ra8_err_null_ptrstore NULL.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_hw_init_failedLevelX write/close failed.
Precondition
store->inited is true.
No reader is mid-stream against this store.
Postcondition
On k_ra8_ok, store->inited is false and the flash marker is clean.
A subsequent ra8_cache_store_init loads the checkpoint directly.
Note
Not thread-safe.
See also
ra8_cache_store_init
Since
0.1.0

Definition at line 548 of file ra8_cache_store.c.

References ra8_cache_store_t::flash, ra8_cache_store_t::inited, internal_checkpoint(), k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, RA8_VALIDATE_INIT, and s_tag.

Referenced by cache_store_demo_run(), and internal_demo_phase_remount().

◆ ra8_cache_store_evict()

ra8_err_t ra8_cache_store_evict ( ra8_cache_store_t * store,
uint32_t key )
nodiscard

Drop an entry and reclaim its sectors (no write-back).

Releases the entry's LevelX logical sectors (returning them to the free pool for GC) and clears its index slot. Because every cached blob is re-derivable from its SD source, nothing is ever written back on eviction – the write-once invariant makes eviction unconditionally cheap. A pinned entry is refused.

Parameters
[in,out]storeInitialised store.
[in]keyContent key to drop.
Returns
Error code.
Return values
k_ra8_okEntry dropped and reclaimed.
k_ra8_err_null_ptrstore NULL.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_not_foundkey is not cached.
k_ra8_err_busyEntry is pinned (unpin first).
k_ra8_err_hw_init_failedLevelX sector release failed.
Precondition
store->inited is true.
key is not pinned.
Postcondition
On k_ra8_ok a later ra8_cache_store_get on key returns not-found.
On k_ra8_ok the freed sectors are available to a later put.
Note
Not thread-safe.
See also
ra8_cache_store_pin
Since
0.1.0

Definition at line 502 of file ra8_cache_store.c.

References ra8_cache_store_entry_t::flags, ra8_cache_store_t::index, ra8_cache_store_t::inited, internal_mark_dirty(), internal_release_run(), k_ra8_cache_store_flag_pinned, k_ra8_err_busy, k_ra8_err_not_found, k_ra8_ok, ra8_cache_store_t::live_sectors, priv_cache_store_index_find(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, RA8_VALIDATE_INIT, s_tag, ra8_cache_store_entry_t::sector_count, and ra8_cache_store_entry_t::start_sector.

Referenced by internal_demo_phase_evict(), and internal_demo_phase_remount().

◆ ra8_cache_store_get()

ra8_err_t ra8_cache_store_get ( const ra8_cache_store_t * store,
uint32_t key,
ra8_cache_store_reader_t * out_reader )
nodiscard

Open a sealed entry for random reads through ra8_cache_store_read.

Looks key up in the index and fills out_reader so the caller can register it with ra8_vsource_add_paged(vs, ra8_cache_store_read, out_reader, 0, out_reader->byte_len, &id). No data is copied here.

Parameters
[in]storeInitialised store.
[in]keyContent key to open.
[out]out_readerReceives the streaming handle (out-lives the vsource).
Returns
Error code.
Return values
k_ra8_okEntry found; out_reader populated.
k_ra8_err_null_ptrstore or out_reader NULL.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_not_foundkey is not cached.
Precondition
store->inited is true.
out_reader is writable.
Postcondition
On k_ra8_ok, out_reader->byte_len is the entry's payload length.
On any error out_reader is untouched.
Note
Not thread-safe.
See also
ra8_cache_store_read
Since
0.1.0

Definition at line 424 of file ra8_cache_store.c.

References ra8_cache_store_entry_t::byte_len, ra8_cache_store_t::index, ra8_cache_store_t::inited, k_ra8_err_not_found, k_ra8_ok, priv_cache_store_index_find(), RA8_CHECK_NULL_PTR, RA8_VALIDATE_INIT, s_tag, ra8_cache_store_entry_t::sector_count, and ra8_cache_store_entry_t::start_sector.

Referenced by internal_demo_get_and_verify(), internal_demo_phase_evict(), internal_demo_phase_remount(), and internal_demo_put_and_verify().

◆ ra8_cache_store_init()

ra8_err_t ra8_cache_store_init ( ra8_cache_store_t * store,
const ra8_cache_store_cfg_t * cfg )
nodiscard

Bind a LevelX NOR flash instance and mount (or format) the store.

Opens the injected LevelX NOR partition (formatting first when cfg->format), then recovers the key index:

  • a clean shutdown marker plus a valid on-flash directory checkpoint is loaded directly (fast path);
  • otherwise the append log is replayed (scanned) to rebuild the index and discard any entry whose append never completed. The store is then marked dirty on flash so a later crash forces a replay.
Parameters
[out]storeZero-initialised handle to populate.
[in]cfgInjected dependencies + geometry (see the struct).
Returns
Error code.
Return values
k_ra8_okStore mounted (or formatted) and ready.
k_ra8_err_null_ptrstore, cfg, or a required cfg member NULL.
k_ra8_err_invalid_sizestaging_bytes too small, index_cap zero, or logical_sectors too small for the layout.
k_ra8_err_invalid_argoverprovision_pct out of range.
k_ra8_err_hw_init_failedLevelX open/format failed.
k_ra8_err_invalid_stateOn-flash checkpoint/superblock is corrupt.
Precondition
store, cfg, and every non-optional cfg member are non-NULL.
cfg->nor_driver_init brings a working LevelX NOR flash up.
Postcondition
On k_ra8_ok, store->inited is true and the index reflects flash.
On any error the store is left uninitialised.
Note
Not thread-safe.
See also
ra8_cache_store_close
Since
0.1.0

Definition at line 794 of file ra8_cache_store_mount.c.

References ra8_cache_store_t::inited, internal_bringup(), internal_init_fields(), internal_validate_cfg(), k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by cache_store_demo_run(), and internal_demo_phase_remount().

◆ ra8_cache_store_pin()

ra8_err_t ra8_cache_store_pin ( ra8_cache_store_t * store,
uint32_t key,
bool pin )
nodiscard

Pin or unpin an entry (pinned entries are never evicted).

A pin marks the currently-open book's container or the shelf/library metadata as never-evict, buying fast resume without an SD-card wake. The pin state is persisted at the next ra8_cache_store_sync / ra8_cache_store_close.

Parameters
[in,out]storeInitialised store.
[in]keyContent key to (un)pin.
[in]pinTrue to pin, false to unpin.
Returns
Error code.
Return values
k_ra8_okPin state updated.
k_ra8_err_null_ptrstore NULL.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_not_foundkey is not cached.
Precondition
store->inited is true.
key is cached.
Postcondition
On k_ra8_ok the slot's pinned flag matches pin.
ra8_cache_store_evict on a pinned key returns k_ra8_err_busy.
Note
Not thread-safe.
Since
0.1.0

Definition at line 523 of file ra8_cache_store.c.

References ra8_cache_store_entry_t::flags, ra8_cache_store_t::index, ra8_cache_store_t::inited, internal_mark_dirty(), k_ra8_cache_store_flag_pinned, k_ra8_err_not_found, k_ra8_ok, pin, priv_cache_store_index_find(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, RA8_VALIDATE_INIT, and s_tag.

Referenced by internal_demo_phase_evict().

◆ ra8_cache_store_put()

ra8_err_t ra8_cache_store_put ( ra8_cache_store_t * store,
uint32_t key,
const uint8_t * data,
uint32_t len )
nodiscard

Seal a new entry once: append data under key, atomically.

Log-structured append with no in-place-update path: the payload sectors are written first, then the entry header last, so a power loss mid-append leaves an unreferenced (reclaimable) tail rather than a visible corrupt entry. Fails if key already exists (write-once; evict first to replace) or if the overprovisioned budget cannot fit the run.

Parameters
[in,out]storeInitialised store.
[in]keyContent key (source CRC-32).
[in]dataPayload bytes (len readable).
[in]lenPayload length in bytes (> 0).
Returns
Error code.
Return values
k_ra8_okEntry sealed and indexed.
k_ra8_err_null_ptrstore or data NULL.
k_ra8_err_invalid_sizelen is zero.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_existskey already present (write-once).
k_ra8_err_no_memIndex full or budget/free-run exhausted.
k_ra8_err_hw_init_failedLevelX sector write failed.
Precondition
store->inited is true.
data covers len bytes.
Postcondition
On k_ra8_ok a subsequent ra8_cache_store_get on key streams data.
On any error no partial entry is visible to ra8_cache_store_get.
Note
Not thread-safe.
See also
ra8_cache_store_get
Since
0.1.0

Definition at line 407 of file ra8_cache_store.c.

References internal_alloc_run(), internal_mark_dirty(), internal_put_check(), internal_write_entry(), k_ra8_ok, ra8_cache_store_t::live_sectors, ra8_cache_store_t::next_seq, priv_cache_store_index_add(), RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_demo_put_and_verify().

◆ ra8_cache_store_read()

ra8_err_t ra8_cache_store_read ( void * ctx,
uint64_t offset,
uint8_t * buf,
uint32_t len )

ra8_vsource_read_fn-shaped random read over an open entry.

Reads len bytes at offset from the entry's payload sectors, one LevelX logical sector at a time through the store staging buffer. Signature matches ra8_vsource_read_fn so it binds straight into ra8_vsource_add_paged.

Parameters
[in]ctxA ra8_cache_store_reader_t populated by ra8_cache_store_get.
[in]offsetByte offset within the payload (< byte_len).
[out]bufDestination (len writable bytes).
[in]lenBytes to read.
Returns
Error code.
Return values
k_ra8_okBytes copied.
k_ra8_err_null_ptrctx or buf NULL.
k_ra8_err_out_of_rangeoffset + len exceeds byte_len.
k_ra8_err_hw_init_failedLevelX sector read failed.
Precondition
ctx is a reader from ra8_cache_store_get on a still-mounted store.
buf covers len bytes.
Postcondition
On k_ra8_ok, buf[0..len) holds the payload slice.
On any error buf content is unspecified.
Note
Not thread-safe; shares the store staging buffer.
Since
0.1.0

Definition at line 489 of file ra8_cache_store.c.

References ra8_cache_store_reader_t::byte_len, ra8_cache_store_reader_t::data_sectors, ra8_cache_store_reader_t::data_start, internal_read_stream(), k_ra8_err_out_of_range, RA8_CHECK_NULL_PTR, s_tag, and ra8_cache_store_reader_t::store.

Referenced by internal_demo_get_and_verify(), and internal_demo_put_and_verify().

◆ ra8_cache_store_sync()

ra8_err_t ra8_cache_store_sync ( ra8_cache_store_t * store)
nodiscard

Checkpoint the index to flash (directory + clean marker not set).

Serialises the live index into the on-flash directory region and rewrites the superblock. Called internally by ra8_cache_store_close; exposed so a caller can periodically shorten the replay a future crash would need. The clean marker stays unset until close.

Parameters
[in,out]storeInitialised store.
Returns
Error code.
Return values
k_ra8_okCheckpoint written.
k_ra8_err_null_ptrstore NULL.
k_ra8_err_not_initializedStore not initialised.
k_ra8_err_hw_init_failedLevelX write failed.
Precondition
store->inited is true.
The index reflects the intended live set.
Postcondition
On k_ra8_ok a clean remount can rebuild the index without a full scan.
The on-flash clean marker remains unset (dirty).
Note
Not thread-safe.
Since
0.1.0

Definition at line 541 of file ra8_cache_store.c.

References ra8_cache_store_t::inited, internal_checkpoint(), RA8_CHECK_NULL_PTR, RA8_VALIDATE_INIT, and s_tag.