Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rgw / test_rgw_compression.cc
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
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
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
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));
117 }
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 }