From 8d088464a75a1ba2da00ac71d88fc7acbb4932c2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 15 Apr 2024 18:28:46 +0200 Subject: [PATCH] fetchToStore(): Avoid duplicate copying if the input is already a store path This is needed for the path:// input scheme (until it returns a FSInputAccessor to the original path, but that's blocked by #10089) and the Mercurial input scheme. --- src/libfetchers/fetch-to-store.cc | 14 +++++++++++--- src/libfetchers/path.cc | 7 ++++++- src/libfetchers/unix/mercurial.cc | 3 +++ src/libutil/input-accessor.hh | 7 +++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/libfetchers/fetch-to-store.cc b/src/libfetchers/fetch-to-store.cc index 398286065e6..465396eabb1 100644 --- a/src/libfetchers/fetch-to-store.cc +++ b/src/libfetchers/fetch-to-store.cc @@ -1,6 +1,7 @@ #include "fetch-to-store.hh" #include "fetchers.hh" #include "cache.hh" +#include "posix-source-accessor.hh" namespace nix { @@ -13,8 +14,16 @@ StorePath fetchToStore( PathFilter * filter, RepairFlag repair) { - // FIXME: add an optimisation for the case where the accessor is - // an FSInputAccessor pointing to a store path. + if (path.accessor->isStorePath + && path.path.isRoot() + && method == FileIngestionMethod::Recursive + && !filter) + { + if (auto accessor = path.accessor.dynamic_pointer_cast()) + if (auto storePath = store.maybeParseStorePath(accessor->root.string())) + if (storePath->name() == name) + return *storePath; + } std::optional cacheKey; @@ -52,5 +61,4 @@ StorePath fetchToStore( return storePath; } - } diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index 0af1bad7381..adc8cf46ee1 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -155,7 +155,12 @@ struct PathInputScheme : InputScheme } input.attrs.insert_or_assign("lastModified", uint64_t(mtime)); - return {makeStorePathAccessor(store, *storePath), std::move(input)}; + auto accessor = makeStorePathAccessor(store, *storePath); + + /* Optimize fetchToStore() calls on this path. */ + accessor->isStorePath = true; + + return {accessor, std::move(input)}; } std::optional getFingerprint(ref store, const Input & input) const override diff --git a/src/libfetchers/unix/mercurial.cc b/src/libfetchers/unix/mercurial.cc index 4e0b26274fe..d5e198ed1c6 100644 --- a/src/libfetchers/unix/mercurial.cc +++ b/src/libfetchers/unix/mercurial.cc @@ -356,6 +356,9 @@ struct MercurialInputScheme : InputScheme accessor->setPathDisplay("«" + input.to_string() + "»"); + /* Optimize fetchToStore() calls on this path. */ + accessor->isStorePath = true; + return {accessor, input}; } diff --git a/src/libutil/input-accessor.hh b/src/libutil/input-accessor.hh index 55b7c2f2f84..8d73cf7ab13 100644 --- a/src/libutil/input-accessor.hh +++ b/src/libutil/input-accessor.hh @@ -13,6 +13,13 @@ struct InputAccessor : virtual SourceAccessor, std::enable_shared_from_this fingerprint; + /** + * Whether this is a store path using + * FileIngestionMethod::Recursive. This is used to optimize + * `fetchToStore()`. + */ + bool isStorePath = false; + /** * Return the maximum last-modified time of the files in this * tree, if available.