fix: retier never deletes an intact plain roll in favor of a corrupt .gz twin

the beyond-keep delete branch had no _gz_intact guard: when an intact plain file and its
CORRUPT .gz twin (same mtime) straddled the keep boundary and listdir yielded the .gz first,
the .gz sorted into the kept range while the intact plain sorted past it and was deleted -
leaving the corrupt archive as the sole copy (permanent data loss), violating the 'corrupt
.gz never wins over intact plain' invariant the two dedupe sites already enforce. the delete
now skips an intact plain whose only surviving twin is a corrupt .gz; a later retier retires
it once a clean .gz exists. reproduced with a forced .gz-first listdir: old deleted the plain,
new keeps it.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-06 16:46:51 -04:00
parent f8d3322591
commit 4ad066ca5c
+6
View File
@@ -288,8 +288,14 @@ def retier(log_dir: str, stem: str, keep_uncompressed: int, keep_compressed: int
files.sort(key=lambda t: (t[1], t[2]), reverse=True)
keep = keep_uncompressed + keep_compressed
present = {p for p, _, _ in files}
for index, (path, _, _) in enumerate(files):
if index >= keep:
# never delete an intact plain whose only surviving twin is a CORRUPT .gz -
# that would leave the corrupt archive as the sole copy (data loss). keep the
# plain; a later retier retires it once a clean .gz exists.
if not path.endswith(".gz") and (path + ".gz") in present and not _gz_intact(path + ".gz"):
continue
try:
os.remove(path)
except OSError: