mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4830] [Bug]: [Store] offload_on_evict is silently bypassed when OpLog is enabled; evicted objects never reach LOCAL_DISK #1228
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#1228
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @he-yufeng on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4830
Describe the bug
With
enable_ha=true+enable_oplog=true+enable_offload=true+offload_on_evict=true, evicted objects never reach the LOCAL_DISK tier: they are removed from DRAM on the primary (and via the OpLog on the standby) without any disk replica ever being created. The startup log still says offload happens at eviction time.On current
main(3b08b7716,mooncake-store/src/master_service.cpp):PutEndqueues an eager offload only whenoffload_on_evict_is false (L5386), so nothing is offloaded at write time in this mode. That part is intended.BatchEvictpath,try_evict_or_offloadreturns early with a plainevict_replicaswhenenable_oplog_is set (L11642-L11650), ahead of the whole offload branch.persist_evict_oplog_or_skip(L11710) has already marked the memory replicasREMOVEDand appended the REMOVE record, so the standby drops its copy too.Net effect for an operator running HA with the disk tier: eviction silently deletes objects that the configuration says should be spilled to disk. The first visible symptom is elevated cache misses; nothing in the log says the disk tier is inactive.
The tenant-quota pass added in #4723 orders its own record correctly (offload decision first, record only on actual eviction), but the global
BatchEvictpath above is the one that runs on the watermark trigger.Identification and reproduction
Found by code reading while measuring the HA paths for #4666 (Appendix §F item 3); the same reading was confirmed independently in #4723. We have not run this exact flag combination in the rig yet. A probe that should demonstrate it: master with
enable_ha,enable_oplog,enable_offload,offload_on_evict, small segments; fill past the eviction high watermark; then check that evicted keys have no LOCAL_DISK replica (has_local_disk_replicanever became true) and that reads of those keys miss instead of restoring from disk.If the early return is deliberate (for example because the offload ordering cannot be made durable with the current OpLog), the startup log line and the deployment docs should say that the two flags are mutually exclusive; otherwise the fix is to let the offload decision precede the record in this path as well.
Related: #4723, #4666.
@github-actions[bot] commented on GitHub (Oct 21, 2026):
Thanks for opening this issue, @he-yufeng!
40085740A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide
@apex-mochen commented on GitHub (Oct 21, 2026):
I ran the probe as two scenario tests in
master_service_evict_scenario_test.cpp. Both useenable_ha+enable_oplog+enable_offload+offload_on_evict, withoffload_force_evict=falseand one completed, lease-expired 1 KiB objectcold, followed byEvictMemory(1.0), which goes throughBatchEvict.The second test is the same without
MountLocalDisk. There the offload cannot be queued, so withoffload_force_evict=falsethe object should stay.Results on
d855a6a(the base of #4723; #4723 does not touchBatchEvict). Each test was run 3 times, with the same result every time:OffloadHeartbeat(memory) returned 0 offload tasks; expected 1, thenObject(cold) is not readable: OBJECT_NOT_FOUNDObject(cold) is not readable: OBJECT_NOT_FOUNDThe log shows
[EVICT-RESULT] evicted_count=1. I got the same "without disk" result earlier on129c961.So both effects reproduce:
offload_force_evict=false, the only copy is deleted even when the offload cannot be queued.For comparison, the tenant-watermark pass in #4723 keeps the object in both cases; two regression tests there cover this.
I haven't checked the grouped-object path. If the early return turns out not to be deliberate, I'm happy to send a PR that applies the same ordering to
BatchEvict(offload decision first, record only right before an actual eviction), with these two tests as regressions.@he-yufeng commented on GitHub (Oct 21, 2026):
Thanks for running the probe — that matches the reading exactly, and it pins the second effect too, which is the worse one: with
offload_force_evict=falsethe delete already happened by the time the offload queue comes up empty, so the object is gone on the one configuration that explicitly asked not to lose it. The eviction-counting half of this family is what #4723 fixed for the watermark pass; BatchEvict taking the same ordering (decide offload first, record only when an eviction actually happens) sounds right to me.On scope: the two scenario tests you ran are the regression pair I would want, one with the disk mounted and one without. The grouped-object path is worth a look while you are in there — if a group member is evicted while its siblings are mid-write the same ordering question applies, but I have not traced whether group eviction shares this code path. If it turns out to be separate, leaving it for a follow-up is fine; the single-object case is the one the probe proves.
Happy to review when the PR is up.
@he-yufeng commented on GitHub (Oct 22, 2026):
Correction to the write-up above: the parenthetical about the tenant-quota pass was wrong, and worth fixing since #4723 is referenced there.
The tenant pass does not order its own record correctly because it writes no record at all. #4722 tracks exactly that gap (tenant-watermark eviction removes replicas and releases quota with no OpLog entry, while BatchEvict persists first), and #4723 is the fix that adds the persistence. What the tenant pass does order correctly in the current tree is its internal offload-versus-evict bookkeeping; the record side is still missing there and is #4723's to land.
This does not change anything in this issue or in #4868: the BatchEvict path this issue is about had its own bypass, which #4868 fixes, independent of the tenant pass.