Skip to content

Commit

Permalink
Allow substituting paths when building remotely using ssh-ng://
Browse files Browse the repository at this point in the history
Until now, it was not possible to substitute missing paths from e.g.
`https://cache.nixos.org` on a remote server when building on it using
the new `ssh-ng` protocol.

This is because every store implementation except legacy `ssh://`
ignores the substitution flag passed to `Store::queryValidPaths` while
the `legacy-ssh-store` substitutes the remote store using
`cmdQueryValidPaths` when the remote store is opened with `nix-store
--serve`.

This patch slightly modifies the daemon protocol to allow passing an
integer value suggesting whether to substitute missing paths during
`wopQueryValidPaths`. To implement this on the daemon-side, the
substitution logic from `nix-store --serve` has been moved into a
protected method named `Store::substitutePaths` which gets currently
called from `LocalStore::queryValidPaths` and `Store::queryValidPaths`
if `maybeSubstitute` is `true`.

Fixes #2770
  • Loading branch information
Ma27 committed Oct 23, 2020
1 parent a78582c commit db19618
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 29 deletions.
3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
versionSuffix =
if officialRelease
then ""
else "pre${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified)}_${self.shortRev or "dirty"}";
else "pre${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}_${self.shortRev or "dirty"}";

officialRelease = false;

Expand Down Expand Up @@ -116,6 +116,7 @@

nix = with final; with commonDeps pkgs; (stdenv.mkDerivation {
name = "nix-${version}";
inherit version;

src = self;

Expand Down
8 changes: 7 additions & 1 deletion src/libstore/daemon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,14 @@ static void performOp(TunnelLogger * logger, ref<Store> store,

case wopQueryValidPaths: {
auto paths = worker_proto::read(*store, from, Phantom<StorePathSet> {});

SubstituteFlag substitute = NoSubstitute;
if (GET_PROTOCOL_MINOR(clientVersion) >= 27) {
substitute = readInt(from) ? Substitute : NoSubstitute;
}

logger->startWork();
auto res = store->queryValidPaths(paths);
auto res = store->queryValidPaths(paths, substitute);
logger->stopWork();
worker_proto::write(*store, to, res);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/libstore/local-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,10 @@ bool LocalStore::isValidPathUncached(const StorePath & path)

StorePathSet LocalStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute)
{
if (maybeSubstitute) {
substitutePaths(paths);
}

StorePathSet res;
for (auto & i : paths)
if (isValidPath(i)) res.insert(i);
Expand Down
3 changes: 3 additions & 0 deletions src/libstore/remote-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, Substitute
} else {
conn->to << wopQueryValidPaths;
worker_proto::write(*this, conn->to, paths);
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 27) {
conn->to << (settings.buildersUseSubstitutes ? 1 : 0);
}
conn.processStderr();
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
}
Expand Down
26 changes: 26 additions & 0 deletions src/libstore/store-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,28 @@ void Store::queryPathInfo(const StorePath & storePath,
}


void Store::substitutePaths(const StorePathSet & paths)
{
std::vector<StorePathWithOutputs> paths2;
for (auto & path : paths)
if (!path.isDerivation())
paths2.push_back({path});
uint64_t downloadSize, narSize;
StorePathSet willBuild, willSubstitute, unknown;
queryMissing(paths2,
willBuild, willSubstitute, unknown, downloadSize, narSize);

if (!willSubstitute.empty())
try {
std::vector<StorePathWithOutputs> subs;
for (auto & p : willSubstitute) subs.push_back({p});
buildPaths(subs);
} catch (Error & e) {
logWarning(e.info());
}
}


StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute)
{
struct State
Expand All @@ -531,6 +553,10 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
std::exception_ptr exc;
};

if (maybeSubstitute) {
substitutePaths(paths);
}

Sync<State> state_(State{paths.size(), StorePathSet()});

std::condition_variable wakeup;
Expand Down
5 changes: 5 additions & 0 deletions src/libstore/store-api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,11 @@ protected:

virtual bool isValidPathUncached(const StorePath & path);

/* If requested, substitute missing paths. This
implements nix-copy-closure's --use-substitutes
flag. */
void substitutePaths(const StorePathSet & paths);

public:

/* Query which of the given paths is valid. Optionally, try to
Expand Down
2 changes: 1 addition & 1 deletion src/libstore/worker-protocol.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f

#define PROTOCOL_VERSION 0x11a
#define PROTOCOL_VERSION 0x11b
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)

Expand Down
28 changes: 2 additions & 26 deletions src/nix-store/nix-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -830,32 +830,8 @@ static void opServe(Strings opFlags, Strings opArgs)
for (auto & path : paths)
store->addTempRoot(path);

/* If requested, substitute missing paths. This
implements nix-copy-closure's --use-substitutes
flag. */
if (substitute && writeAllowed) {
/* Filter out .drv files (we don't want to build anything). */
std::vector<StorePathWithOutputs> paths2;
for (auto & path : paths)
if (!path.isDerivation())
paths2.push_back({path});
uint64_t downloadSize, narSize;
StorePathSet willBuild, willSubstitute, unknown;
store->queryMissing(paths2,
willBuild, willSubstitute, unknown, downloadSize, narSize);
/* FIXME: should use ensurePath(), but it only
does one path at a time. */
if (!willSubstitute.empty())
try {
std::vector<StorePathWithOutputs> subs;
for (auto & p : willSubstitute) subs.push_back({p});
store->buildPaths(subs);
} catch (Error & e) {
logWarning(e.info());
}
}

worker_proto::write(*store, out, store->queryValidPaths(paths));
SubstituteFlag maybeSubstitute = substitute && writeAllowed ? Substitute : NoSubstitute;
worker_proto::write(*store, out, store->queryValidPaths(paths, maybeSubstitute));
break;
}

Expand Down

0 comments on commit db19618

Please sign in to comment.