aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2018-08-03 21:10:03 +0200
committerEelco Dolstra <edolstra@gmail.com>2018-08-03 21:21:16 +0200
commit2825e05d21ecabc8b8524836baf0b9b05da993c6 (patch)
treedbdfb391c835dc4baebee804653bbf7e399b6b27
parent34c17fdae535d0128d178dde676f56f1bc8439e3 (diff)
Make adding paths via nix-store --serve run in constant memory
It adds a new operation, cmdAddToStoreNar, that does the same thing as the corresponding nix-daemon operation, i.e. call addToStore(). This replaces cmdImportPaths, which has the major issue that it sends the NAR first and the store path second, thus requiring us to store the incoming NAR either in memory or on disk until we decide what to do with it. For example, this reduces the memory usage of $ nix copy --to 'ssh://localhost?remote-store=/tmp/nix' /nix/store/95cwv4q54dc6giaqv6q6p4r02ia2km35-blender-2.79 from 267 MiB to 12 MiB. Probably fixes #1988.
-rw-r--r--src/libstore/legacy-ssh-store.cc59
-rw-r--r--src/libstore/serve-protocol.hh3
-rw-r--r--src/nix-daemon/nix-daemon.cc1
-rw-r--r--src/nix-store/nix-store.cc22
4 files changed, 70 insertions, 15 deletions
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index f9b0b42c8..ddfd17d64 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -28,6 +28,7 @@ struct LegacySSHStore : public Store
FdSink to;
FdSource from;
int remoteVersion;
+ bool good = true;
};
std::string host;
@@ -42,7 +43,7 @@ struct LegacySSHStore : public Store
, connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections),
[this]() { return openConnection(); },
- [](const ref<Connection> & r) { return true; }
+ [](const ref<Connection> & r) { return r->good; }
))
, master(
host,
@@ -58,7 +59,7 @@ struct LegacySSHStore : public Store
{
auto conn = make_ref<Connection>();
conn->sshConn = master.startCommand(
- fmt("%s --serve --write", remoteProgram)
+ fmt("command time %s --serve --write", remoteProgram)
+ (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));
conn->to = FdSink(conn->sshConn->in.get());
conn->from = FdSource(conn->sshConn->out.get());
@@ -130,18 +131,48 @@ struct LegacySSHStore : public Store
auto conn(connections->get());
- conn->to
- << cmdImportPaths
- << 1;
- copyNAR(source, conn->to);
- conn->to
- << exportMagic
- << info.path
- << info.references
- << info.deriver
- << 0
- << 0;
- conn->to.flush();
+ if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4) {
+
+ conn->to
+ << cmdAddToStoreNar
+ << info.path
+ << info.deriver
+ << info.narHash.to_string(Base16, false)
+ << info.references
+ << info.registrationTime
+ << info.narSize
+ << info.ultimate
+ << info.sigs
+ << info.ca;
+ try {
+ copyNAR(source, conn->to);
+ } catch (...) {
+ conn->good = false;
+ throw;
+ }
+ conn->to.flush();
+
+ } else {
+
+ conn->to
+ << cmdImportPaths
+ << 1;
+ try {
+ copyNAR(source, conn->to);
+ } catch (...) {
+ conn->good = false;
+ throw;
+ }
+ conn->to
+ << exportMagic
+ << info.path
+ << info.references
+ << info.deriver
+ << 0
+ << 0;
+ conn->to.flush();
+
+ }
if (readInt(conn->from) != 1)
throw Error("failed to add path '%s' to remote host '%s', info.path, host");
diff --git a/src/libstore/serve-protocol.hh b/src/libstore/serve-protocol.hh
index f67d1e258..9fae6d534 100644
--- a/src/libstore/serve-protocol.hh
+++ b/src/libstore/serve-protocol.hh
@@ -5,7 +5,7 @@ namespace nix {
#define SERVE_MAGIC_1 0x390c9deb
#define SERVE_MAGIC_2 0x5452eecb
-#define SERVE_PROTOCOL_VERSION 0x204
+#define SERVE_PROTOCOL_VERSION 0x205
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
@@ -18,6 +18,7 @@ typedef enum {
cmdBuildPaths = 6,
cmdQueryClosure = 7,
cmdBuildDerivation = 8,
+ cmdAddToStoreNar = 9,
} ServeCommand;
}
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index a2e54b93c..644fa6681 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -707,6 +707,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork();
+ // FIXME: race if addToStore doesn't read source?
store.cast<Store>()->addToStore(info, *source, (RepairFlag) repair,
dontCheckSigs ? NoCheckSigs : CheckSigs, nullptr);
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 942fe50e8..fe68f681a 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -924,6 +924,28 @@ static void opServe(Strings opFlags, Strings opArgs)
break;
}
+ case cmdAddToStoreNar: {
+ if (!writeAllowed) throw Error("importing paths is not allowed");
+
+ ValidPathInfo info;
+ info.path = readStorePath(*store, in);
+ in >> info.deriver;
+ if (!info.deriver.empty())
+ store->assertStorePath(info.deriver);
+ info.narHash = Hash(readString(in), htSHA256);
+ info.references = readStorePaths<PathSet>(*store, in);
+ in >> info.registrationTime >> info.narSize >> info.ultimate;
+ info.sigs = readStrings<StringSet>(in);
+ in >> info.ca;
+
+ // FIXME: race if addToStore doesn't read source?
+ store->addToStore(info, in, NoRepair, NoCheckSigs);
+
+ out << 1; // indicate success
+
+ break;
+ }
+
default:
throw Error(format("unknown serve command %1%") % cmd);
}