This is a general-purpose key-value database format that uses an SBSF container as its backing store.
This header is found at the start of the User Header area of the SBSF container.
Byte[4] | Signature "BTDB" | ||||
Uint64 | Root Block ID | ||||
Bool | Is Root Leaf | ||||
Byte[19] | Reserved | ||||
Packed | Metadata length | ||||
Metadata |
|
Since this database uses the SBSF format as its backing store, all data is stored in blocks. The problem is that a single Leaf can be larger than a single block. To compensate for this, leaves are cut up and stored in this Leaf Block Format.
Byte[2] | Leaf Block Signature "LL" |
Byte[*] | Leaf Data |
Int64 | Next Leaf Block ID |
Let's assume the Block Size is set to 512 bytes. Each block contains 2 bytes of signature, 502 bytes of Leaf data, and 8 bytes that point to the next block. If the Next Leaf Block ID is -1, then there aren't any more Leaf Blocks.
Now let's look at the format of the actual leaf inside the Leaf Blocks.
Uint32 | Number of Children | ||||||
Child[*] |
|
The children are sorted by their keys. This allows you to use binary searching to search for the matching key in Log time.
The Indexes are also stored in blocks, but they're always smaller than a single block, so they don't need to be cut up into multiple Index Blocks.
Byte[2] | Index Block Signature "II" | ||||
Byte | Level | ||||
Uint32 | Number of Children | ||||
Uint64 | Default Block ID | ||||
Child[*] |
|
Again, the children are sorted by their keys to allow for binary searching.
Here's some pseudocode that demonstrates how to search through the btree for a key. This pseudocode uses linear searching instead of binary searching for clarity.
find(Key key) { if (rootIsLeaf) return findLeaf(rootBlockID,key); else return findIndex(rootBlockID,key); } findLeaf(Uint64 blockID,Key key) { Leaf leaf = loadLeaf(blockID); foreach (child in leaf) { if (child.key == key) return child.value; } return null; } findIndex(Uint64 blockID,Key key) { Index index = loadIndex(blockID); Uint64 valueID = index.defaultBlockID; foreach (child in index) { if (child.minimumKey > key) break; valueID = child.blockID; } if (index.level == 0) return findLeaf(valueID,key); else return findIndex(valueID,key); }