aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2020-07-13 03:01:44 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2020-07-13 03:01:44 +0000
commit44157653850ce18536f837d7ed53521d61a238a1 (patch)
tree643d13fd44a642152dd32bb2f31e9c91b340623a /src/libstore
parentdbffd309fed95d306135617fdc18ce4cf6109025 (diff)
parent8efa23bb996161af74f89401902450e51e9d4b54 (diff)
Merge remote-tracking branch 'upstream/master' into hash-always-has-type
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/build.cc5
-rw-r--r--src/libstore/content-address.cc12
-rw-r--r--src/libstore/content-address.hh2
-rw-r--r--src/libstore/daemon.cc4
-rw-r--r--src/libstore/globals.hh7
-rw-r--r--src/libstore/local-store.cc135
-rw-r--r--src/libstore/remote-store.cc3
-rw-r--r--src/libstore/store-api.cc35
-rw-r--r--src/libstore/store-api.hh7
9 files changed, 188 insertions, 22 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index a57055168..6970363b0 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2041,7 +2041,10 @@ void DerivationGoal::startBuilder()
if (!std::regex_match(fileName, regex))
throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName);
- auto storePath = worker.store.parseStorePath(*i++);
+ auto storePathS = *i++;
+ if (!worker.store.isInStore(storePathS))
+ throw BuildError("'exportReferencesGraph' contains a non-store path '%1%'", storePathS);
+ auto storePath = worker.store.parseStorePath(worker.store.toStorePath(storePathS));
/* Write closure info to <fileName>. */
writeFile(tmpDir + "/" + fileName,
diff --git a/src/libstore/content-address.cc b/src/libstore/content-address.cc
index 5ccb1a7b3..f83b98a98 100644
--- a/src/libstore/content-address.cc
+++ b/src/libstore/content-address.cc
@@ -82,4 +82,16 @@ std::string renderContentAddress(std::optional<ContentAddress> ca) {
return ca ? renderContentAddress(*ca) : "";
}
+Hash getContentAddressHash(const ContentAddress & ca)
+{
+ return std::visit(overloaded {
+ [](TextHash th) {
+ return th.hash;
+ },
+ [](FixedOutputHash fsh) {
+ return fsh.hash;
+ }
+ }, ca);
+}
+
}
diff --git a/src/libstore/content-address.hh b/src/libstore/content-address.hh
index ba4797f5b..22a039242 100644
--- a/src/libstore/content-address.hh
+++ b/src/libstore/content-address.hh
@@ -53,4 +53,6 @@ ContentAddress parseContentAddress(std::string_view rawCa);
std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt);
+Hash getContentAddressHash(const ContentAddress & ca);
+
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index c66b58251..bbbfc8e10 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -78,10 +78,10 @@ struct TunnelLogger : public Logger
if (ei.level > verbosity) return;
std::stringstream oss;
- oss << ei;
+ showErrorInfo(oss, ei, false);
StringSink buf;
- buf << STDERR_NEXT << oss.str() << "\n"; // (fs.s + "\n");
+ buf << STDERR_NEXT << oss.str();
enqueueMsg(*buf.s);
}
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 2fbcafff8..4d5eec7bf 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -196,10 +196,6 @@ public:
/* Whether to lock the Nix client and worker to the same CPU. */
bool lockCPU;
- /* Whether to show a stack trace if Nix evaluation fails. */
- Setting<bool> showTrace{this, false, "show-trace",
- "Whether to show a stack trace on evaluation errors."};
-
Setting<SandboxMode> sandboxMode{this,
#if __linux__
smEnabled
@@ -369,6 +365,9 @@ public:
Setting<bool> warnDirty{this, true, "warn-dirty",
"Whether to warn about dirty Git/Mercurial trees."};
+
+ Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
+ "Maximum size of NARs before spilling them to disk."};
};
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index c9758f680..57c83412e 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -976,7 +976,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
PathLocks outputLock;
- Path realPath = realStoreDir + "/" + std::string(info.path.to_string());
+ auto realPath = Store::toRealPath(info.path);
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
@@ -1047,8 +1047,7 @@ StorePath LocalStore::addToStoreFromDump(const string & dump, const string & nam
/* The first check above is an optimisation to prevent
unnecessary lock acquisition. */
- Path realPath = realStoreDir + "/";
- realPath += dstPath.to_string();
+ auto realPath = Store::toRealPath(dstPath);
PathLocks outputLock({realPath});
@@ -1098,16 +1097,125 @@ StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
{
Path srcPath(absPath(_srcPath));
- /* Read the whole path into memory. This is not a very scalable
- method for very large paths, but `copyPath' is mainly used for
- small files. */
- StringSink sink;
- if (method == FileIngestionMethod::Recursive)
- dumpPath(srcPath, sink, filter);
- else
- sink.s = make_ref<std::string>(readFile(srcPath));
+ /* For computing the NAR hash. */
+ auto sha256Sink = std::make_unique<HashSink>(htSHA256);
+
+ /* For computing the store path. In recursive SHA-256 mode, this
+ is the same as the NAR hash, so no need to do it again. */
+ std::unique_ptr<HashSink> hashSink =
+ method == FileIngestionMethod::Recursive && hashAlgo == htSHA256
+ ? nullptr
+ : std::make_unique<HashSink>(hashAlgo);
+
+ /* Read the source path into memory, but only if it's up to
+ narBufferSize bytes. If it's larger, write it to a temporary
+ location in the Nix store. If the subsequently computed
+ destination store path is already valid, we just delete the
+ temporary path. Otherwise, we move it to the destination store
+ path. */
+ bool inMemory = true;
+ std::string nar;
+
+ auto source = sinkToSource([&](Sink & sink) {
+
+ LambdaSink sink2([&](const unsigned char * buf, size_t len) {
+ (*sha256Sink)(buf, len);
+ if (hashSink) (*hashSink)(buf, len);
+
+ if (inMemory) {
+ if (nar.size() + len > settings.narBufferSize) {
+ inMemory = false;
+ sink << 1;
+ sink((const unsigned char *) nar.data(), nar.size());
+ nar.clear();
+ } else {
+ nar.append((const char *) buf, len);
+ }
+ }
+
+ if (!inMemory) sink(buf, len);
+ });
+
+ if (method == FileIngestionMethod::Recursive)
+ dumpPath(srcPath, sink2, filter);
+ else
+ readFile(srcPath, sink2);
+ });
+
+ std::unique_ptr<AutoDelete> delTempDir;
+ Path tempPath;
+
+ try {
+ /* Wait for the source coroutine to give us some dummy
+ data. This is so that we don't create the temporary
+ directory if the NAR fits in memory. */
+ readInt(*source);
+
+ auto tempDir = createTempDir(realStoreDir, "add");
+ delTempDir = std::make_unique<AutoDelete>(tempDir);
+ tempPath = tempDir + "/x";
+
+ if (method == FileIngestionMethod::Recursive)
+ restorePath(tempPath, *source);
+ else
+ writeFile(tempPath, *source);
+
+ } catch (EndOfFile &) {
+ if (!inMemory) throw;
+ /* The NAR fits in memory, so we didn't do restorePath(). */
+ }
+
+ auto sha256 = sha256Sink->finish();
+
+ Hash hash = hashSink ? hashSink->finish().first : sha256.first;
+
+ auto dstPath = makeFixedOutputPath(method, hash, name);
+
+ addTempRoot(dstPath);
+
+ if (repair || !isValidPath(dstPath)) {
+
+ /* The first check above is an optimisation to prevent
+ unnecessary lock acquisition. */
+
+ auto realPath = Store::toRealPath(dstPath);
- return addToStoreFromDump(*sink.s, name, method, hashAlgo, repair);
+ PathLocks outputLock({realPath});
+
+ if (repair || !isValidPath(dstPath)) {
+
+ deletePath(realPath);
+
+ autoGC();
+
+ if (inMemory) {
+ /* Restore from the NAR in memory. */
+ StringSource source(nar);
+ if (method == FileIngestionMethod::Recursive)
+ restorePath(realPath, source);
+ else
+ writeFile(realPath, source);
+ } else {
+ /* Move the temporary path we restored above. */
+ if (rename(tempPath.c_str(), realPath.c_str()))
+ throw Error("renaming '%s' to '%s'", tempPath, realPath);
+ }
+
+ canonicalisePathMetaData(realPath, -1); // FIXME: merge into restorePath
+
+ optimisePath(realPath);
+
+ ValidPathInfo info(dstPath);
+ info.narHash = sha256.first;
+ info.narSize = sha256.second;
+ info.ca = FixedOutputHash { .method = method, .hash = hash };
+ registerValidPath(info);
+ }
+
+ outputLock.setDeletion(true);
+ }
+
+ return dstPath;
}
@@ -1121,8 +1229,7 @@ StorePath LocalStore::addTextToStore(const string & name, const string & s,
if (repair || !isValidPath(dstPath)) {
- Path realPath = realStoreDir + "/";
- realPath += dstPath.to_string();
+ auto realPath = Store::toRealPath(dstPath);
PathLocks outputLock({realPath});
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 2b328ea77..0cec6ca65 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -8,6 +8,7 @@
#include "derivations.hh"
#include "pool.hh"
#include "finally.hh"
+#include "logging.hh"
#include <sys/types.h>
#include <sys/stat.h>
@@ -220,7 +221,7 @@ void RemoteStore::setOptions(Connection & conn)
overrides.erase(settings.maxSilentTime.name);
overrides.erase(settings.buildCores.name);
overrides.erase(settings.useSubstitutes.name);
- overrides.erase(settings.showTrace.name);
+ overrides.erase(loggerSettings.showTrace.name);
conn.to << overrides.size();
for (auto & i : overrides)
conn.to << i.first << i.second.value;
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 0bfffbc36..f35e34aee 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -7,6 +7,7 @@
#include "json.hh"
#include "derivations.hh"
#include "url.hh"
+#include "archive.hh"
#include <future>
@@ -221,6 +222,40 @@ StorePath Store::computeStorePathForText(const string & name, const string & s,
}
+ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
+ FileIngestionMethod method, HashType hashAlgo,
+ std::optional<Hash> expectedCAHash)
+{
+ /* FIXME: inefficient: we're reading/hashing 'tmpFile' three
+ times. */
+
+ auto [narHash, narSize] = hashPath(htSHA256, srcPath);
+
+ auto hash = method == FileIngestionMethod::Recursive
+ ? hashAlgo == htSHA256
+ ? narHash
+ : hashPath(hashAlgo, srcPath).first
+ : hashFile(hashAlgo, srcPath);
+
+ if (expectedCAHash && expectedCAHash != hash)
+ throw Error("hash mismatch for '%s'", srcPath);
+
+ ValidPathInfo info(makeFixedOutputPath(method, hash, name));
+ info.narHash = narHash;
+ info.narSize = narSize;
+ info.ca = FixedOutputHash { .method = method, .hash = hash };
+
+ if (!isValidPath(info.path)) {
+ auto source = sinkToSource([&](Sink & sink) {
+ dumpPath(srcPath, sink);
+ });
+ addToStore(info, *source);
+ }
+
+ return info;
+}
+
+
Store::Store(const Params & params)
: Config(params)
, state({(size_t) pathInfoCacheSize})
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index bb6198662..63e16e5d5 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -451,6 +451,13 @@ public:
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) = 0;
+ /* Copy the contents of a path to the store and register the
+ validity the resulting path, using a constant amount of
+ memory. */
+ ValidPathInfo addToStoreSlow(std::string_view name, const Path & srcPath,
+ FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
+ std::optional<Hash> expectedCAHash = {});
+
// FIXME: remove?
virtual StorePath addToStoreFromDump(const string & dump, const string & name,
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair)