Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011 The LevelDB Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file. See the AUTHORS file for names of contributors.5#include "leveldb/cache.h"7#include <vector>8#include "util/coding.h"9#include "util/testharness.h"11namespace leveldb {13// Conversions between numeric keys/values and the types expected by Cache.14static std::string EncodeKey(int k) {15std::string result;16PutFixed32(&result, k);17return result;18}19static int DecodeKey(const Slice& k) {20assert(k.size() == 4);21return DecodeFixed32(k.data());22}23static void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); }24static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); }26class CacheTest {27public:28static void Deleter(const Slice& key, void* v) {29current_->deleted_keys_.push_back(DecodeKey(key));30current_->deleted_values_.push_back(DecodeValue(v));31}33static const int kCacheSize = 1000;34std::vector<int> deleted_keys_;35std::vector<int> deleted_values_;36Cache* cache_;38CacheTest() : cache_(NewLRUCache(kCacheSize)) { current_ = this; }40~CacheTest() { delete cache_; }42int Lookup(int key) {43Cache::Handle* handle = cache_->Lookup(EncodeKey(key));44const int r = (handle == nullptr) ? -1 : DecodeValue(cache_->Value(handle));45if (handle != nullptr) {46cache_->Release(handle);47}48return r;49}51void Insert(int key, int value, int charge = 1) {52cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge,53&CacheTest::Deleter));54}56Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) {57return cache_->Insert(EncodeKey(key), EncodeValue(value), charge,58&CacheTest::Deleter);59}61void Erase(int key) { cache_->Erase(EncodeKey(key)); }63static CacheTest* current_;64};65CacheTest* CacheTest::current_;67TEST(CacheTest, HitAndMiss) {68ASSERT_EQ(-1, Lookup(100));70Insert(100, 101);71ASSERT_EQ(101, Lookup(100));72ASSERT_EQ(-1, Lookup(200));73ASSERT_EQ(-1, Lookup(300));75Insert(200, 201);76ASSERT_EQ(101, Lookup(100));77ASSERT_EQ(201, Lookup(200));78ASSERT_EQ(-1, Lookup(300));80Insert(100, 102);81ASSERT_EQ(102, Lookup(100));82ASSERT_EQ(201, Lookup(200));83ASSERT_EQ(-1, Lookup(300));85ASSERT_EQ(1, deleted_keys_.size());86ASSERT_EQ(100, deleted_keys_[0]);87ASSERT_EQ(101, deleted_values_[0]);88}90TEST(CacheTest, Erase) {91Erase(200);92ASSERT_EQ(0, deleted_keys_.size());94Insert(100, 101);95Insert(200, 201);96Erase(100);97ASSERT_EQ(-1, Lookup(100));98ASSERT_EQ(201, Lookup(200));99ASSERT_EQ(1, deleted_keys_.size());100ASSERT_EQ(100, deleted_keys_[0]);101ASSERT_EQ(101, deleted_values_[0]);103Erase(100);104ASSERT_EQ(-1, Lookup(100));105ASSERT_EQ(201, Lookup(200));106ASSERT_EQ(1, deleted_keys_.size());107}109TEST(CacheTest, EntriesArePinned) {110Insert(100, 101);111Cache::Handle* h1 = cache_->Lookup(EncodeKey(100));112ASSERT_EQ(101, DecodeValue(cache_->Value(h1)));114Insert(100, 102);115Cache::Handle* h2 = cache_->Lookup(EncodeKey(100));116ASSERT_EQ(102, DecodeValue(cache_->Value(h2)));117ASSERT_EQ(0, deleted_keys_.size());119cache_->Release(h1);120ASSERT_EQ(1, deleted_keys_.size());121ASSERT_EQ(100, deleted_keys_[0]);122ASSERT_EQ(101, deleted_values_[0]);124Erase(100);125ASSERT_EQ(-1, Lookup(100));126ASSERT_EQ(1, deleted_keys_.size());128cache_->Release(h2);129ASSERT_EQ(2, deleted_keys_.size());130ASSERT_EQ(100, deleted_keys_[1]);131ASSERT_EQ(102, deleted_values_[1]);132}134TEST(CacheTest, EvictionPolicy) {135Insert(100, 101);136Insert(200, 201);137Insert(300, 301);138Cache::Handle* h = cache_->Lookup(EncodeKey(300));140// Frequently used entry must be kept around,141// as must things that are still in use.142for (int i = 0; i < kCacheSize + 100; i++) {143Insert(1000 + i, 2000 + i);144ASSERT_EQ(2000 + i, Lookup(1000 + i));145ASSERT_EQ(101, Lookup(100));146}147ASSERT_EQ(101, Lookup(100));148ASSERT_EQ(-1, Lookup(200));149ASSERT_EQ(301, Lookup(300));150cache_->Release(h);151}153TEST(CacheTest, UseExceedsCacheSize) {154// Overfill the cache, keeping handles on all inserted entries.155std::vector<Cache::Handle*> h;156for (int i = 0; i < kCacheSize + 100; i++) {157h.push_back(InsertAndReturnHandle(1000 + i, 2000 + i));158}160// Check that all the entries can be found in the cache.161for (int i = 0; i < h.size(); i++) {162ASSERT_EQ(2000 + i, Lookup(1000 + i));163}165for (int i = 0; i < h.size(); i++) {166cache_->Release(h[i]);167}168}170TEST(CacheTest, HeavyEntries) {171// Add a bunch of light and heavy entries and then count the combined172// size of items still in the cache, which must be approximately the173// same as the total capacity.174const int kLight = 1;175const int kHeavy = 10;176int added = 0;177int index = 0;178while (added < 2 * kCacheSize) {179const int weight = (index & 1) ? kLight : kHeavy;180Insert(index, 1000 + index, weight);181added += weight;182index++;183}185int cached_weight = 0;186for (int i = 0; i < index; i++) {187const int weight = (i & 1 ? kLight : kHeavy);188int r = Lookup(i);189if (r >= 0) {190cached_weight += weight;191ASSERT_EQ(1000 + i, r);192}193}194ASSERT_LE(cached_weight, kCacheSize + kCacheSize / 10);195}197TEST(CacheTest, NewId) {198uint64_t a = cache_->NewId();199uint64_t b = cache_->NewId();200ASSERT_NE(a, b);201}203TEST(CacheTest, Prune) {204Insert(1, 100);205Insert(2, 200);207Cache::Handle* handle = cache_->Lookup(EncodeKey(1));208ASSERT_TRUE(handle);209cache_->Prune();210cache_->Release(handle);212ASSERT_EQ(100, Lookup(1));213ASSERT_EQ(-1, Lookup(2));214}216TEST(CacheTest, ZeroSizeCache) {217delete cache_;218cache_ = NewLRUCache(0);220Insert(1, 100);221ASSERT_EQ(-1, Lookup(1));222}224} // namespace leveldb226int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.