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

replace more std::unordered_* types by faster boost hash maps

This commit is contained in:
Philipp Otterbein 2025-09-06 14:21:48 +02:00 committed by Jörg Thalheim
parent 4f8c50fb77
commit 9f2b6a1b94
17 changed files with 75 additions and 71 deletions

View file

@ -16,7 +16,7 @@
#include "nix_api_util_internal.h" #include "nix_api_util_internal.h"
#if NIX_USE_BOEHMGC #if NIX_USE_BOEHMGC
# include <mutex> # include <boost/unordered/concurrent_flat_map.hpp>
#endif #endif
/** /**
@ -207,28 +207,20 @@ void nix_state_free(EvalState * state)
} }
#if NIX_USE_BOEHMGC #if NIX_USE_BOEHMGC
std::unordered_map< boost::concurrent_flat_map<
const void *, const void *,
unsigned int, unsigned int,
std::hash<const void *>, std::hash<const void *>,
std::equal_to<const void *>, std::equal_to<const void *>,
traceable_allocator<std::pair<const void * const, unsigned int>>> traceable_allocator<std::pair<const void * const, unsigned int>>>
nix_refcounts; nix_refcounts{};
std::mutex nix_refcount_lock;
nix_err nix_gc_incref(nix_c_context * context, const void * p) nix_err nix_gc_incref(nix_c_context * context, const void * p)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
std::scoped_lock lock(nix_refcount_lock); nix_refcounts.insert_or_visit({p, 1}, [](auto & kv) { kv.second++; });
auto f = nix_refcounts.find(p);
if (f != nix_refcounts.end()) {
f->second++;
} else {
nix_refcounts[p] = 1;
}
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
@ -239,12 +231,12 @@ nix_err nix_gc_decref(nix_c_context * context, const void * p)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
std::scoped_lock lock(nix_refcount_lock); bool fail = true;
auto f = nix_refcounts.find(p); nix_refcounts.erase_if(p, [&](auto & kv) {
if (f != nix_refcounts.end()) { fail = false;
if (--f->second == 0) return !--kv.second;
nix_refcounts.erase(f); });
} else if (fail)
throw std::runtime_error("nix_gc_decref: object was not referenced"); throw std::runtime_error("nix_gc_decref: object was not referenced");
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS

View file

@ -4571,11 +4571,13 @@ struct RegexCache
std::regex regex; std::regex regex;
/* No std::regex constructor overload from std::string_view, but can be constructed /* No std::regex constructor overload from std::string_view, but can be constructed
from a pointer + size or an iterator range. */ from a pointer + size or an iterator range. */
cache.try_emplace_and_cvisit(re, cache.try_emplace_and_cvisit(
/*s=*/re.data(), /*count=*/re.size(), std::regex::extended, re,
/*s=*/re.data(),
/*count=*/re.size(),
std::regex::extended,
[&regex](const auto & kv) { regex = kv.second; }, [&regex](const auto & kv) { regex = kv.second; },
[&regex](const auto & kv) { regex = kv.second; } [&regex](const auto & kv) { regex = kv.second; });
);
return regex; return regex;
} }
}; };

View file

@ -1,5 +1,4 @@
#include <limits> #include <limits>
#include <unordered_set>
#include <sstream> #include <sstream>
#include "nix/expr/print.hh" #include "nix/expr/print.hh"
@ -10,6 +9,8 @@
#include "nix/util/english.hh" #include "nix/util/english.hh"
#include "nix/expr/eval.hh" #include "nix/expr/eval.hh"
#include <boost/unordered/unordered_flat_set.hpp>
namespace nix { namespace nix {
void printElided( void printElided(
@ -81,7 +82,7 @@ std::ostream & printLiteralBool(std::ostream & str, bool boolean)
// For example `or' doesn't need to be quoted. // For example `or' doesn't need to be quoted.
bool isReservedKeyword(const std::string_view str) bool isReservedKeyword(const std::string_view str)
{ {
static const std::unordered_set<std::string_view> reservedKeywords = { static const boost::unordered_flat_set<std::string_view> reservedKeywords = {
"if", "then", "else", "assert", "with", "let", "in", "rec", "inherit"}; "if", "then", "else", "assert", "with", "let", "in", "rec", "inherit"};
return reservedKeywords.contains(str); return reservedKeywords.contains(str);
} }

View file

@ -1,5 +1,7 @@
#include "nix/fetchers/filtering-source-accessor.hh" #include "nix/fetchers/filtering-source-accessor.hh"
#include <boost/unordered/unordered_flat_set.hpp>
namespace nix { namespace nix {
std::optional<std::filesystem::path> FilteringSourceAccessor::getPhysicalPath(const CanonPath & path) std::optional<std::filesystem::path> FilteringSourceAccessor::getPhysicalPath(const CanonPath & path)
@ -57,12 +59,12 @@ void FilteringSourceAccessor::checkAccess(const CanonPath & path)
struct AllowListSourceAccessorImpl : AllowListSourceAccessor struct AllowListSourceAccessorImpl : AllowListSourceAccessor
{ {
std::set<CanonPath> allowedPrefixes; std::set<CanonPath> allowedPrefixes;
std::unordered_set<CanonPath> allowedPaths; boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> allowedPaths;
AllowListSourceAccessorImpl( AllowListSourceAccessorImpl(
ref<SourceAccessor> next, ref<SourceAccessor> next,
std::set<CanonPath> && allowedPrefixes, std::set<CanonPath> && allowedPrefixes,
std::unordered_set<CanonPath> && allowedPaths, boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
MakeNotAllowedError && makeNotAllowedError) MakeNotAllowedError && makeNotAllowedError)
: AllowListSourceAccessor(SourcePath(next), std::move(makeNotAllowedError)) : AllowListSourceAccessor(SourcePath(next), std::move(makeNotAllowedError))
, allowedPrefixes(std::move(allowedPrefixes)) , allowedPrefixes(std::move(allowedPrefixes))
@ -84,7 +86,7 @@ struct AllowListSourceAccessorImpl : AllowListSourceAccessor
ref<AllowListSourceAccessor> AllowListSourceAccessor::create( ref<AllowListSourceAccessor> AllowListSourceAccessor::create(
ref<SourceAccessor> next, ref<SourceAccessor> next,
std::set<CanonPath> && allowedPrefixes, std::set<CanonPath> && allowedPrefixes,
std::unordered_set<CanonPath> && allowedPaths, boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
MakeNotAllowedError && makeNotAllowedError) MakeNotAllowedError && makeNotAllowedError)
{ {
return make_ref<AllowListSourceAccessorImpl>( return make_ref<AllowListSourceAccessorImpl>(

View file

@ -30,8 +30,9 @@
#include <git2/sys/mempack.h> #include <git2/sys/mempack.h>
#include <git2/tree.h> #include <git2/tree.h>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <iostream> #include <iostream>
#include <unordered_set>
#include <queue> #include <queue>
#include <regex> #include <regex>
#include <span> #include <span>
@ -315,7 +316,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
uint64_t getRevCount(const Hash & rev) override uint64_t getRevCount(const Hash & rev) override
{ {
std::unordered_set<git_oid> done; boost::unordered_flat_set<git_oid, std::hash<git_oid>> done;
std::queue<Commit> todo; std::queue<Commit> todo;
todo.push(peelObject<Commit>(lookupObject(*this, hashToOID(rev)).get(), GIT_OBJECT_COMMIT)); todo.push(peelObject<Commit>(lookupObject(*this, hashToOID(rev)).get(), GIT_OBJECT_COMMIT));
@ -569,7 +570,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
void verifyCommit(const Hash & rev, const std::vector<fetchers::PublicKey> & publicKeys) override void verifyCommit(const Hash & rev, const std::vector<fetchers::PublicKey> & publicKeys) override
{ {
// Map of SSH key types to their internal OpenSSH representations // Map of SSH key types to their internal OpenSSH representations
static const std::unordered_map<std::string_view, std::string_view> keyTypeMap = { static const boost::unordered_flat_map<std::string_view, std::string_view> keyTypeMap = {
{"ssh-dsa", "ssh-dsa"}, {"ssh-dsa", "ssh-dsa"},
{"ssh-ecdsa", "ssh-ecdsa"}, {"ssh-ecdsa", "ssh-ecdsa"},
{"ssh-ecdsa-sk", "sk-ecdsa-sha2-nistp256@openssh.com"}, {"ssh-ecdsa-sk", "sk-ecdsa-sha2-nistp256@openssh.com"},
@ -816,7 +817,7 @@ struct GitSourceAccessor : SourceAccessor
return toHash(*git_tree_entry_id(entry)); return toHash(*git_tree_entry_id(entry));
} }
std::unordered_map<CanonPath, TreeEntry> lookupCache; boost::unordered_flat_map<CanonPath, TreeEntry, std::hash<CanonPath>> lookupCache;
/* Recursively look up 'path' relative to the root. */ /* Recursively look up 'path' relative to the root. */
git_tree_entry * lookup(State & state, const CanonPath & path) git_tree_entry * lookup(State & state, const CanonPath & path)
@ -1253,7 +1254,7 @@ GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllow
makeFSSourceAccessor(path), makeFSSourceAccessor(path),
std::set<CanonPath>{wd.files}, std::set<CanonPath>{wd.files},
// Always allow access to the root, but not its children. // Always allow access to the root, but not its children.
std::unordered_set<CanonPath>{CanonPath::root}, boost::unordered_flat_set<CanonPath, std::hash<CanonPath>>{CanonPath::root},
std::move(makeNotAllowedError)) std::move(makeNotAllowedError))
.cast<SourceAccessor>(); .cast<SourceAccessor>();
if (exportIgnore) if (exportIgnore)

View file

@ -2,7 +2,7 @@
#include "nix/util/source-path.hh" #include "nix/util/source-path.hh"
#include <unordered_set> #include <boost/unordered/unordered_flat_set_fwd.hpp>
namespace nix { namespace nix {
@ -72,7 +72,7 @@ struct AllowListSourceAccessor : public FilteringSourceAccessor
static ref<AllowListSourceAccessor> create( static ref<AllowListSourceAccessor> create(
ref<SourceAccessor> next, ref<SourceAccessor> next,
std::set<CanonPath> && allowedPrefixes, std::set<CanonPath> && allowedPrefixes,
std::unordered_set<CanonPath> && allowedPaths, boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
MakeNotAllowedError && makeNotAllowedError); MakeNotAllowedError && makeNotAllowedError);
using FilteringSourceAccessor::FilteringSourceAccessor; using FilteringSourceAccessor::FilteringSourceAccessor;

View file

@ -1,5 +1,3 @@
#include <unordered_set>
#include "nix/fetchers/fetch-settings.hh" #include "nix/fetchers/fetch-settings.hh"
#include "nix/flake/settings.hh" #include "nix/flake/settings.hh"
#include "nix/flake/lockfile.hh" #include "nix/flake/lockfile.hh"
@ -9,6 +7,7 @@
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <boost/unordered/unordered_flat_set.hpp>
#include <iterator> #include <iterator>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -162,7 +161,7 @@ std::pair<nlohmann::json, LockFile::KeyMap> LockFile::toJSON() const
{ {
nlohmann::json nodes; nlohmann::json nodes;
KeyMap nodeKeys; KeyMap nodeKeys;
std::unordered_set<std::string> keys; boost::unordered_flat_set<std::string> keys;
std::function<std::string(const std::string & key, ref<const Node> node)> dumpNode; std::function<std::string(const std::string & key, ref<const Node> node)> dumpNode;

View file

@ -11,6 +11,7 @@
#include "nix/util/json-utils.hh" #include "nix/util/json-utils.hh"
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace nix { namespace nix {
@ -834,7 +835,7 @@ DerivationType BasicDerivation::type() const
throw Error("can't mix derivation output types"); throw Error("can't mix derivation output types");
} }
Sync<DrvHashes> drvHashes; DrvHashes drvHashes;
/* pathDerivationModulo and hashDerivationModulo are mutually recursive /* pathDerivationModulo and hashDerivationModulo are mutually recursive
*/ */
@ -844,16 +845,13 @@ Sync<DrvHashes> drvHashes;
*/ */
static const DrvHash pathDerivationModulo(Store & store, const StorePath & drvPath) static const DrvHash pathDerivationModulo(Store & store, const StorePath & drvPath)
{ {
{ std::optional<DrvHash> hash;
auto hashes = drvHashes.lock(); if (drvHashes.cvisit(drvPath, [&hash](const auto & kv) { hash.emplace(kv.second); })) {
auto h = hashes->find(drvPath); return *hash;
if (h != hashes->end()) {
return h->second;
}
} }
auto h = hashDerivationModulo(store, store.readInvalidDerivation(drvPath), false); auto h = hashDerivationModulo(store, store.readInvalidDerivation(drvPath), false);
// Cache it // Cache it
drvHashes.lock()->insert_or_assign(drvPath, h); drvHashes.insert_or_assign(drvPath, h);
return h; return h;
} }

View file

@ -1,6 +1,7 @@
#include "nix/store/derivations.hh" #include "nix/store/derivations.hh"
#include "nix/store/globals.hh" #include "nix/store/globals.hh"
#include "nix/store/local-store.hh" #include "nix/store/local-store.hh"
#include "nix/store/path.hh"
#include "nix/util/finally.hh" #include "nix/util/finally.hh"
#include "nix/util/unix-domain-socket.hh" #include "nix/util/unix-domain-socket.hh"
#include "nix/util/signals.hh" #include "nix/util/signals.hh"
@ -13,14 +14,10 @@
# include "nix/util/processes.hh" # include "nix/util/processes.hh"
#endif #endif
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <functional>
#include <queue> #include <queue>
#include <algorithm>
#include <random>
#include <climits>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -314,7 +311,7 @@ Roots LocalStore::findRoots(bool censor)
/** /**
* Key is a mere string because cannot has path with macOS's libc++ * Key is a mere string because cannot has path with macOS's libc++
*/ */
typedef std::unordered_map<std::string, std::unordered_set<std::string>> UncheckedRoots; typedef boost::unordered_flat_map<std::string, boost::unordered_flat_set<std::string>> UncheckedRoots;
static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots) static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots)
{ {
@ -463,13 +460,13 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
bool gcKeepOutputs = settings.gcKeepOutputs; bool gcKeepOutputs = settings.gcKeepOutputs;
bool gcKeepDerivations = settings.gcKeepDerivations; bool gcKeepDerivations = settings.gcKeepDerivations;
std::unordered_set<StorePath> roots, dead, alive; boost::unordered_flat_set<StorePath, std::hash<StorePath>> roots, dead, alive;
struct Shared struct Shared
{ {
// The temp roots only store the hash part to make it easier to // The temp roots only store the hash part to make it easier to
// ignore suffixes like '.lock', '.chroot' and '.check'. // ignore suffixes like '.lock', '.chroot' and '.check'.
std::unordered_set<std::string> tempRoots; boost::unordered_flat_set<std::string> tempRoots;
// Hash part of the store path currently being deleted, if // Hash part of the store path currently being deleted, if
// any. // any.
@ -672,7 +669,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
} }
}; };
std::unordered_map<StorePath, StorePathSet> referrersCache; boost::unordered_flat_map<StorePath, StorePathSet, std::hash<StorePath>> referrersCache;
/* Helper function that visits all paths reachable from `start` /* Helper function that visits all paths reachable from `start`
via the referrers edges and optionally derivers and derivation via the referrers edges and optionally derivers and derivation

View file

@ -11,7 +11,7 @@
#include "nix/util/sync.hh" #include "nix/util/sync.hh"
#include "nix/util/variant-wrapper.hh" #include "nix/util/variant-wrapper.hh"
#include <map> #include <boost/unordered/concurrent_flat_map_fwd.hpp>
#include <variant> #include <variant>
namespace nix { namespace nix {
@ -507,13 +507,23 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut
*/ */
std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation & drv); std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation & drv);
struct DrvHashFct
{
using is_avalanching = std::true_type;
std::size_t operator()(const StorePath & path) const noexcept
{
return std::hash<std::string_view>{}(path.to_string());
}
};
/** /**
* Memoisation of hashDerivationModulo(). * Memoisation of hashDerivationModulo().
*/ */
typedef std::map<StorePath, DrvHash> DrvHashes; typedef boost::concurrent_flat_map<StorePath, DrvHash, DrvHashFct> DrvHashes;
// FIXME: global, though at least thread-safe. // FIXME: global, though at least thread-safe.
extern Sync<DrvHashes> drvHashes; extern DrvHashes drvHashes;
struct Source; struct Source;
struct Sink; struct Sink;

View file

@ -1,13 +1,13 @@
#pragma once #pragma once
///@file ///@file
#include <unordered_set>
#include "nix/store/store-api.hh" #include "nix/store/store-api.hh"
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
namespace nix { namespace nix {
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots; typedef boost::unordered_flat_map<StorePath, boost::unordered_flat_set<std::string>, std::hash<StorePath>> Roots;
struct GCOptions struct GCOptions
{ {

View file

@ -11,7 +11,7 @@
#include <chrono> #include <chrono>
#include <future> #include <future>
#include <string> #include <string>
#include <unordered_set> #include <boost/unordered/unordered_flat_set.hpp>
namespace nix { namespace nix {
@ -442,7 +442,7 @@ private:
std::pair<std::filesystem::path, AutoCloseFD> createTempDirInStore(); std::pair<std::filesystem::path, AutoCloseFD> createTempDirInStore();
typedef std::unordered_set<ino_t> InodeHash; typedef boost::unordered_flat_set<ino_t> InodeHash;
InodeHash loadInodeHash(); InodeHash loadInodeHash();
Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash); Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash);

View file

@ -1,5 +1,3 @@
#include <unordered_set>
#include "nix/store/derivations.hh" #include "nix/store/derivations.hh"
#include "nix/store/parsed-derivations.hh" #include "nix/store/parsed-derivations.hh"
#include "nix/store/derivation-options.hh" #include "nix/store/derivation-options.hh"
@ -13,6 +11,8 @@
#include "nix/store/filetransfer.hh" #include "nix/store/filetransfer.hh"
#include "nix/util/strings.hh" #include "nix/util/strings.hh"
#include <boost/unordered/unordered_flat_set.hpp>
namespace nix { namespace nix {
void Store::computeFSClosure( void Store::computeFSClosure(
@ -106,7 +106,7 @@ MissingPaths Store::queryMissing(const std::vector<DerivedPath> & targets)
struct State struct State
{ {
std::unordered_set<std::string> done; boost::unordered_flat_set<std::string> done;
MissingPaths res; MissingPaths res;
}; };

View file

@ -258,7 +258,7 @@ public:
*/ */
std::string makeRelative(const CanonPath & path) const; std::string makeRelative(const CanonPath & path) const;
friend class std::hash<CanonPath>; friend struct std::hash<CanonPath>;
}; };
std::ostream & operator<<(std::ostream & stream, const CanonPath & path); std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
@ -268,6 +268,8 @@ std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
template<> template<>
struct std::hash<nix::CanonPath> struct std::hash<nix::CanonPath>
{ {
using is_avalanching = std::true_type;
std::size_t operator()(const nix::CanonPath & s) const noexcept std::size_t operator()(const nix::CanonPath & s) const noexcept
{ {
return std::hash<std::string>{}(s.path); return std::hash<std::string>{}(s.path);

View file

@ -4,10 +4,10 @@
#include "nix/util/file-system.hh" #include "nix/util/file-system.hh"
#include "nix/util/finally.hh" #include "nix/util/finally.hh"
#include <boost/unordered/unordered_flat_set.hpp>
#include <chrono> #include <chrono>
#include <cmath> #include <cmath>
#include <regex> #include <regex>
#include <unordered_set>
#include <thread> #include <thread>
#include <dirent.h> #include <dirent.h>
@ -76,7 +76,7 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
int round = 1; int round = 1;
std::unordered_set<pid_t> pidsShown; boost::unordered_flat_set<pid_t> pidsShown;
while (true) { while (true) {
auto pids = tokenizeString<std::vector<std::string>>(readFile(procsFile)); auto pids = tokenizeString<std::vector<std::string>>(readFile(procsFile));

View file

@ -104,7 +104,7 @@ std::optional<struct stat> PosixSourceAccessor::cachedLstat(const CanonPath & pa
if (cache.size() >= 16384) if (cache.size() >= 16384)
cache.clear(); cache.clear();
cache.emplace(absPath, st); cache.emplace(std::move(absPath), st);
return st; return st;
} }

View file

@ -71,7 +71,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
auto outPaths = auto outPaths =
Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
std::unordered_set<StorePath> done; boost::unordered_flat_set<StorePath, std::hash<StorePath>> done;
std::queue<StorePath> todo; std::queue<StorePath> todo;
for (auto & path : outPaths) for (auto & path : outPaths)
todo.push(path); todo.push(path);