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.
251kNotFound,252kFound,253kDeleted,254kCorrupt,255};256struct Saver {257SaverState state;258const Comparator* ucmp;259Slice user_key;260std::string* value;261};262} // namespace263static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {264Saver* s = reinterpret_cast<Saver*>(arg);265ParsedInternalKey parsed_key;266if (!ParseInternalKey(ikey, &parsed_key)) {267s->state = kCorrupt;268} else {269if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) {270s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted;271if (s->state == kFound) {272s->value->assign(v.data(), v.size());273}274}275}276}278static bool NewestFirst(FileMetaData* a, FileMetaData* b) {279return a->number > b->number;280}282void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,283bool (*func)(void*, int, FileMetaData*)) {284const Comparator* ucmp = vset_->icmp_.user_comparator();286// Search level-0 in order from newest to oldest.287std::vector<FileMetaData*> tmp;288tmp.reserve(files_[0].size());289for (uint32_t i = 0; i < files_[0].size(); i++) {290FileMetaData* f = files_[0][i];291if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&292ucmp->Compare(user_key, f->largest.user_key()) <= 0) {293tmp.push_back(f);294}295}296if (!tmp.empty()) {297std::sort(tmp.begin(), tmp.end(), NewestFirst);298for (uint32_t i = 0; i < tmp.size(); i++) {299if (!(*func)(arg, 0, tmp[i])) {300return;301}302}303}305// Search other levels.306for (int level = 1; level < config::kNumLevels; level++) {307size_t num_files = files_[level].size();308if (num_files == 0) continue;310// Binary search to find earliest index whose largest key >= internal_key.311uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);312if (index < num_files) {313FileMetaData* f = files_[level][index];314if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {315// All of "f" is past any data for user_key316} else {317if (!(*func)(arg, level, f)) {318return;319}320}321}322}323}325Status Version::Get(const ReadOptions& options, const LookupKey& k,326std::string* value, GetStats* stats) {327stats->seek_file = nullptr;328stats->seek_file_level = -1;330struct State {331Saver saver;332GetStats* stats;333const ReadOptions* options;334Slice ikey;335FileMetaData* last_file_read;336int last_file_read_level;338VersionSet* vset;339Status s;340bool found;342static bool Match(void* arg, int level, FileMetaData* f) {343State* state = reinterpret_cast<State*>(arg);345if (state->stats->seek_file == nullptr &&346state->last_file_read != nullptr) {347// We have had more than one seek for this read. Charge the 1st file.348state->stats->seek_file = state->last_file_read;349state->stats->seek_file_level = state->last_file_read_level;350}352state->last_file_read = f;353state->last_file_read_level = level;355state->s = state->vset->table_cache_->Get(*state->options, f->number,356f->file_size, state->ikey,357&state->saver, SaveValue);358if (!state->s.ok()) {359state->found = true;360return false;361}362switch (state->saver.state) {363case kNotFound:364return true; // Keep searching in other files365case kFound:366state->found = true;367return false;368case kDeleted:369return false;370case kCorrupt:371state->s =372Status::Corruption("corrupted key for ", state->saver.user_key);373state->found = true;374return false;375}377// Not reached. Added to avoid false compilation warnings of378// "control reaches end of non-void function".379return false;380}381};383State state;384state.found = false;385state.stats = stats;386state.last_file_read = nullptr;387state.last_file_read_level = -1;389state.options = &options;390state.ikey = k.internal_key();391state.vset = vset_;393state.saver.state = kNotFound;394state.saver.ucmp = vset_->icmp_.user_comparator();395state.saver.user_key = k.user_key();396state.saver.value = value;398ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match);400return state.found ? state.s : Status::NotFound(Slice());401}403bool Version::UpdateStats(const GetStats& /*stats*/) {404// Disable automatic compactions triggered by read seek counters.405// The heuristic was tuned for expensive random seeks and can create406// severe write amplification on large random-key databases.407// Size and manual compactions still run.408return false;409}411bool Version::RecordReadSample(Slice internal_key) {412ParsedInternalKey ikey;413if (!ParseInternalKey(internal_key, &ikey)) {414return false;415}417struct State {418GetStats stats; // Holds first matching file419int matches;421static bool Match(void* arg, int level, FileMetaData* f) {422State* state = reinterpret_cast<State*>(arg);423state->matches++;424if (state->matches == 1) {425// Remember first match.426state->stats.seek_file = f;427state->stats.seek_file_level = level;428}429// We can stop iterating once we have a second match.430return state->matches < 2;431}432};434State state;435state.matches = 0;436ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match);438// Must have at least two matches since we want to merge across439// files. But what if we have a single file that contains many440// overwrites and deletions? Should we have another mechanism for441// finding such files?442if (state.matches >= 2) {443// 1MB cost is about 1 seek (see comment in Builder::Apply).444return UpdateStats(state.stats);445}446return false;447}449void Version::Ref() { ++refs_; }451void Version::Unref() {452assert(this != &vset_->dummy_versions_);453assert(refs_ >= 1);454--refs_;455if (refs_ == 0) {456delete this;457}458}460bool Version::OverlapInLevel(int level, const Slice* smallest_user_key,461const Slice* largest_user_key) {462return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level],463smallest_user_key, largest_user_key);464}466int Version::PickLevelForMemTableOutput(const Slice& smallest_user_key,467const Slice& largest_user_key) {468int level = 0;469if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) {470// Push to next level if there is no overlap in next level,471// and the #bytes overlapping in the level after that are limited.472InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek);473InternalKey limit(largest_user_key, 0, static_cast<ValueType>(0));474std::vector<FileMetaData*> overlaps;475while (level < config::kMaxMemCompactLevel) {476if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {477break;478}479if (level + 2 < config::kNumLevels) {480// Check that file does not overlap too many grandparent bytes.481GetOverlappingInputs(level + 2, &start, &limit, &overlaps);482const int64_t sum = TotalFileSize(overlaps);483if (sum > MaxGrandParentOverlapBytes(vset_->options_)) {484break;485}486}487level++;488}489}490return level;491}493// Store in "*inputs" all files in "level" that overlap [begin,end]494void Version::GetOverlappingInputs(int level, const InternalKey* begin,495const InternalKey* end,496std::vector<FileMetaData*>* inputs) {497assert(level >= 0);498assert(level < config::kNumLevels);499inputs->clear();500Slice user_begin, user_end;
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.