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.
251define a proper subclass of `leveldb::Comparator` that expresses these rules:253```c++254class TwoPartComparator : public leveldb::Comparator {255public:256// Three-way comparison function:257// if a < b: negative result258// if a > b: positive result259// else: zero result260int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {261int a1, a2, b1, b2;262ParseKey(a, &a1, &a2);263ParseKey(b, &b1, &b2);264if (a1 < b1) return -1;265if (a1 > b1) return +1;266if (a2 < b2) return -1;267if (a2 > b2) return +1;268return 0;269}271// Ignore the following methods for now:272const char* Name() const { return "TwoPartComparator"; }273void FindShortestSeparator(std::string*, const leveldb::Slice&) const {}274void FindShortSuccessor(std::string*) const {}275};276```278Now create a database using this custom comparator:280```c++281TwoPartComparator cmp;282leveldb::DB* db;283leveldb::Options options;284options.create_if_missing = true;285options.comparator = &cmp;286leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);287...288```290### Backwards compatibility292The result of the comparator's Name method is attached to the database when it293is created, and is checked on every subsequent database open. If the name294changes, the `leveldb::DB::Open` call will fail. Therefore, change the name if295and only if the new key format and comparison function are incompatible with296existing databases, and it is ok to discard the contents of all existing297databases.299You can however still gradually evolve your key format over time with a little300bit of pre-planning. For example, you could store a version number at the end of301each key (one byte should suffice for most uses). When you wish to switch to a302new key format (e.g., adding an optional third part to the keys processed by303`TwoPartComparator`), (a) keep the same comparator name (b) increment the304version number for new keys (c) change the comparator function so it uses the305version numbers found in the keys to decide how to interpret them.307## Performance309Performance can be tuned by changing the default values of the types defined in310`include/options.h`.312### Block size314leveldb groups adjacent keys together into the same block and such a block is315the unit of transfer to and from persistent storage. The default block size is316approximately 4096 uncompressed bytes. Applications that mostly do bulk scans317over the contents of the database may wish to increase this size. Applications318that do a lot of point reads of small values may wish to switch to a smaller319block size if performance measurements indicate an improvement. There isn't much320benefit in using blocks smaller than one kilobyte, or larger than a few321megabytes. Also note that compression will be more effective with larger block322sizes.324### Compression326Each block is individually compressed before being written to persistent327storage. Compression is on by default since the default compression method is328very fast, and is automatically disabled for incompressible data. In rare cases,329applications may want to disable compression entirely, but should only do so if330benchmarks show a performance improvement:332```c++333leveldb::Options options;334options.compression = leveldb::kNoCompression;335... leveldb::DB::Open(options, name, ...) ....336```338### Cache340The contents of the database are stored in a set of files in the filesystem and341each file stores a sequence of compressed blocks. If options.block_cache is342non-NULL, it is used to cache frequently used uncompressed block contents.344```c++345#include "leveldb/cache.h"347leveldb::Options options;348options.block_cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache349leveldb::DB* db;350leveldb::DB::Open(options, name, &db);351... use the db ...352delete db353delete options.block_cache;354```356Note that the cache holds uncompressed data, and therefore it should be sized357according to application level data sizes, without any reduction from358compression. (Caching of compressed blocks is left to the operating system359buffer cache, or any custom Env implementation provided by the client.)361When performing a bulk read, the application may wish to disable caching so that362the data processed by the bulk read does not end up displacing most of the363cached contents. A per-iterator option can be used to achieve this:365```c++366leveldb::ReadOptions options;367options.fill_cache = false;368leveldb::Iterator* it = db->NewIterator(options);369for (it->SeekToFirst(); it->Valid(); it->Next()) {370...371}372```374### Key Layout376Note that the unit of disk transfer and caching is a block. Adjacent keys377(according to the database sort order) will usually be placed in the same block.378Therefore the application can improve its performance by placing keys that are379accessed together near each other and placing infrequently used keys in a380separate region of the key space.382For example, suppose we are implementing a simple file system on top of leveldb.383The types of entries we might wish to store are:385filename -> permission-bits, length, list of file_block_ids386file_block_id -> data388We might want to prefix filename keys with one letter (say '/') and the389`file_block_id` keys with a different letter (say '0') so that scans over just390the metadata do not force us to fetch and cache bulky file contents.392### Filters394Because of the way leveldb data is organized on disk, a single `Get()` call may395involve multiple reads from disk. The optional FilterPolicy mechanism can be396used to reduce the number of disk reads substantially.398```c++399leveldb::Options options;400options.filter_policy = NewBloomFilterPolicy(10);401leveldb::DB* db;402leveldb::DB::Open(options, "/tmp/testdb", &db);403... use the database ...404delete db;405delete options.filter_policy;406```408The preceding code associates a Bloom filter based filtering policy with the409database. Bloom filter based filtering relies on keeping some number of bits of410data in memory per key (in this case 10 bits per key since that is the argument411we passed to `NewBloomFilterPolicy`). This filter will reduce the number of412unnecessary disk reads needed for Get() calls by a factor of approximately413a 100. Increasing the bits per key will lead to a larger reduction at the cost414of more memory usage. We recommend that applications whose working set does not415fit in memory and that do a lot of random reads set a filter policy.417If you are using a custom comparator, you should ensure that the filter policy418you are using is compatible with your comparator. For example, consider a419comparator that ignores trailing spaces when comparing keys.420`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the421application should provide a custom filter policy that also ignores trailing422spaces. For example:424```c++425class CustomFilterPolicy : public leveldb::FilterPolicy {426private:427FilterPolicy* builtin_policy_;429public:430CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {}431~CustomFilterPolicy() { delete builtin_policy_; }433const char* Name() const { return "IgnoreTrailingSpacesFilter"; }435void CreateFilter(const Slice* keys, int n, std::string* dst) const {436// Use builtin bloom filter code after removing trailing spaces437std::vector<Slice> trimmed(n);438for (int i = 0; i < n; i++) {439trimmed[i] = RemoveTrailingSpaces(keys[i]);440}441return builtin_policy_->CreateFilter(&trimmed[i], n, dst);442}443};444```446Advanced applications may provide a filter policy that does not use a bloom447filter but uses some other mechanism for summarizing a set of keys. See448`leveldb/filter_policy.h` for detail.450## Checksums452leveldb associates checksums with all data it stores in the file system. There453are two separate controls provided over how aggressively these checksums are454verified:456`ReadOptions::verify_checksums` may be set to true to force checksum457verification of all data that is read from the file system on behalf of a458particular read. By default, no such verification is done.460`Options::paranoid_checks` may be set to true before opening a database to make461the database implementation raise an error as soon as it detects an internal462corruption. Depending on which portion of the database has been corrupted, the463error may be raised when the database is opened, or later by another database464operation. By default, paranoid checking is off so that the database can be used465even if parts of its persistent storage have been corrupted.467If a database is corrupted (perhaps it cannot be opened when paranoid checking468is turned on), the `leveldb::RepairDB` function may be used to recover as much469of the data as possible471## Approximate Sizes473The `GetApproximateSizes` method can used to get the approximate number of bytes474of file system space used by one or more key ranges.476```c++477leveldb::Range ranges[2];478ranges[0] = leveldb::Range("a", "c");479ranges[1] = leveldb::Range("x", "z");480uint64_t sizes[2];481leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);482```484The preceding call will set `sizes[0]` to the approximate number of bytes of485file system space used by the key range `[a..c)` and `sizes[1]` to the486approximate number of bytes used by the key range `[x..z)`.488## Environment490All file operations (and other operating system calls) issued by the leveldb491implementation are routed through a `leveldb::Env` object. Sophisticated clients492may wish to provide their own Env implementation to get better control.493For example, an application may introduce artificial delays in the file IO494paths to limit the impact of leveldb on other activities in the system.496```c++497class SlowEnv : public leveldb::Env {498... implementation of the Env interface ...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.