Write Path
This page explains how Set and Del behave in each mode, and how writes during fallback are batched to disk through a queue.
Set
| Mode | Behavior | Source |
|---|---|---|
| Normal | Write Redis with SET (no expiry when TTL is 0), up to MaxRetry times; on success, store in the memory cache |
set.go:33-48 |
| Normal (retries exhausted) | Switch to fallback; the same call continues with a fallback write | set.go:50-55 |
| Fallback | Store in the memory cache, then send a WriteRequest to the queue |
set.go:58-68 |
When Set returns nil in fallback mode, the data is already in memory and Get can read it immediately; the file write happens later.
Batch File Writes
graph LR
Set[Set] --> Q{Queue has room?}
Q -->|Yes| Queue[queue of length MaxQueue]
Q -->|No| Sync[Synchronous writeToFile]
Queue --> Pending[pending map merged by key]
Timer[Every TimeToWrite] --> Flush[Take and reset pending]
Pending --> Flush
Flush --> Par[One goroutine per key writes its file]
| Item | Behavior | Source |
|---|---|---|
| Queue | Length MaxQueue (default 1000) |
instance.go:36 |
| Merging | Multiple writes to one key within an interval keep only the last | writer.go:13-16 |
| Flush interval | TimeToWrite (default 3 seconds) |
writer.go:17-18 |
| Parallelism | One goroutine per key; the round ends when all finish | writer.go:38-48 |
| Full queue | Does not block; writes the file synchronously and returns its error | set.go:61-65 |
| File content | JSON of the whole Cache structure, mode 0644 |
writer.go:52-65 |
Del
Del (del.go:7-23) always deletes the memory entry and the local file; in normal mode it also runs Redis DEL and returns an error if that fails (no mode switch, no retry). Deleting a missing key returns no error.
| Mode | Memory | Local file | Redis |
|---|---|---|---|
| Normal | Deleted | Deleted | DEL |
| Fallback | Deleted | Deleted | Untouched |
A key deleted during fallback still exists in Redis; the recovery resync does not replay deletes, so the key stays in Redis until it expires on its own.
Example
if err := rf.Set("user:1", map[string]any{"name": "pardn"}, 30*time.Minute); err != nil {
// only when serialization fails, or the fallback queue is full and the synchronous file write fails
log.Println(err)
}
if err := rf.Del("user:1"); err != nil {
// only when Redis DEL fails in normal mode
log.Println(err)
}