aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/store-api.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-09-16 18:54:14 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-09-16 18:54:14 +0200
commit75989bdca773eedb8b8d1cc8a7675900358acd25 (patch)
tree2d1dce1431662f441cead67d8754e96eb4db6807 /src/libstore/store-api.cc
parent054be5025762c5e1c7e853c4fa5d7eed8da1727f (diff)
Make computeFSClosure() single-threaded again
The fact that queryPathInfo() is synchronous meant that we needed a thread for every concurrent binary cache lookup, even though they end up being handled by the same download thread. Requiring hundreds of threads is not a good idea. So now there is an asynchronous version of queryPathInfo() that takes a callback function to process the result. Similarly, enqueueDownload() now takes a callback rather than returning a future. Thus, a command like nix path-info --store https://cache.nixos.org/ -r /nix/store/slljrzwmpygy1daay14kjszsr9xix063-nixos-16.09beta231.dccf8c5 that returns 4941 paths now takes 1.87s using only 2 threads (the main thread and the downloader thread). (This is with a prewarmed CloudFront.)
Diffstat (limited to 'src/libstore/store-api.cc')
-rw-r--r--src/libstore/store-api.cc98
1 files changed, 64 insertions, 34 deletions
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 5dd56f905..427170843 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -4,6 +4,8 @@
#include "util.hh"
#include "nar-info-disk-cache.hh"
+#include <future>
+
namespace nix {
@@ -283,51 +285,79 @@ bool Store::isValidPath(const Path & storePath)
ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath)
{
+ std::promise<ref<ValidPathInfo>> promise;
+
+ queryPathInfo(storePath,
+ [&](ref<ValidPathInfo> info) {
+ promise.set_value(info);
+ },
+ [&](std::exception_ptr exc) {
+ promise.set_exception(exc);
+ });
+
+ return promise.get_future().get();
+}
+
+
+void Store::queryPathInfo(const Path & storePath,
+ std::function<void(ref<ValidPathInfo>)> success,
+ std::function<void(std::exception_ptr exc)> failure)
+{
auto hashPart = storePathToHash(storePath);
- {
- auto state_(state.lock());
- auto res = state_->pathInfoCache.get(hashPart);
- if (res) {
- stats.narInfoReadAverted++;
- if (!*res)
- throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
- return ref<ValidPathInfo>(*res);
+ try {
+
+ {
+ auto res = state.lock()->pathInfoCache.get(hashPart);
+ if (res) {
+ stats.narInfoReadAverted++;
+ if (!*res)
+ throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
+ return success(ref<ValidPathInfo>(*res));
+ }
}
- }
- if (diskCache) {
- auto res = diskCache->lookupNarInfo(getUri(), hashPart);
- if (res.first != NarInfoDiskCache::oUnknown) {
- stats.narInfoReadAverted++;
- auto state_(state.lock());
- state_->pathInfoCache.upsert(hashPart,
- res.first == NarInfoDiskCache::oInvalid ? 0 : res.second);
- if (res.first == NarInfoDiskCache::oInvalid ||
- (res.second->path != storePath && storePathToName(storePath) != ""))
- throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
- return ref<ValidPathInfo>(res.second);
+ if (diskCache) {
+ auto res = diskCache->lookupNarInfo(getUri(), hashPart);
+ if (res.first != NarInfoDiskCache::oUnknown) {
+ stats.narInfoReadAverted++;
+ {
+ auto state_(state.lock());
+ state_->pathInfoCache.upsert(hashPart,
+ res.first == NarInfoDiskCache::oInvalid ? 0 : res.second);
+ if (res.first == NarInfoDiskCache::oInvalid ||
+ (res.second->path != storePath && storePathToName(storePath) != ""))
+ throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
+ }
+ return success(ref<ValidPathInfo>(res.second));
+ }
}
+
+ } catch (std::exception & e) {
+ return callFailure(failure);
}
- auto info = queryPathInfoUncached(storePath);
+ queryPathInfoUncached(storePath,
+ [this, storePath, hashPart, success, failure](std::shared_ptr<ValidPathInfo> info) {
- if (diskCache)
- diskCache->upsertNarInfo(getUri(), hashPart, info);
+ if (diskCache)
+ diskCache->upsertNarInfo(getUri(), hashPart, info);
- {
- auto state_(state.lock());
- state_->pathInfoCache.upsert(hashPart, info);
- }
+ {
+ auto state_(state.lock());
+ state_->pathInfoCache.upsert(hashPart, info);
+ }
- if (!info
- || (info->path != storePath && storePathToName(storePath) != ""))
- {
- stats.narInfoMissing++;
- throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
- }
+ if (!info
+ || (info->path != storePath && storePathToName(storePath) != ""))
+ {
+ stats.narInfoMissing++;
+ return failure(std::make_exception_ptr(InvalidPath(format("path ‘%s’ is not valid") % storePath)));
+ }
+
+ callSuccess(success, failure, ref<ValidPathInfo>(info));
- return ref<ValidPathInfo>(info);
+ }, failure);
}