1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "gtest/gtest.h"
5 #include "rgw/rgw_compression.h"
7 class ut_get_sink
: public RGWGetObj_Filter
{
11 virtual ~ut_get_sink() {}
13 int handle_data(bufferlist
& bl
, off_t bl_ofs
, off_t bl_len
) override
15 auto& bl_buffers
= bl
.buffers();
16 auto i
= bl_buffers
.begin();
19 ceph_assert(i
!= bl_buffers
.end());
20 off_t len
= std::min
<off_t
>(bl_len
, i
->length());
21 sink
.append(*i
, 0, len
);
27 bufferlist
& get_sink()
33 class ut_get_sink_size
: public RGWGetObj_Filter
{
37 virtual ~ut_get_sink_size() {}
39 int handle_data(bufferlist
& bl
, off_t bl_ofs
, off_t bl_len
) override
41 if (bl_len
> (off_t
)max_size
)
51 class ut_put_sink
: public rgw::sal::DataProcessor
55 int process(bufferlist
&& bl
, uint64_t ofs
) override
57 sink
.claim_append(bl
);
60 bufferlist
& get_sink()
67 struct MockGetDataCB
: public RGWGetObj_Filter
{
68 int handle_data(bufferlist
& bl
, off_t bl_ofs
, off_t bl_len
) override
{
73 using range_t
= std::pair
<off_t
, off_t
>;
75 // call filter->fixup_range() and return the range as a pair. this makes it easy
76 // to fit on a single line for ASSERT_EQ()
77 range_t
fixup_range(RGWGetObj_Decompress
*filter
, off_t ofs
, off_t end
)
79 filter
->fixup_range(ofs
, end
);
84 TEST(Decompress
, FixupRangePartial
)
86 RGWCompressionInfo cs_info
;
88 // array of blocks with original len=8, compressed to len=6
89 auto& blocks
= cs_info
.blocks
;
90 blocks
.emplace_back(compression_block
{0, 0, 6});
91 blocks
.emplace_back(compression_block
{8, 6, 6});
92 blocks
.emplace_back(compression_block
{16, 12, 6});
93 blocks
.emplace_back(compression_block
{24, 18, 6});
95 const bool partial
= true;
96 RGWGetObj_Decompress
decompress(g_ceph_context
, &cs_info
, partial
, &cb
);
98 // test translation from logical ranges to compressed ranges
99 ASSERT_EQ(range_t(0, 5), fixup_range(&decompress
, 0, 1));
100 ASSERT_EQ(range_t(0, 5), fixup_range(&decompress
, 1, 7));
101 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress
, 7, 8));
102 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress
, 0, 9));
103 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress
, 7, 9));
104 ASSERT_EQ(range_t(6, 11), fixup_range(&decompress
, 8, 9));
105 ASSERT_EQ(range_t(6, 17), fixup_range(&decompress
, 8, 16));
106 ASSERT_EQ(range_t(6, 17), fixup_range(&decompress
, 8, 17));
107 ASSERT_EQ(range_t(12, 23), fixup_range(&decompress
, 16, 24));
108 ASSERT_EQ(range_t(12, 23), fixup_range(&decompress
, 16, 999));
109 ASSERT_EQ(range_t(18, 23), fixup_range(&decompress
, 998, 999));
112 TEST(Compress
, LimitedChunkSize
)
114 CompressorRef plugin
;
115 plugin
= Compressor::create(g_ceph_context
, Compressor::COMP_ALG_ZLIB
);
116 ASSERT_NE(plugin
.get(), nullptr);
118 for (size_t s
= 100 ; s
< 10000000 ; s
= s
*5/4)
125 RGWPutObj_Compress
compressor(g_ceph_context
, plugin
, &c_sink
);
126 compressor
.process(std::move(bl
), 0);
127 compressor
.process({}, s
); // flush
129 RGWCompressionInfo cs_info
;
130 cs_info
.compression_type
= plugin
->get_type_name();
131 cs_info
.orig_size
= s
;
132 cs_info
.compressor_message
= compressor
.get_compressor_message();
133 cs_info
.blocks
= move(compressor
.get_compression_blocks());
135 ut_get_sink_size d_sink
;
136 RGWGetObj_Decompress
decompress(g_ceph_context
, &cs_info
, false, &d_sink
);
140 decompress
.fixup_range(f_begin
, f_end
);
142 decompress
.handle_data(c_sink
.get_sink(), 0, c_sink
.get_sink().length());
144 decompress
.handle_data(empty
, 0, 0);
146 ASSERT_LE(d_sink
.get_size(), (size_t)g_ceph_context
->_conf
->rgw_max_chunk_size
);
151 TEST(Compress
, BillionZeros
)
153 CompressorRef plugin
;
155 plugin
= Compressor::create(g_ceph_context
, Compressor::COMP_ALG_ZLIB
);
156 ASSERT_NE(plugin
.get(), nullptr);
157 RGWPutObj_Compress
compressor(g_ceph_context
, plugin
, &c_sink
);
159 constexpr size_t size
= 1000000;
164 for (int i
=0; i
<1000;i
++)
165 compressor
.process(bufferlist
{bl
}, size
*i
);
166 compressor
.process({}, size
*1000); // flush
168 RGWCompressionInfo cs_info
;
169 cs_info
.compression_type
= plugin
->get_type_name();
170 cs_info
.orig_size
= size
*1000;
171 cs_info
.compressor_message
= compressor
.get_compressor_message();
172 cs_info
.blocks
= move(compressor
.get_compression_blocks());
175 RGWGetObj_Decompress
decompress(g_ceph_context
, &cs_info
, false, &d_sink
);
178 off_t f_end
= size
*1000 - 1;
179 decompress
.fixup_range(f_begin
, f_end
);
181 decompress
.handle_data(c_sink
.get_sink(), 0, c_sink
.get_sink().length());
183 decompress
.handle_data(empty
, 0, 0);
185 ASSERT_EQ(d_sink
.get_sink().length() , size
*1000);