forked from lix-project/hydra
Cache .narinfo lookups
This commit is contained in:
parent
a0f74047da
commit
bd76f9120a
|
@ -1,4 +1,5 @@
|
||||||
#include "binary-cache-store.hh"
|
#include "binary-cache-store.hh"
|
||||||
|
#include "sync.hh"
|
||||||
|
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "compression.hh"
|
#include "compression.hh"
|
||||||
|
@ -93,18 +94,33 @@ void BinaryCacheStore::addToCache(const ValidPathInfo & info,
|
||||||
|
|
||||||
NarInfo BinaryCacheStore::readNarInfo(const Path & storePath)
|
NarInfo BinaryCacheStore::readNarInfo(const Path & storePath)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
auto state_(state.lock());
|
||||||
|
auto res = state_->narInfoCache.get(storePath);
|
||||||
|
if (res) {
|
||||||
|
stats.narInfoReadAverted++;
|
||||||
|
return **res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stats.narInfoRead++;
|
stats.narInfoRead++;
|
||||||
|
|
||||||
auto narInfoFile = narInfoFileFor(storePath);
|
auto narInfoFile = narInfoFileFor(storePath);
|
||||||
auto narInfo = NarInfo(getFile(narInfoFile), narInfoFile);
|
auto narInfo = make_ref<NarInfo>(getFile(narInfoFile), narInfoFile);
|
||||||
assert(narInfo.path == storePath);
|
assert(narInfo->path == storePath);
|
||||||
|
|
||||||
if (publicKeys) {
|
if (publicKeys) {
|
||||||
if (!narInfo.checkSignature(*publicKeys))
|
if (!narInfo->checkSignature(*publicKeys))
|
||||||
throw Error(format("invalid signature on NAR info file ‘%1%’") % narInfoFile);
|
throw Error(format("invalid signature on NAR info file ‘%1%’") % narInfoFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return narInfo;
|
{
|
||||||
|
auto state_(state.lock());
|
||||||
|
state_->narInfoCache.upsert(storePath, narInfo);
|
||||||
|
stats.narInfoCacheSize = state_->narInfoCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *narInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BinaryCacheStore::isValidPath(const Path & storePath)
|
bool BinaryCacheStore::isValidPath(const Path & storePath)
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include "crypto.hh"
|
#include "crypto.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
#include "lru-cache.hh"
|
||||||
|
#include "sync.hh"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -23,6 +26,13 @@ private:
|
||||||
|
|
||||||
StoreFactory storeFactory;
|
StoreFactory storeFactory;
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
LRUCache<Path, ref<NarInfo>> narInfoCache{32 * 1024};
|
||||||
|
};
|
||||||
|
|
||||||
|
Sync<State> state;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
BinaryCacheStore(const StoreFactory & storeFactory,
|
BinaryCacheStore(const StoreFactory & storeFactory,
|
||||||
|
@ -41,7 +51,9 @@ public:
|
||||||
struct Stats
|
struct Stats
|
||||||
{
|
{
|
||||||
std::atomic<uint64_t> narInfoRead{0};
|
std::atomic<uint64_t> narInfoRead{0};
|
||||||
|
std::atomic<uint64_t> narInfoReadAverted{0};
|
||||||
std::atomic<uint64_t> narInfoWrite{0};
|
std::atomic<uint64_t> narInfoWrite{0};
|
||||||
|
std::atomic<uint64_t> narInfoCacheSize{0};
|
||||||
std::atomic<uint64_t> narRead{0};
|
std::atomic<uint64_t> narRead{0};
|
||||||
std::atomic<uint64_t> narReadBytes{0};
|
std::atomic<uint64_t> narReadBytes{0};
|
||||||
std::atomic<uint64_t> narReadCompressedBytes{0};
|
std::atomic<uint64_t> narReadCompressedBytes{0};
|
||||||
|
|
|
@ -591,7 +591,9 @@ void State::dumpStatus(Connection & conn, bool log)
|
||||||
|
|
||||||
auto & stats = store->getStats();
|
auto & stats = store->getStats();
|
||||||
nested.attr("narInfoRead", stats.narInfoRead);
|
nested.attr("narInfoRead", stats.narInfoRead);
|
||||||
|
nested.attr("narInfoReadAverted", stats.narInfoReadAverted);
|
||||||
nested.attr("narInfoWrite", stats.narInfoWrite);
|
nested.attr("narInfoWrite", stats.narInfoWrite);
|
||||||
|
nested.attr("narInfoCacheSize", stats.narInfoCacheSize);
|
||||||
nested.attr("narRead", stats.narRead);
|
nested.attr("narRead", stats.narRead);
|
||||||
nested.attr("narReadBytes", stats.narReadBytes);
|
nested.attr("narReadBytes", stats.narReadBytes);
|
||||||
nested.attr("narReadCompressedBytes", stats.narReadCompressedBytes);
|
nested.attr("narReadCompressedBytes", stats.narReadCompressedBytes);
|
||||||
|
|
80
src/hydra-queue-runner/lru-cache.hh
Normal file
80
src/hydra-queue-runner/lru-cache.hh
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
/* A simple least-recently used cache. Not thread-safe. */
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
class LRUCache
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
size_t maxSize;
|
||||||
|
|
||||||
|
// Stupid wrapper to get around circular dependency between Data
|
||||||
|
// and LRU.
|
||||||
|
struct LRUIterator;
|
||||||
|
|
||||||
|
using Data = std::map<Key, std::pair<LRUIterator, Value>>;
|
||||||
|
using LRU = std::list<typename Data::iterator>;
|
||||||
|
|
||||||
|
struct LRUIterator { typename LRU::iterator it; };
|
||||||
|
|
||||||
|
Data data;
|
||||||
|
LRU lru;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
LRUCache(size_t maxSize) : maxSize(maxSize) { }
|
||||||
|
|
||||||
|
/* Insert or upsert an item in the cache. */
|
||||||
|
void upsert(const Key & key, const Value & value)
|
||||||
|
{
|
||||||
|
erase(key);
|
||||||
|
|
||||||
|
if (data.size() >= maxSize) {
|
||||||
|
/* Retire the oldest item. */
|
||||||
|
auto oldest = lru.begin();
|
||||||
|
data.erase(*oldest);
|
||||||
|
lru.erase(oldest);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = data.emplace(key, std::make_pair(LRUIterator(), value));
|
||||||
|
assert(res.second);
|
||||||
|
auto & i(res.first);
|
||||||
|
|
||||||
|
auto j = lru.insert(lru.end(), i);
|
||||||
|
|
||||||
|
i->second.first.it = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase(const Key & key)
|
||||||
|
{
|
||||||
|
auto i = data.find(key);
|
||||||
|
if (i == data.end()) return false;
|
||||||
|
lru.erase(i->second.first.it);
|
||||||
|
data.erase(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look up an item in the cache. If it's exists, it becomes the
|
||||||
|
most recently used item. */
|
||||||
|
// FIXME: use boost::optional?
|
||||||
|
Value * get(const Key & key)
|
||||||
|
{
|
||||||
|
auto i = data.find(key);
|
||||||
|
if (i == data.end()) return 0;
|
||||||
|
|
||||||
|
/* Move this item to the back of the LRU list. */
|
||||||
|
lru.erase(i->second.first.it);
|
||||||
|
auto j = lru.insert(lru.end(), i);
|
||||||
|
i->second.first.it = j;
|
||||||
|
|
||||||
|
return &i->second.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue