Skip to content

Commit 550c894

Browse files
authored
Merge pull request #93 from DeterminateSystems/fix-fetcher-cache
Fix fetchToStore() caching
2 parents 96874f4 + 86785fd commit 550c894

8 files changed

Lines changed: 73 additions & 10 deletions

File tree

src/libexpr/paths.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ StorePath EvalState::mountInput(
8080
storeFS->mount(CanonPath(store->printStorePath(storePath)), accessor);
8181

8282
if (requireLockable && (!settings.lazyTrees || !input.isLocked()) && !input.getNarHash()) {
83+
// FIXME: use fetchToStore to make it cache this
8384
auto narHash = accessor->hashPath(CanonPath::root);
8485
input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
8586
}

src/libfetchers/fetch-to-store.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@ StorePath fetchToStore(
3131
// a `PosixSourceAccessor` pointing to a store path.
3232

3333
std::optional<fetchers::Cache::Key> cacheKey;
34+
std::optional<std::string> fingerprint;
3435

35-
if (!filter && path.accessor->fingerprint) {
36-
cacheKey = makeFetchToStoreCacheKey(std::string{name}, *path.accessor->fingerprint, method, path.path.abs());
36+
if (!filter && (fingerprint = path.accessor->getFingerprint(path.path))) {
37+
cacheKey = makeFetchToStoreCacheKey(std::string{name}, *fingerprint, method, path.path.abs());
3738
if (auto res = fetchers::getCache()->lookupStorePath(*cacheKey, store)) {
3839
debug("store path cache hit for '%s'", path);
3940
return res->storePath;
4041
}
4142
} else
42-
debug("source path '%s' is uncacheable", path);
43+
debug("source path '%s' is uncacheable (%d, %d)", path, filter, (bool) fingerprint);
4344

4445
Activity act(*logger, lvlChatty, actUnknown,
4546
fmt(mode == FetchMode::DryRun ? "hashing '%s'" : "copying '%s' to the store", path));
@@ -55,7 +56,7 @@ StorePath fetchToStore(
5556

5657
debug(mode == FetchMode::DryRun ? "hashed '%s'" : "copied '%s' to '%s'", path, store.printStorePath(storePath));
5758

58-
if (cacheKey && mode == FetchMode::Copy)
59+
if (cacheKey)
5960
fetchers::getCache()->upsert(*cacheKey, store, {}, storePath);
6061

6162
return storePath;

src/libfetchers/fetchers.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
338338

339339
auto accessor = make_ref<SubstitutedSourceAccessor>(makeStorePathAccessor(store, storePath));
340340

341-
accessor->fingerprint = getFingerprint(store);
341+
if (auto fingerprint = getFingerprint(store))
342+
accessor->setFingerprint(*fingerprint);
342343

343344
// FIXME: ideally we would use the `showPath()` of the
344345
// "real" accessor for this fetcher type.
@@ -352,8 +353,10 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
352353

353354
auto [accessor, result] = scheme->getAccessor(store, *this);
354355

355-
assert(!accessor->fingerprint);
356-
accessor->fingerprint = result.getFingerprint(store);
356+
assert(!accessor->getFingerprint(CanonPath::root));
357+
358+
if (auto fingerprint = getFingerprint(store))
359+
accessor->setFingerprint(*fingerprint);
357360

358361
return {accessor, std::move(result)};
359362
}

src/libfetchers/filtering-source-accessor.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ std::string FilteringSourceAccessor::readFile(const CanonPath & path)
1414
return next->readFile(prefix / path);
1515
}
1616

17+
void FilteringSourceAccessor::readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback)
18+
{
19+
checkAccess(path);
20+
return next->readFile(prefix / path, sink, sizeCallback);
21+
}
22+
1723
bool FilteringSourceAccessor::pathExists(const CanonPath & path)
1824
{
1925
return isAllowed(path) && next->pathExists(prefix / path);
@@ -52,6 +58,16 @@ std::string FilteringSourceAccessor::showPath(const CanonPath & path)
5258
return displayPrefix + next->showPath(prefix / path) + displaySuffix;
5359
}
5460

61+
std::optional<std::string> FilteringSourceAccessor::getFingerprint(const CanonPath & path)
62+
{
63+
return next->getFingerprint(prefix / path);
64+
}
65+
66+
void FilteringSourceAccessor::setFingerprint(std::string fingerprint)
67+
{
68+
next->setFingerprint(std::move(fingerprint));
69+
}
70+
5571
void FilteringSourceAccessor::checkAccess(const CanonPath & path)
5672
{
5773
if (!isAllowed(path))

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ struct FilteringSourceAccessor : SourceAccessor
3636

3737
std::string readFile(const CanonPath & path) override;
3838

39+
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override;
40+
3941
bool pathExists(const CanonPath & path) override;
4042

4143
Stat lstat(const CanonPath & path) override;
@@ -48,6 +50,10 @@ struct FilteringSourceAccessor : SourceAccessor
4850

4951
std::string showPath(const CanonPath & path) override;
5052

53+
std::optional<std::string> getFingerprint(const CanonPath & path) override;
54+
55+
void setFingerprint(std::string fingerprint) override;
56+
5157
/**
5258
* Call `makeNotAllowedError` to throw a `RestrictedPathError`
5359
* exception if `isAllowed()` returns `false` for `path`.

src/libutil/include/nix/util/forwarding-source-accessor.hh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ struct ForwardingSourceAccessor : SourceAccessor
5252
{
5353
return next->getPhysicalPath(path);
5454
}
55+
56+
std::optional<std::string> getFingerprint(const CanonPath & path) override
57+
{
58+
return next->getFingerprint(path);
59+
}
60+
61+
void setFingerprint(std::string fingerprint) override
62+
{
63+
next->setFingerprint(std::move(fingerprint));
64+
}
5565
};
5666

5767
}

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,27 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
177177
SymlinkResolution mode = SymlinkResolution::Full);
178178

179179
/**
180-
* A string that uniquely represents the contents of this
181-
* accessor. This is used for caching lookups (see `fetchToStore()`).
180+
* Return a string that uniquely represents the contents of this
181+
* accessor. This is used for caching lookups (see
182+
* `fetchToStore()`).
183+
*
184+
* Fingerprints are generally for the entire accessor, but this
185+
* method takes a `path` argument to support accessors like
186+
* `MountedSourceAccessor` that combine multiple underlying
187+
* accessors. A fingerprint should only be returned if it uniquely
188+
* represents everything under `path`.
182189
*/
183-
std::optional<std::string> fingerprint;
190+
virtual std::optional<std::string> getFingerprint(const CanonPath & path)
191+
{
192+
return _fingerprint;
193+
}
194+
195+
virtual void setFingerprint(std::string fingerprint)
196+
{
197+
_fingerprint = std::move(fingerprint);
198+
}
199+
200+
std::optional<std::string> _fingerprint;
184201

185202
/**
186203
* Return the maximum last-modified time of the files in this

src/libutil/mounted-source-accessor.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ struct MountedSourceAccessorImpl : MountedSourceAccessor
9090
else
9191
return nullptr;
9292
}
93+
94+
std::optional<std::string> getFingerprint(const CanonPath & path) override
95+
{
96+
auto [accessor, subpath] = resolve(path);
97+
// FIXME: check that there are no mounts underneath the mount
98+
// point of `accessor`, since that would invalidate the
99+
// fingerprint. (However we don't have such at the moment.)
100+
return accessor->getFingerprint(subpath);
101+
}
93102
};
94103

95104
ref<MountedSourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts)

0 commit comments

Comments
 (0)