Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
bitcoinleveldb-versionedit
Low-level encoding/decoding and manipulation of LevelDB VersionEdit records, extracted from the bitcoin-rs project. This crate provides a faithful, byte-for-byte compatible Rust implementation of LevelDB's manifest version-edit logic as used by Bitcoin-like workloads.
Overview
LevelDB stores the evolution of its on-disk state (files per level, sequence-number metadata, compaction pointers, etc.) in a manifest file. Each record in the manifest is a VersionEdit: a compact, varint-encoded description of mutations to the logical database version.
This crate implements:
- A
VersionEditstruct mirroring LevelDB's internal representation - Deterministic encoding of
VersionEditinto the manifest binary format - Robust decoding from manifest records back into a
VersionEdit - Convenience APIs to:
- Track added files (per level)
- Track deleted files (per level)
- Maintain compaction pointers
- Maintain log / sequence-number bookkeeping
- Derive human-readable debug summaries
It is designed to be interoperable with existing LevelDB/Bitcoin data, focusing on correctness of serialization and deterministic ordering.
This crate is not a full LevelDB implementation; it is targeted infrastructure for higher-level components (like VersionSet and the full storage engine) in bitcoin-rs.
Features
-
Binary compatibility with LevelDB manifest format
- Uses varint32/varint64 and length-prefixed slices to match LevelDB's on-disk representation
- Tags and field semantics match LevelDB's
VersionEdit:kComparator(tag 1)kLogNumber(tag 2)kNextFileNumber(tag 3)kLastSequence(tag 4)kCompactPointer(tag 5)kDeletedFile(tag 6)kNewFile(tag 7)kPrevLogNumber(tag 9)
-
Deterministic encoding
- Deleted-file entries are sorted by
(level, file_number)prior to encoding, guaranteeing thatencode_to -> decode_from -> encode_toproduces bit-identical manifest bytes.
- Deleted-file entries are sorted by
-
Convenient high-level mutation API
add_file(level, file, size, smallest, largest)delete_file(level, file)set_comparator_name,set_log_number,set_prev_log_number,set_next_file,set_last_sequenceset_compact_pointer(level, key)
-
Introspectable
debug_string()yields a multi-line, human-readable summary suitable for logging and debugging, including all scalar fields, compaction pointers, deletions, and new files.
-
Safe defaults & state reset
Defaultconstructs an empty, "no-op"VersionEditwith allhas_flags cleared.clear()/reset_core_state()allow reuse of aVersionEditwhile preserving compaction pointers if desired.
Crate Status
- License: MIT
- Edition: Rust 2021
- Repository: https://github.com/klebs6/bitcoin-rs
- Intended users: implementers of LevelDB-compatible storage layers, Bitcoin node developers, and systems programmers requiring exact reproduction of LevelDB manifest semantics.
Core Data Structures
VersionEdit
pub type VersionEditDeletedFileSet = ;
Conceptually, a VersionEdit is a sparse patch to the current logical version:
-
Scalar metadata
comparator: name of the key comparatorlog_number: current log file numberprev_log_number: previous log file numbernext_file_number: global file-number allocator watermarklast_sequence: maximal sequence number visible after applying this edithas_*flags: which of the above are present in this edit
-
Collections
compact_pointers: Vec<(level, InternalKey)>deleted_files: HashSet<(level, file_number)>new_files: Vec<(level, FileMetaData)>
These mutate the file layout per compaction level.
Helper functions
These implement the manifest's binary protocol for specific logical units:
get_levelreads a LevelDB level (0..N) from a varint32-encoded field.get_internal_keyreads a length-prefixed slice and decodes it into anInternalKey.
Encoding & Decoding Semantics
Encoding: VersionEdit::encode_to
- Accepts a raw pointer to an owned
Stringthat serves as a byte buffer. - Serializes the
VersionEditfields into the LevelDB manifest wire format:- Scalars are emitted only if the corresponding
has_*flag is true. compact_pointers,deleted_files, andnew_filesare written sequentially.
- Scalars are emitted only if the corresponding
deleted_filesare pre-sorted:
let mut deleted_files_sorted: =
self.deleted_files.iter.copied.collect;
deleted_files_sorted.sort_unstable;
This guarantees deterministic encoding irrespective of the internal HashSet iteration order.
Safety model:
- The method uses
unsafefor the raw pointer; you must ensure:dstis non-null and points to a validString- The
Stringoutlives the call
A higher-level wrapper can be constructed to hide the raw pointer, e.g. by allocating and passing &mut String and then casting internally.
Decoding: VersionEdit::decode_from
- Resets the core scalar state and file collections before decoding.
- Consumes a copy of the input
Sliceand incrementally parses tagged fields. - Each tag is matched against the LevelDB tag set; unknown or malformed tags result in a
Status::corruptionwith contextual diagnostics. - Parsed values are routed through the higher-level mutation functions (
set_*,add_file,delete_file,set_compact_pointer).
The loop structure is essentially:
while msg.is_none && get_varint32
Post-conditions:
- On success: returns
Status::ok()and a fully-populatedVersionEdit. - On failure: returns a corruption
Statusindicating the failing component, and leaves theVersionEditin a reset state (partial mutations are not guaranteed useful).
Public API Usage
Constructing a basic VersionEdit
use VersionEdit;
use ;
Adding a new file
Preconditions (mirroring LevelDB's invariants):
smallestandlargestmust be the true extremal internal keys in the file.- The file must not have been persisted to the VersionSet yet (
VersionSet::SaveTo()expectation).
Deleting a file
Internally, this records (level, file_number) in deleted_files, which will be serialized as one or more kDeletedFile entries.
Compaction pointers
This denotes the logical resume key for future compactions at that level.
Debugging
Example output:
VersionEdit {
Comparator: leveldb.BytewiseComparator
LogNumber: 42
PrevLogNumber: 41
NextFile: 1000
LastSeq: 123456
CompactPointer: 1 userkey1@123
DeleteFile: 2 57
AddFile: 1 1001 1048576 smallest_key .. largest_key
}
Clearing and reusing a VersionEdit
clear() simply delegates to reset_core_state(), which zeroes scalars, clears deleted_files and new_files, and resets has_* flags.
Binary Format Details
This crate encodes/decodes the same schema as canonical LevelDB:
- Tags are varint32-encoded integers.
- Levels are varint32-encoded unsigned integers, cast to
i32in-memory. - File numbers and sizes use varint64.
- Internal keys are serialized as a length-prefixed slice (
lenas varint32, followed by bytes) and then decoded viaInternalKey::decode_from. - Comparator name is also a length-prefixed slice of UTF-8 bytes.
The serialization order is purely determined by the order of fields in the VersionEdit and the order of compact_pointers and new_files vectors, except for deleted_files, which are explicitly sorted, providing deterministic binary output.
This determinism is critical when one wants to ensure that two logically identical VersionEdits result in the same manifest bytes, which facilitates:
- Reproducible tests
- Content-addressable storage and hashing
- Stable replication and snapshot mechanics across nodes
Relationship to LevelDB and Bitcoin
In LevelDB (and by inheritance, Bitcoin Core's database layout), VersionEdit is the backbone for describing structural mutations in the set of SSTables. Bitcoin stores UTXO and block index information in LevelDB-style databases; exact adherence to manifest semantics is mandatory if you need to:
- Read or write existing Bitcoin Core databases
- Implement alternative nodes that share storage layouts
- Perform analysis or replay of historical LevelDB states from archived manifests
This crate intentionally mirrors the C++ LevelDB logic, with additional Rust idioms (e.g., Default, strong typing around Status, and improved logging).
Safety & Concurrency Considerations
- The core APIs are
&mut selfand therefore not thread-safe by themselves; wrap in synchronization primitives (Mutex, etc.) if accessed concurrently. encode_touses a raw pointer. Incorrect usage can lead to undefined behavior. If you design higher-level APIs on top of this crate, you are encouraged to encapsulate this unsafety in a small, well-tested layer that exposes only safe abstractions.decode_fromtrusts theSlicesize; it validates structure but not cryptographic authenticity. For untrusted input, pair it with higher-level validation or checksums.
When to Use This Crate
Use this crate if you need:
- Precise, LevelDB-compatible manifest handling in Rust
- To interoperate with Bitcoin or other LevelDB-based systems at the storage format level
- Deterministic, testable
VersionEditencoding/decoding
This crate is probably too low-level if you only need a high-level key-value database abstraction; in that case, integrate through whatever higher-layer VersionSet or storage API bitcoin-rs exposes.
License
This crate is distributed under the MIT license, consistent with the bitcoin-rs repository.
Provenance
This crate is part of the bitcoin-rs repository and focuses exclusively on the VersionEdit component of a LevelDB-compatible storage engine.