Nulls
Nulls
A non-aligned timeseries stores only the (timestamp, value) points that exist. Its Pages do not contain null markers.
An aligned value column records nulls in the bitmap of each Value Page:
AlignedValuePagePayload :=
int32 position_count
byte present_bitmap[ceil(position_count / 8)]
byte encoded_non_null_values[remaining bytes]Position i corresponds to bit 7 - (i mod 8) of present_bitmap[i / 8]:
- A set bit means that the position has a value.
- A clear bit means that the position is null.
The encoded value stream contains only values whose bitmap bits are set, in position order. position_count equals the number of timestamps in the corresponding Time Page.
For example, with position_count = 10, bitmap bytes 10110000 01000000 indicate values at positions 0, 2, 3, and 9. The value decoder therefore produces four values and places them at those positions; the remaining six positions are null. Unused low-order bits in the final byte are not logical positions and are ignored.
For a non-empty Value Page the following invariants hold:
bitmap_bytes = ceil(position_count / 8)
decoded_value_count = popcount(present_bitmap over position_count bits)
position_count = decoded_timestamp_count of the corresponding Time PageA mismatch is structural corruption; the reader must not infer additional positions from trailing bitmap bits or encoded values.
If an entire Value Page is null, the Page consists only of an uncompressed_size equal to zero:
EmptyAlignedValuePage := UVarInt(0)An empty Page has no compressed_size, Statistics, bitmap, or value stream. Its position count is obtained from the corresponding Time Page.
An empty Value Page preserves its position in the Page sequence, so subsequent Value Pages still match the correct Time Pages. An absent Value Chunk has no physical column for that aligned Chunk set. A Value Chunk with data_size = 0 is a third case: its Header exists, but it contains no Pages. These cases must be distinguished when walking the aligned Chunk set.