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.
251// (in case there is a race that allows other incarnations)252keep = (number >= versions_->ManifestFileNumber());253break;254case kTableFile:255keep = (live.find(number) != live.end());256break;257case kTempFile:258// Any temp files that are currently being written to must259// be recorded in pending_outputs_, which is inserted into "live"260keep = (live.find(number) != live.end());261break;262case kCurrentFile:263case kDBLockFile:264case kInfoLogFile:265keep = true;266break;267}269if (!keep) {270files_to_delete.push_back(std::move(filename));271if (type == kTableFile) {272table_cache_->Evict(number);273}274Log(options_.info_log, "Delete type=%d #%lld\n", static_cast<int>(type),275static_cast<unsigned long long>(number));276}277}278}280// While deleting all files unblock other threads. All files being deleted281// have unique names which will not collide with newly created files and282// are therefore safe to delete while allowing other threads to proceed.283mutex_.Unlock();284for (const std::string& filename : files_to_delete) {285env_->DeleteFile(dbname_ + "/" + filename);286}287mutex_.Lock();288}290Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {291mutex_.AssertHeld();293// Ignore error from CreateDir since the creation of the DB is294// committed only when the descriptor is created, and this directory295// may already exist from a previous failed creation attempt.296env_->CreateDir(dbname_);297assert(db_lock_ == nullptr);298Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);299if (!s.ok()) {300return s;301}303if (!env_->FileExists(CurrentFileName(dbname_))) {304if (options_.create_if_missing) {305s = NewDB();306if (!s.ok()) {307return s;308}309} else {310return Status::InvalidArgument(311dbname_, "does not exist (create_if_missing is false)");312}313} else {314if (options_.error_if_exists) {315return Status::InvalidArgument(dbname_,316"exists (error_if_exists is true)");317}318}320s = versions_->Recover(save_manifest);321if (!s.ok()) {322return s;323}324SequenceNumber max_sequence(0);326// Recover from all newer log files than the ones named in the327// descriptor (new log files may have been added by the previous328// incarnation without registering them in the descriptor).329//330// Note that PrevLogNumber() is no longer used, but we pay331// attention to it in case we are recovering a database332// produced by an older version of leveldb.333const uint64_t min_log = versions_->LogNumber();334const uint64_t prev_log = versions_->PrevLogNumber();335std::vector<std::string> filenames;336s = env_->GetChildren(dbname_, &filenames);337if (!s.ok()) {338return s;339}340std::set<uint64_t> expected;341versions_->AddLiveFiles(&expected);342uint64_t number;343FileType type;344std::vector<uint64_t> logs;345for (size_t i = 0; i < filenames.size(); i++) {346if (ParseFileName(filenames[i], &number, &type)) {347expected.erase(number);348if (type == kLogFile && ((number >= min_log) || (number == prev_log)))349logs.push_back(number);350}351}352if (!expected.empty()) {353char buf[50];354snprintf(buf, sizeof(buf), "%d missing files; e.g.",355static_cast<int>(expected.size()));356return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));357}359// Recover in the order in which the logs were generated360std::sort(logs.begin(), logs.end());361for (size_t i = 0; i < logs.size(); i++) {362s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit,363&max_sequence);364if (!s.ok()) {365return s;366}368// The previous incarnation may not have written any MANIFEST369// records after allocating this log number. So we manually370// update the file number allocation counter in VersionSet.371versions_->MarkFileNumberUsed(logs[i]);372}374if (versions_->LastSequence() < max_sequence) {375versions_->SetLastSequence(max_sequence);376}378return Status::OK();379}381Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log,382bool* save_manifest, VersionEdit* edit,383SequenceNumber* max_sequence) {384struct LogReporter : public log::Reader::Reporter {385Env* env;386Logger* info_log;387const char* fname;388Status* status; // null if options_.paranoid_checks==false389void Corruption(size_t bytes, const Status& s) override {390Log(info_log, "%s%s: dropping %d bytes; %s",391(this->status == nullptr ? "(ignoring error) " : ""), fname,392static_cast<int>(bytes), s.ToString().c_str());393if (this->status != nullptr && this->status->ok()) *this->status = s;394}395};397mutex_.AssertHeld();399// Open the log file400std::string fname = LogFileName(dbname_, log_number);401SequentialFile* file;402Status status = env_->NewSequentialFile(fname, &file);403if (!status.ok()) {404MaybeIgnoreError(&status);405return status;406}408// Create the log reader.409LogReporter reporter;410reporter.env = env_;411reporter.info_log = options_.info_log;412reporter.fname = fname.c_str();413reporter.status = (options_.paranoid_checks ? &status : nullptr);414// We intentionally make log::Reader do checksumming even if415// paranoid_checks==false so that corruptions cause entire commits416// to be skipped instead of propagating bad information (like overly417// large sequence numbers).418log::Reader reader(file, &reporter, true /*checksum*/, 0 /*initial_offset*/);419Log(options_.info_log, "Recovering log #%llu",420(unsigned long long)log_number);422// Read all the records and add to a memtable423std::string scratch;424Slice record;425WriteBatch batch;426int compactions = 0;427MemTable* mem = nullptr;428while (reader.ReadRecord(&record, &scratch) && status.ok()) {429if (record.size() < 12) {430reporter.Corruption(record.size(),431Status::Corruption("log record too small", fname));432continue;433}434WriteBatchInternal::SetContents(&batch, record);436if (mem == nullptr) {437mem = new MemTable(internal_comparator_);438mem->Ref();439}440status = WriteBatchInternal::InsertInto(&batch, mem);441MaybeIgnoreError(&status);442if (!status.ok()) {443break;444}445const SequenceNumber last_seq = WriteBatchInternal::Sequence(&batch) +446WriteBatchInternal::Count(&batch) - 1;447if (last_seq > *max_sequence) {448*max_sequence = last_seq;449}451if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) {452compactions++;453*save_manifest = true;454status = WriteLevel0Table(mem, edit, nullptr);455mem->Unref();456mem = nullptr;457if (!status.ok()) {458// Reflect errors immediately so that conditions like full459// file-systems cause the DB::Open() to fail.460break;461}462}463}465delete file;467// See if we should keep reusing the last log file.468if (status.ok() && options_.reuse_logs && last_log && compactions == 0) {469assert(logfile_ == nullptr);470assert(log_ == nullptr);471assert(mem_ == nullptr);472uint64_t lfile_size;473if (env_->GetFileSize(fname, &lfile_size).ok() &&474env_->NewAppendableFile(fname, &logfile_).ok()) {475Log(options_.info_log, "Reusing old log %s \n", fname.c_str());476log_ = new log::Writer(logfile_, lfile_size);477logfile_number_ = log_number;478if (mem != nullptr) {479mem_ = mem;480mem = nullptr;481} else {482// mem can be nullptr if lognum exists but was empty.483mem_ = new MemTable(internal_comparator_);484mem_->Ref();485}486}487}489if (mem != nullptr) {490// mem did not get reused; compact it.491if (status.ok()) {492*save_manifest = true;493status = WriteLevel0Table(mem, edit, nullptr);494}495mem->Unref();496}498return status;499}
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.