Variable length records are contained in "frames". A record can be put in one or more frames, also called the record "parts" or "blocks". The sense of the frames is to allow reusage of the space of deleted records. Starting with an empty data file, records are put in a single frame each, unless a record is bigger than the maximum frame size (16MB - 4). When a record is deleted, its frame is marked deleted. When a record is inserted after this, it reuses the old frame. If the new record is smaller, the frame is split. The unused part is marked deleted. If a new record is bigger than the old frame, the frame is filled with the record as much as fits. The rest is inserted in other old frames, or, if non is available, in a new frame at end of file.
MI_MIN_BLOCK_LENGTH 20 /* 20 bytes are required for the biggest frame type: Deleted block. */ MI_MAX_BLOCK_LENGTH 16777212 /* 16MB - 4, max 3 bytes for length available, 4-byte aligned. */ MI_DYN_ALIGN_SIZE 4 /* Frames start a 4-byte boundaries. */
Part header[0] (decimal/hexadecimal, one byte):
0/00: Deleted block
block_len 3 bytes [1-3]
next_filepos 8 bytes [4-11]
prev_filepos 8 bytes [12-19]
=> header length 20
1/01: Full small record, full block
rec_len,data_len,block_len 2 bytes [1-2]
=> header length 3
2/02: Full big record, full block
rec_len,data_len,block_len 3 bytes [1-3]
=> header length 4
3/03: Full small record, unused space
rec_len,data_len 2 bytes [1-2]
unused_len 1 byte [3]
=> header length 4
4/04: Full big record, unused space
rec_len,data_len 3 bytes [1-3]
unused_len 1 byte [4]
=> header length 5
5/05: Start small record
rec_len 2 bytes [1-2]
data_len,block_len 2 bytes [3-4]
next_filepos 8 bytes [5-12]
=> header length 13
6/06: Start big record
rec_len 3 bytes [1-3]
data_len,block_len 3 bytes [4-6]
next_filepos 8 bytes [7-14]
=> header length 15
7/07: End small record, full block
data_len,block_len 2 bytes [1-2]
=> header length 3
8/08: End big record, full block
data_len,block_len 3 bytes [1-3]
=> header length 4
9/09: End small record, unused space
data_len 2 bytes [1-2]
unused_len 1 byte [3]
=> header length 4
10/0A: End big record, unused space
data_len 3 bytes [1-3]
unused_len 1 byte [4]
=> header length 5
11/0B: Continue small record
data_len,block_len 2 bytes [1-2]
next_filepos 8 bytes [3-10]
=> header length 11
12/0C: Continue big record
data_len,block_len 3 bytes [1-3]
next_filepos 8 bytes [4-11]
=> header length 12
13/0D: Start giant record
rec_len 4 bytes [1-4]
data_len,block_len 3 bytes [5-7]
next_filepos 8 bytes [8-15]
=> header length 16
block_len does not include the header length except of deleted blocks. In deleted blocks block_len includes the header length.
data_len is the number of bytes within this block that are part of the record.
rec_len is the total record length including the data lengths of all belonging blocks.
In deleted blocks next_filepos and prev_filepos make a doubly linked list over all deleted blocks. At list start, prev_filepos is HA_OFFSET_ERROR (all bits set). At list end, next_filepos is HA_OFFSET_ERROR (all bits set).
In non-deleted blocks next_filepos points to the next part of the record.
The read function for the block header of dynamic records is mi_dynrec.c:_mi_get_block_info().
pack bits (!= NULL bits!): One bit per packable column:
FIELD_BLOB: Set if blob is empty. No blob data in record.
FIELD_SKIP_ZERO: Set if all bytes zero, no data in record.
FIELD_SKIP_ENDSPACE,
FIELD_SKIP_PRESPACE: Set if some blanks stripped in record.
=> The "pack bits" are rounded up to the next byte boundary.
Record contents from the in-memory representation. Each field is copied verbatim unless packed according to the "pack bits" paragraph.
null bits: One bit per column that can be NULL.
The "null bits" are rounded up to the next byte boundary.
the number of "null bytes" are also referred as data_offset.
fields: One field per column. No separators, length fields, etc.
Length (pack_length) and layout of the fields depend on the
field type:
-- to be added --
Note: The "in-memory record layout" is used by the SQL layer. It is independent from storage engines. All storage engines have to accept and produce this in-memory format at the handler interface.
