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.4//5// Decodes the blocks generated by block_builder.cc.7#include "table/block.h"9#include <algorithm>10#include <cstdint>11#include <vector>13#include "leveldb/comparator.h"14#include "table/format.h"15#include "util/coding.h"16#include "util/logging.h"18namespace leveldb {20inline uint32_t Block::NumRestarts() const {21assert(size_ >= sizeof(uint32_t));22return DecodeFixed32(data_ + size_ - sizeof(uint32_t));23}25Block::Block(const BlockContents& contents)26: data_(contents.data.data()),27size_(contents.data.size()),28owned_(contents.heap_allocated) {29if (size_ < sizeof(uint32_t)) {30size_ = 0; // Error marker31} else {32size_t max_restarts_allowed = (size_ - sizeof(uint32_t)) / sizeof(uint32_t);33if (NumRestarts() > max_restarts_allowed) {34// The size is too small for NumRestarts()35size_ = 0;36} else {37restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);38}39}40}42Block::~Block() {43if (owned_) {44delete[] data_;45}46}48// Helper routine: decode the next block entry starting at "p",49// storing the number of shared key bytes, non_shared key bytes,50// and the length of the value in "*shared", "*non_shared", and51// "*value_length", respectively. Will not dereference past "limit".52//53// If any errors are detected, returns nullptr. Otherwise, returns a54// pointer to the key delta (just past the three decoded values).55static inline const char* DecodeEntry(const char* p, const char* limit,56uint32_t* shared, uint32_t* non_shared,57uint32_t* value_length) {58if (limit - p < 3) return nullptr;59*shared = reinterpret_cast<const uint8_t*>(p)[0];60*non_shared = reinterpret_cast<const uint8_t*>(p)[1];61*value_length = reinterpret_cast<const uint8_t*>(p)[2];62if ((*shared | *non_shared | *value_length) < 128) {63// Fast path: all three values are encoded in one byte each64p += 3;65} else {66if ((p = GetVarint32Ptr(p, limit, shared)) == nullptr) return nullptr;67if ((p = GetVarint32Ptr(p, limit, non_shared)) == nullptr) return nullptr;68if ((p = GetVarint32Ptr(p, limit, value_length)) == nullptr) return nullptr;69}71if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {72return nullptr;73}74return p;75}77class Block::Iter : public Iterator {78private:79const Comparator* const comparator_;80const char* const data_; // underlying block contents81uint32_t const restarts_; // Offset of restart array (list of fixed32)82uint32_t const num_restarts_; // Number of uint32_t entries in restart array84// current_ is offset in data_ of current entry. >= restarts_ if !Valid85uint32_t current_;86uint32_t restart_index_; // Index of restart block in which current_ falls87std::string key_;88Slice value_;89Status status_;91inline int Compare(const Slice& a, const Slice& b) const {92return comparator_->Compare(a, b);93}95// Return the offset in data_ just past the end of the current entry.96inline uint32_t NextEntryOffset() const {97return (value_.data() + value_.size()) - data_;98}100uint32_t GetRestartPoint(uint32_t index) {101assert(index < num_restarts_);102return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));103}105void SeekToRestartPoint(uint32_t index) {106key_.clear();107restart_index_ = index;108// current_ will be fixed by ParseNextKey();110// ParseNextKey() starts at the end of value_, so set value_ accordingly111uint32_t offset = GetRestartPoint(index);112value_ = Slice(data_ + offset, 0);113}115public:116Iter(const Comparator* comparator, const char* data, uint32_t restarts,117uint32_t num_restarts)118: comparator_(comparator),119data_(data),120restarts_(restarts),121num_restarts_(num_restarts),122current_(restarts_),123restart_index_(num_restarts_) {124assert(num_restarts_ > 0);125}127bool Valid() const override { return current_ < restarts_; }128Status status() const override { return status_; }129Slice key() const override {130assert(Valid());131return key_;132}133Slice value() const override {134assert(Valid());135return value_;136}138void Next() override {139assert(Valid());140ParseNextKey();141}143void Prev() override {144assert(Valid());146// Scan backwards to a restart point before current_147const uint32_t original = current_;148while (GetRestartPoint(restart_index_) >= original) {149if (restart_index_ == 0) {150// No more entries151current_ = restarts_;152restart_index_ = num_restarts_;153return;154}155restart_index_--;156}158SeekToRestartPoint(restart_index_);159do {160// Loop until end of current entry hits the start of original entry161} while (ParseNextKey() && NextEntryOffset() < original);162}164void Seek(const Slice& target) override {165// Binary search in restart array to find the last restart point166// with a key < target167uint32_t left = 0;168uint32_t right = num_restarts_ - 1;169while (left < right) {170uint32_t mid = (left + right + 1) / 2;171uint32_t region_offset = GetRestartPoint(mid);172uint32_t shared, non_shared, value_length;173const char* key_ptr =174DecodeEntry(data_ + region_offset, data_ + restarts_, &shared,175&non_shared, &value_length);176if (key_ptr == nullptr || (shared != 0)) {177CorruptionError();178return;179}180Slice mid_key(key_ptr, non_shared);181if (Compare(mid_key, target) < 0) {182// Key at "mid" is smaller than "target". Therefore all183// blocks before "mid" are uninteresting.184left = mid;185} else {186// Key at "mid" is >= "target". Therefore all blocks at or187// after "mid" are uninteresting.188right = mid - 1;189}190}192// Linear search (within restart block) for first key >= target193SeekToRestartPoint(left);194while (true) {195if (!ParseNextKey()) {196return;197}198if (Compare(key_, target) >= 0) {199return;200}201}202}204void SeekToFirst() override {205SeekToRestartPoint(0);206ParseNextKey();207}209void SeekToLast() override {210SeekToRestartPoint(num_restarts_ - 1);211while (ParseNextKey() && NextEntryOffset() < restarts_) {212// Keep skipping213}214}216private:217void CorruptionError() {218current_ = restarts_;219restart_index_ = num_restarts_;220status_ = Status::Corruption("bad entry in block");221key_.clear();222value_.clear();223}225bool ParseNextKey() {226current_ = NextEntryOffset();227const char* p = data_ + current_;228const char* limit = data_ + restarts_; // Restarts come right after data229if (p >= limit) {230// No more entries to return. Mark as invalid.231current_ = restarts_;232restart_index_ = num_restarts_;233return false;234}236// Decode next entry237uint32_t shared, non_shared, value_length;238p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);239if (p == nullptr || key_.size() < shared) {240CorruptionError();241return false;242} else {243key_.resize(shared);244key_.append(p, non_shared);245value_ = Slice(p + non_shared, value_length);246while (restart_index_ + 1 < num_restarts_ &&247GetRestartPoint(restart_index_ + 1) < current_) {248++restart_index_;249}250return true;
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.