fix(daemon,win): give conflict-log share collisions a contention budget

The private-file prepare treated slow CONTENTION like permanent
OBSTRUCTION: one 250 ms deadline for both. With many concurrent
appenders on a loaded, sanitized runner the last writer can
legitimately wait longer than that behind its peers' brief exclusive
windows, and the concurrent-append guard correctly failed a dropped
conflict event (dry run: one appender of the pack lost). Transient
share/lock violations now retry against a 2000 ms contention budget
while every other error class keeps the 250 ms fast-fail — a rejected
client is still waiting behind this on the hello path.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel
2026-07-23 09:02:17 +02:00
parent dc5649d1e6
commit e06d1b520e
+15 -1
View File
@@ -856,12 +856,26 @@ static bool windows_private_file_prepare(const char *directory, const char *base
* to the ~16 ms timer granularity, and a permanently obstructed path
* (e.g. a directory squatting on it) must fail fast — a rejected client
* is waiting behind this on the hello path with its own timeout. */
ULONGLONG deadline = GetTickCount64() + 250;
ULONGLONG obstruction_deadline = GetTickCount64() + 250;
/* Genuine share collisions get a wider budget than obstruction: with
* many concurrent appenders on a loaded, sanitized CI runner the
* last-in-line writer can legitimately spend more than 250 ms behind
* its peers' brief exclusive windows, and the no-drop contract for
* conflict events outranks latency there — while a permanently
* obstructed path (a directory squatting on the name) still fails
* inside 250 ms, because a rejected client is waiting behind this on
* the hello path with its own timeout. */
ULONGLONG contention_deadline = GetTickCount64() + 2000;
for (;;) {
SetLastError(ERROR_SUCCESS);
FILE *file = cbm_daemon_ipc_private_log_open(directory, base, SIZE_MAX);
if (file) {
return fclose(file) == 0;
}
DWORD open_error = GetLastError();
bool transient_collision =
open_error == ERROR_SHARING_VIOLATION || open_error == ERROR_LOCK_VIOLATION;
ULONGLONG deadline = transient_collision ? contention_deadline : obstruction_deadline;
if (GetTickCount64() >= deadline) {
return false;
}