1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-17 06:21:06 +01:00

Merge branch 'master' into fzakaria/shellcheck-systemd-multi-user

This commit is contained in:
Jörg Thalheim 2025-09-25 08:35:10 +02:00 committed by GitHub
commit 6dcfce0450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 247 additions and 44 deletions

View file

@ -106,11 +106,8 @@
enable = true; enable = true;
excludes = [ excludes = [
# We haven't linted these files yet # We haven't linted these files yet
''^tests/functional/compute-levels\.sh$''
''^tests/functional/db-migration\.sh$'' ''^tests/functional/db-migration\.sh$''
''^tests/functional/dependencies\.builder0\.sh$''
''^tests/functional/dump-db\.sh$'' ''^tests/functional/dump-db\.sh$''
''^tests/functional/dyn-drv/build-built-drv\.sh$''
''^tests/functional/dyn-drv/eval-outputOf\.sh$'' ''^tests/functional/dyn-drv/eval-outputOf\.sh$''
''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$'' ''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$''
''^tests/functional/dyn-drv/recursive-mod-json\.sh$'' ''^tests/functional/dyn-drv/recursive-mod-json\.sh$''

View file

@ -287,6 +287,7 @@ EvalState::EvalState(
assertGCInitialized(); assertGCInitialized();
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
static_assert(sizeof(Counter) == 64, "counters must be 64 bytes");
/* Construct the Nix expression search path. */ /* Construct the Nix expression search path. */
assert(lookupPath.elements.empty()); assert(lookupPath.elements.empty());
@ -892,7 +893,7 @@ Value * EvalState::getBool(bool b)
return b ? &Value::vTrue : &Value::vFalse; return b ? &Value::vTrue : &Value::vFalse;
} }
unsigned long nrThunks = 0; static Counter nrThunks;
static inline void mkThunk(Value & v, Env & env, Expr * expr) static inline void mkThunk(Value & v, Env & env, Expr * expr)
{ {
@ -2891,11 +2892,11 @@ bool EvalState::fullGC()
#endif #endif
} }
bool Counter::enabled = getEnv("NIX_SHOW_STATS").value_or("0") != "0";
void EvalState::maybePrintStats() void EvalState::maybePrintStats()
{ {
bool showStats = getEnv("NIX_SHOW_STATS").value_or("0") != "0"; if (Counter::enabled) {
if (showStats) {
// Make the final heap size more deterministic. // Make the final heap size more deterministic.
#if NIX_USE_BOEHMGC #if NIX_USE_BOEHMGC
if (!fullGC()) { if (!fullGC()) {
@ -2940,18 +2941,18 @@ void EvalState::printStatistics()
#endif #endif
}; };
topObj["envs"] = { topObj["envs"] = {
{"number", nrEnvs}, {"number", nrEnvs.load()},
{"elements", nrValuesInEnvs}, {"elements", nrValuesInEnvs.load()},
{"bytes", bEnvs}, {"bytes", bEnvs},
}; };
topObj["nrExprs"] = Expr::nrExprs; topObj["nrExprs"] = Expr::nrExprs.load();
topObj["list"] = { topObj["list"] = {
{"elements", nrListElems}, {"elements", nrListElems.load()},
{"bytes", bLists}, {"bytes", bLists},
{"concats", nrListConcats}, {"concats", nrListConcats.load()},
}; };
topObj["values"] = { topObj["values"] = {
{"number", nrValues}, {"number", nrValues.load()},
{"bytes", bValues}, {"bytes", bValues},
}; };
topObj["symbols"] = { topObj["symbols"] = {
@ -2959,9 +2960,9 @@ void EvalState::printStatistics()
{"bytes", symbols.totalSize()}, {"bytes", symbols.totalSize()},
}; };
topObj["sets"] = { topObj["sets"] = {
{"number", nrAttrsets}, {"number", nrAttrsets.load()},
{"bytes", bAttrsets}, {"bytes", bAttrsets},
{"elements", nrAttrsInAttrsets}, {"elements", nrAttrsInAttrsets.load()},
}; };
topObj["sizes"] = { topObj["sizes"] = {
{"Env", sizeof(Env)}, {"Env", sizeof(Env)},
@ -2969,13 +2970,13 @@ void EvalState::printStatistics()
{"Bindings", sizeof(Bindings)}, {"Bindings", sizeof(Bindings)},
{"Attr", sizeof(Attr)}, {"Attr", sizeof(Attr)},
}; };
topObj["nrOpUpdates"] = nrOpUpdates; topObj["nrOpUpdates"] = nrOpUpdates.load();
topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied; topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied.load();
topObj["nrThunks"] = nrThunks; topObj["nrThunks"] = nrThunks.load();
topObj["nrAvoided"] = nrAvoided; topObj["nrAvoided"] = nrAvoided.load();
topObj["nrLookups"] = nrLookups; topObj["nrLookups"] = nrLookups.load();
topObj["nrPrimOpCalls"] = nrPrimOpCalls; topObj["nrPrimOpCalls"] = nrPrimOpCalls.load();
topObj["nrFunctionCalls"] = nrFunctionCalls; topObj["nrFunctionCalls"] = nrFunctionCalls.load();
#if NIX_USE_BOEHMGC #if NIX_USE_BOEHMGC
topObj["gc"] = { topObj["gc"] = {
{"heapSize", heapSize}, {"heapSize", heapSize},

View file

@ -0,0 +1,70 @@
#pragma once
#include <atomic>
#include <cstdint>
namespace nix {
/**
* An atomic counter aligned on a cache line to prevent false sharing.
* The counter is only enabled when the `NIX_SHOW_STATS` environment
* variable is set. This is to prevent contention on these counters
* when multi-threaded evaluation is enabled.
*/
struct alignas(64) Counter
{
using value_type = uint64_t;
std::atomic<value_type> inner{0};
static bool enabled;
Counter() {}
operator value_type() const noexcept
{
return inner;
}
void operator=(value_type n) noexcept
{
inner = n;
}
value_type load() const noexcept
{
return inner;
}
value_type operator++() noexcept
{
return enabled ? ++inner : 0;
}
value_type operator++(int) noexcept
{
return enabled ? inner++ : 0;
}
value_type operator--() noexcept
{
return enabled ? --inner : 0;
}
value_type operator--(int) noexcept
{
return enabled ? inner-- : 0;
}
value_type operator+=(value_type n) noexcept
{
return enabled ? inner += n : 0;
}
value_type operator-=(value_type n) noexcept
{
return enabled ? inner -= n : 0;
}
};
} // namespace nix

View file

@ -16,6 +16,7 @@
#include "nix/expr/search-path.hh" #include "nix/expr/search-path.hh"
#include "nix/expr/repl-exit-status.hh" #include "nix/expr/repl-exit-status.hh"
#include "nix/util/ref.hh" #include "nix/util/ref.hh"
#include "nix/expr/counter.hh"
// For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS` // For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS`
#include "nix/expr/config.hh" #include "nix/expr/config.hh"
@ -961,19 +962,19 @@ private:
*/ */
std::string mkSingleDerivedPathStringRaw(const SingleDerivedPath & p); std::string mkSingleDerivedPathStringRaw(const SingleDerivedPath & p);
unsigned long nrEnvs = 0; Counter nrEnvs;
unsigned long nrValuesInEnvs = 0; Counter nrValuesInEnvs;
unsigned long nrValues = 0; Counter nrValues;
unsigned long nrListElems = 0; Counter nrListElems;
unsigned long nrLookups = 0; Counter nrLookups;
unsigned long nrAttrsets = 0; Counter nrAttrsets;
unsigned long nrAttrsInAttrsets = 0; Counter nrAttrsInAttrsets;
unsigned long nrAvoided = 0; Counter nrAvoided;
unsigned long nrOpUpdates = 0; Counter nrOpUpdates;
unsigned long nrOpUpdateValuesCopied = 0; Counter nrOpUpdateValuesCopied;
unsigned long nrListConcats = 0; Counter nrListConcats;
unsigned long nrPrimOpCalls = 0; Counter nrPrimOpCalls;
unsigned long nrFunctionCalls = 0; Counter nrFunctionCalls;
bool countCalls; bool countCalls;

View file

@ -10,6 +10,7 @@ config_pub_h = configure_file(
headers = [ config_pub_h ] + files( headers = [ config_pub_h ] + files(
'attr-path.hh', 'attr-path.hh',
'attr-set.hh', 'attr-set.hh',
'counter.hh',
'eval-cache.hh', 'eval-cache.hh',
'eval-error.hh', 'eval-error.hh',
'eval-gc.hh', 'eval-gc.hh',

View file

@ -9,6 +9,7 @@
#include "nix/expr/symbol-table.hh" #include "nix/expr/symbol-table.hh"
#include "nix/expr/eval-error.hh" #include "nix/expr/eval-error.hh"
#include "nix/util/pos-idx.hh" #include "nix/util/pos-idx.hh"
#include "nix/expr/counter.hh"
namespace nix { namespace nix {
@ -92,7 +93,7 @@ struct Expr
Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body; Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
}; };
static unsigned long nrExprs; static Counter nrExprs;
Expr() Expr()
{ {

View file

@ -11,7 +11,7 @@
namespace nix { namespace nix {
unsigned long Expr::nrExprs = 0; Counter Expr::nrExprs;
ExprBlackHole eBlackHole; ExprBlackHole eBlackHole;

View file

@ -0,0 +1,6 @@
{
"dependentRealisations": {},
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
"signatures": []
}

View file

@ -0,0 +1,8 @@
{
"dependentRealisations": {
"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
},
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
"signatures": []
}

View file

@ -0,0 +1,8 @@
{
"dependentRealisations": {},
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
"signatures": [
"asdfasdfasdf"
]
}

View file

@ -74,6 +74,7 @@ sources = files(
'outputs-spec.cc', 'outputs-spec.cc',
'path-info.cc', 'path-info.cc',
'path.cc', 'path.cc',
'realisation.cc',
'references.cc', 'references.cc',
's3-binary-cache-store.cc', 's3-binary-cache-store.cc',
's3.cc', 's3.cc',

View file

@ -0,0 +1,105 @@
#include <regex>
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include "nix/store/store-api.hh"
#include "nix/util/tests/characterization.hh"
#include "nix/store/tests/libstore.hh"
namespace nix {
class RealisationTest : public CharacterizationTest, public LibStoreTest
{
std::filesystem::path unitTestData = getUnitTestData() / "realisation";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
};
/* ----------------------------------------------------------------------------
* JSON
* --------------------------------------------------------------------------*/
using nlohmann::json;
struct RealisationJsonTest : RealisationTest, ::testing::WithParamInterface<std::pair<std::string_view, Realisation>>
{};
TEST_P(RealisationJsonTest, from_json)
{
auto [name, expected] = GetParam();
readTest(name + ".json", [&](const auto & encoded_) {
auto encoded = json::parse(encoded_);
Realisation got = static_cast<Realisation>(encoded);
ASSERT_EQ(got, expected);
});
}
TEST_P(RealisationJsonTest, to_json)
{
auto [name, value] = GetParam();
writeTest(
name + ".json",
[&]() -> json { return static_cast<json>(value); },
[](const auto & file) { return json::parse(readFile(file)); },
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); });
}
INSTANTIATE_TEST_SUITE_P(
RealisationJSON,
RealisationJsonTest,
([] {
Realisation simple{
.id =
{
.drvHash = Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Base16),
.outputName = "foo",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
};
return ::testing::Values(
std::pair{
"simple",
simple,
},
std::pair{
"with-signature",
[&] {
auto r = simple;
// FIXME actually sign properly
r.signatures = {"asdfasdfasdf"};
return r;
}()},
std::pair{
"with-dependent-realisations",
[&] {
auto r = simple;
r.dependentRealisations = {{
{
.drvHash = Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Base16),
.outputName = "foo",
},
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
}};
return r;
}(),
});
}
()));
} // namespace nix

View file

@ -1,16 +1,20 @@
# shellcheck shell=bash
# shellcheck disable=SC2154
[ "${input1: -2}" = /. ] [ "${input1: -2}" = /. ]
# shellcheck disable=SC2154
[ "${input2: -2}" = /. ] [ "${input2: -2}" = /. ]
mkdir $out # shellcheck disable=SC2154
echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar mkdir "$out"
echo "$(cat "$input1"/foo)$(cat "$input2"/bar)" > "$out"/foobar
ln -s $input2 $out/reference-to-input-2 ln -s "$input2" "$out"/reference-to-input-2
# Self-reference. # Self-reference.
ln -s $out $out/self ln -s "$out" "$out"/self
# Executable. # Executable.
echo program > $out/program echo program > "$out"/program
chmod +x $out/program chmod +x "$out"/program
echo FOO echo FOO

View file

@ -23,4 +23,4 @@ requireDaemonNewerThan "2.30pre20250515"
out2=$(nix build "${drvDep}^out^out" --no-link) out2=$(nix build "${drvDep}^out^out" --no-link)
test $out1 == $out2 test "$out1" == "$out2"