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) 2012 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 "leveldb/dumpfile.h"7#include <stdio.h>9#include "db/dbformat.h"10#include "db/filename.h"11#include "db/log_reader.h"12#include "db/version_edit.h"13#include "db/write_batch_internal.h"14#include "leveldb/env.h"15#include "leveldb/iterator.h"16#include "leveldb/options.h"17#include "leveldb/status.h"18#include "leveldb/table.h"19#include "leveldb/write_batch.h"20#include "util/logging.h"22namespace leveldb {24namespace {26bool GuessType(const std::string& fname, FileType* type) {27size_t pos = fname.rfind('/');28std::string basename;29if (pos == std::string::npos) {30basename = fname;31} else {32basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);33}34uint64_t ignored;35return ParseFileName(basename, &ignored, type);36}38// Notified when log reader encounters corruption.39class CorruptionReporter : public log::Reader::Reporter {40public:41void Corruption(size_t bytes, const Status& status) override {42std::string r = "corruption: ";43AppendNumberTo(&r, bytes);44r += " bytes; ";45r += status.ToString();46r.push_back('\n');47dst_->Append(r);48}50WritableFile* dst_;51};53// Print contents of a log file. (*func)() is called on every record.54Status PrintLogContents(Env* env, const std::string& fname,55void (*func)(uint64_t, Slice, WritableFile*),56WritableFile* dst) {57SequentialFile* file;58Status s = env->NewSequentialFile(fname, &file);59if (!s.ok()) {60return s;61}62CorruptionReporter reporter;63reporter.dst_ = dst;64log::Reader reader(file, &reporter, true, 0);65Slice record;66std::string scratch;67while (reader.ReadRecord(&record, &scratch)) {68(*func)(reader.LastRecordOffset(), record, dst);69}70delete file;71return Status::OK();72}74// Called on every item found in a WriteBatch.75class WriteBatchItemPrinter : public WriteBatch::Handler {76public:77void Put(const Slice& key, const Slice& value) override {78std::string r = " put '";79AppendEscapedStringTo(&r, key);80r += "' '";81AppendEscapedStringTo(&r, value);82r += "'\n";83dst_->Append(r);84}85void Delete(const Slice& key) override {86std::string r = " del '";87AppendEscapedStringTo(&r, key);88r += "'\n";89dst_->Append(r);90}92WritableFile* dst_;93};95// Called on every log record (each one of which is a WriteBatch)96// found in a kLogFile.97static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {98std::string r = "--- offset ";99AppendNumberTo(&r, pos);100r += "; ";101if (record.size() < 12) {102r += "log record length ";103AppendNumberTo(&r, record.size());104r += " is too small\n";105dst->Append(r);106return;107}108WriteBatch batch;109WriteBatchInternal::SetContents(&batch, record);110r += "sequence ";111AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));112r.push_back('\n');113dst->Append(r);114WriteBatchItemPrinter batch_item_printer;115batch_item_printer.dst_ = dst;116Status s = batch.Iterate(&batch_item_printer);117if (!s.ok()) {118dst->Append(" error: " + s.ToString() + "\n");119}120}122Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {123return PrintLogContents(env, fname, WriteBatchPrinter, dst);124}126// Called on every log record (each one of which is a WriteBatch)127// found in a kDescriptorFile.128static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {129std::string r = "--- offset ";130AppendNumberTo(&r, pos);131r += "; ";132VersionEdit edit;133Status s = edit.DecodeFrom(record);134if (!s.ok()) {135r += s.ToString();136r.push_back('\n');137} else {138r += edit.DebugString();139}140dst->Append(r);141}143Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {144return PrintLogContents(env, fname, VersionEditPrinter, dst);145}147Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {148uint64_t file_size;149RandomAccessFile* file = nullptr;150Table* table = nullptr;151Status s = env->GetFileSize(fname, &file_size);152if (s.ok()) {153s = env->NewRandomAccessFile(fname, &file);154}155if (s.ok()) {156// We use the default comparator, which may or may not match the157// comparator used in this database. However this should not cause158// problems since we only use Table operations that do not require159// any comparisons. In particular, we do not call Seek or Prev.160s = Table::Open(Options(), file, file_size, &table);161}162if (!s.ok()) {163delete table;164delete file;165return s;166}168ReadOptions ro;169ro.fill_cache = false;170Iterator* iter = table->NewIterator(ro);171std::string r;172for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {173r.clear();174ParsedInternalKey key;175if (!ParseInternalKey(iter->key(), &key)) {176r = "badkey '";177AppendEscapedStringTo(&r, iter->key());178r += "' => '";179AppendEscapedStringTo(&r, iter->value());180r += "'\n";181dst->Append(r);182} else {183r = "'";184AppendEscapedStringTo(&r, key.user_key);185r += "' @ ";186AppendNumberTo(&r, key.sequence);187r += " : ";188if (key.type == kTypeDeletion) {189r += "del";190} else if (key.type == kTypeValue) {191r += "val";192} else {193AppendNumberTo(&r, key.type);194}195r += " => '";196AppendEscapedStringTo(&r, iter->value());197r += "'\n";198dst->Append(r);199}200}201s = iter->status();202if (!s.ok()) {203dst->Append("iterator error: " + s.ToString() + "\n");204}206delete iter;207delete table;208delete file;209return Status::OK();210}212} // namespace214Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) {215FileType ftype;216if (!GuessType(fname, &ftype)) {217return Status::InvalidArgument(fname + ": unknown file type");218}219switch (ftype) {220case kLogFile:221return DumpLog(env, fname, dst);222case kDescriptorFile:223return DumpDescriptor(env, fname, dst);224case kTableFile:225return DumpTable(env, fname, dst);226default:227break;228}229return Status::InvalidArgument(fname + ": not a dump-able file type");230}232} // namespace leveldb
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.