This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
StorageCacheExt: TTL-Based Caching
Loading…
StorageCacheExt: TTL-Based Caching
Relevant source files
- extensions/src/constants.rs
- extensions/src/storage_cache_ext.rs
- extensions/src/storage_option_ext.rs
- extensions/tests/storage_cache_tests.rs
- extensions/tests/storage_option_tests.rs
The StorageCacheExt trait provides a high-level caching layer on top of the core DataStore engine. It introduces Time-To-Live (TTL) functionality, allowing entries to be stored with an expiration timestamp. This extension handles namespacing, serialization via bitcode, and automatic eviction of expired entries during read operations.
Overview of TTL Storage
Unlike the core DataStore which treats payloads as opaque byte slices, StorageCacheExt structures the payload to include metadata. Every entry written via this extension is prefixed with an 8-byte Little-Endian (LE) timestamp representing the absolute expiration time in seconds since the Unix Epoch extensions/src/storage_cache_ext.rs:19-22
Key Features
- Namespace Isolation : Uses a dedicated
TTL_PREFIX(defined as a namespaced byte array0xF7+ttl+0xFD) to ensure TTL-managed keys do not collide with standard keys or other extensions extensions/src/constants.rs42 extensions/src/storage_cache_ext.rs:1-7 - Automatic Eviction : If a
read_with_ttl()call encounters an expired timestamp, it triggers adelete()on the underlying store and returnsNoneextensions/src/storage_cache_ext.rs:95-98 - Bitcode Serialization : Values are serialized using the
bitcodecrate, making this a non-zero-copy operation compared to the core engine’s raw byte access extensions/src/storage_cache_ext.rs41 - Option Support : The implementation safely handles
Option<T>types, allowingSomeorNoneto be cached with a TTL without requiring additional logic extensions/src/storage_cache_ext.rs:21-22
Data Flow and Implementation
The following table and diagrams illustrate the transformation of data from high-level Rust types to the on-disk format.
TTL Write and Read Flow
| Phase | Action | Code Entity |
|---|---|---|
| Write | Calculate now + ttl_secs, encode value, and prepend timestamp | write_with_ttl extensions/src/storage_cache_ext.rs:55-71 |
| Namespace | Apply TTL_PREFIX to the user key via NamespaceHasher | TTL_NAMESPACE_HASHER extensions/src/storage_cache_ext.rs:56-58 |
| Read | Retrieve raw bytes and extract first 8 bytes | read_with_ttl extensions/src/storage_cache_ext.rs:73-89 |
| Eviction | Compare timestamp; call delete() if now >= expiration | self.delete(&namespaced_key) extensions/src/storage_cache_ext.rs:95-98 |
Code Entity Relationship Diagram
This diagram shows how StorageCacheExt interacts with the core DataStore and utility classes.
Sources: extensions/src/storage_cache_ext.rs:1-54 extensions/src/storage_cache_ext.rs:73-78 extensions/src/constants.rs42
graph TD
subgraph "Extensions_Crate [extensions/src/]"
SCE["StorageCacheExt (Trait)"]
IMPL["DataStore Implementation"]
TNH["TTL_NAMESPACE_HASHER (OnceLock)"]
BC["bitcode (External)"]
TP["TTL_PREFIX (Constant)"]
end
subgraph "Core_Library [src/]"
DS["DataStore (Struct)"]
NH["NamespaceHasher"]
DSR["DataStoreReader (Trait)"]
DSW["DataStoreWriter (Trait)"]
end
SCE --> IMPL
IMPL -- "uses" --> TNH
IMPL -- "serializes_via" --> BC
TNH -- "initializes_with" --> TP
TNH -- "creates" --> NH
IMPL -- "calls" --> DS
DS -- "implements" --> DSR
DS -- "implements" --> DSW
IMPL -- "write_with_ttl()" --> DSW
IMPL -- "read_with_ttl()" --> DSR
Binary Layout
When using write_with_ttl(), the payload stored in the DataStore follows a specific binary structure.
| Offset | Size | Description |
|---|---|---|
0x00 | 8 Bytes | Expiration Timestamp : u64 in Little-Endian format (Unix seconds) extensions/src/storage_cache_ext.rs66 |
0x08 | Variable | Serialized Data : The bitcode encoded representation of type T extensions/src/storage_cache_ext.rs:67-68 |
TTL Payload Transformation
Sources: extensions/src/storage_cache_ext.rs:60-71
Key Functions
write_with_ttl<T: Encode>
Calculates the expiration by adding ttl_secs to the current SystemTime extensions/src/storage_cache_ext.rs:60-64 It prevents overflow using saturating_add extensions/src/storage_cache_ext.rs64 The final payload is a concatenation of the 8-byte timestamp and the bitcode-encoded value extensions/src/storage_cache_ext.rs:66-70
read_with_ttl<T: Decode>
- Retrieval : Reads the entry from the
DataStoreusing the namespaced key extensions/src/storage_cache_ext.rs:73-78 - Validation : Checks if the data is at least 8 bytes long to ensure the timestamp is present extensions/src/storage_cache_ext.rs:82-87
- Expiration Check : Extracts the
u64timestamp viau64::from_le_bytesextensions/src/storage_cache_ext.rs89 If the current time is greater than or equal to the timestamp, it callsself.delete()and returnsOk(None)extensions/src/storage_cache_ext.rs:95-98 - Deserialization : If valid, decodes the remaining bytes starting at offset 8 into type
Tusingbitcode::decodeextensions/src/storage_cache_ext.rs:100-102
Usage Example
Sources: extensions/tests/storage_cache_tests.rs:29-69
Error Handling
ErrorKind::NotFound: Returned if the key does not exist in the underlying store extensions/src/storage_cache_ext.rs104ErrorKind::InvalidData: Returned if the payload is less than 8 bytes or ifbitcodedeserialization fails extensions/src/storage_cache_ext.rs:83-86 extensions/src/storage_cache_ext.rs102- Regular Read Failure : Attempting to use
read_with_ttlon a key written with the standardwrite()method (without the 8-byte prefix) will result in a deserialization error because the first 8 bytes of the raw data will be interpreted as a timestamp extensions/tests/storage_cache_tests.rs:154-173
Sources:
- extensions/src/storage_cache_ext.rs:1-107
- extensions/src/constants.rs:20-42
- extensions/tests/storage_cache_tests.rs:29-151