]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
4 | ||
5 | #include "rgw/rgw_compression.h" | |
6 | ||
224ce89b WB |
7 | class ut_get_sink : public RGWGetDataCB { |
8 | bufferlist sink; | |
9 | public: | |
10 | ut_get_sink() {} | |
11 | virtual ~ut_get_sink() {} | |
12 | ||
13 | int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override | |
14 | { | |
15 | auto bl_buffers = bl.buffers(); | |
16 | auto i = bl_buffers.begin(); | |
17 | while (bl_len > 0) | |
18 | { | |
19 | assert(i != bl_buffers.end()); | |
20 | off_t len = std::min<off_t>(bl_len, i->length()); | |
21 | sink.append(*i, 0, len); | |
22 | bl_len -= len; | |
23 | i++; | |
24 | } | |
25 | return 0; | |
26 | } | |
27 | bufferlist& get_sink() | |
28 | { | |
29 | return sink; | |
30 | } | |
31 | }; | |
32 | ||
33 | class ut_get_sink_size : public RGWGetDataCB { | |
34 | size_t max_size = 0; | |
35 | public: | |
36 | ut_get_sink_size() {} | |
37 | virtual ~ut_get_sink_size() {} | |
38 | ||
39 | int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override | |
40 | { | |
41 | if (bl_len > (off_t)max_size) | |
42 | max_size = bl_len; | |
43 | return 0; | |
44 | } | |
45 | size_t get_size() | |
46 | { | |
47 | return max_size; | |
48 | } | |
49 | }; | |
50 | ||
51 | class ut_put_sink: public RGWPutObjDataProcessor | |
52 | { | |
53 | bufferlist sink; | |
54 | public: | |
55 | ut_put_sink(){} | |
56 | virtual ~ut_put_sink(){} | |
57 | int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again) override | |
58 | { | |
59 | sink.append(bl); | |
60 | *again = false; | |
61 | return 0; | |
62 | } | |
63 | int throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait) override | |
64 | { | |
65 | return 0; | |
66 | } | |
67 | bufferlist& get_sink() | |
68 | { | |
69 | return sink; | |
70 | } | |
71 | }; | |
72 | ||
73 | ||
7c673cae FG |
74 | struct MockGetDataCB : public RGWGetDataCB { |
75 | int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override { | |
76 | return 0; | |
77 | } | |
78 | } cb; | |
79 | ||
80 | using range_t = std::pair<off_t, off_t>; | |
81 | ||
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) | |
85 | { | |
86 | filter->fixup_range(ofs, end); | |
87 | return {ofs, end}; | |
88 | } | |
89 | ||
90 | ||
91 | TEST(Decompress, FixupRangePartial) | |
92 | { | |
93 | RGWCompressionInfo cs_info; | |
94 | ||
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}); | |
101 | ||
102 | const bool partial = true; | |
103 | RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, partial, &cb); | |
104 | ||
105 | // test translation from logical ranges to compressed ranges | |
31f18b77 FG |
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)); | |
7c673cae | 117 | } |
224ce89b WB |
118 | |
119 | TEST(Compress, LimitedChunkSize) | |
120 | { | |
121 | CompressorRef plugin; | |
122 | plugin = Compressor::create(g_ceph_context, Compressor::COMP_ALG_ZLIB); | |
123 | ASSERT_NE(plugin.get(), nullptr); | |
124 | ||
125 | for (size_t s = 100 ; s < 10000000 ; s = s*5/4) | |
126 | { | |
127 | bufferptr bp(s); | |
128 | bufferlist bl; | |
129 | bl.append(bp); | |
130 | ||
131 | void* handle; | |
132 | rgw_raw_obj obj; | |
133 | bool again = false; | |
134 | ||
135 | ut_put_sink c_sink; | |
136 | RGWPutObj_Compress compressor(g_ceph_context, plugin, &c_sink); | |
137 | compressor.handle_data(bl, 0, &handle, &obj, &again); | |
138 | ||
139 | bufferlist empty; | |
140 | compressor.handle_data(empty, s, &handle, &obj, &again); | |
141 | ||
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()); | |
146 | ||
147 | ut_get_sink_size d_sink; | |
148 | RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, false, &d_sink); | |
149 | ||
150 | off_t f_begin = 0; | |
151 | off_t f_end = s - 1; | |
152 | decompress.fixup_range(f_begin, f_end); | |
153 | ||
154 | decompress.handle_data(c_sink.get_sink(), 0, c_sink.get_sink().length()); | |
155 | decompress.handle_data(empty, 0, 0); | |
156 | ||
157 | ASSERT_LE(d_sink.get_size(), (size_t)g_ceph_context->_conf->rgw_max_chunk_size); | |
158 | } | |
159 | } | |
160 | ||
161 | ||
162 | TEST(Compress, BillionZeros) | |
163 | { | |
164 | CompressorRef plugin; | |
165 | ut_put_sink c_sink; | |
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); | |
169 | ||
170 | constexpr size_t size = 1000000; | |
171 | bufferptr bp(size); | |
172 | bufferlist bl; | |
173 | bl.append(bp); | |
174 | ||
175 | void* handle; | |
176 | rgw_raw_obj obj; | |
177 | bool again = false; | |
178 | ||
179 | for (int i=0; i<1000;i++) | |
180 | compressor.handle_data(bl, size*i, &handle, &obj, &again); | |
181 | ||
182 | bufferlist empty; | |
183 | compressor.handle_data(empty, size*1000, &handle, &obj, &again); | |
184 | ||
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()); | |
189 | ||
190 | ut_get_sink d_sink; | |
191 | RGWGetObj_Decompress decompress(g_ceph_context, &cs_info, false, &d_sink); | |
192 | ||
193 | off_t f_begin = 0; | |
194 | off_t f_end = size*1000 - 1; | |
195 | decompress.fixup_range(f_begin, f_end); | |
196 | ||
197 | decompress.handle_data(c_sink.get_sink(), 0, c_sink.get_sink().length()); | |
198 | decompress.handle_data(empty, 0, 0); | |
199 | ||
200 | ASSERT_EQ(d_sink.get_sink().length() , size*1000); | |
201 | } |