do-memory-storage-redb 0.1.31

redb embedded storage backend for do-memory-core episodic learning system (cache layer)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# do-memory-storage-redb

[![Crates.io](https://img.shields.io/crates/v/do-memory-storage-redb.svg)](https://crates.io/crates/do-memory-storage-redb)
[![Documentation](https://docs.rs/do-memory-storage-redb/badge.svg)](https://docs.rs/do-memory-storage-redb)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Purpose**: High-performance embedded cache layer for do-memory-core

## Overview

`do-memory-storage-redb` implements the high-performance cache layer for AI agent episodic memory using [redb](https://www.redb.org), an embedded key-value database. It provides blazing fast reads for hot-path operations with minimal overhead.

## Features

- **Blazing Fast**: Sub-microsecond read latency for cached data
- **Embedded**: No separate server process required
- **LRU Caching**: Automatic eviction of least recently used entries
- **TTL Support**: Configurable time-to-live for cache entries
- **Safe Concurrency**: Multiple readers with single writer (MVCC)
- **Crash Safe**: ACID guarantees with automatic recovery
- **Zero Copy**: Direct memory mapping for minimal overhead

## Key Modules

| Module | Purpose |
|--------|---------|
| `storage` | Core storage operations and cache management |
| `tables` | Table definitions and schema management |
| `cache` | Cache-specific operations (LRU, TTL, eviction) |

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
do-memory-storage-redb = "0.1"
```

## Quick Start

```rust
use memory_storage_redb::RedbStorage;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create cache with default settings
    let cache = RedbStorage::new("./data/cache.redb")?;

    // Configure cache size (max episodes)
    let cache = RedbStorage::with_config(
        "./data/cache.redb",
        1000,  // max_cache_size
    )?;

    // Cache is ready to use
    Ok(())
}
```

## ⚠️ IMPORTANT: v0.1.7+ Breaking Change (Current: v0.1.13)

### Postcard Serialization (NOT bincode)

**Version v0.1.7 introduced a breaking change**: The serialization format changed from **bincode** to **postcard** (current version: v0.1.13).

### What Changed?
- **Old (< v0.1.7)**: Used `bincode` for serialization
- **New (≥ v0.1.7)**: Uses `postcard` for serialization (v0.1.13)
- **Why**: Postcard provides better memory safety and is more Rust-idiomatic

### Migration Requirements

If you have existing cache files from v0.1.6 or earlier:

```bash
# 1. Backup your existing cache (if needed)
cp ./data/cache.redb ./data/cache.redb.backup

# 2. Clear the cache to force re-build from Turso
rm ./data/cache.redb

# 3. Restart your application
# The cache will be repopulated from Turso storage
```

### No Data Loss

The cache is a **secondary storage layer**. Your primary data is stored in Turso. Clearing the cache simply forces a rebuild from the durable storage layer.

## Configuration

### Basic Configuration

```rust
use memory_storage_redb::{RedbStorage, RedbConfig};

let config = RedbConfig {
    max_cache_size: 1000,        // Maximum episodes to cache
    ttl_seconds: Some(3600),      // 1 hour TTL
    enable_compression: true,     // Enable value compression
};

let cache = RedbStorage::with_full_config("./data/cache.redb", config)?;
```

### Environment Variables

```bash
# Optional: Configure cache settings
export REDB_CACHE_PATH="./data/cache.redb"
export REDB_MAX_CACHE_SIZE="1000"
export REDB_TTL_SECONDS="3600"
```

## Cache Tables

The cache maintains four tables for different data types:

- **episodes**: Full episode data for fast retrieval
- **patterns**: Extracted patterns with similarity keys
- **embeddings**: Vector embeddings (if enabled)
- **metadata**: Cache statistics and health info

## Performance

Optimized for extremely fast read operations:

| Operation | Latency | Throughput |
|-----------|---------|------------|
| Cache Read | < 10µs | 100K+ ops/s |
| Cache Write | < 100µs | 10K+ ops/s |
| LRU Eviction | < 1ms | Background |
| TTL Cleanup | < 10ms | Background |

### Real-world Performance

In production with do-memory-core (v0.1.13):
- **Cache hit rate**: 85-95% (varies by workload)
- **Average read latency**: 5-8µs (cache hits)
- **Average write latency**: 50-80µs
- **Throughput**: 50K+ reads/s, 8K+ writes/s

## LRU Cache Strategy

The cache uses an LRU (Least Recently Used) eviction policy:

1. Cache fills up to `max_cache_size`
2. New entries trigger eviction of oldest entries
3. Access updates entry timestamp
4. TTL expiration runs in background

### LRU Behavior

```rust
// Entries are tracked by last access time
cache.get("episode-123")?;  // Updates access time

// When cache is full, oldest entry is evicted
cache.insert("episode-456", data)?;  // May trigger eviction
```

## TTL Management

Time-to-live (TTL) automatically expires old entries:

```rust
use memory_storage_redb::{RedbConfig, RedbStorage};

let config = RedbConfig {
    ttl_seconds: Some(3600),  // Expire after 1 hour
    ..Default::default()
};

let cache = RedbStorage::with_full_config("./data/cache.redb", config)?;

// TTL cleanup runs every 60 seconds in background
// Expired entries are automatically removed
```

### TTL Settings

| Setting | Description | Default |
|---------|-------------|---------|
| `ttl_seconds` | Time-to-live in seconds | `None` (no TTL) |
| `ttl_check_interval` | Cleanup interval in seconds | 60 |

## Usage with do-memory-core

```rust
use memory_core::SelfLearningMemory;
use memory_storage_turso::TursoStorage;
use memory_storage_redb::RedbStorage;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Turso for durable storage
    let turso = TursoStorage::new(
        std::env::var("TURSO_DATABASE_URL")?,
        std::env::var("TURSO_AUTH_TOKEN")?,
    ).await?;

    // redb for fast caching
    let redb = RedbStorage::new("./data/cache.redb")?;

    // Hybrid storage for best performance
    let memory = SelfLearningMemory::with_storage(turso, redb).await?;

    Ok(())
}
```

## Cache Synchronization

The cache automatically synchronizes with Turso:

- **Write-through**: Writes go to both Turso and redb
- **Read-aside**: Reads check cache first, then Turso
- **Invalidation**: Cache can be refreshed from Turso
- **Reconciliation**: Periodic sync ensures consistency

```rust
// Manual cache refresh (force sync from Turso)
memory.sync_memories().await?;

// Get cache statistics
let stats = cache.get_stats()?;
println!("Cache hit rate: {:.2}%", stats.hit_rate * 100.0);
println!("Total entries: {}", stats.total_entries);
println!("Cache size: {} bytes", stats.cache_size_bytes);
```

## Background Tasks

The cache runs background tasks for maintenance:

- **TTL Cleanup**: Removes expired entries (every 60s)
- **LRU Eviction**: Maintains size limits (on write)
- **Compression**: Optional value compression (configurable)
- **Health Checks**: Monitors cache health (on demand)

### Background Task Configuration

```rust
use memory_storage_redb::{RedbConfig, RedbStorage};

let config = RedbConfig {
    ttl_check_interval: 30,      // Check TTL every 30s
    enable_compression: true,     // Compress values
    compression_threshold: 1024, // Compress values > 1KB
    ..Default::default()
};

let cache = RedbStorage::with_full_config("./data/cache.redb", config)?;
```

## File Management

redb stores all data in a single file:

```bash
# Check cache file size
ls -lh ./data/cache.redb

# Backup cache
cp ./data/cache.redb ./backups/cache-$(date +%Y%m%d).redb

# Clear cache (forces rebuild from Turso)
rm ./data/cache.redb

# Monitor cache growth
watch -n 5 'ls -lh ./data/cache.redb'
```

### Cache File Structure

- **Single file database**: All tables and data in one file
- **Memory mapped**: Direct access for zero-copy reads
- **Crash recovery**: Automatic recovery from unclean shutdown
- **Incremental writes**: Only modified data is written

## Compression

Optional value compression reduces cache size:

```rust
let config = RedbConfig {
    enable_compression: true,          // Enable compression
    compression_threshold: 1024,        // Compress values > 1KB
    compression_level: 6,               // Compression level (0-9)
    ..Default::default()
};

let cache = RedbStorage::with_full_config("./data/cache.redb", config)?;
```

### Compression Benefits

- **Reduced memory usage**: 40-60% smaller cache files
- **Faster disk I/O**: Less data to read/write
- **Trade-off**: Slightly higher CPU usage

## Monitoring & Statistics

### Cache Statistics

```rust
let stats = cache.get_stats()?;
println!("=== Cache Statistics ===");
println!("Hit rate: {:.2}%", stats.hit_rate * 100.0);
println!("Total entries: {}", stats.total_entries);
println!("Cache size: {} bytes", stats.cache_size_bytes);
println!("Reads: {}", stats.total_reads);
println!("Writes: {}", stats.total_writes);
println!("Evictions: {}", stats.total_evictions);
```

### Health Check

```rust
let health = cache.health_check()?;
println!("Cache healthy: {}", health.is_healthy);
println!("Disk available: {} bytes", health.available_disk_space);
println!("Cache file: {} bytes", health.cache_file_size);
```

## Testing

Run tests with an in-memory database:

```bash
cargo test -p do-memory-storage-redb
```

For integration tests with a real database file:

```bash
cargo test -p do-memory-storage-redb -- --ignored
```

## Dependencies

### Core Dependencies
- **redb**: Embedded key-value database
- **tokio**: Async runtime
- **async-trait**: Async trait support
- **anyhow**: Error handling
- **serde**: Serialization framework
- **postcard**: Serialization format (v0.1.7+, current: v0.1.13)

### Breaking Change Dependencies
- **postcard** (v0.1.7+, current: v0.1.13): Replaces bincode for safer serialization

## Documentation

Full API documentation: [docs.rs/do-memory-storage-redb](https://docs.rs/do-memory-storage-redb)

## Best Practices

### Production Deployment
- Enable TTL for automatic cleanup
- Set appropriate `max_cache_size` based on memory constraints
- Monitor cache hit rate to optimize size
- Enable compression for large datasets
- Run periodic health checks

### Development
- Use smaller cache sizes for local development
- Disable compression for easier debugging
- Monitor cache file growth
- Clear cache frequently during development

### Performance Tuning
- Adjust `max_cache_size` to balance memory and hit rate
- Use TTL for time-sensitive data
- Enable compression for memory-constrained environments
- Monitor eviction rate to detect undersized cache

### Cache Size Guidelines

| Workload | Max Cache Size | Expected Hit Rate |
|----------|----------------|-------------------|
| Low traffic | 100-500 | 85-90% |
| Medium traffic | 500-2000 | 90-95% |
| High traffic | 2000-10000 | 95-98% |

## Troubleshooting

### Cache Not Populating
```rust
// Check Turso connection first
let turso = TursoStorage::new(url, token).await?;
let episodes = turso.get_all_episodes().await?;
println!("Turso has {} episodes", episodes.len());

// Force cache sync
memory.sync_memories().await?;
```

### High Eviction Rate
```rust
let stats = cache.get_stats()?;
if stats.total_evictions > stats.total_writes / 2 {
    // Increase cache size
    let config = RedbConfig {
        max_cache_size: stats.total_entries * 2,
        ..Default::default()
    };
}
```

### Low Cache Hit Rate
```rust
let stats = cache.get_stats()?;
if stats.hit_rate < 0.8 {
    // Check if cache is being used correctly
    // Verify do-memory-core is configured to use cache
    println!("Consider increasing cache size or TTL");
}
```

## License

Licensed under the MIT License. See [LICENSE](../LICENSE) for details.

## Project

Part of the [rust-self-learning-memory](https://github.com/d-o-hub/rust-self-learning-memory) project.

## Version History

- **v0.1.13** (Current): Postcard serialization, improved performance
- **v0.1.7**: Postcard serialization introduced
- **v0.1.6**: Initial release with bincode serialization