Skip to content

Reclaim: a store with NARs and no narinfo blocks the run - #84

Merged
aoinoikaz merged 1 commit into
mainfrom
reclaim/refuse-no-narinfos
Nov 1, 2026
Merged

aoinoikaz merged 1 commit into
mainfrom
reclaim/refuse-no-narinfos

Conversation

@aoinoikaz

Copy link
Copy Markdown
Contributor

reclaim-nars treats a store with an empty narinfo/ directory as a store with no references, so every NAR past the minimum age is eligible. --delete removes them all and exits 0.

fileStoreAt makes a missing directory an error for this reason, but newFileStore recreates a missing narinfo/ empty when the server starts, so a store that lost its narinfos reaches the same plan after any restart.

Change

  • planReclaim returns ReclaimBlocked: UnresolvedNarInfos, as before, or NoNarInfos for a store holding NARs and no narinfo. An empty store still plans nothing.
  • reclaim-nars refuses in both modes, lists and deletes nothing, and exits nonzero, as it does for an unresolved narinfo.

There is no override. A store whose every NAR really is unreferenced looks identical, and deleting is right for that store and destroys the other. Removing those NARs by hand is the cheaper mistake to allow.

A run and the server

The README and the module header now state the limit scanStore already documents: a run is not atomic with the server. A narinfo that arrives during a run for a NAR past the minimum age loses that NAR, including from upstream's nix copy, which skips a NAR already present. A NAR uploaded again after the listing goes too, since removal does not look at the file again. The changelog fragment said the two rules kept a run safe on a cache in use, which that contradicts.

Checks

  • cabal build all -f server --enable-tests --ghc-options="-Werror", then cabal test -f server --ghc-options="-Werror": pass on macOS arm64, GHC 9.14.1. ormolu 0.9.0.0 and hlint 3.10: clean. ASCII only.
  • With the guard disabled, the new property fails, and so does the new store-level test once the property is removed.
  • The executable on a store with a two-month-old NAR and an empty narinfo/: with the guard disabled, --delete removes the NAR and exits 0. With it, both modes exit 1 and the NAR stays. An empty store reports 0 NARs and exits 0.

An empty narinfo directory left no references, so every NAR past the minimum
age was eligible, and --delete removed them all and exited 0. fileStoreAt
refuses a missing directory, but the server's newFileStore recreates it empty
when it starts. A scan cannot tell that store from one whose every NAR is
unreferenced, and the two want opposite answers, so neither mode proceeds.

The README, the module header and the changelog fragment also say a run is not
atomic with the server, which the fragment and the header claimed more than.
@aoinoikaz
aoinoikaz merged commit 30deff6 into main Nov 1, 2026
12 checks passed
@aoinoikaz
aoinoikaz deleted the reclaim/refuse-no-narinfos branch November 1, 2026 13:24
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