-
-
Couldn't load subscription status.
- Fork 1.7k
Fix fetchToStore caching #14050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix fetchToStore caching #14050
Conversation
| struct MountedSourceAccessor : SourceAccessor | ||
| { | ||
| virtual void mount(CanonPath mountPoint, ref<SourceAccessor> accessor) = 0; | ||
|
|
||
| /** | ||
| * Return the accessor mounted on `mountPoint`, or `nullptr` if | ||
| * there is no such mount point. | ||
| */ | ||
| virtual std::shared_ptr<SourceAccessor> getMount(CanonPath mountPoint) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great. Like this exactly what's needed for in-memory dummy store.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to use this with care. E.g. the path ${m}/foo != getMount m foo, so if both are observable in the language, that would be a problem. (And they are substantially different in terms of root and path components)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be a problem here since we don't have lazy trees yet. I.e. identical inputs are deterministically mounted on the same store paths.
|
|
||
| if (originalInput.getNarHash() && narHash != *originalInput.getNarHash()) | ||
| throw Error( | ||
| (unsigned int) 102, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there an enum for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think so... There is Worker::failingExitStatus() which should probably be factored out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was meaning to clean that up and unify with BuildResult statuses at some point, fwiw.
| { | ||
| auto storePath = fetchToStore(fetchSettings, *store, accessor, FetchMode::Copy, input.getName()); | ||
|
|
||
| allowPath(storePath); // FIXME: should just whitelist the entire virtual store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like this part done sooner rather than later
|
I took the "easy parts" of this and did some other cleanups and put in #14080. |
src/libexpr/eval.cc
Outdated
| auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); | ||
| if (settings.pureEval || store->storeDir != realStoreDir) { | ||
| accessor = settings.pureEval ? storeFS : makeUnionSourceAccessor({accessor, storeFS}); | ||
| } | ||
| accessor = settings.pureEval ? storeFS.cast<SourceAccessor>() : makeUnionSourceAccessor({accessor, storeFS}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is quite right --- evidently we need better unit tests to catch this.
#14080 removes redundant branches while keeping the store->storeDir != realStoreDir fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this change is necessary. Otherwise, if pureEval isn't enabled, rootFS ends up not containing storeFS, so the mounts on storeFS won't be visible in rootFS.
|
@Ericson2314 now this one needs a rebase? |
With FilteringSourceAccessor, lstat() needs to throw a different exception if the path is inaccessible than if it doesn't exist.
This returns the fingerprint for a specific subpath. This is intended for "composite" accessors like MountedSourceAccessor, where different subdirectories can have different fingerprints.
|
I'll rebase it |
fetchToStore() caching was broken because it uses the fingerprint of the accessor, but now that the accessor (typically storeFS) is a composite (like MountedSourceAccessor or AllowListSourceAccessor), there was no fingerprint anymore. So fetchToStore now uses the new getFingerprint() method to get the specific fingerprint for the subpath.
This is to test the non-functional property that most paths should be cacheable. We've had frequent cases where caching broken but we didn't notice.
7618094 to
4b9735b
Compare
|
|
||
| // Backward compatibility hack: throw an exception if access | ||
| // to this path is not allowed. | ||
| if (auto accessor = res.accessor.dynamic_pointer_cast<FilteringSourceAccessor>()) | ||
| accessor->checkAccess(res.path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This stuff has been on lazy trees for a while I know, but I guess a this point I am skeptical it is still needed? Especially with #14081
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, they're still needed.
|
So my current plan (as of yesterday) is that after @xokdvium fixes some bugs, I think #14081 will pass tests, and then I hope we can do that, and then I think we will be better prepared to review this. I want avoid a mixture of mounting and filtering in the pure eval case because I think that is hard to reason about. |
Let's please not block pretty important bug fixes on nice-to-have refactorings. Currently the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Other nice-to-haves we can improve on in follow-ups
|
This seems to have regressed: |
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
Motivation
fetchToStore()caching is broken because it uses the fingerprint of the accessor, but now that the accessor (typicallystoreFS) is a composite (likeMountedSourceAccessororAllowListSourceAccessor), there is no fingerprint anymore.So
fetchToStore()now uses the newgetFingerprint()method to get the specific fingerprint for the subpath. We now also mount inputs on top ofstoreFSto make their fingerprints visible tofetchToStore().To prevent future regressions like this, this PR also adds tests to make sure that most paths are cacheable.
Context
Mostly cherry-picked from DetSys Nix and #13225.
Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.