Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions ds4_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -9188,6 +9188,8 @@ struct server_slot {
live_tool_state anthropic_live;
visible_live_state thinking_live;
int continued_last_store_tokens;
char disk_reload_path[128]; /* last disk-restored file (repeat-loop guard) */
int disk_reload_frontier; /* its frontier; same file+depth twice = dead tail */

job *assigned;
job *running;
Expand Down Expand Up @@ -10511,6 +10513,27 @@ static void kv_cache_slot_restore_suppressed(server_slot *slot,
}
}

/* Reload-loop guard: a disk checkpoint restored twice by the same slot at
* the same frontier proves its tail can never match future prompts'
* re-tokenizations (text-keyed tiers validate text, not tokens). Discard it
* exactly like the prefill-failed path does and let the retry land on the
* next candidate or a cold rebuild, which rewrites fresh under the key. */
static bool kv_cache_reload_repeat(server *s, server_slot *slot,
const char *path, int frontier) {
if (!slot || !path || !slot->disk_reload_path[0]) return false;
if (slot->disk_reload_frontier != frontier ||
strcmp(slot->disk_reload_path, path) != 0) return false;
server_log(DS4_LOG_KVCACHE,
"ds4-server: kv cache discarded reason=frontier-contradicted file=%s",
path);
pthread_mutex_lock(&s->kv_mu);
unlink(path);
pthread_mutex_unlock(&s->kv_mu);
slot->disk_reload_path[0] = '\0';
slot->disk_reload_frontier = 0;
return true;
}

static void kv_cache_discard_failed_disk_entry(server *s, server_slot *slot,
const char *path) {
if (!s || !slot || !path) return;
Expand Down Expand Up @@ -12435,6 +12458,10 @@ static void generate_job_inner(server *s, server_slot *slot, job *j) {
j->req.image_count, cached, prompt_for_sync->len);
}
if (cached == 0) slot->continued_last_store_tokens = 0;
if (cached > 0 && cache_source && cache_source[0] != 'd') {
slot->disk_reload_path[0] = '\0';
slot->disk_reload_frontier = 0;
}
if (!multimodal && s->kv.enabled && cached == 0 &&
old_pos >= s->kv.opt.min_tokens) {
/* Loading a disk snapshot replaces the live Metal session. Persist the
Expand All @@ -12443,10 +12470,23 @@ static void generate_job_inner(server *s, server_slot *slot, job *j) {
kv_cache_store_current(s, slot, "evict");
}
if (!multimodal && cached == 0) {
disk_cached = kv_cache_try_load(s, slot, &j->req, &effective_prompt,
&disk_cache_path,
&disk_cache_ext_flags);
for (int kv_reload_try = 0; kv_reload_try < 2; kv_reload_try++) {
disk_cached = kv_cache_try_load(s, slot, &j->req, &effective_prompt,
&disk_cache_path,
&disk_cache_ext_flags);
if (disk_cached > 0 && kv_reload_try == 0 &&
kv_cache_reload_repeat(s, slot, disk_cache_path, disk_cached)) {
free(disk_cache_path);
disk_cache_path = NULL;
disk_cached = 0;
continue;
}
break;
}
if (disk_cached > 0) {
snprintf(slot->disk_reload_path, sizeof(slot->disk_reload_path),
"%s", disk_cache_path ? disk_cache_path : "");
slot->disk_reload_frontier = disk_cached;
cached = disk_cached;
cache_source = "disk-text";
prompt_for_sync = &effective_prompt;
Expand Down