@@ -1028,17 +1028,41 @@ reader_parse_block_header(BinaryReader *reader, const ByteBuffer *section,
10281028 return 0 ;
10291029}
10301030
1031+ /* A constant stream index or residual column that holds the same one-byte
1032+ * varint for every sample is read from its stored byte, not expanded. */
1033+ static int
1034+ constant_varint_column (const DecodedBlock * block , unsigned column ,
1035+ uint8_t value )
1036+ {
1037+ const ColumnDescriptor * descriptor = & block -> header .columns [column ];
1038+ return (column == COLUMN_SAMPLE_STREAM_IDS ||
1039+ column == COLUMN_TIMESTAMP_RESIDUALS ) &&
1040+ descriptor -> encoding == COLUMN_CONSTANT &&
1041+ descriptor -> decoded_size == block -> header .sample_count &&
1042+ value < 0x80 ;
1043+ }
1044+
10311045static int
10321046decode_block_columns (BinaryReader * reader , const ByteBuffer * section ,
10331047 size_t * offset , DecodedBlock * block )
10341048{
10351049 const ColumnDescriptor * descriptors = block -> header .columns ;
1036- /* Constant and zstd columns share one buffer, reused across blocks.
1037- * It is reserved up front so decoded columns never move. */
1050+ /* Find where each column is stored and how much of the shared buffer
1051+ * the expanded and decompressed columns need. The buffer is reused
1052+ * across blocks and reserved up front so decoded columns never move. */
1053+ uint8_t * stored [COLUMN_COUNT ];
10381054 size_t buffered_total = 0 ;
10391055 for (unsigned column = 0 ; column < COLUMN_COUNT ; column ++ ) {
1040- if (descriptors [column ].encoding != COMPRESSION_NONE ) {
1041- buffered_total += descriptors [column ].decoded_size ;
1056+ const ColumnDescriptor * descriptor = & descriptors [column ];
1057+ if (descriptor -> stored_size > section -> size - * offset ) {
1058+ return block_error ("column extends past the sample section" );
1059+ }
1060+ stored [column ] = section -> data + * offset ;
1061+ * offset += descriptor -> stored_size ;
1062+ if (descriptor -> encoding == COMPRESSION_ZSTD ||
1063+ (descriptor -> encoding == COLUMN_CONSTANT &&
1064+ !constant_varint_column (block , column , stored [column ][0 ]))) {
1065+ buffered_total += descriptor -> decoded_size ;
10421066 }
10431067 }
10441068 ByteBuffer * buffer = & reader -> block_data ;
@@ -1049,10 +1073,7 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10491073 buffer -> size = 0 ;
10501074 for (unsigned column = 0 ; column < COLUMN_COUNT ; column ++ ) {
10511075 const ColumnDescriptor * descriptor = & descriptors [column ];
1052- if (descriptor -> stored_size > section -> size - * offset ) {
1053- return block_error ("column extends past the sample section" );
1054- }
1055- uint8_t * stored_data = section -> data + * offset ;
1076+ uint8_t * stored_data = stored [column ];
10561077 ByteBuffer * decoded = & block -> columns [column ];
10571078 decoded -> size = descriptor -> decoded_size ;
10581079 switch (descriptor -> encoding ) {
@@ -1061,6 +1082,11 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10611082 decoded -> data = stored_data ;
10621083 break ;
10631084 case COLUMN_CONSTANT :
1085+ if (constant_varint_column (block , column , stored_data [0 ])) {
1086+ decoded -> data = stored_data ;
1087+ decoded -> size = 1 ;
1088+ break ;
1089+ }
10641090 decoded -> data = buffer -> data + buffer -> size ;
10651091 memset (decoded -> data , stored_data [0 ], decoded -> size );
10661092 buffer -> size += decoded -> size ;
@@ -1076,7 +1102,6 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10761102 default :
10771103 return block_error ("unknown column encoding" );
10781104 }
1079- * offset += descriptor -> stored_size ;
10801105 }
10811106 return 0 ;
10821107}
@@ -1203,23 +1228,38 @@ decode_samples(BinaryReader *reader, DecodedBlock *block)
12031228 & block -> columns [COLUMN_SAMPLE_STREAM_IDS ];
12041229 const ByteBuffer * residual_column =
12051230 & block -> columns [COLUMN_TIMESTAMP_RESIDUALS ];
1231+ int constant_stream_ids = constant_varint_column (
1232+ block , COLUMN_SAMPLE_STREAM_IDS , stream_id_column -> data [0 ]);
1233+ int constant_residuals = constant_varint_column (
1234+ block , COLUMN_TIMESTAMP_RESIDUALS , residual_column -> data [0 ]);
12061235 size_t stream_id_offset = 0 ;
12071236 size_t residual_offset = 0 ;
1237+ int64_t constant_residual = 0 ;
1238+ if (constant_residuals ) {
1239+ constant_residual = decode_varint_i64 (residual_column -> data ,
1240+ & residual_offset , 1 );
1241+ }
12081242 for (uint32_t sample = 0 ; sample < block -> header .sample_count ; sample ++ ) {
12091243 uint64_t stream_id ;
1210- if (block_read_varint (stream_id_column , & stream_id_offset ,
1211- & stream_id ) < 0 ) {
1244+ if (constant_stream_ids ) {
1245+ stream_id = stream_id_column -> data [0 ];
1246+ }
1247+ else if (block_read_varint (stream_id_column , & stream_id_offset ,
1248+ & stream_id ) < 0 ) {
12121249 return -1 ;
12131250 }
12141251 if (stream_id >= block -> stream_count ) {
12151252 return block_error ("sample refers to an unknown stream" );
12161253 }
1217- size_t prev_offset = residual_offset ;
1218- int64_t residual = decode_varint_i64 (residual_column -> data ,
1219- & residual_offset ,
1220- residual_column -> size );
1221- if (residual_offset == prev_offset ) {
1222- return -1 ;
1254+ int64_t residual = constant_residual ;
1255+ if (!constant_residuals ) {
1256+ size_t prev_offset = residual_offset ;
1257+ residual = decode_varint_i64 (residual_column -> data ,
1258+ & residual_offset ,
1259+ residual_column -> size );
1260+ if (residual_offset == prev_offset ) {
1261+ return -1 ;
1262+ }
12231263 }
12241264
12251265 /* Timestamp is the expected time plus the stored residual */
@@ -1230,7 +1270,7 @@ decode_samples(BinaryReader *reader, DecodedBlock *block)
12301270 stream_ids [sample ] = (uint32_t )stream_id ;
12311271 timestamps [sample ] = stream -> prev_timestamp ;
12321272 }
1233- if (stream_id_offset != stream_id_column -> size ) {
1273+ if (! constant_stream_ids && stream_id_offset != stream_id_column -> size ) {
12341274 return block_error ("stream index column has trailing data" );
12351275 }
12361276 if (residual_offset != residual_column -> size ) {
0 commit comments