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 RGWGetDataCB {
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 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 RGWGetDataCB {
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 RGWPutObjDataProcessor
56 virtual ~ut_put_sink(){}
57 int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again) override
63 int throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait) override
67 bufferlist& get_sink()
74 struct MockGetDataCB : public RGWGetDataCB {
75 int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override {
80 using range_t = std::pair<off_t, off_t>;
82 // call filter->fixup_range() and return the range as a pair. this makes it easy
83 // to fit on a single line for ASSERT_EQ()
84 range_t fixup_range(RGWGetObj_Decompress *filter, off_t ofs, off_t end)
86 filter->fixup_range(ofs, end);
91 TEST(Decompress, FixupRangePartial)
93 RGWCompressionInfo cs_info;
95 // array of blocks with original len=8, compressed to len=6
96 auto& blocks = cs_info.blocks;
97 blocks.emplace_back(compression_block{0, 0, 6});
98 blocks.emplace_back(compression_block{8, 6, 6});
99 blocks.emplace_back(compression_block{16, 12, 6});
100 blocks.emplace_back(compression_block{24, 18, 6});
102 const bool partial = true;
103 RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, partial, &cb);
105 // test translation from logical ranges to compressed ranges
106 ASSERT_EQ(range_t(0, 5), fixup_range(&decompress, 0, 1));
107 ASSERT_EQ(range_t(0, 5), fixup_range(&decompress, 1, 7));
108 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress, 7, 8));
109 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress, 0, 9));
110 ASSERT_EQ(range_t(0, 11), fixup_range(&decompress, 7, 9));
111 ASSERT_EQ(range_t(6, 11), fixup_range(&decompress, 8, 9));
112 ASSERT_EQ(range_t(6, 17), fixup_range(&decompress, 8, 16));
113 ASSERT_EQ(range_t(6, 17), fixup_range(&decompress, 8, 17));
114 ASSERT_EQ(range_t(12, 23), fixup_range(&decompress, 16, 24));
115 ASSERT_EQ(range_t(12, 23), fixup_range(&decompress, 16, 999));
116 ASSERT_EQ(range_t(18, 23), fixup_range(&decompress, 998, 999));
119 TEST(Compress, LimitedChunkSize)
121 CompressorRef plugin;
122 plugin = Compressor::create(g_ceph_context, Compressor::COMP_ALG_ZLIB);
123 ASSERT_NE(plugin.get(), nullptr);
125 for (size_t s = 100 ; s < 10000000 ; s = s*5/4)
136 RGWPutObj_Compress compressor(g_ceph_context, plugin, &c_sink);
137 compressor.handle_data(bl, 0, &handle, &obj, &again);
140 compressor.handle_data(empty, s, &handle, &obj, &again);
142 RGWCompressionInfo cs_info;
143 cs_info.compression_type = plugin->get_type_name();
144 cs_info.orig_size = s;
145 cs_info.blocks = move(compressor.get_compression_blocks());
147 ut_get_sink_size d_sink;
148 RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, false, &d_sink);
152 decompress.fixup_range(f_begin, f_end);
154 decompress.handle_data(c_sink.get_sink(), 0, c_sink.get_sink().length());
155 decompress.handle_data(empty, 0, 0);
157 ASSERT_LE(d_sink.get_size(), (size_t)g_ceph_context->_conf->rgw_max_chunk_size);
162 TEST(Compress, BillionZeros)
164 CompressorRef plugin;
166 plugin = Compressor::create(g_ceph_context, Compressor::COMP_ALG_ZLIB);
167 ASSERT_NE(plugin.get(), nullptr);
168 RGWPutObj_Compress compressor(g_ceph_context, plugin, &c_sink);
170 constexpr size_t size = 1000000;
179 for (int i=0; i<1000;i++)
180 compressor.handle_data(bl, size*i, &handle, &obj, &again);
183 compressor.handle_data(empty, size*1000, &handle, &obj, &again);
185 RGWCompressionInfo cs_info;
186 cs_info.compression_type = plugin->get_type_name();
187 cs_info.orig_size = size*1000;
188 cs_info.blocks = move(compressor.get_compression_blocks());
191 RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, false, &d_sink);
194 off_t f_end = size*1000 - 1;
195 decompress.fixup_range(f_begin, f_end);
197 decompress.handle_data(c_sink.get_sink(), 0, c_sink.get_sink().length());
198 decompress.handle_data(empty, 0, 0);
200 ASSERT_EQ(d_sink.get_sink().length() , size*1000);