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 "db/version_set.h"7#include <stdio.h>9#include <algorithm>11#include "db/filename.h"12#include "db/log_reader.h"13#include "db/log_writer.h"14#include "db/memtable.h"15#include "db/table_cache.h"16#include "leveldb/env.h"17#include "leveldb/table_builder.h"18#include "table/merger.h"19#include "table/two_level_iterator.h"20#include "util/coding.h"21#include "util/logging.h"23namespace leveldb {25static size_t TargetFileSize(const Options* options) {26return options->max_file_size;27}29// Maximum bytes of overlaps in grandparent (i.e., level+2) before we30// stop building a single file in a level->level+1 compaction.31static int64_t MaxGrandParentOverlapBytes(const Options* options) {32return 10 * TargetFileSize(options);33}35// Maximum number of bytes in all compacted files. We avoid expanding36// the lower level file set of a compaction if it would make the37// total compaction cover more than this many bytes.38static int64_t ExpandedCompactionByteSizeLimit(const Options* options) {39return 25 * TargetFileSize(options);40}42static double MaxBytesForLevel(const Options* options, int level) {43// Note: the result for level zero is not really used since we set44// the level-0 compaction threshold based on number of files.46// Result for both level-0 and level-147double result = 10. * 1048576.0;48while (level > 1) {49result *= 10;50level--;51}52return result;53}55static uint64_t MaxFileSizeForLevel(const Options* options, int level) {56// We could vary per level to reduce number of files?57return TargetFileSize(options);58}60static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {61int64_t sum = 0;62for (size_t i = 0; i < files.size(); i++) {63sum += files[i]->file_size;64}65return sum;66}68Version::~Version() {69assert(refs_ == 0);71// Remove from linked list72prev_->next_ = next_;73next_->prev_ = prev_;75// Drop references to files76for (int level = 0; level < config::kNumLevels; level++) {77for (size_t i = 0; i < files_[level].size(); i++) {78FileMetaData* f = files_[level][i];79assert(f->refs > 0);80f->refs--;81if (f->refs <= 0) {82delete f;83}84}85}86}88int FindFile(const InternalKeyComparator& icmp,89const std::vector<FileMetaData*>& files, const Slice& key) {90uint32_t left = 0;91uint32_t right = files.size();92while (left < right) {93uint32_t mid = (left + right) / 2;94const FileMetaData* f = files[mid];95if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {96// Key at "mid.largest" is < "target". Therefore all97// files at or before "mid" are uninteresting.98left = mid + 1;99} else {100// Key at "mid.largest" is >= "target". Therefore all files101// after "mid" are uninteresting.102right = mid;103}104}105return right;106}108static bool AfterFile(const Comparator* ucmp, const Slice* user_key,109const FileMetaData* f) {110// null user_key occurs before all keys and is therefore never after *f111return (user_key != nullptr &&112ucmp->Compare(*user_key, f->largest.user_key()) > 0);113}115static bool BeforeFile(const Comparator* ucmp, const Slice* user_key,116const FileMetaData* f) {117// null user_key occurs after all keys and is therefore never before *f118return (user_key != nullptr &&119ucmp->Compare(*user_key, f->smallest.user_key()) < 0);120}122bool SomeFileOverlapsRange(const InternalKeyComparator& icmp,123bool disjoint_sorted_files,124const std::vector<FileMetaData*>& files,125const Slice* smallest_user_key,126const Slice* largest_user_key) {127const Comparator* ucmp = icmp.user_comparator();128if (!disjoint_sorted_files) {129// Need to check against all files130for (size_t i = 0; i < files.size(); i++) {131const FileMetaData* f = files[i];132if (AfterFile(ucmp, smallest_user_key, f) ||133BeforeFile(ucmp, largest_user_key, f)) {134// No overlap135} else {136return true; // Overlap137}138}139return false;140}142// Binary search over file list143uint32_t index = 0;144if (smallest_user_key != nullptr) {145// Find the earliest possible internal key for smallest_user_key146InternalKey small_key(*smallest_user_key, kMaxSequenceNumber,147kValueTypeForSeek);148index = FindFile(icmp, files, small_key.Encode());149}151if (index >= files.size()) {152// beginning of range is after all files, so no overlap.153return false;154}156return !BeforeFile(ucmp, largest_user_key, files[index]);157}159// An internal iterator. For a given version/level pair, yields160// information about the files in the level. For a given entry, key()161// is the largest key that occurs in the file, and value() is an162// 16-byte value containing the file number and file size, both163// encoded using EncodeFixed64.164class Version::LevelFileNumIterator : public Iterator {165public:166LevelFileNumIterator(const InternalKeyComparator& icmp,167const std::vector<FileMetaData*>* flist)168: icmp_(icmp), flist_(flist), index_(flist->size()) { // Marks as invalid169}170bool Valid() const override { return index_ < flist_->size(); }171void Seek(const Slice& target) override {172index_ = FindFile(icmp_, *flist_, target);173}174void SeekToFirst() override { index_ = 0; }175void SeekToLast() override {176index_ = flist_->empty() ? 0 : flist_->size() - 1;177}178void Next() override {179assert(Valid());180index_++;181}182void Prev() override {183assert(Valid());184if (index_ == 0) {185index_ = flist_->size(); // Marks as invalid186} else {187index_--;188}189}190Slice key() const override {191assert(Valid());192return (*flist_)[index_]->largest.Encode();193}194Slice value() const override {195assert(Valid());196EncodeFixed64(value_buf_, (*flist_)[index_]->number);197EncodeFixed64(value_buf_ + 8, (*flist_)[index_]->file_size);198return Slice(value_buf_, sizeof(value_buf_));199}200Status status() const override { return Status::OK(); }202private:203const InternalKeyComparator icmp_;204const std::vector<FileMetaData*>* const flist_;205uint32_t index_;207// Backing store for value(). Holds the file number and size.208mutable char value_buf_[16];209};211static Iterator* GetFileIterator(void* arg, const ReadOptions& options,212const Slice& file_value) {213TableCache* cache = reinterpret_cast<TableCache*>(arg);214if (file_value.size() != 16) {215return NewErrorIterator(216Status::Corruption("FileReader invoked with unexpected value"));217} else {218return cache->NewIterator(options, DecodeFixed64(file_value.data()),219DecodeFixed64(file_value.data() + 8));220}221}223Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,224int level) const {225return NewTwoLevelIterator(226new LevelFileNumIterator(vset_->icmp_, &files_[level]), &GetFileIterator,227vset_->table_cache_, options);228}230void Version::AddIterators(const ReadOptions& options,231std::vector<Iterator*>* iters) {232// Merge all level zero files together since they may overlap233for (size_t i = 0; i < files_[0].size(); i++) {234iters->push_back(vset_->table_cache_->NewIterator(235options, files_[0][i]->number, files_[0][i]->file_size));236}238// For levels > 0, we can use a concatenating iterator that sequentially239// walks through the non-overlapping files in the level, opening them240// lazily.241for (int level = 1; level < config::kNumLevels; level++) {242if (!files_[level].empty()) {243iters->push_back(NewConcatenatingIterator(options, level));244}245}246}248// Callback from TableCache::Get()249namespace {250enum SaverState {
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.