···4141All blocks have an address consisting of the `{index, checksum}` of the block.
42424343The `index` is the index of the block within the file.
4444-The byte-offset of the block within the file is therefore `index * block_size`.
4444+The byte offset of the block within the file is therefore `index * block_size`.
45454646The `checksum` is a crypto-safe checksum of the block's contents.
4747This is currently a 128-bit truncation of the SHA256 hash of the contents,
···182182183183The trailer consists of:
184184185185-- A list of block addresses (`index` and `checksum`) for the blocks in the table
185185+- An array of block addresses (`index` and `checksum`) for the blocks in the table
186186- The fixed-length metadata needed to decode the table
187187188188#### Metadata
···213213index (8 bytes) | checksum (16 bytes)
214214```
215215216216-By storing the list of block addresses entirely within the last block,
216216+By storing the array of block addresses entirely within the last block,
217217we avoid having to build a linked list of blocks for the trailer.
218218We can fit roughly 20,000 24-byte addresses within a 512 KiB block,
219219so this approach limits us to a table size of around 10 GiB: *far* larger than we will ever need.
220220221221+### Table index
222222+223223+The table index is an index used to look up subs within a table.
224224+Each sub has an entry in the index consisting of its key range and its byte offset within the table.
225225+226226+The index entries are written contiguously in the following format:
227227+228228+```
229229+# Index entry
230230+start_key (variable) | start_key_version (8 bytes) | sub_offset (4 bytes) | sub_size (4 bytes)
231231+```
232232+233233+The `start_key` and `start_key_version` are the key/version of the first pair in the sub.
234234+235235+The `sub_offset` and `sub_size` are the byte offset and byte size of the sub within the table.
236236+237237+Because keys are variable in length,
238238+the index entries are followed by an array of fixed-length slots (one per entry):
239239+240240+```
241241+# Entry slot
242242+offset (4 bytes) | key_size (4 bytes)
243243+```
244244+245245+The `offset` is the byte offset of the entry within the table.
246246+The `key_size` is the length of the key.
247247+248248+After decoding the table metadata we obtain the location and size of this slot array.
249249+We can then binary search the index by looking up the keys for slots in the array.
250250+221251### Subtables
222252223253Each sub consists of key/value pairs in sorted order followed by their indexes and then a trailer indicating the number of pairs.
···2622924. Binary search the pairs.
263293 Using the offsets, we can look up any pair's key at the byte range `[index, index + key_length + 8)`.
264294 Note that we *include* the version (8 bytes) in the key when binary searching because this is a multiversion LSM.
265265-266266-### Table Index
267267-268268-The table index is an index of all subs within the table and their corresponding key ranges.
269269-The purpose of this is to avoid loading the entire (large) table into memory to perform a binary search.
270270-We can binary search the index first to find the right sub and then search the sub for a pair.
271271-272272-The index consists of sub keys/addresses stored contiguously and then their offsets stored contiguously.
273273-274274-```
275275-# Sub entry:
276276-key (variable) | key_version (8 bytes) | sub_offset (8 bytes) | sub_size (4 bytes)
277277-278278-# Entry slot:
279279-offset (4 bytes)
280280-```
281281-282282-The `key` and `key_version` are the key/version of the first key in the sub.
283283-284284-The `sub_offset` is the byte offset of the sub *within the table*,
285285-and the `sub_size` is the byte length of the sub.
286286-287287-The `offset` stores the byte offset of each entry within the index.
288288-289289-The length of the `key` is stored implicitly as the difference between slot `offset`s.
290290-291291-The sub entries can be binary searched with an algorithm similar to that of the subs detailed above.