Cache .narinfo lookups

This commit is contained in:
Eelco Dolstra 2016-02-19 16:19:40 +01:00
parent a0f74047da
commit bd76f9120a
5 changed files with 115 additions and 5 deletions

View file

@ -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)

View file

@ -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};

View file

@ -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);

View 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();
}
};

View file

@ -20,7 +20,7 @@
scope. scope.
*/ */
template <class T> template<class T>
class Sync class Sync
{ {
private: private: