Skip to content

Commit 8b8925b

Browse files
committed
Refactor the simple8b size calculation
to split up the UUID compression PR Disable-check: force-changelog-file
1 parent 4e7c307 commit 8b8925b

2 files changed

Lines changed: 138 additions & 7 deletions

File tree

tsl/src/compression/algorithms/simple8b_rle.h

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,20 @@ static inline char *bytes_serialize_simple8b_and_advance(char *dest, size_t expe
159159
static inline Simple8bRleSerialized *bytes_deserialize_simple8b_and_advance(StringInfo si);
160160
static inline size_t simple8brle_serialized_slot_size(const Simple8bRleSerialized *data);
161161
static inline size_t simple8brle_serialized_total_size(const Simple8bRleSerialized *data);
162-
static inline size_t simple8brle_compressor_compressed_size(Simple8bRleCompressor *compressor);
162+
163+
/*
164+
* Calculate the size of the compressed data with the assumption that all uncompressed
165+
* data is flushed and pushed already.
166+
*/
167+
static inline size_t
168+
simple8brle_compressor_compressed_size(const Simple8bRleCompressor *compressor);
169+
170+
/*
171+
* Calculate the size of the compressed data without modifying the compressor and without
172+
* making assumptions about the compressor state.
173+
*/
174+
static inline size_t
175+
simple8brle_compressor_compressed_const_size(const Simple8bRleCompressor *compressor);
163176

164177
/*********************
165178
*** Private API ***
@@ -205,7 +218,7 @@ static uint32 simple8brle_num_selector_slots_for_num_blocks(uint32 num_blocks);
205218
*** Simple8bRleSerialized ***
206219
*******************************/
207220

208-
static Simple8bRleSerialized *
221+
static inline Simple8bRleSerialized *
209222
simple8brle_serialized_recv(StringInfo buffer)
210223
{
211224
uint32 i;
@@ -300,10 +313,7 @@ simple8brle_serialized_total_size(const Simple8bRleSerialized *data)
300313
static void
301314
simple8brle_compressor_init(Simple8bRleCompressor *compressor)
302315
{
303-
*compressor = (Simple8bRleCompressor){
304-
.num_elements = 0,
305-
.num_uncompressed_elements = 0,
306-
};
316+
*compressor = (Simple8bRleCompressor){ .num_elements = 0, .num_uncompressed_elements = 0 };
307317
/*
308318
* It is good to have some estimate of the resulting size of compressed
309319
* data, because it helps to allocate memory in advance to avoid frequent
@@ -343,7 +353,7 @@ simple8brle_compressor_is_empty(Simple8bRleCompressor *compressor)
343353
}
344354

345355
static size_t
346-
simple8brle_compressor_compressed_size(Simple8bRleCompressor *compressor)
356+
simple8brle_compressor_compressed_size(const Simple8bRleCompressor *compressor)
347357
{
348358
/* we store 16 selectors per selector_slot, and one selector_slot per compressed_data_slot.
349359
* use num_compressed_data_slots / 16 + 1 to ensure that rounding doesn't truncate our slots
@@ -354,6 +364,66 @@ simple8brle_compressor_compressed_size(Simple8bRleCompressor *compressor)
354364
bit_array_data_bytes_used(&compressor->selectors);
355365
}
356366

367+
static size_t
368+
simple8brle_compressor_compressed_const_size(const Simple8bRleCompressor *compressor)
369+
{
370+
/* Allocate temp space where the temp_compressor will put the data.
371+
* The temp sizes are set to accommodate for the worst case scenario of
372+
* both the last block and the uncompressed data.
373+
*/
374+
#define TEMP_DATA_SIZE (SIMPLE8B_MAX_VALUES_PER_SLOT * 2)
375+
#define TEMP_SELECTORS_SIZE (TEMP_DATA_SIZE / SIMPLE8B_SELECTORS_PER_SELECTOR_SLOT)
376+
377+
uint64 temp_data[TEMP_DATA_SIZE];
378+
uint64 temp_selectors[TEMP_SELECTORS_SIZE];
379+
380+
Simple8bRleCompressor temp_compressor = *compressor;
381+
382+
/* Replace the data and selectors with the temp space.*/
383+
temp_compressor.compressed_data.data = temp_data;
384+
temp_compressor.compressed_data.num_elements = 0;
385+
temp_compressor.compressed_data.max_elements = TEMP_DATA_SIZE;
386+
temp_compressor.selectors.buckets.data = temp_selectors;
387+
temp_compressor.selectors.buckets.num_elements = 0;
388+
temp_compressor.selectors.buckets.max_elements = TEMP_SELECTORS_SIZE;
389+
temp_compressor.selectors.bits_used_in_last_bucket = 0;
390+
391+
/*
392+
* If the compressor has no uncompressed data, we can use the original size calculation.
393+
* Note that after every append, it is guaranteed that we have at least one uncompressed
394+
* element. Not having uncompressed elements can only happen if the compressor is empty
395+
* or finish was called, so we can use the original size calculation.
396+
*/
397+
if (compressor->num_uncompressed_elements == 0 && compressor->num_elements > 0)
398+
return simple8brle_compressor_compressed_size(compressor);
399+
400+
/* Flush the compressor to ensure all uncompressed data is placed into the last_block.*/
401+
simple8brle_compressor_flush(&temp_compressor);
402+
403+
/* If the compressor is empty, we can return 0, similar to finish. */
404+
if (temp_compressor.num_elements == 0)
405+
return 0;
406+
407+
Assert(temp_compressor.last_block_set);
408+
simple8brle_compressor_push_block(&temp_compressor, temp_compressor.last_block);
409+
410+
size_t num_data_blocks =
411+
compressor->compressed_data.num_elements + temp_compressor.compressed_data.num_elements;
412+
413+
/* Add up the size of the compressed data blocks and the header. */
414+
size_t result = sizeof(Simple8bRleSerialized) +
415+
num_data_blocks * sizeof(*temp_compressor.compressed_data.data);
416+
417+
/* Add up the selector bits. */
418+
size_t selector_bits = num_data_blocks * SIMPLE8B_BITS_PER_SELECTOR;
419+
result += ((selector_bits + 63) / 64) * sizeof(uint64);
420+
421+
#undef TEMP_DATA_SIZE
422+
#undef TEMP_SELECTORS_SIZE
423+
424+
return result;
425+
}
426+
357427
static void
358428
simple8brle_compressor_push_block(Simple8bRleCompressor *compressor, Simple8bRleBlock block)
359429
{

tsl/test/src/compression_unit_test.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "compression/algorithms/float_utils.h"
3232
#include "compression/algorithms/gorilla.h"
3333
#include "compression/algorithms/null.h"
34+
#include "compression/algorithms/simple8b_rle.h"
3435
#include "compression/arrow_c_data_interface.h"
3536
#include "compression/batch_metadata_builder_minmax.h"
3637

@@ -1009,6 +1010,65 @@ test_null()
10091010
}
10101011
}
10111012

1013+
static void
1014+
test_simple8b_rle_compressed_size(uint64 *elements, int num_elements)
1015+
{
1016+
Simple8bRleCompressor compressor;
1017+
simple8brle_compressor_init(&compressor);
1018+
1019+
for (int i = 0; i < num_elements; i++)
1020+
{
1021+
simple8brle_compressor_append(&compressor, elements[i]);
1022+
}
1023+
1024+
size_t compressed_size = simple8brle_compressor_compressed_const_size(&compressor);
1025+
if (num_elements == 0)
1026+
{
1027+
TestAssertInt64Eq(compressed_size, 0);
1028+
return;
1029+
}
1030+
1031+
Simple8bRleSerialized *serialized = simple8brle_compressor_finish(&compressor);
1032+
size_t serialized_size = simple8brle_serialized_total_size(serialized);
1033+
TestAssertInt64Eq(compressed_size, serialized_size);
1034+
1035+
/* Check the const size function after the compressor is finished,
1036+
* this may happen accidentally, not on purpose.
1037+
*/
1038+
compressed_size = simple8brle_compressor_compressed_const_size(&compressor);
1039+
TestAssertInt64Eq(compressed_size, serialized_size);
1040+
1041+
pfree(serialized);
1042+
}
1043+
1044+
static void
1045+
test_simple8b_rle()
1046+
{
1047+
/* clang-format off */
1048+
/* clang would place all the elements on a single line otherwise */
1049+
uint64 elements[] = {
1050+
1, 2, 4, 8, 16, 7, 3, 32, 64, 63, 31, 15, 7, 3, 1, 0,
1051+
128, 127, 63, 31, 15, 7, 3, 1, 0, 256, 255, 127, 63, 31, 15, 7,
1052+
3, 1, 0, 512, 511, 126, 63, 31, 15, 7, 3, 1, 0, 1024, 1023, 511,
1053+
255, 127, 63, 31, 15, 7, 3, 1, 0, 2048, 2047, 1023, 511, 255, 127,
1054+
63, 31, 15, 7, 3, 1, 0, 4096, 4095, 2047, 1023, 511, 255, 127, 63,
1055+
31, 15, 7, 3, 1, 0, 8192, 8191, 4095, 2047, 1023, 511, 255, 127,
1056+
63, 31, 15, 7, 3, 1, 0, 16384, 16383, 8191, 4095, 2047, 1023, 511,
1057+
255, 127, 63, 31, 15, 7, 3, 1, 0, 32768, 32767, 16383, 8191, 4095,
1058+
2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 65536, 65535,
1059+
32767, 16383, 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15,
1060+
131072, 131071, 65535, 16777216, 16777211, 16777215, 4294967296ULL,
1061+
12884901888ULL
1062+
};
1063+
/* clang-format on */
1064+
1065+
int n = sizeof(elements) / sizeof(*elements);
1066+
for (int i = 0; i < n; i++)
1067+
{
1068+
test_simple8b_rle_compressed_size(elements, i);
1069+
}
1070+
}
1071+
10121072
Datum
10131073
ts_test_compression(PG_FUNCTION_ARGS)
10141074
{
@@ -1030,6 +1090,7 @@ ts_test_compression(PG_FUNCTION_ARGS)
10301090
test_delta3(/* have_nulls = */ true, /* have_random = */ true);
10311091
test_bool();
10321092
test_null();
1093+
test_simple8b_rle();
10331094

10341095
/* Some tests for zig-zag encoding overflowing the original element width. */
10351096
test_delta4(test_delta4_case1, sizeof(test_delta4_case1) / sizeof(*test_delta4_case1));

0 commit comments

Comments
 (0)