Move path info caching from BinaryCacheStore to Store

Caching path info is generally useful. For instance, it speeds up "nix
path-info -rS /run/current-system" (i.e. showing the closure sizes of
all paths in the closure of the current system) from 5.6s to 0.15s.

This also eliminates some APIs like Store::queryDeriver() and
Store::queryReferences().
This commit is contained in:
Eelco Dolstra 2016-04-19 18:50:15 +02:00
parent 608b0265e1
commit e0204f8d46
21 changed files with 318 additions and 353 deletions

View file

@ -70,8 +70,7 @@ int isValidPath(char * path)
SV * queryReferences(char * path) SV * queryReferences(char * path)
PPCODE: PPCODE:
try { try {
PathSet paths; PathSet paths = store()->queryPathInfo(path)->references;
store()->queryReferences(path, paths);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
@ -82,7 +81,7 @@ SV * queryReferences(char * path)
SV * queryPathHash(char * path) SV * queryPathHash(char * path)
PPCODE: PPCODE:
try { try {
Hash hash = store()->queryPathHash(path); auto hash = store()->queryPathInfo(path)->narHash;
string s = "sha256:" + printHash32(hash); string s = "sha256:" + printHash32(hash);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
@ -93,7 +92,7 @@ SV * queryPathHash(char * path)
SV * queryDeriver(char * path) SV * queryDeriver(char * path)
PPCODE: PPCODE:
try { try {
Path deriver = store()->queryDeriver(path); auto deriver = store()->queryPathInfo(path)->deriver;
if (deriver == "") XSRETURN_UNDEF; if (deriver == "") XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
@ -104,17 +103,17 @@ SV * queryDeriver(char * path)
SV * queryPathInfo(char * path, int base32) SV * queryPathInfo(char * path, int base32)
PPCODE: PPCODE:
try { try {
ValidPathInfo info = store()->queryPathInfo(path); auto info = store()->queryPathInfo(path);
if (info.deriver == "") if (info->deriver == "")
XPUSHs(&PL_sv_undef); XPUSHs(&PL_sv_undef);
else else
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(info->deriver.c_str(), 0)));
string s = "sha256:" + (base32 ? printHash32(info.narHash) : printHash(info.narHash)); string s = "sha256:" + (base32 ? printHash32(info->narHash) : printHash(info->narHash));
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info.registrationTime); mXPUSHi(info->registrationTime);
mXPUSHi(info.narSize); mXPUSHi(info->narSize);
AV * arr = newAV(); AV * arr = newAV();
for (PathSet::iterator i = info.references.begin(); i != info.references.end(); ++i) for (PathSet::iterator i = info->references.begin(); i != info->references.end(); ++i)
av_push(arr, newSVpv(i->c_str(), 0)); av_push(arr, newSVpv(i->c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) arr))); XPUSHs(sv_2mortal(newRV((SV *) arr)));
} catch (Error & e) { } catch (Error & e) {

View file

@ -40,11 +40,6 @@ void BinaryCacheStore::notImpl()
throw Error("operation not implemented for binary cache stores"); throw Error("operation not implemented for binary cache stores");
} }
const BinaryCacheStore::Stats & BinaryCacheStore::getStats()
{
return stats;
}
Path BinaryCacheStore::narInfoFileFor(const Path & storePath) Path BinaryCacheStore::narInfoFileFor(const Path & storePath)
{ {
assertStorePath(storePath); assertStorePath(storePath);
@ -100,67 +95,15 @@ void BinaryCacheStore::addToCache(const ValidPathInfo & info,
{ {
auto state_(state.lock()); auto state_(state.lock());
state_->narInfoCache.upsert(narInfo->path, narInfo); state_->pathInfoCache.upsert(narInfo->path, std::shared_ptr<NarInfo>(narInfo));
stats.narInfoCacheSize = state_->narInfoCache.size(); stats.pathInfoCacheSize = state_->pathInfoCache.size();
} }
stats.narInfoWrite++; stats.narInfoWrite++;
} }
NarInfo BinaryCacheStore::readNarInfo(const Path & storePath) bool BinaryCacheStore::isValidPathUncached(const Path & storePath)
{ {
{
auto state_(state.lock());
auto res = state_->narInfoCache.get(storePath);
if (res) {
stats.narInfoReadAverted++;
if (!*res)
throw InvalidPath(format("path %s is not valid") % storePath);
return **res;
}
}
auto narInfoFile = narInfoFileFor(storePath);
auto data = getFile(narInfoFile);
if (!data) {
stats.narInfoMissing++;
auto state_(state.lock());
state_->narInfoCache.upsert(storePath, 0);
stats.narInfoCacheSize = state_->narInfoCache.size();
throw InvalidPath(format("path %s is not valid") % storePath);
}
auto narInfo = make_ref<NarInfo>(*data, narInfoFile);
if (narInfo->path != storePath)
throw Error(format("NAR info file for store path %1% does not match %2%") % narInfo->path % storePath);
stats.narInfoRead++;
if (publicKeys) {
if (!narInfo->checkSignatures(*publicKeys))
throw Error(format("no good signature on NAR info file %1%") % narInfoFile);
}
{
auto state_(state.lock());
state_->narInfoCache.upsert(storePath, narInfo);
stats.narInfoCacheSize = state_->narInfoCache.size();
}
return *narInfo;
}
bool BinaryCacheStore::isValidPath(const Path & storePath)
{
{
auto state_(state.lock());
auto res = state_->narInfoCache.get(storePath);
if (res) {
stats.narInfoReadAverted++;
return *res != 0;
}
}
// FIXME: this only checks whether a .narinfo with a matching hash // FIXME: this only checks whether a .narinfo with a matching hash
// part exists. So f4kb...-foo matches f4kb...-bar, even // part exists. So f4kb...-foo matches f4kb...-bar, even
// though they shouldn't. Not easily fixed. // though they shouldn't. Not easily fixed.
@ -169,20 +112,20 @@ bool BinaryCacheStore::isValidPath(const Path & storePath)
void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink) void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
{ {
auto res = readNarInfo(storePath); auto info = queryPathInfo(storePath).cast<const NarInfo>();
auto nar = getFile(res.url); auto nar = getFile(info->url);
if (!nar) throw Error(format("file %s missing from binary cache") % res.url); if (!nar) throw Error(format("file %s missing from binary cache") % info->url);
stats.narRead++; stats.narRead++;
stats.narReadCompressedBytes += nar->size(); stats.narReadCompressedBytes += nar->size();
/* Decompress the NAR. FIXME: would be nice to have the remote /* Decompress the NAR. FIXME: would be nice to have the remote
side do this. */ side do this. */
if (res.compression == "none") if (info->compression == "none")
; ;
else if (res.compression == "xz") else if (info->compression == "xz")
nar = decompressXZ(*nar); nar = decompressXZ(*nar);
else else
throw Error(format("unknown NAR compression type %1%") % nar); throw Error(format("unknown NAR compression type %1%") % nar);
@ -200,13 +143,13 @@ void BinaryCacheStore::exportPath(const Path & storePath, bool sign, Sink & sink
{ {
assert(!sign); assert(!sign);
auto res = readNarInfo(storePath); auto res = queryPathInfo(storePath);
narFromPath(storePath, sink); narFromPath(storePath, sink);
// FIXME: check integrity of NAR. // FIXME: check integrity of NAR.
sink << exportMagic << storePath << res.references << res.deriver << 0; sink << exportMagic << storePath << res->references << res->deriver << 0;
} }
Paths BinaryCacheStore::importPaths(bool requireSignature, Source & source, Paths BinaryCacheStore::importPaths(bool requireSignature, Source & source,
@ -244,9 +187,24 @@ struct NopSink : ParseSink
{ {
}; };
ValidPathInfo BinaryCacheStore::queryPathInfo(const Path & storePath) std::shared_ptr<ValidPathInfo> BinaryCacheStore::queryPathInfoUncached(const Path & storePath)
{ {
return ValidPathInfo(readNarInfo(storePath)); auto narInfoFile = narInfoFileFor(storePath);
auto data = getFile(narInfoFile);
if (!data) return 0;
auto narInfo = make_ref<NarInfo>(*data, narInfoFile);
if (narInfo->path != storePath)
throw Error(format("NAR info file for store path %1% does not match %2%") % narInfo->path % storePath);
stats.narInfoRead++;
if (publicKeys) {
if (!narInfo->checkSignatures(*publicKeys))
throw Error(format("no good signature on NAR info file %1%") % narInfoFile);
}
return std::shared_ptr<NarInfo>(narInfo);
} }
void BinaryCacheStore::querySubstitutablePathInfos(const PathSet & paths, void BinaryCacheStore::querySubstitutablePathInfos(const PathSet & paths,
@ -257,16 +215,16 @@ void BinaryCacheStore::querySubstitutablePathInfos(const PathSet & paths,
if (!localStore) return; if (!localStore) return;
for (auto & storePath : paths) { for (auto & storePath : paths) {
if (!localStore->isValidPath(storePath)) { try {
left.insert(storePath); auto info = localStore->queryPathInfo(storePath);
continue;
}
ValidPathInfo info = localStore->queryPathInfo(storePath);
SubstitutablePathInfo sub; SubstitutablePathInfo sub;
sub.references = info.references; sub.references = info->references;
sub.downloadSize = 0; sub.downloadSize = 0;
sub.narSize = info.narSize; sub.narSize = info->narSize;
infos.emplace(storePath, sub); infos.emplace(storePath, sub);
} catch (InvalidPath &) {
left.insert(storePath);
}
} }
if (settings.useSubstitutes) if (settings.useSubstitutes)
@ -332,16 +290,16 @@ void BinaryCacheStore::buildPaths(const PathSet & paths, BuildMode buildMode)
if (!localStore->isValidPath(storePath)) if (!localStore->isValidPath(storePath))
localStore->ensurePath(storePath); localStore->ensurePath(storePath);
ValidPathInfo info = localStore->queryPathInfo(storePath); auto info = localStore->queryPathInfo(storePath);
for (auto & ref : info.references) for (auto & ref : info->references)
if (ref != storePath) if (ref != storePath)
ensurePath(ref); ensurePath(ref);
StringSink sink; StringSink sink;
dumpPath(storePath, sink); dumpPath(storePath, sink);
addToCache(info, *sink.s); addToCache(*info, *sink.s);
} }
} }

View file

@ -3,8 +3,6 @@
#include "crypto.hh" #include "crypto.hh"
#include "store-api.hh" #include "store-api.hh"
#include "lru-cache.hh"
#include "sync.hh"
#include "pool.hh" #include "pool.hh"
#include <atomic> #include <atomic>
@ -22,13 +20,6 @@ private:
std::shared_ptr<Store> localStore; std::shared_ptr<Store> localStore;
struct State
{
LRUCache<Path, std::shared_ptr<NarInfo>> narInfoCache{64 * 1024};
};
Sync<State> state;
protected: protected:
BinaryCacheStore(std::shared_ptr<Store> localStore, const Path & secretKeyFile); BinaryCacheStore(std::shared_ptr<Store> localStore, const Path & secretKeyFile);
@ -47,42 +38,17 @@ public:
virtual void init(); virtual void init();
struct Stats
{
std::atomic<uint64_t> narInfoRead{0};
std::atomic<uint64_t> narInfoReadAverted{0};
std::atomic<uint64_t> narInfoMissing{0};
std::atomic<uint64_t> narInfoWrite{0};
std::atomic<uint64_t> narInfoCacheSize{0};
std::atomic<uint64_t> narRead{0};
std::atomic<uint64_t> narReadBytes{0};
std::atomic<uint64_t> narReadCompressedBytes{0};
std::atomic<uint64_t> narWrite{0};
std::atomic<uint64_t> narWriteAverted{0};
std::atomic<uint64_t> narWriteBytes{0};
std::atomic<uint64_t> narWriteCompressedBytes{0};
std::atomic<uint64_t> narWriteCompressionTimeMs{0};
};
const Stats & getStats();
private: private:
Stats stats;
std::string narMagic; std::string narMagic;
std::string narInfoFileFor(const Path & storePath); std::string narInfoFileFor(const Path & storePath);
void addToCache(const ValidPathInfo & info, const string & nar); void addToCache(const ValidPathInfo & info, const string & nar);
protected:
NarInfo readNarInfo(const Path & storePath);
public: public:
bool isValidPath(const Path & path) override; bool isValidPathUncached(const Path & path) override;
PathSet queryValidPaths(const PathSet & paths) override PathSet queryValidPaths(const PathSet & paths) override
{ notImpl(); } { notImpl(); }
@ -90,18 +56,12 @@ public:
PathSet queryAllValidPaths() override PathSet queryAllValidPaths() override
{ notImpl(); } { notImpl(); }
ValidPathInfo queryPathInfo(const Path & path) override; std::shared_ptr<ValidPathInfo> queryPathInfoUncached(const Path & path) override;
Hash queryPathHash(const Path & path) override
{ notImpl(); }
void queryReferrers(const Path & path, void queryReferrers(const Path & path,
PathSet & referrers) override PathSet & referrers) override
{ notImpl(); } { notImpl(); }
Path queryDeriver(const Path & path) override
{ return ""; }
PathSet queryValidDerivers(const Path & path) override PathSet queryValidDerivers(const Path & path) override
{ return {}; } { return {}; }

View file

@ -2724,7 +2724,7 @@ void DerivationGoal::registerOutputs()
if (buildMode == bmCheck) { if (buildMode == bmCheck) {
if (!worker.store.isValidPath(path)) continue; if (!worker.store.isValidPath(path)) continue;
ValidPathInfo info = worker.store.queryPathInfo(path); auto info = *worker.store.queryPathInfo(path);
if (hash.first != info.narHash) { if (hash.first != info.narHash) {
if (settings.keepFailed) { if (settings.keepFailed) {
Path dst = path + checkSuffix; Path dst = path + checkSuffix;
@ -3778,14 +3778,14 @@ bool Worker::pathContentsGood(const Path & path)
std::map<Path, bool>::iterator i = pathContentsGoodCache.find(path); std::map<Path, bool>::iterator i = pathContentsGoodCache.find(path);
if (i != pathContentsGoodCache.end()) return i->second; if (i != pathContentsGoodCache.end()) return i->second;
printMsg(lvlInfo, format("checking path %1%...") % path); printMsg(lvlInfo, format("checking path %1%...") % path);
ValidPathInfo info = store.queryPathInfo(path); auto info = store.queryPathInfo(path);
bool res; bool res;
if (!pathExists(path)) if (!pathExists(path))
res = false; res = false;
else { else {
HashResult current = hashPath(info.narHash.type, path); HashResult current = hashPath(info->narHash.type, path);
Hash nullHash(htSHA256); Hash nullHash(htSHA256);
res = info.narHash == nullHash || info.narHash == current.first; res = info->narHash == nullHash || info->narHash == current.first;
} }
pathContentsGoodCache[path] = res; pathContentsGoodCache[path] = res;
if (!res) printMsg(lvlError, format("path %1% is corrupted or missing!") % path); if (!res) printMsg(lvlError, format("path %1% is corrupted or missing!") % path);
@ -3881,7 +3881,7 @@ void LocalStore::repairPath(const Path & path)
if (goal->getExitCode() != Goal::ecSuccess) { if (goal->getExitCode() != Goal::ecSuccess) {
/* Since substituting the path didn't work, if we have a valid /* Since substituting the path didn't work, if we have a valid
deriver, then rebuild the deriver. */ deriver, then rebuild the deriver. */
Path deriver = queryDeriver(path); auto deriver = queryPathInfo(path)->deriver;
if (deriver != "" && isValidPath(deriver)) { if (deriver != "" && isValidPath(deriver)) {
goals.clear(); goals.clear();
goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair)); goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair));

View file

@ -407,7 +407,7 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
queryReferrers(path, referrers); queryReferrers(path, referrers);
for (auto & i : referrers) for (auto & i : referrers)
if (i != path) deletePathRecursive(state, i); if (i != path) deletePathRecursive(state, i);
size = queryPathInfo(path).narSize; size = queryPathInfo(path)->narSize;
invalidatePathChecked(path); invalidatePathChecked(path);
} }
@ -485,7 +485,7 @@ bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & p
if (state.gcKeepDerivations && isDerivation(path)) { if (state.gcKeepDerivations && isDerivation(path)) {
PathSet outputs = queryDerivationOutputs(path); PathSet outputs = queryDerivationOutputs(path);
for (auto & i : outputs) for (auto & i : outputs)
if (isValidPath(i) && queryDeriver(i) == path) if (isValidPath(i) && queryPathInfo(i)->deriver == path)
incoming.insert(i); incoming.insert(i);
} }

View file

@ -577,6 +577,12 @@ uint64_t LocalStore::addValidPath(State & state,
} }
} }
{
auto state_(Store::state.lock());
state_->pathInfoCache.upsert(info.path, std::make_shared<ValidPathInfo>(info));
stats.pathInfoCacheSize = state_->pathInfoCache.size();
}
return id; return id;
} }
@ -595,44 +601,44 @@ Hash parseHashField(const Path & path, const string & s)
} }
ValidPathInfo LocalStore::queryPathInfo(const Path & path) std::shared_ptr<ValidPathInfo> LocalStore::queryPathInfoUncached(const Path & path)
{ {
ValidPathInfo info; auto info = std::make_shared<ValidPathInfo>();
info.path = path; info->path = path;
assertStorePath(path); assertStorePath(path);
return retrySQLite<ValidPathInfo>([&]() { return retrySQLite<std::shared_ptr<ValidPathInfo>>([&]() {
auto state(_state.lock()); auto state(_state.lock());
/* Get the path info. */ /* Get the path info. */
auto useQueryPathInfo(state->stmtQueryPathInfo.use()(path)); auto useQueryPathInfo(state->stmtQueryPathInfo.use()(path));
if (!useQueryPathInfo.next()) if (!useQueryPathInfo.next())
throw Error(format("path %1% is not valid") % path); return std::shared_ptr<ValidPathInfo>();
info.id = useQueryPathInfo.getInt(0); info->id = useQueryPathInfo.getInt(0);
info.narHash = parseHashField(path, useQueryPathInfo.getStr(1)); info->narHash = parseHashField(path, useQueryPathInfo.getStr(1));
info.registrationTime = useQueryPathInfo.getInt(2); info->registrationTime = useQueryPathInfo.getInt(2);
auto s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 3); auto s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 3);
if (s) info.deriver = s; if (s) info->deriver = s;
/* Note that narSize = NULL yields 0. */ /* Note that narSize = NULL yields 0. */
info.narSize = useQueryPathInfo.getInt(4); info->narSize = useQueryPathInfo.getInt(4);
info.ultimate = useQueryPathInfo.getInt(5) == 1; info->ultimate = useQueryPathInfo.getInt(5) == 1;
s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 6); s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 6);
if (s) info.sigs = tokenizeString<StringSet>(s, " "); if (s) info->sigs = tokenizeString<StringSet>(s, " ");
/* Get the references. */ /* Get the references. */
auto useQueryReferences(state->stmtQueryReferences.use()(info.id)); auto useQueryReferences(state->stmtQueryReferences.use()(info->id));
while (useQueryReferences.next()) while (useQueryReferences.next())
info.references.insert(useQueryReferences.getStr(0)); info->references.insert(useQueryReferences.getStr(0));
return info; return info;
}); });
@ -661,17 +667,17 @@ uint64_t LocalStore::queryValidPathId(State & state, const Path & path)
} }
bool LocalStore::isValidPath(State & state, const Path & path) bool LocalStore::isValidPath_(State & state, const Path & path)
{ {
return state.stmtQueryPathInfo.use()(path).next(); return state.stmtQueryPathInfo.use()(path).next();
} }
bool LocalStore::isValidPath(const Path & path) bool LocalStore::isValidPathUncached(const Path & path)
{ {
return retrySQLite<bool>([&]() { return retrySQLite<bool>([&]() {
auto state(_state.lock()); auto state(_state.lock());
return isValidPath(*state, path); return isValidPath_(*state, path);
}); });
} }
@ -716,12 +722,6 @@ void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
} }
Path LocalStore::queryDeriver(const Path & path)
{
return queryPathInfo(path).deriver;
}
PathSet LocalStore::queryValidDerivers(const Path & path) PathSet LocalStore::queryValidDerivers(const Path & path)
{ {
assertStorePath(path); assertStorePath(path);
@ -996,12 +996,6 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
} }
Hash LocalStore::queryPathHash(const Path & path)
{
return queryPathInfo(path).narHash;
}
void LocalStore::registerValidPath(const ValidPathInfo & info) void LocalStore::registerValidPath(const ValidPathInfo & info)
{ {
ValidPathInfos infos; ValidPathInfos infos;
@ -1026,7 +1020,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
for (auto & i : infos) { for (auto & i : infos) {
assert(i.narHash.type == htSHA256); assert(i.narHash.type == htSHA256);
if (isValidPath(*state, i.path)) if (isValidPath_(*state, i.path))
updatePathInfo(*state, i); updatePathInfo(*state, i);
else else
addValidPath(*state, i, false); addValidPath(*state, i, false);
@ -1071,6 +1065,12 @@ void LocalStore::invalidatePath(State & state, const Path & path)
/* Note that the foreign key constraints on the Refs table take /* Note that the foreign key constraints on the Refs table take
care of deleting the references entries for `path'. */ care of deleting the references entries for `path'. */
{
auto state_(Store::state.lock());
state_->pathInfoCache.erase(path);
stats.pathInfoCacheSize = state_->pathInfoCache.size();
}
} }
@ -1225,8 +1225,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
printMsg(lvlTalkative, format("exporting path %1%") % path); printMsg(lvlTalkative, format("exporting path %1%") % path);
if (!isValidPath(path)) auto info = queryPathInfo(path);
throw Error(format("path %1% is not valid") % path);
HashAndWriteSink hashAndWriteSink(sink); HashAndWriteSink hashAndWriteSink(sink);
@ -1236,15 +1235,11 @@ void LocalStore::exportPath(const Path & path, bool sign,
filesystem corruption from spreading to other machines. filesystem corruption from spreading to other machines.
Don't complain if the stored hash is zero (unknown). */ Don't complain if the stored hash is zero (unknown). */
Hash hash = hashAndWriteSink.currentHash(); Hash hash = hashAndWriteSink.currentHash();
Hash storedHash = queryPathHash(path); if (hash != info->narHash && info->narHash != Hash(info->narHash.type))
if (hash != storedHash && storedHash != Hash(storedHash.type))
throw Error(format("hash of path %1% has changed from %2% to %3%!") % path throw Error(format("hash of path %1% has changed from %2% to %3%!") % path
% printHash(storedHash) % printHash(hash)); % printHash(info->narHash) % printHash(hash));
PathSet references; hashAndWriteSink << exportMagic << path << info->references << info->deriver;
queryReferences(path, references);
hashAndWriteSink << exportMagic << path << references << queryDeriver(path);
if (sign) { if (sign) {
Hash hash = hashAndWriteSink.currentHash(); Hash hash = hashAndWriteSink.currentHash();
@ -1440,7 +1435,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
SQLiteTxn txn(state->db); SQLiteTxn txn(state->db);
if (isValidPath(*state, path)) { if (isValidPath_(*state, path)) {
PathSet referrers; queryReferrers(*state, path, referrers); PathSet referrers; queryReferrers(*state, path, referrers);
referrers.erase(path); /* ignore self-references */ referrers.erase(path); /* ignore self-references */
if (!referrers.empty()) if (!referrers.empty())
@ -1486,38 +1481,38 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
for (auto & i : validPaths) { for (auto & i : validPaths) {
try { try {
ValidPathInfo info = queryPathInfo(i); auto info = std::const_pointer_cast<ValidPathInfo>(std::shared_ptr<const ValidPathInfo>(queryPathInfo(i)));
/* Check the content hash (optionally - slow). */ /* Check the content hash (optionally - slow). */
printMsg(lvlTalkative, format("checking contents of %1%") % i); printMsg(lvlTalkative, format("checking contents of %1%") % i);
HashResult current = hashPath(info.narHash.type, i); HashResult current = hashPath(info->narHash.type, i);
if (info.narHash != nullHash && info.narHash != current.first) { if (info->narHash != nullHash && info->narHash != current.first) {
printMsg(lvlError, format("path %1% was modified! " printMsg(lvlError, format("path %1% was modified! "
"expected hash %2%, got %3%") "expected hash %2%, got %3%")
% i % printHash(info.narHash) % printHash(current.first)); % i % printHash(info->narHash) % printHash(current.first));
if (repair) repairPath(i); else errors = true; if (repair) repairPath(i); else errors = true;
} else { } else {
bool update = false; bool update = false;
/* Fill in missing hashes. */ /* Fill in missing hashes. */
if (info.narHash == nullHash) { if (info->narHash == nullHash) {
printMsg(lvlError, format("fixing missing hash on %1%") % i); printMsg(lvlError, format("fixing missing hash on %1%") % i);
info.narHash = current.first; info->narHash = current.first;
update = true; update = true;
} }
/* Fill in missing narSize fields (from old stores). */ /* Fill in missing narSize fields (from old stores). */
if (info.narSize == 0) { if (info->narSize == 0) {
printMsg(lvlError, format("updating size field on %1% to %2%") % i % current.second); printMsg(lvlError, format("updating size field on %1% to %2%") % i % current.second);
info.narSize = current.second; info->narSize = current.second;
update = true; update = true;
} }
if (update) { if (update) {
auto state(_state.lock()); auto state(_state.lock());
updatePathInfo(*state, info); updatePathInfo(*state, *info);
} }
} }
@ -1656,11 +1651,11 @@ void LocalStore::addSignatures(const Path & storePath, const StringSet & sigs)
SQLiteTxn txn(state->db); SQLiteTxn txn(state->db);
auto info = queryPathInfo(storePath); auto info = std::const_pointer_cast<ValidPathInfo>(std::shared_ptr<const ValidPathInfo>(queryPathInfo(storePath)));
info.sigs.insert(sigs.begin(), sigs.end()); info->sigs.insert(sigs.begin(), sigs.end());
updatePathInfo(*state, info); updatePathInfo(*state, *info);
txn.commit(); txn.commit();
}); });

View file

@ -102,20 +102,16 @@ public:
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */
bool isValidPath(const Path & path) override; bool isValidPathUncached(const Path & path) override;
PathSet queryValidPaths(const PathSet & paths) override; PathSet queryValidPaths(const PathSet & paths) override;
PathSet queryAllValidPaths() override; PathSet queryAllValidPaths() override;
ValidPathInfo queryPathInfo(const Path & path) override; std::shared_ptr<ValidPathInfo> queryPathInfoUncached(const Path & path) override;
Hash queryPathHash(const Path & path) override;
void queryReferrers(const Path & path, PathSet & referrers) override; void queryReferrers(const Path & path, PathSet & referrers) override;
Path queryDeriver(const Path & path) override;
PathSet queryValidDerivers(const Path & path) override; PathSet queryValidDerivers(const Path & path) override;
PathSet queryDerivationOutputs(const Path & path) override; PathSet queryDerivationOutputs(const Path & path) override;
@ -270,7 +266,7 @@ private:
void optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash); void optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash);
// Internal versions that are not wrapped in retry_sqlite. // Internal versions that are not wrapped in retry_sqlite.
bool isValidPath(State & state, const Path & path); bool isValidPath_(State & state, const Path & path);
void queryReferrers(State & state, const Path & path, PathSet & referrers); void queryReferrers(State & state, const Path & path, PathSet & referrers);
/* Add signatures to a ValidPathInfo using the secret keys /* Add signatures to a ValidPathInfo using the secret keys

View file

@ -35,12 +35,13 @@ void Store::computeFSClosure(const Path & path,
if (includeDerivers && isDerivation(path)) { if (includeDerivers && isDerivation(path)) {
PathSet outputs = queryDerivationOutputs(path); PathSet outputs = queryDerivationOutputs(path);
for (auto & i : outputs) for (auto & i : outputs)
if (isValidPath(i) && queryDeriver(i) == path) if (isValidPath(i) && queryPathInfo(i)->deriver == path)
edges.insert(i); edges.insert(i);
} }
} else { } else {
queryReferences(path, edges); auto info = queryPathInfo(path);
edges = info->references;
if (includeOutputs && isDerivation(path)) { if (includeOutputs && isDerivation(path)) {
PathSet outputs = queryDerivationOutputs(path); PathSet outputs = queryDerivationOutputs(path);
@ -48,10 +49,8 @@ void Store::computeFSClosure(const Path & path,
if (isValidPath(i)) edges.insert(i); if (isValidPath(i)) edges.insert(i);
} }
if (includeDerivers) { if (includeDerivers && isValidPath(info->deriver))
Path deriver = queryDeriver(path); edges.insert(info->deriver);
if (isValidPath(deriver)) edges.insert(deriver);
}
} }
for (auto & i : edges) for (auto & i : edges)
@ -189,8 +188,10 @@ Paths Store::topoSortPaths(const PathSet & paths)
parents.insert(path); parents.insert(path);
PathSet references; PathSet references;
if (isValidPath(path)) try {
queryReferences(path, references); references = queryPathInfo(path)->references;
} catch (InvalidPath &) {
}
for (auto & i : references) for (auto & i : references)
/* Don't traverse into paths that don't exist. That can /* Don't traverse into paths that don't exist. That can

View file

@ -141,7 +141,7 @@ void RemoteStore::setOptions(ref<Connection> conn)
} }
bool RemoteStore::isValidPath(const Path & path) bool RemoteStore::isValidPathUncached(const Path & path)
{ {
auto conn(connections->get()); auto conn(connections->get());
conn->to << wopIsValidPath << path; conn->to << wopIsValidPath << path;
@ -239,48 +239,27 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
} }
ValidPathInfo RemoteStore::queryPathInfo(const Path & path) std::shared_ptr<ValidPathInfo> RemoteStore::queryPathInfoUncached(const Path & path)
{ {
auto conn(connections->get()); auto conn(connections->get());
conn->to << wopQueryPathInfo << path; conn->to << wopQueryPathInfo << path;
conn->processStderr(); conn->processStderr();
ValidPathInfo info; auto info = std::make_shared<ValidPathInfo>();
info.path = path; info->path = path;
info.deriver = readString(conn->from); info->deriver = readString(conn->from);
if (info.deriver != "") assertStorePath(info.deriver); if (info->deriver != "") assertStorePath(info->deriver);
info.narHash = parseHash(htSHA256, readString(conn->from)); info->narHash = parseHash(htSHA256, readString(conn->from));
info.references = readStorePaths<PathSet>(conn->from); info->references = readStorePaths<PathSet>(conn->from);
info.registrationTime = readInt(conn->from); info->registrationTime = readInt(conn->from);
info.narSize = readLongLong(conn->from); info->narSize = readLongLong(conn->from);
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) { if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) {
info.ultimate = readInt(conn->from) != 0; info->ultimate = readInt(conn->from) != 0;
info.sigs = readStrings<StringSet>(conn->from); info->sigs = readStrings<StringSet>(conn->from);
} }
return info; return info;
} }
Hash RemoteStore::queryPathHash(const Path & path)
{
auto conn(connections->get());
conn->to << wopQueryPathHash << path;
conn->processStderr();
string hash = readString(conn->from);
return parseHash(htSHA256, hash);
}
void RemoteStore::queryReferences(const Path & path,
PathSet & references)
{
auto conn(connections->get());
conn->to << wopQueryReferences << path;
conn->processStderr();
PathSet references2 = readStorePaths<PathSet>(conn->from);
references.insert(references2.begin(), references2.end());
}
void RemoteStore::queryReferrers(const Path & path, void RemoteStore::queryReferrers(const Path & path,
PathSet & referrers) PathSet & referrers)
{ {
@ -292,17 +271,6 @@ void RemoteStore::queryReferrers(const Path & path,
} }
Path RemoteStore::queryDeriver(const Path & path)
{
auto conn(connections->get());
conn->to << wopQueryDeriver << path;
conn->processStderr();
Path drvPath = readString(conn->from);
if (drvPath != "") assertStorePath(drvPath);
return drvPath;
}
PathSet RemoteStore::queryValidDerivers(const Path & path) PathSet RemoteStore::queryValidDerivers(const Path & path)
{ {
auto conn(connections->get()); auto conn(connections->get());
@ -517,6 +485,12 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
results.paths = readStrings<PathSet>(conn->from); results.paths = readStrings<PathSet>(conn->from);
results.bytesFreed = readLongLong(conn->from); results.bytesFreed = readLongLong(conn->from);
readLongLong(conn->from); // obsolete readLongLong(conn->from); // obsolete
{
auto state_(Store::state.lock());
state_->pathInfoCache.clear();
stats.pathInfoCacheSize = 0;
}
} }

View file

@ -26,22 +26,16 @@ public:
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */
bool isValidPath(const Path & path) override; bool isValidPathUncached(const Path & path) override;
PathSet queryValidPaths(const PathSet & paths) override; PathSet queryValidPaths(const PathSet & paths) override;
PathSet queryAllValidPaths() override; PathSet queryAllValidPaths() override;
ValidPathInfo queryPathInfo(const Path & path) override; std::shared_ptr<ValidPathInfo> queryPathInfoUncached(const Path & path) override;
Hash queryPathHash(const Path & path) override;
void queryReferences(const Path & path, PathSet & references) override;
void queryReferrers(const Path & path, PathSet & referrers) override; void queryReferrers(const Path & path, PathSet & referrers) override;
Path queryDeriver(const Path & path) override;
PathSet queryValidDerivers(const Path & path) override; PathSet queryValidDerivers(const Path & path) override;
PathSet queryDerivationOutputs(const Path & path) override; PathSet queryDerivationOutputs(const Path & path) override;

View file

@ -225,10 +225,48 @@ Path computeStorePathForText(const string & name, const string & s,
} }
void Store::queryReferences(const Path & path, PathSet & references) bool Store::isValidPath(const Path & storePath)
{ {
ValidPathInfo info = queryPathInfo(path); {
references.insert(info.references.begin(), info.references.end()); auto state_(state.lock());
auto res = state_->pathInfoCache.get(storePath);
if (res) {
stats.narInfoReadAverted++;
return *res != 0;
}
}
return isValidPathUncached(storePath);
}
ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath)
{
{
auto state_(state.lock());
auto res = state_->pathInfoCache.get(storePath);
if (res) {
stats.narInfoReadAverted++;
if (!*res)
throw InvalidPath(format("path %s is not valid") % storePath);
return ref<ValidPathInfo>(*res);
}
}
auto info = queryPathInfoUncached(storePath);
{
auto state_(state.lock());
state_->pathInfoCache.upsert(storePath, info);
stats.pathInfoCacheSize = state_->pathInfoCache.size();
}
if (!info) {
stats.narInfoMissing++;
throw InvalidPath(format("path %s is not valid") % storePath);
}
return ref<ValidPathInfo>(info);
} }
@ -243,19 +281,19 @@ string Store::makeValidityRegistration(const PathSet & paths,
for (auto & i : paths) { for (auto & i : paths) {
s += i + "\n"; s += i + "\n";
ValidPathInfo info = queryPathInfo(i); auto info = queryPathInfo(i);
if (showHash) { if (showHash) {
s += printHash(info.narHash) + "\n"; s += printHash(info->narHash) + "\n";
s += (format("%1%\n") % info.narSize).str(); s += (format("%1%\n") % info->narSize).str();
} }
Path deriver = showDerivers ? info.deriver : ""; Path deriver = showDerivers ? info->deriver : "";
s += deriver + "\n"; s += deriver + "\n";
s += (format("%1%\n") % info.references.size()).str(); s += (format("%1%\n") % info->references.size()).str();
for (auto & j : info.references) for (auto & j : info->references)
s += j + "\n"; s += j + "\n";
} }
@ -263,6 +301,12 @@ string Store::makeValidityRegistration(const PathSet & paths,
} }
const Store::Stats & Store::getStats()
{
return stats;
}
ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven) ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
{ {
ValidPathInfo info; ValidPathInfo info;

View file

@ -3,11 +3,14 @@
#include "hash.hh" #include "hash.hh"
#include "serialise.hh" #include "serialise.hh"
#include "crypto.hh" #include "crypto.hh"
#include "lru-cache.hh"
#include "sync.hh"
#include <string> #include <atomic>
#include <limits> #include <limits>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string>
namespace nix { namespace nix {
@ -130,6 +133,8 @@ struct ValidPathInfo
/* Verify a single signature. */ /* Verify a single signature. */
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const; bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
virtual ~ValidPathInfo() { }
}; };
typedef list<ValidPathInfo> ValidPathInfos; typedef list<ValidPathInfo> ValidPathInfos;
@ -169,12 +174,27 @@ class FSAccessor;
class Store : public std::enable_shared_from_this<Store> class Store : public std::enable_shared_from_this<Store>
{ {
protected:
struct State
{
LRUCache<Path, std::shared_ptr<ValidPathInfo>> pathInfoCache{64 * 1024};
};
Sync<State> state;
public: public:
virtual ~Store() { } virtual ~Store() { }
/* Check whether a path is valid. */ /* Check whether a path is valid. */
virtual bool isValidPath(const Path & path) = 0; bool isValidPath(const Path & path);
protected:
virtual bool isValidPathUncached(const Path & path) = 0;
public:
/* Query which of the given paths is valid. */ /* Query which of the given paths is valid. */
virtual PathSet queryValidPaths(const PathSet & paths) = 0; virtual PathSet queryValidPaths(const PathSet & paths) = 0;
@ -183,24 +203,19 @@ public:
virtual PathSet queryAllValidPaths() = 0; virtual PathSet queryAllValidPaths() = 0;
/* Query information about a valid path. */ /* Query information about a valid path. */
virtual ValidPathInfo queryPathInfo(const Path & path) = 0; ref<const ValidPathInfo> queryPathInfo(const Path & path);
/* Query the hash of a valid path. */ protected:
virtual Hash queryPathHash(const Path & path) = 0;
/* Query the set of outgoing FS references for a store path. The virtual std::shared_ptr<ValidPathInfo> queryPathInfoUncached(const Path & path) = 0;
result is not cleared. */
virtual void queryReferences(const Path & path, PathSet & references); public:
/* Queries the set of incoming FS references for a store path. /* Queries the set of incoming FS references for a store path.
The result is not cleared. */ The result is not cleared. */
virtual void queryReferrers(const Path & path, virtual void queryReferrers(const Path & path,
PathSet & referrers) = 0; PathSet & referrers) = 0;
/* Query the deriver of a store path. Return the empty string if
no deriver has been set. */
virtual Path queryDeriver(const Path & path) = 0;
/* Return all currently valid derivations that have `path' as an /* Return all currently valid derivations that have `path' as an
output. (Note that the result of `queryDeriver()' is the output. (Note that the result of `queryDeriver()' is the
derivation that was actually used to produce `path', which may derivation that was actually used to produce `path', which may
@ -373,6 +388,29 @@ public:
relation. If p refers to q, then p preceeds q in this list. */ relation. If p refers to q, then p preceeds q in this list. */
Paths topoSortPaths(const PathSet & paths); Paths topoSortPaths(const PathSet & paths);
struct Stats
{
std::atomic<uint64_t> narInfoRead{0};
std::atomic<uint64_t> narInfoReadAverted{0};
std::atomic<uint64_t> narInfoMissing{0};
std::atomic<uint64_t> narInfoWrite{0};
std::atomic<uint64_t> pathInfoCacheSize{0};
std::atomic<uint64_t> narRead{0};
std::atomic<uint64_t> narReadBytes{0};
std::atomic<uint64_t> narReadCompressedBytes{0};
std::atomic<uint64_t> narWrite{0};
std::atomic<uint64_t> narWriteAverted{0};
std::atomic<uint64_t> narWriteBytes{0};
std::atomic<uint64_t> narWriteCompressedBytes{0};
std::atomic<uint64_t> narWriteCompressionTimeMs{0};
};
const Stats & getStats();
protected:
Stats stats;
}; };

View file

@ -14,8 +14,8 @@ namespace nix {
typedef enum { typedef enum {
wopIsValidPath = 1, wopIsValidPath = 1,
wopHasSubstitutes = 3, wopHasSubstitutes = 3,
wopQueryPathHash = 4, wopQueryPathHash = 4, // obsolete
wopQueryReferences = 5, wopQueryReferences = 5, // obsolete
wopQueryReferrers = 6, wopQueryReferrers = 6,
wopAddToStore = 7, wopAddToStore = 7,
wopAddTextToStore = 8, wopAddTextToStore = 8,
@ -26,7 +26,7 @@ typedef enum {
wopSyncWithGC = 13, wopSyncWithGC = 13,
wopFindRoots = 14, wopFindRoots = 14,
wopExportPath = 16, wopExportPath = 16,
wopQueryDeriver = 18, wopQueryDeriver = 18, // obsolete
wopSetOptions = 19, wopSetOptions = 19,
wopCollectGarbage = 20, wopCollectGarbage = 20,
wopQuerySubstitutablePathInfo = 21, wopQuerySubstitutablePathInfo = 21,

View file

@ -79,6 +79,12 @@ public:
{ {
return data.size(); return data.size();
} }
void clear()
{
data.clear();
lru.clear();
}
}; };
} }

View file

@ -43,6 +43,12 @@ public:
return p; return p;
} }
template<typename T2>
ref<T2> cast()
{
return ref<T2>(std::dynamic_pointer_cast<T2>(p));
}
template<typename T2> template<typename T2>
operator ref<T2> () operator ref<T2> ()
{ {

View file

@ -199,7 +199,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
case wopQueryPathHash: { case wopQueryPathHash: {
Path path = readStorePath(from); Path path = readStorePath(from);
startWork(); startWork();
Hash hash = store->queryPathHash(path); auto hash = store->queryPathInfo(path)->narHash;
stopWork(); stopWork();
to << printHash(hash); to << printHash(hash);
break; break;
@ -213,7 +213,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
startWork(); startWork();
PathSet paths; PathSet paths;
if (op == wopQueryReferences) if (op == wopQueryReferences)
store->queryReferences(path, paths); paths = store->queryPathInfo(path)->references;
else if (op == wopQueryReferrers) else if (op == wopQueryReferrers)
store->queryReferrers(path, paths); store->queryReferrers(path, paths);
else if (op == wopQueryValidDerivers) else if (op == wopQueryValidDerivers)
@ -237,7 +237,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
case wopQueryDeriver: { case wopQueryDeriver: {
Path path = readStorePath(from); Path path = readStorePath(from);
startWork(); startWork();
Path deriver = store->queryDeriver(path); auto deriver = store->queryPathInfo(path)->deriver;
stopWork(); stopWork();
to << deriver; to << deriver;
break; break;
@ -496,13 +496,13 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
case wopQueryPathInfo: { case wopQueryPathInfo: {
Path path = readStorePath(from); Path path = readStorePath(from);
startWork(); startWork();
ValidPathInfo info = store->queryPathInfo(path); auto info = store->queryPathInfo(path);
stopWork(); stopWork();
to << info.deriver << printHash(info.narHash) << info.references to << info->deriver << printHash(info->narHash) << info->references
<< info.registrationTime << info.narSize; << info->registrationTime << info->narSize;
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) { if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
to << info.ultimate to << info->ultimate
<< info.sigs; << info->sigs;
} }
break; break;
} }

View file

@ -110,19 +110,13 @@ void printDotGraph(ref<Store> store, const PathSet & roots)
cout << makeNode(path, symbolicName(path), "#ff0000"); cout << makeNode(path, symbolicName(path), "#ff0000");
PathSet references; for (auto & p : store->queryPathInfo(path)->references) {
store->queryReferences(path, references); if (p != path) {
workList.insert(p);
for (PathSet::iterator i = references.begin(); cout << makeEdge(p, path);
i != references.end(); ++i)
{
if (*i != path) {
workList.insert(*i);
cout << makeEdge(*i, path);
} }
} }
#if 0 #if 0
StoreExpr ne = storeExprFromPath(path); StoreExpr ne = storeExprFromPath(path);

View file

@ -51,7 +51,7 @@ ref<LocalStore> ensureLocalStore()
static Path useDeriver(Path path) static Path useDeriver(Path path)
{ {
if (isDerivation(path)) return path; if (isDerivation(path)) return path;
Path drvPath = store->queryDeriver(path); Path drvPath = store->queryPathInfo(path)->deriver;
if (drvPath == "") if (drvPath == "")
throw Error(format("deriver of path %1% is not known") % path); throw Error(format("deriver of path %1% is not known") % path);
return drvPath; return drvPath;
@ -247,8 +247,7 @@ static void printTree(const Path & path,
cout << format("%1%%2%\n") % firstPad % path; cout << format("%1%%2%\n") % firstPad % path;
PathSet references; auto references = store->queryPathInfo(path)->references;
store->queryReferences(path, references);
/* Topologically sort under the relation A < B iff A \in /* Topologically sort under the relation A < B iff A \in
closure(B). That is, if derivation A is an (possibly indirect) closure(B). That is, if derivation A is an (possibly indirect)
@ -335,7 +334,10 @@ static void opQuery(Strings opFlags, Strings opArgs)
PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : ps) { for (auto & j : ps) {
if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs); if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs);
else if (query == qReferences) store->queryReferences(j, paths); else if (query == qReferences) {
for (auto & p : store->queryPathInfo(j)->references)
paths.insert(p);
}
else if (query == qReferrers) store->queryReferrers(j, paths); else if (query == qReferrers) store->queryReferrers(j, paths);
else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true); else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true);
} }
@ -349,7 +351,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qDeriver: case qDeriver:
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path deriver = store->queryDeriver(followLinksToStorePath(i)); Path deriver = store->queryPathInfo(followLinksToStorePath(i))->deriver;
cout << format("%1%\n") % cout << format("%1%\n") %
(deriver == "" ? "unknown-deriver" : deriver); (deriver == "" ? "unknown-deriver" : deriver);
} }
@ -372,12 +374,12 @@ static void opQuery(Strings opFlags, Strings opArgs)
for (auto & i : opArgs) { for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : paths) { for (auto & j : paths) {
ValidPathInfo info = store->queryPathInfo(j); auto info = store->queryPathInfo(j);
if (query == qHash) { if (query == qHash) {
assert(info.narHash.type == htSHA256); assert(info->narHash.type == htSHA256);
cout << format("sha256:%1%\n") % printHash32(info.narHash); cout << format("sha256:%1%\n") % printHash32(info->narHash);
} else if (query == qSize) } else if (query == qSize)
cout << format("%1%\n") % info.narSize; cout << format("%1%\n") % info->narSize;
} }
} }
break; break;
@ -782,14 +784,14 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path path = followLinksToStorePath(i); Path path = followLinksToStorePath(i);
printMsg(lvlTalkative, format("checking path %1%...") % path); printMsg(lvlTalkative, format("checking path %1%...") % path);
ValidPathInfo info = store->queryPathInfo(path); auto info = store->queryPathInfo(path);
HashSink sink(info.narHash.type); HashSink sink(info->narHash.type);
store->narFromPath(path, sink); store->narFromPath(path, sink);
auto current = sink.finish(); auto current = sink.finish();
if (current.first != info.narHash) { if (current.first != info->narHash) {
printMsg(lvlError, printMsg(lvlError,
format("path %1% was modified! expected hash %2%, got %3%") format("path %1% was modified! expected hash %2%, got %3%")
% path % printHash(info.narHash) % printHash(current.first)); % path % printHash(info->narHash) % printHash(current.first));
status = 1; status = 1;
} }
} }
@ -901,13 +903,14 @@ static void opServe(Strings opFlags, Strings opArgs)
PathSet paths = readStorePaths<PathSet>(in); PathSet paths = readStorePaths<PathSet>(in);
// !!! Maybe we want a queryPathInfos? // !!! Maybe we want a queryPathInfos?
for (auto & i : paths) { for (auto & i : paths) {
if (!store->isValidPath(i)) try {
continue; auto info = store->queryPathInfo(i);
ValidPathInfo info = store->queryPathInfo(i); out << info->path << info->deriver << info->references;
out << info.path << info.deriver << info.references;
// !!! Maybe we want compression? // !!! Maybe we want compression?
out << info.narSize // downloadSize out << info->narSize // downloadSize
<< info.narSize; << info->narSize;
} catch (InvalidPath &) {
}
} }
out << ""; out << "";
break; break;

View file

@ -50,15 +50,10 @@ void printXmlGraph(ref<Store> store, const PathSet & roots)
cout << makeNode(path); cout << makeNode(path);
PathSet references; for (auto & p : store->queryPathInfo(path)->references) {
store->queryReferences(path, references); if (p != path) {
workList.insert(p);
for (PathSet::iterator i = references.begin(); cout << makeEdge(p, path);
i != references.end(); ++i)
{
if (*i != path) {
workList.insert(*i);
cout << makeEdge(*i, path);
} }
} }

View file

@ -64,19 +64,21 @@ struct CmdCopySigs : StorePathsCommand
StringSet newSigs; StringSet newSigs;
for (auto & store2 : substituters) { for (auto & store2 : substituters) {
if (!store2->isValidPath(storePath)) continue; try {
auto info2 = store2->queryPathInfo(storePath); auto info2 = store2->queryPathInfo(storePath);
/* Don't import signatures that don't match this /* Don't import signatures that don't match this
binary. */ binary. */
if (info.narHash != info2.narHash || if (info->narHash != info2->narHash ||
info.narSize != info2.narSize || info->narSize != info2->narSize ||
info.references != info2.references) info->references != info2->references)
continue; continue;
for (auto & sig : info2.sigs) for (auto & sig : info2->sigs)
if (!info.sigs.count(sig)) if (!info->sigs.count(sig))
newSigs.insert(sig); newSigs.insert(sig);
} catch (InvalidPath &) {
}
} }
if (!newSigs.empty()) { if (!newSigs.empty()) {
@ -122,8 +124,8 @@ struct CmdQueryPathSigs : StorePathsCommand
for (auto & storePath : storePaths) { for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath); auto info = store->queryPathInfo(storePath);
std::cout << storePath << " "; std::cout << storePath << " ";
if (info.ultimate) std::cout << "ultimate "; if (info->ultimate) std::cout << "ultimate ";
for (auto & sig : info.sigs) for (auto & sig : info->sigs)
std::cout << sig << " "; std::cout << sig << " ";
std::cout << "\n"; std::cout << "\n";
} }
@ -163,12 +165,12 @@ struct CmdSignPaths : StorePathsCommand
for (auto & storePath : storePaths) { for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath); auto info = store->queryPathInfo(storePath);
auto info2(info); auto info2(*info);
info2.sigs.clear(); info2.sigs.clear();
info2.sign(secretKey); info2.sign(secretKey);
assert(!info2.sigs.empty()); assert(!info2.sigs.empty());
if (!info.sigs.count(*info2.sigs.begin())) { if (!info->sigs.count(*info2.sigs.begin())) {
store->addSignatures(storePath, info2.sigs); store->addSignatures(storePath, info2.sigs);
added++; added++;
} }

View file

@ -83,16 +83,16 @@ struct CmdVerify : StorePathsCommand
if (!noContents) { if (!noContents) {
HashSink sink(info.narHash.type); HashSink sink(info->narHash.type);
store->narFromPath(storePath, sink); store->narFromPath(storePath, sink);
auto hash = sink.finish(); auto hash = sink.finish();
if (hash.first != info.narHash) { if (hash.first != info->narHash) {
corrupted = 1; corrupted = 1;
printMsg(lvlError, printMsg(lvlError,
format("path %s was modified! expected hash %s, got %s") format("path %s was modified! expected hash %s, got %s")
% storePath % printHash(info.narHash) % printHash(hash.first)); % storePath % printHash(info->narHash) % printHash(hash.first));
} }
} }
@ -101,7 +101,7 @@ struct CmdVerify : StorePathsCommand
bool good = false; bool good = false;
if (info.ultimate && !sigsNeeded) if (info->ultimate && !sigsNeeded)
good = true; good = true;
else { else {
@ -114,18 +114,18 @@ struct CmdVerify : StorePathsCommand
for (auto sig : sigs) { for (auto sig : sigs) {
if (sigsSeen.count(sig)) continue; if (sigsSeen.count(sig)) continue;
sigsSeen.insert(sig); sigsSeen.insert(sig);
if (info.checkSignature(publicKeys, sig)) if (info->checkSignature(publicKeys, sig))
validSigs++; validSigs++;
} }
}; };
doSigs(info.sigs); doSigs(info->sigs);
for (auto & store2 : substituters) { for (auto & store2 : substituters) {
if (validSigs >= actualSigsNeeded) break; if (validSigs >= actualSigsNeeded) break;
try { try {
if (!store2->isValidPath(storePath)) continue; doSigs(store2->queryPathInfo(storePath)->sigs);
doSigs(store2->queryPathInfo(storePath).sigs); } catch (InvalidPath &) {
} catch (Error & e) { } catch (Error & e) {
printMsg(lvlError, format(ANSI_RED "error:" ANSI_NORMAL " %s") % e.what()); printMsg(lvlError, format(ANSI_RED "error:" ANSI_NORMAL " %s") % e.what());
} }