diff --git a/include/leveldb/cache.h b/include/leveldb/cache.h index 1a201e5..5f86cd0 100644 --- a/include/leveldb/cache.h +++ b/include/leveldb/cache.h @@ -81,6 +81,13 @@ class Cache { // its cache keys. virtual uint64_t NewId() = 0; + // Remove all cache entries that are not actively in use. Memory-constrained + // applications may wish to call this method to reduce memory usage. + // Default implementation of Prune() does nothing. Subclasses are strongly + // encouraged to override the default implementation. A future release of + // leveldb may change Prune() to a pure abstract method. + virtual void Prune() {} + private: void LRU_Remove(Handle* e); void LRU_Append(Handle* e); diff --git a/util/cache.cc b/util/cache.cc index 8b197bc..7f5fc07 100644 --- a/util/cache.cc +++ b/util/cache.cc @@ -147,6 +147,7 @@ class LRUCache { Cache::Handle* Lookup(const Slice& key, uint32_t hash); void Release(Cache::Handle* handle); void Erase(const Slice& key, uint32_t hash); + void Prune(); private: void LRU_Remove(LRUHandle* e); @@ -264,6 +265,19 @@ void LRUCache::Erase(const Slice& key, uint32_t hash) { } } +void LRUCache::Prune() { + MutexLock l(&mutex_); + for (LRUHandle* e = lru_.next; e != &lru_; ) { + LRUHandle* next = e->next; + if (e->refs == 1) { + table_.Remove(e->key(), e->hash); + LRU_Remove(e); + Unref(e); + } + e = next; + } +} + static const int kNumShardBits = 4; static const int kNumShards = 1 << kNumShardBits; @@ -314,6 +328,11 @@ class ShardedLRUCache : public Cache { MutexLock l(&id_mutex_); return ++(last_id_); } + virtual void Prune() { + for (int s = 0; s < kNumShards; s++) { + shard_[s].Prune(); + } + } }; } // end anonymous namespace diff --git a/util/cache_test.cc b/util/cache_test.cc index 4371671..90af5fe 100644 --- a/util/cache_test.cc +++ b/util/cache_test.cc @@ -179,6 +179,19 @@ TEST(CacheTest, NewId) { ASSERT_NE(a, b); } +TEST(CacheTest, Prune) { + Insert(1, 100); + Insert(2, 200); + + Cache::Handle* handle = cache_->Lookup(EncodeKey(1)); + ASSERT_TRUE(handle); + cache_->Prune(); + cache_->Release(handle); + + ASSERT_EQ(100, Lookup(1)); + ASSERT_EQ(-1, Lookup(2)); +} + } // namespace leveldb int main(int argc, char** argv) {