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/log_reader.h"6#include "db/log_writer.h"7#include "leveldb/env.h"8#include "util/coding.h"9#include "util/crc32c.h"10#include "util/random.h"11#include "util/testharness.h"13namespace leveldb {14namespace log {16// Construct a string of the specified length made out of the supplied17// partial string.18static std::string BigString(const std::string& partial_string, size_t n) {19std::string result;20while (result.size() < n) {21result.append(partial_string);22}23result.resize(n);24return result;25}27// Construct a string from a number28static std::string NumberString(int n) {29char buf[50];30snprintf(buf, sizeof(buf), "%d.", n);31return std::string(buf);32}34// Return a skewed potentially long string35static std::string RandomSkewedString(int i, Random* rnd) {36return BigString(NumberString(i), rnd->Skewed(17));37}39class LogTest {40public:41LogTest()42: reading_(false),43writer_(new Writer(&dest_)),44reader_(new Reader(&source_, &report_, true /*checksum*/,450 /*initial_offset*/)) {}47~LogTest() {48delete writer_;49delete reader_;50}52void ReopenForAppend() {53delete writer_;54writer_ = new Writer(&dest_, dest_.contents_.size());55}57void Write(const std::string& msg) {58ASSERT_TRUE(!reading_) << "Write() after starting to read";59writer_->AddRecord(Slice(msg));60}62size_t WrittenBytes() const { return dest_.contents_.size(); }64std::string Read() {65if (!reading_) {66reading_ = true;67source_.contents_ = Slice(dest_.contents_);68}69std::string scratch;70Slice record;71if (reader_->ReadRecord(&record, &scratch)) {72return record.ToString();73} else {74return "EOF";75}76}78void IncrementByte(int offset, int delta) {79dest_.contents_[offset] += delta;80}82void SetByte(int offset, char new_byte) {83dest_.contents_[offset] = new_byte;84}86void ShrinkSize(int bytes) {87dest_.contents_.resize(dest_.contents_.size() - bytes);88}90void FixChecksum(int header_offset, int len) {91// Compute crc of type/len/data92uint32_t crc = crc32c::Value(&dest_.contents_[header_offset + 6], 1 + len);93crc = crc32c::Mask(crc);94EncodeFixed32(&dest_.contents_[header_offset], crc);95}97void ForceError() { source_.force_error_ = true; }99size_t DroppedBytes() const { return report_.dropped_bytes_; }101std::string ReportMessage() const { return report_.message_; }103// Returns OK iff recorded error message contains "msg"104std::string MatchError(const std::string& msg) const {105if (report_.message_.find(msg) == std::string::npos) {106return report_.message_;107} else {108return "OK";109}110}112void WriteInitialOffsetLog() {113for (int i = 0; i < num_initial_offset_records_; i++) {114std::string record(initial_offset_record_sizes_[i],115static_cast<char>('a' + i));116Write(record);117}118}120void StartReadingAt(uint64_t initial_offset) {121delete reader_;122reader_ = new Reader(&source_, &report_, true /*checksum*/, initial_offset);123}125void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) {126WriteInitialOffsetLog();127reading_ = true;128source_.contents_ = Slice(dest_.contents_);129Reader* offset_reader = new Reader(&source_, &report_, true /*checksum*/,130WrittenBytes() + offset_past_end);131Slice record;132std::string scratch;133ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch));134delete offset_reader;135}137void CheckInitialOffsetRecord(uint64_t initial_offset,138int expected_record_offset) {139WriteInitialOffsetLog();140reading_ = true;141source_.contents_ = Slice(dest_.contents_);142Reader* offset_reader =143new Reader(&source_, &report_, true /*checksum*/, initial_offset);145// Read all records from expected_record_offset through the last one.146ASSERT_LT(expected_record_offset, num_initial_offset_records_);147for (; expected_record_offset < num_initial_offset_records_;148++expected_record_offset) {149Slice record;150std::string scratch;151ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch));152ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset],153record.size());154ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset],155offset_reader->LastRecordOffset());156ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]);157}158delete offset_reader;159}161private:162class StringDest : public WritableFile {163public:164Status Close() override { return Status::OK(); }165Status Flush() override { return Status::OK(); }166Status Sync() override { return Status::OK(); }167Status Append(const Slice& slice) override {168contents_.append(slice.data(), slice.size());169return Status::OK();170}171std::string GetName() const override { return ""; }173std::string contents_;174};176class StringSource : public SequentialFile {177public:178StringSource() : force_error_(false), returned_partial_(false) {}180Status Read(size_t n, Slice* result, char* scratch) override {181ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error";183if (force_error_) {184force_error_ = false;185returned_partial_ = true;186return Status::Corruption("read error");187}189if (contents_.size() < n) {190n = contents_.size();191returned_partial_ = true;192}193*result = Slice(contents_.data(), n);194contents_.remove_prefix(n);195return Status::OK();196}198Status Skip(uint64_t n) override {199if (n > contents_.size()) {200contents_.clear();201return Status::NotFound("in-memory file skipped past end");202}204contents_.remove_prefix(n);206return Status::OK();207}208std::string GetName() const override { return ""; }210Slice contents_;211bool force_error_;212bool returned_partial_;213};215class ReportCollector : public Reader::Reporter {216public:217ReportCollector() : dropped_bytes_(0) {}218void Corruption(size_t bytes, const Status& status) override {219dropped_bytes_ += bytes;220message_.append(status.ToString());221}223size_t dropped_bytes_;224std::string message_;225};227// Record metadata for testing initial offset functionality228static size_t initial_offset_record_sizes_[];229static uint64_t initial_offset_last_record_offsets_[];230static int num_initial_offset_records_;232StringDest dest_;233StringSource source_;234ReportCollector report_;235bool reading_;236Writer* writer_;237Reader* reader_;238};240size_t LogTest::initial_offset_record_sizes_[] = {24110000, // Two sizable records in first block24210000,2432 * log::kBlockSize - 1000, // Span three blocks2441,24513716, // Consume all but two bytes of block 3.246log::kBlockSize - kHeaderSize, // Consume the entirety of block 4.247};249uint64_t LogTest::initial_offset_last_record_offsets_[] = {2500,
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.