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.
501if (begin != nullptr) {502user_begin = begin->user_key();503}504if (end != nullptr) {505user_end = end->user_key();506}507const Comparator* user_cmp = vset_->icmp_.user_comparator();508for (size_t i = 0; i < files_[level].size();) {509FileMetaData* f = files_[level][i++];510const Slice file_start = f->smallest.user_key();511const Slice file_limit = f->largest.user_key();512if (begin != nullptr && user_cmp->Compare(file_limit, user_begin) < 0) {513// "f" is completely before specified range; skip it514} else if (end != nullptr && user_cmp->Compare(file_start, user_end) > 0) {515// "f" is completely after specified range; skip it516} else {517inputs->push_back(f);518if (level == 0) {519// Level-0 files may overlap each other. So check if the newly520// added file has expanded the range. If so, restart search.521if (begin != nullptr && user_cmp->Compare(file_start, user_begin) < 0) {522user_begin = file_start;523inputs->clear();524i = 0;525} else if (end != nullptr &&526user_cmp->Compare(file_limit, user_end) > 0) {527user_end = file_limit;528inputs->clear();529i = 0;530}531}532}533}534}536std::string Version::DebugString() const {537std::string r;538for (int level = 0; level < config::kNumLevels; level++) {539// E.g.,540// --- level 1 ---541// 17:123['a' .. 'd']542// 20:43['e' .. 'g']543r.append("--- level ");544AppendNumberTo(&r, level);545r.append(" ---\n");546const std::vector<FileMetaData*>& files = files_[level];547for (size_t i = 0; i < files.size(); i++) {548r.push_back(' ');549AppendNumberTo(&r, files[i]->number);550r.push_back(':');551AppendNumberTo(&r, files[i]->file_size);552r.append("[");553r.append(files[i]->smallest.DebugString());554r.append(" .. ");555r.append(files[i]->largest.DebugString());556r.append("]\n");557}558}559return r;560}562// A helper class so we can efficiently apply a whole sequence563// of edits to a particular state without creating intermediate564// Versions that contain full copies of the intermediate state.565class VersionSet::Builder {566private:567// Helper to sort by v->files_[file_number].smallest568struct BySmallestKey {569const InternalKeyComparator* internal_comparator;571bool operator()(FileMetaData* f1, FileMetaData* f2) const {572int r = internal_comparator->Compare(f1->smallest, f2->smallest);573if (r != 0) {574return (r < 0);575} else {576// Break ties by file number577return (f1->number < f2->number);578}579}580};582typedef std::set<FileMetaData*, BySmallestKey> FileSet;583struct LevelState {584std::set<uint64_t> deleted_files;585FileSet* added_files;586};588VersionSet* vset_;589Version* base_;590LevelState levels_[config::kNumLevels];592public:593// Initialize a builder with the files from *base and other info from *vset594Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) {595base_->Ref();596BySmallestKey cmp;597cmp.internal_comparator = &vset_->icmp_;598for (int level = 0; level < config::kNumLevels; level++) {599levels_[level].added_files = new FileSet(cmp);600}601}603~Builder() {604for (int level = 0; level < config::kNumLevels; level++) {605const FileSet* added = levels_[level].added_files;606std::vector<FileMetaData*> to_unref;607to_unref.reserve(added->size());608for (FileSet::const_iterator it = added->begin(); it != added->end();609++it) {610to_unref.push_back(*it);611}612delete added;613for (uint32_t i = 0; i < to_unref.size(); i++) {614FileMetaData* f = to_unref[i];615f->refs--;616if (f->refs <= 0) {617delete f;618}619}620}621base_->Unref();622}624// Apply all of the edits in *edit to the current state.625void Apply(VersionEdit* edit) {626// Update compaction pointers627for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {628const int level = edit->compact_pointers_[i].first;629vset_->compact_pointer_[level] =630edit->compact_pointers_[i].second.Encode().ToString();631}633// Delete files634for (const auto& deleted_file_set_kvp : edit->deleted_files_) {635const int level = deleted_file_set_kvp.first;636const uint64_t number = deleted_file_set_kvp.second;637levels_[level].deleted_files.insert(number);638}640// Add new files641for (size_t i = 0; i < edit->new_files_.size(); i++) {642const int level = edit->new_files_[i].first;643FileMetaData* f = new FileMetaData(edit->new_files_[i].second);644f->refs = 1;646// We arrange to automatically compact this file after647// a certain number of seeks. Let's assume:648// (1) One seek costs 10ms649// (2) Writing or reading 1MB costs 10ms (100MB/s)650// (3) A compaction of 1MB does 25MB of IO:651// 1MB read from this level652// 10-12MB read from next level (boundaries may be misaligned)653// 10-12MB written to next level654// This implies that 25 seeks cost the same as the compaction655// of 1MB of data. I.e., one seek costs approximately the656// same as the compaction of 40KB of data. We are a little657// conservative and allow approximately one seek for every 16KB658// of data before triggering a compaction.659//660// Note: seek compactions are disabled. See Version::UpdateStats.661f->allowed_seeks = static_cast<int>((f->file_size / 16384U));662if (f->allowed_seeks < 100) f->allowed_seeks = 100;664levels_[level].deleted_files.erase(f->number);665levels_[level].added_files->insert(f);666}667}669// Save the current state in *v.670void SaveTo(Version* v) {671BySmallestKey cmp;672cmp.internal_comparator = &vset_->icmp_;673for (int level = 0; level < config::kNumLevels; level++) {674// Merge the set of added files with the set of pre-existing files.675// Drop any deleted files. Store the result in *v.676const std::vector<FileMetaData*>& base_files = base_->files_[level];677std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();678std::vector<FileMetaData*>::const_iterator base_end = base_files.end();679const FileSet* added_files = levels_[level].added_files;680v->files_[level].reserve(base_files.size() + added_files->size());681for (const auto& added_file : *added_files) {682// Add all smaller files listed in base_683for (std::vector<FileMetaData*>::const_iterator bpos =684std::upper_bound(base_iter, base_end, added_file, cmp);685base_iter != bpos; ++base_iter) {686MaybeAddFile(v, level, *base_iter);687}689MaybeAddFile(v, level, added_file);690}692// Add remaining base files693for (; base_iter != base_end; ++base_iter) {694MaybeAddFile(v, level, *base_iter);695}697#ifndef NDEBUG698// Make sure there is no overlap in levels > 0699if (level > 0) {700for (uint32_t i = 1; i < v->files_[level].size(); i++) {701const InternalKey& prev_end = v->files_[level][i - 1]->largest;702const InternalKey& this_begin = v->files_[level][i]->smallest;703if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {704fprintf(stderr, "overlapping ranges in same level %s vs. %s\n",705prev_end.DebugString().c_str(),706this_begin.DebugString().c_str());707abort();708}709}710}711#endif712}713}715void MaybeAddFile(Version* v, int level, FileMetaData* f) {716if (levels_[level].deleted_files.count(f->number) > 0) {717// File is deleted: do nothing718} else {719std::vector<FileMetaData*>* files = &v->files_[level];720if (level > 0 && !files->empty()) {721// Must not overlap722assert(vset_->icmp_.Compare((*files)[files->size() - 1]->largest,723f->smallest) < 0);724}725f->refs++;726files->push_back(f);727}728}729};731VersionSet::VersionSet(const std::string& dbname, const Options* options,732TableCache* table_cache,733const InternalKeyComparator* cmp)734: env_(options->env),735dbname_(dbname),736options_(options),737table_cache_(table_cache),738icmp_(*cmp),739next_file_number_(2),740manifest_file_number_(0), // Filled by Recover()741last_sequence_(0),742log_number_(0),743prev_log_number_(0),744descriptor_file_(nullptr),745descriptor_log_(nullptr),746dummy_versions_(this),747current_(nullptr) {748AppendVersion(new Version(this));749}
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.