Skip to content

Commit 9d8c6a6

Browse files
authored
Merge pull request #14013 from xokdvium/revert-13938
Revert "Merge pull request #13938 from NixOS/import-thunk"
2 parents b4fcb64 + fd03481 commit 9d8c6a6

File tree

9 files changed

+86
-133
lines changed

9 files changed

+86
-133
lines changed

src/libexpr/eval.cc

Lines changed: 53 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
#include <nlohmann/json.hpp>
4040
#include <boost/container/small_vector.hpp>
41-
#include <boost/unordered/concurrent_flat_map.hpp>
4241

4342
#include "nix/util/strings-inline.hh"
4443

@@ -265,9 +264,6 @@ EvalState::EvalState(
265264
, debugRepl(nullptr)
266265
, debugStop(false)
267266
, trylevel(0)
268-
, srcToStore(make_ref<decltype(srcToStore)::element_type>())
269-
, importResolutionCache(make_ref<decltype(importResolutionCache)::element_type>())
270-
, fileEvalCache(make_ref<decltype(fileEvalCache)::element_type>())
271267
, regexCache(makeRegexCache())
272268
#if NIX_USE_BOEHMGC
273269
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
@@ -1030,85 +1026,63 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
10301026
return &v;
10311027
}
10321028

1033-
/**
1034-
* A helper `Expr` class to lets us parse and evaluate Nix expressions
1035-
* from a thunk, ensuring that every file is parsed/evaluated only
1036-
* once (via the thunk stored in `EvalState::fileEvalCache`).
1037-
*/
1038-
struct ExprParseFile : Expr
1039-
{
1040-
SourcePath & path;
1041-
bool mustBeTrivial;
1042-
1043-
ExprParseFile(SourcePath & path, bool mustBeTrivial)
1044-
: path(path)
1045-
, mustBeTrivial(mustBeTrivial)
1046-
{
1047-
}
1048-
1049-
void eval(EvalState & state, Env & env, Value & v) override
1050-
{
1051-
printTalkative("evaluating file '%s'", path);
1052-
1053-
auto e = state.parseExprFromFile(path);
1054-
1055-
try {
1056-
auto dts =
1057-
state.debugRepl
1058-
? makeDebugTraceStacker(
1059-
state, *e, state.baseEnv, e->getPos(), "while evaluating the file '%s':", path.to_string())
1060-
: nullptr;
1061-
1062-
// Enforce that 'flake.nix' is a direct attrset, not a
1063-
// computation.
1064-
if (mustBeTrivial && !(dynamic_cast<ExprAttrs *>(e)))
1065-
state.error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
1066-
1067-
state.eval(e, v);
1068-
} catch (Error & e) {
1069-
state.addErrorTrace(e, "while evaluating the file '%s':", path.to_string());
1070-
throw;
1071-
}
1072-
}
1073-
};
1074-
10751029
void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
10761030
{
1077-
auto resolvedPath = getConcurrent(*importResolutionCache, path);
1078-
1079-
if (!resolvedPath) {
1080-
resolvedPath = resolveExprPath(path);
1081-
importResolutionCache->emplace(path, *resolvedPath);
1031+
FileEvalCache::iterator i;
1032+
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
1033+
v = i->second;
1034+
return;
10821035
}
10831036

1084-
if (auto v2 = getConcurrent(*fileEvalCache, *resolvedPath)) {
1085-
forceValue(**v2, noPos);
1086-
v = **v2;
1037+
auto resolvedPath = resolveExprPath(path);
1038+
if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) {
1039+
v = i->second;
10871040
return;
10881041
}
10891042

1090-
Value * vExpr;
1091-
ExprParseFile expr{*resolvedPath, mustBeTrivial};
1043+
printTalkative("evaluating file '%1%'", resolvedPath);
1044+
Expr * e = nullptr;
10921045

1093-
fileEvalCache->try_emplace_and_cvisit(
1094-
*resolvedPath,
1095-
nullptr,
1096-
[&](auto & i) {
1097-
vExpr = allocValue();
1098-
vExpr->mkThunk(&baseEnv, &expr);
1099-
i.second = vExpr;
1100-
},
1101-
[&](auto & i) { vExpr = i.second; });
1046+
auto j = fileParseCache.find(resolvedPath);
1047+
if (j != fileParseCache.end())
1048+
e = j->second;
1049+
1050+
if (!e)
1051+
e = parseExprFromFile(resolvedPath);
1052+
1053+
fileParseCache.emplace(resolvedPath, e);
11021054

1103-
forceValue(*vExpr, noPos);
1055+
try {
1056+
auto dts = debugRepl ? makeDebugTraceStacker(
1057+
*this,
1058+
*e,
1059+
this->baseEnv,
1060+
e->getPos(),
1061+
"while evaluating the file '%1%':",
1062+
resolvedPath.to_string())
1063+
: nullptr;
1064+
1065+
// Enforce that 'flake.nix' is a direct attrset, not a
1066+
// computation.
1067+
if (mustBeTrivial && !(dynamic_cast<ExprAttrs *>(e)))
1068+
error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
1069+
eval(e, v);
1070+
} catch (Error & e) {
1071+
addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
1072+
throw;
1073+
}
11041074

1105-
v = *vExpr;
1075+
fileEvalCache.emplace(resolvedPath, v);
1076+
if (path != resolvedPath)
1077+
fileEvalCache.emplace(path, v);
11061078
}
11071079

11081080
void EvalState::resetFileCache()
11091081
{
1110-
importResolutionCache->clear();
1111-
fileEvalCache->clear();
1082+
fileEvalCache.clear();
1083+
fileEvalCache.rehash(0);
1084+
fileParseCache.clear();
1085+
fileParseCache.rehash(0);
11121086
inputCache->clear();
11131087
}
11141088

@@ -2427,26 +2401,24 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
24272401
if (nix::isDerivation(path.path.abs()))
24282402
error<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
24292403

2430-
auto dstPathCached = getConcurrent(*srcToStore, path);
2431-
2432-
auto dstPath = dstPathCached ? *dstPathCached : [&]() {
2433-
auto dstPath = fetchToStore(
2404+
std::optional<StorePath> dstPath;
2405+
if (!srcToStore.cvisit(path, [&dstPath](const auto & kv) { dstPath.emplace(kv.second); })) {
2406+
dstPath.emplace(fetchToStore(
24342407
fetchSettings,
24352408
*store,
24362409
path.resolveSymlinks(SymlinkResolution::Ancestors),
24372410
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
24382411
path.baseName(),
24392412
ContentAddressMethod::Raw::NixArchive,
24402413
nullptr,
2441-
repair);
2442-
allowPath(dstPath);
2443-
srcToStore->try_emplace(path, dstPath);
2444-
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
2445-
return dstPath;
2446-
}();
2414+
repair));
2415+
allowPath(*dstPath);
2416+
srcToStore.try_emplace(path, *dstPath);
2417+
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(*dstPath));
2418+
}
24472419

2448-
context.insert(NixStringContextElem::Opaque{.path = dstPath});
2449-
return dstPath;
2420+
context.insert(NixStringContextElem::Opaque{.path = *dstPath});
2421+
return *dstPath;
24502422
}
24512423

24522424
SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)

src/libexpr/include/nix/expr/eval.hh

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
// For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS`
2121
#include "nix/expr/config.hh"
2222

23+
#include <boost/unordered/concurrent_flat_map.hpp>
2324
#include <boost/unordered/unordered_flat_map.hpp>
24-
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
25-
2625
#include <map>
2726
#include <optional>
2827
#include <functional>
@@ -404,30 +403,37 @@ private:
404403

405404
/* Cache for calls to addToStore(); maps source paths to the store
406405
paths. */
407-
ref<boost::concurrent_flat_map<SourcePath, StorePath>> srcToStore;
406+
boost::concurrent_flat_map<SourcePath, StorePath, std::hash<SourcePath>> srcToStore;
408407

409408
/**
410-
* A cache that maps paths to "resolved" paths for importing Nix
411-
* expressions, i.e. `/foo` to `/foo/default.nix`.
409+
* A cache from path names to parse trees.
412410
*/
413-
ref<boost::concurrent_flat_map<SourcePath, SourcePath>> importResolutionCache;
411+
typedef boost::unordered_flat_map<
412+
SourcePath,
413+
Expr *,
414+
std::hash<SourcePath>,
415+
std::equal_to<SourcePath>,
416+
traceable_allocator<std::pair<const SourcePath, Expr *>>>
417+
FileParseCache;
418+
FileParseCache fileParseCache;
414419

415420
/**
416-
* A cache from resolved paths to values.
421+
* A cache from path names to values.
417422
*/
418-
ref<boost::concurrent_flat_map<
423+
typedef boost::unordered_flat_map<
419424
SourcePath,
420-
Value *,
425+
Value,
421426
std::hash<SourcePath>,
422427
std::equal_to<SourcePath>,
423-
traceable_allocator<std::pair<const SourcePath, Value *>>>>
424-
fileEvalCache;
428+
traceable_allocator<std::pair<const SourcePath, Value>>>
429+
FileEvalCache;
430+
FileEvalCache fileEvalCache;
425431

426432
/**
427433
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
428434
* Grouped by file.
429435
*/
430-
boost::unordered_flat_map<SourcePath, DocCommentMap> positionToDocComment;
436+
boost::unordered_flat_map<SourcePath, DocCommentMap, std::hash<SourcePath>> positionToDocComment;
431437

432438
LookupPath lookupPath;
433439

src/libfetchers/filtering-source-accessor.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ void FilteringSourceAccessor::checkAccess(const CanonPath & path)
5959
struct AllowListSourceAccessorImpl : AllowListSourceAccessor
6060
{
6161
std::set<CanonPath> allowedPrefixes;
62-
boost::unordered_flat_set<CanonPath> allowedPaths;
62+
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> allowedPaths;
6363

6464
AllowListSourceAccessorImpl(
6565
ref<SourceAccessor> next,
6666
std::set<CanonPath> && allowedPrefixes,
67-
boost::unordered_flat_set<CanonPath> && allowedPaths,
67+
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
6868
MakeNotAllowedError && makeNotAllowedError)
6969
: AllowListSourceAccessor(SourcePath(next), std::move(makeNotAllowedError))
7070
, allowedPrefixes(std::move(allowedPrefixes))
@@ -86,7 +86,7 @@ struct AllowListSourceAccessorImpl : AllowListSourceAccessor
8686
ref<AllowListSourceAccessor> AllowListSourceAccessor::create(
8787
ref<SourceAccessor> next,
8888
std::set<CanonPath> && allowedPrefixes,
89-
boost::unordered_flat_set<CanonPath> && allowedPaths,
89+
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
9090
MakeNotAllowedError && makeNotAllowedError)
9191
{
9292
return make_ref<AllowListSourceAccessorImpl>(

src/libfetchers/git-utils.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ struct GitSourceAccessor : SourceAccessor
817817
return toHash(*git_tree_entry_id(entry));
818818
}
819819

820-
boost::unordered_flat_map<CanonPath, TreeEntry> lookupCache;
820+
boost::unordered_flat_map<CanonPath, TreeEntry, std::hash<CanonPath>> lookupCache;
821821

822822
/* Recursively look up 'path' relative to the root. */
823823
git_tree_entry * lookup(State & state, const CanonPath & path)
@@ -1254,7 +1254,7 @@ GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllow
12541254
makeFSSourceAccessor(path),
12551255
std::set<CanonPath>{wd.files},
12561256
// Always allow access to the root, but not its children.
1257-
boost::unordered_flat_set<CanonPath>{CanonPath::root},
1257+
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>>{CanonPath::root},
12581258
std::move(makeNotAllowedError))
12591259
.cast<SourceAccessor>();
12601260
if (exportIgnore)

src/libfetchers/include/nix/fetchers/filtering-source-accessor.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct AllowListSourceAccessor : public FilteringSourceAccessor
7272
static ref<AllowListSourceAccessor> create(
7373
ref<SourceAccessor> next,
7474
std::set<CanonPath> && allowedPrefixes,
75-
boost::unordered_flat_set<CanonPath> && allowedPaths,
75+
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
7676
MakeNotAllowedError && makeNotAllowedError);
7777

7878
using FilteringSourceAccessor::FilteringSourceAccessor;

src/libutil/include/nix/util/canon-path.hh

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
#include <set>
99
#include <vector>
1010

11-
#include <boost/container_hash/hash.hpp>
12-
1311
namespace nix {
1412

1513
/**
@@ -260,26 +258,20 @@ public:
260258
*/
261259
std::string makeRelative(const CanonPath & path) const;
262260

263-
friend std::size_t hash_value(const CanonPath &);
261+
friend struct std::hash<CanonPath>;
264262
};
265263

266264
std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
267265

268-
inline std::size_t hash_value(const CanonPath & path)
269-
{
270-
boost::hash<std::string_view> hasher;
271-
return hasher(path.path);
272-
}
273-
274266
} // namespace nix
275267

276268
template<>
277269
struct std::hash<nix::CanonPath>
278270
{
279271
using is_avalanching = std::true_type;
280272

281-
std::size_t operator()(const nix::CanonPath & path) const noexcept
273+
std::size_t operator()(const nix::CanonPath & s) const noexcept
282274
{
283-
return nix::hash_value(path);
275+
return std::hash<std::string>{}(s.path);
284276
}
285277
};

src/libutil/include/nix/util/source-path.hh

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,23 +119,15 @@ struct SourcePath
119119

120120
std::ostream & operator<<(std::ostream & str, const SourcePath & path);
121121

122-
inline std::size_t hash_value(const SourcePath & path)
123-
{
124-
std::size_t hash = 0;
125-
boost::hash_combine(hash, path.accessor->number);
126-
boost::hash_combine(hash, path.path);
127-
return hash;
128-
}
129-
130122
} // namespace nix
131123

132124
template<>
133125
struct std::hash<nix::SourcePath>
134126
{
135-
using is_avalanching = std::true_type;
136-
137127
std::size_t operator()(const nix::SourcePath & s) const noexcept
138128
{
139-
return nix::hash_value(s);
129+
std::size_t hash = 0;
130+
hash_combine(hash, s.accessor->number, s.path);
131+
return hash;
140132
}
141133
};

src/libutil/include/nix/util/util.hh

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -220,17 +220,6 @@ typename T::mapped_type * get(T & map, const K & key)
220220
template<class T, typename K>
221221
typename T::mapped_type * get(T && map, const K & key) = delete;
222222

223-
/**
224-
* Look up a value in a `boost::concurrent_flat_map`.
225-
*/
226-
template<class T>
227-
std::optional<typename T::mapped_type> getConcurrent(const T & map, const typename T::key_type & key)
228-
{
229-
std::optional<typename T::mapped_type> res;
230-
map.cvisit(key, [&](auto & x) { res = x.second; });
231-
return res;
232-
}
233-
234223
/**
235224
* Get a value for the specified key from an associate container, or a default value if the key isn't present.
236225
*/

src/libutil/posix-source-accessor.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ std::optional<struct stat> PosixSourceAccessor::cachedLstat(const CanonPath & pa
9595
// former is not hashable on libc++.
9696
Path absPath = makeAbsPath(path).string();
9797

98-
if (auto res = getConcurrent(cache, absPath))
98+
std::optional<Cache::mapped_type> res;
99+
cache.cvisit(absPath, [&](auto & x) { res.emplace(x.second); });
100+
if (res)
99101
return *res;
100102

101103
auto st = nix::maybeLstat(absPath.c_str());

0 commit comments

Comments
 (0)