]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/compressor/test_compression.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / test / compressor / test_compression.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2015 Mirantis, Inc.
7 *
8 * Author: Alyona Kiseleva <akiselyova@mirantis.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 */
16
17 #include <errno.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include "gtest/gtest.h"
21 #include "common/config.h"
22 #include "compressor/Compressor.h"
23 #include "compressor/CompressionPlugin.h"
24 #include "global/global_context.h"
25
26 class CompressorTest : public ::testing::Test,
27 public ::testing::WithParamInterface<const char*> {
28 public:
29 std::string plugin;
30 CompressorRef compressor;
31 bool old_zlib_isal;
32
33 CompressorTest() {
34 // note for later
35 old_zlib_isal = g_conf->compressor_zlib_isal;
36
37 plugin = GetParam();
38 size_t pos = plugin.find('/');
39 if (pos != std::string::npos) {
40 string isal = plugin.substr(pos + 1);
41 plugin = plugin.substr(0, pos);
42 if (isal == "isal") {
43 g_conf->set_val("compressor_zlib_isal", "true");
44 g_ceph_context->_conf->apply_changes(NULL);
45 } else if (isal == "noisal") {
46 g_conf->set_val("compressor_zlib_isal", "false");
47 g_ceph_context->_conf->apply_changes(NULL);
48 } else {
49 assert(0 == "bad option");
50 }
51 }
52 cout << "[plugin " << plugin << " (" << GetParam() << ")]" << std::endl;
53 }
54 ~CompressorTest() override {
55 g_conf->set_val("compressor_zlib_isal", old_zlib_isal ? "true" : "false");
56 g_ceph_context->_conf->apply_changes(NULL);
57 }
58
59 void SetUp() override {
60 compressor = Compressor::create(g_ceph_context, plugin);
61 ASSERT_TRUE(compressor);
62 }
63 void TearDown() override {
64 compressor.reset();
65 }
66 };
67
68 TEST_P(CompressorTest, load_plugin)
69 {
70 }
71
72 TEST_P(CompressorTest, small_round_trip)
73 {
74 bufferlist orig;
75 orig.append("This is a short string. There are many strings like it but this one is mine.");
76 bufferlist compressed;
77 int r = compressor->compress(orig, compressed);
78 ASSERT_EQ(0, r);
79 bufferlist decompressed;
80 r = compressor->decompress(compressed, decompressed);
81 ASSERT_EQ(0, r);
82 ASSERT_EQ(decompressed.length(), orig.length());
83 ASSERT_TRUE(decompressed.contents_equal(orig));
84 cout << "orig " << orig.length() << " compressed " << compressed.length()
85 << " with " << GetParam() << std::endl;
86 }
87
88 TEST_P(CompressorTest, big_round_trip_repeated)
89 {
90 unsigned len = 1048576 * 4;
91 bufferlist orig;
92 while (orig.length() < len) {
93 orig.append("This is a short string. There are many strings like it but this one is mine.");
94 }
95 bufferlist compressed;
96 int r = compressor->compress(orig, compressed);
97 ASSERT_EQ(0, r);
98 bufferlist decompressed;
99 r = compressor->decompress(compressed, decompressed);
100 ASSERT_EQ(0, r);
101 ASSERT_EQ(decompressed.length(), orig.length());
102 ASSERT_TRUE(decompressed.contents_equal(orig));
103 cout << "orig " << orig.length() << " compressed " << compressed.length()
104 << " with " << GetParam() << std::endl;
105 }
106
107 TEST_P(CompressorTest, big_round_trip_randomish)
108 {
109 unsigned len = 1048576 * 100;//269;
110 bufferlist orig;
111 const char *alphabet = "abcdefghijklmnopqrstuvwxyz";
112 if (false) {
113 while (orig.length() < len) {
114 orig.append(alphabet[rand() % 10]);
115 }
116 } else {
117 bufferptr bp(len);
118 char *p = bp.c_str();
119 for (unsigned i=0; i<len; ++i) {
120 p[i] = alphabet[rand() % 10];
121 }
122 orig.append(bp);
123 }
124 bufferlist compressed;
125 int r = compressor->compress(orig, compressed);
126 ASSERT_EQ(0, r);
127 bufferlist decompressed;
128 r = compressor->decompress(compressed, decompressed);
129 ASSERT_EQ(0, r);
130 ASSERT_EQ(decompressed.length(), orig.length());
131 ASSERT_TRUE(decompressed.contents_equal(orig));
132 cout << "orig " << orig.length() << " compressed " << compressed.length()
133 << " with " << GetParam() << std::endl;
134 }
135
136 #if 0
137 TEST_P(CompressorTest, big_round_trip_file)
138 {
139 bufferlist orig;
140 int fd = ::open("bin/ceph-osd", O_RDONLY);
141 struct stat st;
142 ::fstat(fd, &st);
143 orig.read_fd(fd, st.st_size);
144
145 bufferlist compressed;
146 int r = compressor->compress(orig, compressed);
147 ASSERT_EQ(0, r);
148 bufferlist decompressed;
149 r = compressor->decompress(compressed, decompressed);
150 ASSERT_EQ(0, r);
151 ASSERT_EQ(decompressed.length(), orig.length());
152 ASSERT_TRUE(decompressed.contents_equal(orig));
153 cout << "orig " << orig.length() << " compressed " << compressed.length()
154 << " with " << GetParam() << std::endl;
155 }
156 #endif
157
158
159 TEST_P(CompressorTest, compress_decompress)
160 {
161 const char* test = "This is test text";
162 int res;
163 int len = strlen(test);
164 bufferlist in, out;
165 bufferlist after;
166 bufferlist exp;
167 in.append(test, len);
168 res = compressor->compress(in, out);
169 EXPECT_EQ(res, 0);
170 res = compressor->decompress(out, after);
171 EXPECT_EQ(res, 0);
172 exp.append(test);
173 EXPECT_TRUE(exp.contents_equal(after));
174 after.clear();
175 size_t compressed_len = out.length();
176 out.append_zero(12);
177 auto it = out.begin();
178 res = compressor->decompress(it, compressed_len, after);
179 EXPECT_EQ(res, 0);
180 EXPECT_TRUE(exp.contents_equal(after));
181
182 //large block and non-begin iterator for continuous block
183 std::string data;
184 data.resize(0x10000 * 1);
185 for(size_t i = 0; i < data.size(); i++)
186 data[i] = i / 256;
187 in.clear();
188 out.clear();
189 in.append(data);
190 exp = in;
191 res = compressor->compress(in, out);
192 EXPECT_EQ(res, 0);
193 compressed_len = out.length();
194 out.append_zero(0x10000 - out.length());
195 after.clear();
196 out.c_str();
197 bufferlist prefix;
198 prefix.append(string("some prefix"));
199 size_t prefix_len = prefix.length();
200 out.claim_prepend(prefix);
201 it = out.begin();
202 it.advance(prefix_len);
203 res = compressor->decompress(it, compressed_len, after);
204 EXPECT_EQ(res, 0);
205 EXPECT_TRUE(exp.contents_equal(after));
206 }
207
208 TEST_P(CompressorTest, sharded_input_decompress)
209 {
210 const size_t small_prefix_size=3;
211
212 string test(128*1024,0);
213 int len = test.size();
214 bufferlist in, out;
215 in.append(test.c_str(), len);
216 int res = compressor->compress(in, out);
217 EXPECT_EQ(res, 0);
218 EXPECT_GT(out.length(), small_prefix_size);
219
220 bufferlist out2, tmp;
221 tmp.substr_of(out, 0, small_prefix_size );
222 out2.append( tmp );
223 size_t left = out.length()-small_prefix_size;
224 size_t offs = small_prefix_size;
225 while( left > 0 ){
226 size_t shard_size = MIN( 2048, left );
227 tmp.substr_of(out, offs, shard_size );
228 out2.append( tmp );
229 left -= shard_size;
230 offs += shard_size;
231 }
232
233 bufferlist after;
234 res = compressor->decompress(out2, after);
235 EXPECT_EQ(res, 0);
236 }
237
238 void test_compress(CompressorRef compressor, size_t size)
239 {
240 char* data = (char*) malloc(size);
241 for (size_t t = 0; t < size; t++) {
242 data[t] = (t & 0xff) | (t >> 8);
243 }
244 bufferlist in;
245 in.append(data, size);
246 for (size_t t = 0; t < 100000; t++) {
247 bufferlist out;
248 int res = compressor->compress(in, out);
249 EXPECT_EQ(res, 0);
250 }
251 }
252
253 void test_decompress(CompressorRef compressor, size_t size)
254 {
255 char* data = (char*) malloc(size);
256 for (size_t t = 0; t < size; t++) {
257 data[t] = (t & 0xff) | (t >> 8);
258 }
259 bufferlist in, out;
260 in.append(data, size);
261 int res = compressor->compress(in, out);
262 EXPECT_EQ(res, 0);
263 for (size_t t = 0; t < 100000; t++) {
264 bufferlist out_dec;
265 int res = compressor->decompress(out, out_dec);
266 EXPECT_EQ(res, 0);
267 }
268 }
269
270 TEST_P(CompressorTest, compress_1024)
271 {
272 test_compress(compressor, 1024);
273 }
274
275 TEST_P(CompressorTest, compress_2048)
276 {
277 test_compress(compressor, 2048);
278 }
279
280 TEST_P(CompressorTest, compress_4096)
281 {
282 test_compress(compressor, 4096);
283 }
284
285 TEST_P(CompressorTest, compress_8192)
286 {
287 test_compress(compressor, 8192);
288 }
289
290 TEST_P(CompressorTest, compress_16384)
291 {
292 test_compress(compressor, 16384);
293 }
294
295 TEST_P(CompressorTest, decompress_1024)
296 {
297 test_decompress(compressor, 1024);
298 }
299
300 TEST_P(CompressorTest, decompress_2048)
301 {
302 test_decompress(compressor, 2048);
303 }
304
305 TEST_P(CompressorTest, decompress_4096)
306 {
307 test_decompress(compressor, 4096);
308 }
309
310 TEST_P(CompressorTest, decompress_8192)
311 {
312 test_decompress(compressor, 8192);
313 }
314
315 TEST_P(CompressorTest, decompress_16384)
316 {
317 test_decompress(compressor, 16384);
318 }
319
320
321 INSTANTIATE_TEST_CASE_P(
322 Compressor,
323 CompressorTest,
324 ::testing::Values(
325 #ifdef __x86_64__
326 "zlib/isal",
327 #endif
328 "zlib/noisal",
329 "snappy",
330 "zstd"));
331
332 #ifdef __x86_64__
333
334 TEST(ZlibCompressor, zlib_isal_compatibility)
335 {
336 g_conf->set_val("compressor_zlib_isal", "true");
337 g_ceph_context->_conf->apply_changes(NULL);
338 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
339 if (!isal) {
340 // skip the test if the plugin is not ready
341 return;
342 }
343 g_conf->set_val("compressor_zlib_isal", "false");
344 g_ceph_context->_conf->apply_changes(NULL);
345 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
346 char test[101];
347 srand(time(0));
348 for (int i=0; i<100; ++i)
349 test[i] = 'a' + rand()%26;
350 test[100] = '\0';
351 int len = strlen(test);
352 bufferlist in, out;
353 in.append(test, len);
354 // isal -> zlib
355 int res = isal->compress(in, out);
356 EXPECT_EQ(res, 0);
357 bufferlist after;
358 res = zlib->decompress(out, after);
359 EXPECT_EQ(res, 0);
360 bufferlist exp;
361 exp.append(test);
362 EXPECT_TRUE(exp.contents_equal(after));
363 after.clear();
364 out.clear();
365 exp.clear();
366 // zlib -> isal
367 res = zlib->compress(in, out);
368 EXPECT_EQ(res, 0);
369 res = isal->decompress(out, after);
370 EXPECT_EQ(res, 0);
371 exp.append(test);
372 EXPECT_TRUE(exp.contents_equal(after));
373 }
374 #endif
375
376 TEST(CompressionPlugin, all)
377 {
378 const char* env = getenv("CEPH_LIB");
379 std::string directory(env ? env : ".libs");
380 CompressorRef compressor;
381 PluginRegistry *reg = g_ceph_context->get_plugin_registry();
382 EXPECT_TRUE(reg);
383 CompressionPlugin *factory = dynamic_cast<CompressionPlugin*>(reg->get_with_load("compressor", "invalid"));
384 EXPECT_FALSE(factory);
385 factory = dynamic_cast<CompressionPlugin*>(reg->get_with_load("compressor", "example"));
386 EXPECT_TRUE(factory);
387 stringstream ss;
388 EXPECT_EQ(0, factory->factory(&compressor, &ss));
389 EXPECT_TRUE(compressor.get());
390 {
391 Mutex::Locker l(reg->lock);
392 EXPECT_EQ(-ENOENT, reg->remove("compressor", "does not exist"));
393 EXPECT_EQ(0, reg->remove("compressor", "example"));
394 EXPECT_EQ(0, reg->load("compressor", "example"));
395 }
396 }
397
398 #ifdef __x86_64__
399
400 TEST(ZlibCompressor, isal_compress_zlib_decompress_random)
401 {
402 g_conf->set_val("compressor_zlib_isal", "true");
403 g_ceph_context->_conf->apply_changes(NULL);
404 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
405 if (!isal) {
406 // skip the test if the plugin is not ready
407 return;
408 }
409 g_conf->set_val("compressor_zlib_isal", "false");
410 g_ceph_context->_conf->apply_changes(NULL);
411 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
412
413 for (int cnt=0; cnt<1000; cnt++)
414 {
415 srand(cnt + 1000);
416 int log2 = (rand()%18) + 1;
417 int size = (rand() % (1 << log2)) + 1;
418
419 char test[size];
420 for (int i=0; i<size; ++i)
421 test[i] = rand()%256;
422 bufferlist in, out;
423 in.append(test, size);
424
425 int res = isal->compress(in, out);
426 EXPECT_EQ(res, 0);
427 bufferlist after;
428 res = zlib->decompress(out, after);
429 EXPECT_EQ(res, 0);
430 bufferlist exp;
431 exp.append(test, size);
432 EXPECT_TRUE(exp.contents_equal(after));
433 }
434 }
435
436 TEST(ZlibCompressor, isal_compress_zlib_decompress_walk)
437 {
438 g_conf->set_val("compressor_zlib_isal", "true");
439 g_ceph_context->_conf->apply_changes(NULL);
440 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
441 if (!isal) {
442 // skip the test if the plugin is not ready
443 return;
444 }
445 g_conf->set_val("compressor_zlib_isal", "false");
446 g_ceph_context->_conf->apply_changes(NULL);
447 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
448
449 for (int cnt=0; cnt<1000; cnt++)
450 {
451 srand(cnt + 1000);
452 int log2 = (rand()%18) + 1;
453 int size = (rand() % (1 << log2)) + 1;
454
455 int range = 1;
456
457 char test[size];
458 test[0] = rand()%256;
459 for (int i=1; i<size; ++i)
460 test[i] = test[i-1] + rand()%(range*2+1) - range;
461 bufferlist in, out;
462 in.append(test, size);
463
464 int res = isal->compress(in, out);
465 EXPECT_EQ(res, 0);
466 bufferlist after;
467 res = zlib->decompress(out, after);
468 EXPECT_EQ(res, 0);
469 bufferlist exp;
470 exp.append(test, size);
471 EXPECT_TRUE(exp.contents_equal(after));
472 }
473 }
474
475 #endif // __x86_64__