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.
1001}1003assert(descriptor_file_ == nullptr);1004assert(descriptor_log_ == nullptr);1005Status r = env_->NewAppendableFile(dscname, &descriptor_file_);1006if (!r.ok()) {1007Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str());1008assert(descriptor_file_ == nullptr);1009return false;1010}1012Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str());1013descriptor_log_ = new log::Writer(descriptor_file_, manifest_size);1014manifest_file_number_ = manifest_number;1015return true;1016}1018void VersionSet::MarkFileNumberUsed(uint64_t number) {1019if (next_file_number_ <= number) {1020next_file_number_ = number + 1;1021}1022}1024void VersionSet::Finalize(Version* v) {1025// Precomputed best level for next compaction1026int best_level = -1;1027double best_score = -1;1029for (int level = 0; level < config::kNumLevels - 1; level++) {1030double score;1031if (level == 0) {1032// We treat level-0 specially by bounding the number of files1033// instead of number of bytes for two reasons:1034//1035// (1) With larger write-buffer sizes, it is nice not to do too1036// many level-0 compactions.1037//1038// (2) The files in level-0 are merged on every read and1039// therefore we wish to avoid too many files when the individual1040// file size is small (perhaps because of a small write-buffer1041// setting, or very high compression ratios, or lots of1042// overwrites/deletions).1043score = v->files_[level].size() /1044static_cast<double>(config::kL0_CompactionTrigger);1045} else {1046// Compute the ratio of current size to size limit.1047const uint64_t level_bytes = TotalFileSize(v->files_[level]);1048score =1049static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level);1050}1052if (score > best_score) {1053best_level = level;1054best_score = score;1055}1056}1058v->compaction_level_ = best_level;1059v->compaction_score_ = best_score;1060}1062Status VersionSet::WriteSnapshot(log::Writer* log) {1063// TODO: Break up into multiple records to reduce memory usage on recovery?1065// Save metadata1066VersionEdit edit;1067edit.SetComparatorName(icmp_.user_comparator()->Name());1069// Save compaction pointers1070for (int level = 0; level < config::kNumLevels; level++) {1071if (!compact_pointer_[level].empty()) {1072InternalKey key;1073key.DecodeFrom(compact_pointer_[level]);1074edit.SetCompactPointer(level, key);1075}1076}1078// Save files1079for (int level = 0; level < config::kNumLevels; level++) {1080const std::vector<FileMetaData*>& files = current_->files_[level];1081for (size_t i = 0; i < files.size(); i++) {1082const FileMetaData* f = files[i];1083edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);1084}1085}1087std::string record;1088edit.EncodeTo(&record);1089return log->AddRecord(record);1090}1092int VersionSet::NumLevelFiles(int level) const {1093assert(level >= 0);1094assert(level < config::kNumLevels);1095return current_->files_[level].size();1096}1098const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {1099// Update code if kNumLevels changes1100static_assert(config::kNumLevels == 7, "");1101snprintf(scratch->buffer, sizeof(scratch->buffer),1102"files[ %d %d %d %d %d %d %d ]", int(current_->files_[0].size()),1103int(current_->files_[1].size()), int(current_->files_[2].size()),1104int(current_->files_[3].size()), int(current_->files_[4].size()),1105int(current_->files_[5].size()), int(current_->files_[6].size()));1106return scratch->buffer;1107}1109uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {1110uint64_t result = 0;1111for (int level = 0; level < config::kNumLevels; level++) {1112const std::vector<FileMetaData*>& files = v->files_[level];1113for (size_t i = 0; i < files.size(); i++) {1114if (icmp_.Compare(files[i]->largest, ikey) <= 0) {1115// Entire file is before "ikey", so just add the file size1116result += files[i]->file_size;1117} else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {1118// Entire file is after "ikey", so ignore1119if (level > 0) {1120// Files other than level 0 are sorted by meta->smallest, so1121// no further files in this level will contain data for1122// "ikey".1123break;1124}1125} else {1126// "ikey" falls in the range for this table. Add the1127// approximate offset of "ikey" within the table.1128Table* tableptr;1129Iterator* iter = table_cache_->NewIterator(1130ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);1131if (tableptr != nullptr) {1132result += tableptr->ApproximateOffsetOf(ikey.Encode());1133}1134delete iter;1135}1136}1137}1138return result;1139}1141void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {1142for (Version* v = dummy_versions_.next_; v != &dummy_versions_;1143v = v->next_) {1144for (int level = 0; level < config::kNumLevels; level++) {1145const std::vector<FileMetaData*>& files = v->files_[level];1146for (size_t i = 0; i < files.size(); i++) {1147live->insert(files[i]->number);1148}1149}1150}1151}1153int64_t VersionSet::NumLevelBytes(int level) const {1154assert(level >= 0);1155assert(level < config::kNumLevels);1156return TotalFileSize(current_->files_[level]);1157}1159int64_t VersionSet::MaxNextLevelOverlappingBytes() {1160int64_t result = 0;1161std::vector<FileMetaData*> overlaps;1162for (int level = 1; level < config::kNumLevels - 1; level++) {1163for (size_t i = 0; i < current_->files_[level].size(); i++) {1164const FileMetaData* f = current_->files_[level][i];1165current_->GetOverlappingInputs(level + 1, &f->smallest, &f->largest,1166&overlaps);1167const int64_t sum = TotalFileSize(overlaps);1168if (sum > result) {1169result = sum;1170}1171}1172}1173return result;1174}1176// Stores the minimal range that covers all entries in inputs in1177// *smallest, *largest.1178// REQUIRES: inputs is not empty1179void VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,1180InternalKey* smallest, InternalKey* largest) {1181assert(!inputs.empty());1182smallest->Clear();1183largest->Clear();1184for (size_t i = 0; i < inputs.size(); i++) {1185FileMetaData* f = inputs[i];1186if (i == 0) {1187*smallest = f->smallest;1188*largest = f->largest;1189} else {1190if (icmp_.Compare(f->smallest, *smallest) < 0) {1191*smallest = f->smallest;1192}1193if (icmp_.Compare(f->largest, *largest) > 0) {1194*largest = f->largest;1195}1196}1197}1198}1200// Stores the minimal range that covers all entries in inputs1 and inputs21201// in *smallest, *largest.1202// REQUIRES: inputs is not empty1203void VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,1204const std::vector<FileMetaData*>& inputs2,1205InternalKey* smallest, InternalKey* largest) {1206std::vector<FileMetaData*> all = inputs1;1207all.insert(all.end(), inputs2.begin(), inputs2.end());1208GetRange(all, smallest, largest);1209}1211Iterator* VersionSet::MakeInputIterator(Compaction* c) {1212ReadOptions options;1213options.verify_checksums = options_->paranoid_checks;1214options.fill_cache = false;1216// Level-0 files have to be merged together. For other levels,1217// we will make a concatenating iterator per level.1218// TODO(opt): use concatenating iterator for level-0 if there is no overlap1219const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);1220Iterator** list = new Iterator*[space];1221int num = 0;1222for (int which = 0; which < 2; which++) {1223if (!c->inputs_[which].empty()) {1224if (c->level() + which == 0) {1225const std::vector<FileMetaData*>& files = c->inputs_[which];1226for (size_t i = 0; i < files.size(); i++) {1227list[num++] = table_cache_->NewIterator(options, files[i]->number,1228files[i]->file_size);1229}1230} else {1231// Create concatenating iterator for the files from this level1232list[num++] = NewTwoLevelIterator(1233new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),1234&GetFileIterator, table_cache_, options);1235}1236}1237}1238assert(num <= space);1239Iterator* result = NewMergingIterator(&icmp_, list, num);1240delete[] list;1241return result;1242}1244Compaction* VersionSet::PickCompaction() {1245Compaction* c;1246int level;1248// We prefer compactions triggered by too much data in a level over1249// the compactions triggered by seeks.1250const bool size_compaction = (current_->compaction_score_ >= 1);
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.