Skip to content

feat(ram): restore write-back RAM tier as default, keep write-around opt-in - #269

Merged
ketor merged 1 commit into
dingodb:mainfrom
ketor:feat/ram-writeback-restore
Aug 6, 2026
Merged

feat(ram): restore write-back RAM tier as default, keep write-around opt-in#269
ketor merged 1 commit into
dingodb:mainfrom
ketor:feat/ram-writeback-restore

Conversation

@ketor

@ketor ketor commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Motivation

PR#246 (ed4d72b) switched PUT to write-around (direct-to-disk + GET read-promotion) to remove the per-PUT 1MiB arena memcpy (44% serve CPU, PUT 3.42→4.54 GB/s). That traded away the RAM tier's burst absorption and GET-cache role: bursts hit the disk-inflight gate (kCacheFull → PUT failure) and cold GETs served from disk until promotion.

Change

  • write-back is the default again: CacheDirectForKey admits PUT into the RAM arena first (ram_->PutCommitted), the async flusher drains to disk; only genuine arena backpressure (kCacheFull) falls through to direct disk write (existing put_busy_limit_ gate preserved for the disk path).
  • write-around stays available via --ram-write-mode=writearound (env DFKV_RAM_WRITE_MODE; default writeback) — flag→env facade follows the existing pattern.

Verification (0064 B200, RDMA v2, 8GB RAM tier, 32GB cap, 64KB slab granularity, credits=256, t32/b8, 30000 × 64KB)

Mode PUT fails GET fails RAM behavior
write-back (default) 0 (burst absorbed) 0 ram_hit=30000/30000 (100% arena), flushed=30033, bypass=0, evict=0
writearound 0 0 (disk reads) arena untouched (ram_put=0)

Known limitation (pre-existing, out of scope)

Read-promotion (PutDurable) runs on the URING/coalescer async paths only. A UREAD=OFF server's sync-pread GET path never fills the arena in write-around mode — this gap came from ed4d72b and is unchanged here; write-back (the default) fills the arena on every PUT regardless of build flags.

…opt-in

PR#246 (ed4d72b) switched PUT to write-around (direct-to-disk + GET
read-promotion) to remove the per-PUT 1MiB arena memcpy (44% serve CPU,
PUT 3.42->4.54 GB/s). That traded away the RAM tier's burst absorption
and GET-cache role: bursts hit the disk-inflight gate (kCacheFull) and
cold GETs served from disk until promotion.

Restore write-back as the default: CacheDirectForKey admits PUT into
the RAM arena first (async flusher drains to disk); only genuine arena
backpressure falls through to direct disk write. GET serves zero-copy
from the arena. Write-around stays available via
--ram-write-mode=writearound (env DFKV_RAM_WRITE_MODE) for
throughput-first deployments.

Verified on 0064 (B200, RDMA v2, 8GB RAM tier, 32GB cap, 64KB slab
granularity, credits=256, t32/b8, 30000 x 64KB):
- write-back: PUT 0 fails (burst absorbed), GET 0 fails with
  ram_hit=30000/30000 (100% arena), flushed=30033, bypass=0, evict=0
- writearound: PUT 0 fails, GET 0 fails (disk reads), arena untouched
  (note: read-promotion only runs on the URING/coalescer path; a
  UREAD=OFF server's sync-pread GET path never fills the arena — the
  promotion gap is pre-existing from ed4d72b and out of scope here)
@ketor
ketor added this pull request to the merge queue Aug 6, 2026
Merged via the queue into dingodb:main with commit 2a9950e Aug 6, 2026
yuhaijun999 pushed a commit to yuhaijun999/DingoCache that referenced this pull request Aug 7, 2026
…, mode typo guard

Review of v2.6.2 (dingodb#269/dingodb#270) found:

1. SteadyUs() returned steady_clock::count() raw ticks, which are
   NANOSECONDS on Linux. kEvictIdleMinUs=2,000,000 was therefore 2 ms,
   not 2 s: under normal traffic nearly every pooled connection counts
   as idle, so a full segment could evict recently-active connections
   and trigger reconnection storms. Now duration_cast<microseconds>.

2. Eviction woke a live_eps_ pointer whose owning Serve thread then
   exited and destroyed the stack endpoint — a concurrent evictor could
   Wake a freed endpoint (UAF). The evictor now erases the victim from
   live_eps_ under conn_mu_ before Wake (Serve's own erase becomes a
   no-op), so exactly one evictor ever touches an endpoint.

3. Total eviction wait is bounded to 5 s (was up to 32 s, exceeding the
   client's 10 s bootstrap).

4. last_active_us_ == 0 (inserted, not yet stamped by Serve) is never
   treated as idle.

5. DFKV_RAM_WRITE_MODE accepts only writeback|writearound; anything else
   warns and falls back to writeback (was silent writeback on typos).

Verified on 0064 (64MB segment = 15 conns, t16/b1 rounds): A all-active
refusal 26 fails (expected), B-F 1-2 fails each (eviction boundary),
75 evictions, zero crashes/segfaults.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant