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 "leveldb/table.h"7#include "leveldb/cache.h"8#include "leveldb/comparator.h"9#include "leveldb/env.h"10#include "leveldb/filter_policy.h"11#include "leveldb/options.h"12#include "table/block.h"13#include "table/filter_block.h"14#include "table/format.h"15#include "table/two_level_iterator.h"16#include "util/coding.h"18namespace leveldb {20struct Table::Rep {21~Rep() {22delete filter;23delete[] filter_data;24delete index_block;25}27Options options;28Status status;29RandomAccessFile* file;30uint64_t cache_id;31FilterBlockReader* filter;32const char* filter_data;34BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer35Block* index_block;36};38Status Table::Open(const Options& options, RandomAccessFile* file,39uint64_t size, Table** table) {40*table = nullptr;41if (size < Footer::kEncodedLength) {42return Status::Corruption("file is too short to be an sstable");43}45char footer_space[Footer::kEncodedLength];46Slice footer_input;47Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,48&footer_input, footer_space);49if (!s.ok()) return s;51Footer footer;52s = footer.DecodeFrom(&footer_input);53if (!s.ok()) return s;55// Read the index block56BlockContents index_block_contents;57if (s.ok()) {58ReadOptions opt;59if (options.paranoid_checks) {60opt.verify_checksums = true;61}62s = ReadBlock(file, opt, footer.index_handle(), &index_block_contents);63}65if (s.ok()) {66// We've successfully read the footer and the index block: we're67// ready to serve requests.68Block* index_block = new Block(index_block_contents);69Rep* rep = new Table::Rep;70rep->options = options;71rep->file = file;72rep->metaindex_handle = footer.metaindex_handle();73rep->index_block = index_block;74rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);75rep->filter_data = nullptr;76rep->filter = nullptr;77*table = new Table(rep);78(*table)->ReadMeta(footer);79}81return s;82}84void Table::ReadMeta(const Footer& footer) {85if (rep_->options.filter_policy == nullptr) {86return; // Do not need any metadata87}89// TODO(sanjay): Skip this if footer.metaindex_handle() size indicates90// it is an empty block.91ReadOptions opt;92if (rep_->options.paranoid_checks) {93opt.verify_checksums = true;94}95BlockContents contents;96if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {97// Do not propagate errors since meta info is not needed for operation98return;99}100Block* meta = new Block(contents);102Iterator* iter = meta->NewIterator(BytewiseComparator());103std::string key = "filter.";104key.append(rep_->options.filter_policy->Name());105iter->Seek(key);106if (iter->Valid() && iter->key() == Slice(key)) {107ReadFilter(iter->value());108}109delete iter;110delete meta;111}113void Table::ReadFilter(const Slice& filter_handle_value) {114Slice v = filter_handle_value;115BlockHandle filter_handle;116if (!filter_handle.DecodeFrom(&v).ok()) {117return;118}120// We might want to unify with ReadBlock() if we start121// requiring checksum verification in Table::Open.122ReadOptions opt;123if (rep_->options.paranoid_checks) {124opt.verify_checksums = true;125}126BlockContents block;127if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {128return;129}130if (block.heap_allocated) {131rep_->filter_data = block.data.data(); // Will need to delete later132}133rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data);134}136Table::~Table() { delete rep_; }138static void DeleteBlock(void* arg, void* ignored) {139delete reinterpret_cast<Block*>(arg);140}142static void DeleteCachedBlock(const Slice& key, void* value) {143Block* block = reinterpret_cast<Block*>(value);144delete block;145}147static void ReleaseBlock(void* arg, void* h) {148Cache* cache = reinterpret_cast<Cache*>(arg);149Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);150cache->Release(handle);151}153// Convert an index iterator value (i.e., an encoded BlockHandle)154// into an iterator over the contents of the corresponding block.155Iterator* Table::BlockReader(void* arg, const ReadOptions& options,156const Slice& index_value) {157Table* table = reinterpret_cast<Table*>(arg);158Cache* block_cache = table->rep_->options.block_cache;159Block* block = nullptr;160Cache::Handle* cache_handle = nullptr;162BlockHandle handle;163Slice input = index_value;164Status s = handle.DecodeFrom(&input);165// We intentionally allow extra stuff in index_value so that we166// can add more features in the future.168if (s.ok()) {169BlockContents contents;170if (block_cache != nullptr) {171char cache_key_buffer[16];172EncodeFixed64(cache_key_buffer, table->rep_->cache_id);173EncodeFixed64(cache_key_buffer + 8, handle.offset());174Slice key(cache_key_buffer, sizeof(cache_key_buffer));175cache_handle = block_cache->Lookup(key);176if (cache_handle != nullptr) {177block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));178} else {179s = ReadBlock(table->rep_->file, options, handle, &contents);180if (s.ok()) {181block = new Block(contents);182if (contents.cachable && options.fill_cache) {183cache_handle = block_cache->Insert(key, block, block->size(),184&DeleteCachedBlock);185}186}187}188} else {189s = ReadBlock(table->rep_->file, options, handle, &contents);190if (s.ok()) {191block = new Block(contents);192}193}194}196Iterator* iter;197if (block != nullptr) {198iter = block->NewIterator(table->rep_->options.comparator);199if (cache_handle == nullptr) {200iter->RegisterCleanup(&DeleteBlock, block, nullptr);201} else {202iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);203}204} else {205iter = NewErrorIterator(s);206}207return iter;208}210Iterator* Table::NewIterator(const ReadOptions& options) const {211return NewTwoLevelIterator(212rep_->index_block->NewIterator(rep_->options.comparator),213&Table::BlockReader, const_cast<Table*>(this), options);214}216Status Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg,217void (*handle_result)(void*, const Slice&,218const Slice&)) {219Status s;220Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator);221iiter->Seek(k);222if (iiter->Valid()) {223Slice handle_value = iiter->value();224FilterBlockReader* filter = rep_->filter;225BlockHandle handle;226if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() &&227!filter->KeyMayMatch(handle.offset(), k)) {228// Not found229} else {230Iterator* block_iter = BlockReader(this, options, iiter->value());231block_iter->Seek(k);232if (block_iter->Valid()) {233(*handle_result)(arg, block_iter->key(), block_iter->value());234}235s = block_iter->status();236delete block_iter;237}238}239if (s.ok()) {240s = iiter->status();241}242delete iiter;243return s;244}246uint64_t Table::ApproximateOffsetOf(const Slice& key) const {247Iterator* index_iter =248rep_->index_block->NewIterator(rep_->options.comparator);249index_iter->Seek(key);250uint64_t result;
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.