Skip to content

Upstream tracking - #165

Draft
grahamc wants to merge 3706 commits into
2.35-maintenancefrom
main
Draft

grahamc wants to merge 3706 commits into
2.35-maintenancefrom
main

Conversation

@grahamc

@grahamc grahamc commented Jul 31, 2025

Copy link
Copy Markdown
Member

Motivation

Not intended to be merged directly. This PR is a convenience to show the diff between upstream Nix and Determinate Nix (the main branch).

Continuation of #4.

@grahamc
grahamc requested a review from edolstra as a code owner July 31, 2025 17:14
@github-actions
github-actions Bot temporarily deployed to production July 31, 2025 17:14 Inactive
@DeterminateSystems DeterminateSystems locked as off-topic and limited conversation to collaborators Jul 31, 2025
@github-actions
github-actions Bot temporarily deployed to pull request July 31, 2025 18:20 Inactive
@github-actions
github-actions Bot temporarily deployed to production July 31, 2025 18:21 Inactive
@cole-h
cole-h marked this pull request as draft August 1, 2025 14:26
@github-actions
github-actions Bot temporarily deployed to pull request August 4, 2025 22:15 Inactive
@github-actions
github-actions Bot temporarily deployed to commit August 4, 2025 22:15 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 4, 2025 22:15 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 5, 2025 14:25 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 5, 2025 14:25 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 7, 2025 15:58 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 7, 2025 15:58 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 7, 2025 23:01 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 7, 2025 23:02 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 10, 2025 16:36 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 10, 2025 16:36 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 10, 2025 20:06 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 10, 2025 20:06 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 19, 2025 15:04 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 19, 2025 15:04 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 20, 2025 10:41 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 20, 2025 10:41 Inactive
@github-actions
github-actions Bot temporarily deployed to commit August 20, 2025 10:41 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request August 25, 2025 16:07 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 25, 2025 16:07 Inactive
@github-actions
github-actions Bot temporarily deployed to production August 25, 2025 16:14 Inactive
edolstra and others added 30 commits October 5, 2026 15:08
SQLite: Only apply the ZFS -shm workaround on the first open of a database
Previously, if a package was replaced by a different store path with
the same version (e.g. a rebuild due to a dependency or source change),
`nix profile history` reported "No changes" for that generation. Now
it prints a `changed` line.

Also add a `--show-source` flag that shows the (abbreviated) locked
flake reference of each added, removed, upgraded or changed package.
For upgraded/changed packages, the old and new references are shown,
which explains where the change came from.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
…ne-yield

Fix GC stack scanning when a coroutine yields from another coroutine's stack
nix profile history: Show store path changes with the same version
The periodic purge of expired entries from the narinfo disk cache
does

  delete from NARs where (present = 0 and timestamp < ?)
                      or (present = 1 and timestamp < ?)

which, with only the (cache, hashPart) primary key available, is a
full table scan. On busy builders the cache grows to millions of rows
and several GiB, and the scan was measured to hold the SQLite write
lock for over two minutes on a cold file cache (NIX-491). Every
concurrent `nix copy` blocks on that lock, and uploader timeouts that
kill the purging process just cause the next process to start the
scan over.

Add an index on NARs(present, timestamp). SQLite then executes the
purge as two covering-index range searches. On a synthetic 1.5M-row,
3.1 GiB cache with 5000 expired entries, the warm-cache purge drops
from ~9 s and ~3 GiB of page reads to ~1 s and <100 MiB of page
reads for the delete itself (~3.5 s including the commit), and the
`nix` process startup that triggers it goes from 9.8 s to 4.4 s.

Bump the database filename to v4 so the index is created as part of
a fresh, empty database. Building the index in place on an existing
multi-GiB cache would itself hold the write lock for a full table
read, which is exactly the stall this is meant to remove.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
The purge ran as a single DELETE in whichever process happened to
open the cache, holding the SQLite write lock for its entire
duration. Concurrent processes (e.g. parallel `nix copy` uploads)
blocked on it for the whole time, and if the purging process was
killed, e.g. by a caller's timeout, all work was rolled back and the
next process started over from scratch.

Delete in chunks of 1000 rows instead, each in its own autocommit
transaction:

* The write lock is released after every chunk, so concurrent
  writers wait at most for one chunk (a few hundred ms warm, under a
  second cold on NVMe) instead of the whole purge.

* Committed chunks survive if the process is killed. LastPurge is
  only updated once a chunk comes back short, so the next process to
  open the cache resumes where the killed one left off, and
  concurrent processes that both find the purge due simply delete
  chunks cooperatively.

The chunk subquery is served by the (present, timestamp) index, with
the outer delete going by rowid. Total purge cost is unchanged: on
tmpfs, deleting 100k expired rows from a 1.5M-row cache takes ~3 s
either way. In a contention test with a concurrent writer, the
longest wait for the write lock dropped from 33 s to 4.5 s (on ZFS,
which inflates both numbers). Killing the purge after 6 s left the
committed chunks in place with LastPurge unchanged, and the next run
finished the job.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Processes that open the cache at around the same time all see that
the purge is due, since LastPurge is only updated when a purge
completes. With chunked deletion they would interleave harmlessly,
but they'd all contend for the SQLite write lock and do redundant
work.

Take a non-blocking exclusive lock on a lock file next to the
database before purging. Processes that fail to get it skip the
purge. The lock is released when its holder exits or is killed, and
since LastPurge is still only updated on completion, the next process
to open the cache then takes over.

Tested by starting eight processes at once with the purge due: one of
them did the entire purge, the other seven skipped it and started up
in under a second. Killing the lock holder half-way left LastPurge
unchanged and the next process picked up the remaining rows.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Make purging the narinfo disk cache cheap and non-blocking
…manual

Add derivation metadata documentation to the Determinate Nix manual
Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
This skill describes how to edit the auto-generated release notes
(v<version>.md and changes.md) into shape during the release process.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
…f1b-a099-48b4-8864-e0cd3ab2be0b

Release v3.23.1
The GC roots server started a thread per client connection and only
afterwards inserted it into the `connections` map keyed by the client
fd. The client thread's cleanup handler erases its own entry from
that map, so if a client disconnected immediately, the cleanup could
run before the insert. The cleanup then found nothing to erase, the
fd was closed, and the server inserted a finished-but-joinable thread
under a now-closed fd number.

When a later client got the same fd number from accept(), the server
tried to insert under an existing key. std::map::insert doesn't
overwrite, so the temporary pair holding the new (joinable)
std::thread was destroyed, which calls std::terminate(). This showed
up in Sentry as a SIGABRT in nix-daemon with no exception in flight,
and another thread blocked on the `connections` lock in its cleanup
handler.

Fix this by holding the `connections` lock while starting the client
thread and inserting it. The cleanup handler can't run until the
entry exists, and the fd is only closed after the cleanup, so fd
numbers can no longer collide. Also assert that the insert didn't hit
an existing key.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Add make.nix files for libutil-c, libutil-test-support and libutil-tests, transcribed from their meson.build files. The `nix-util-tests` executable gets its main() from gtest_main, which is linked explicitly since no #include refers to it. deps.nix gains entries for gtest, gmock and rapidcheck (the latter with an explicit -lrapidcheck, as rapidcheck.pc lists no libraries).

A new `runTest` helper in lib.nix (with run-test.py) produces a derivation that runs a test program. libutil-tests uses it for `tests.run` and `tests.run-without-new-syscalls`, the latter under `enosys` like package.nix. Every variant of the nix-make flake now has `nix-util-tests-run`, `nix-util-tests-run-without-new-syscalls` and `nix-all-tests`, an aggregate of all test runs (unit and functional); `checks` points at the release `nix-all-tests`, so `nix flake check` runs everything.

Deviations from the Meson build: no static libnixutilc (the plugin C API), no precompiled headers, and `_NIX_TEST_ACCEPT` is not supported inside the derivation (same as package.nix).

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Add make.nix files for libstore-c, libstore-test-support and libstore-tests, transcribed from their meson.build files. The benchmark sources are excluded (Meson's `benchmarks` option is off by default). The test data is rooted at the repository together with tests/functional/derivation, as in package.nix, and the test run has `openssl` on its PATH for the HTTPS binary cache tests.

The store tests keep a store under $HOME, so run-test.py now sets HOME to a writable directory and expands `$HOME` in the `env` values of `runTest`.

Every variant of the nix-make flake gains `nix-store-c`, `nix-store-test-support`, `nix-store-tests` and `nix-store-tests-run`, which is included in `nix-all-tests`.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Add make.nix files for libfetchers-c and libfetchers-tests, transcribed from their meson.build files. The libgit2 entry in deps.nix now matches `<git2.h>` as well as `<git2/...>`, which one of the tests includes.

Every variant of the nix-make flake gains `nix-fetchers-c`, `nix-fetchers-tests` and `nix-fetchers-tests-run`, which is included in `nix-all-tests`.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
…race

Fix crash in the GC roots server on fd reuse
Add make.nix files for libexpr-c, libexpr-test-support and libexpr-tests, transcribed from their meson.build files. The benchmark sources are excluded (Meson's `benchmarks` option is off by default).

Every variant of the nix-make flake gains `nix-expr-c`, `nix-expr-test-support`, `nix-expr-tests` and `nix-expr-tests-run`, which is included in `nix-all-tests`.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
Add make.nix files for libflake-c and libflake-tests, transcribed from their meson.build files. Every variant of the nix-make flake gains `nix-flake-c`, `nix-flake-tests` and `nix-flake-tests-run`, which is included in `nix-all-tests`.

With this, all the unit test suites that the Meson build runs by default are covered.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
packaging/nix-make: Build and run the unit tests
Bash treats `<` and `>` as word breaks, so for e.g.

  nix nario list < /tmp/system-exp<TAB>

`_get_comp_words_by_ref` returned `(nix nario list '<' /tmp/system-exp)`,
and we ran `NIX_GET_COMPLETIONS=4 nix nario list '<' /tmp/system-exp`.
Nix treats `<` as a regular argument and returns no completions, and
since there is no fallback, nothing got completed.

Use `_init_completion` instead. It does filename completion if the
current word is the target of a redirection, and removes redirections
from `words` otherwise (so `nix nario list < foo --j<TAB>` also works).

Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
…ections

bash completion: Handle redirections

This branch was successfully deployed

2 active (1 outdated) and 1 inactive deployments
pull request — ea7e9be2 Deployed Oct 8, 2026 by github-actions[bot]
production — ea7e9be2 Deployed Oct 8, 2026 by github-actions[bot]
commit — 1ef90340 Deployed Oct 6, 2026 by github-actions[bot]
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.