1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
3 * Ceph - scalable distributed file system
5 * Copyright (C) 2014 CERN (Switzerland)
6 * Copyright (C) 2014 Red Hat <contact@redhat.com>
8 * Author: Andreas-Joachim Peters <Andreas.Joachim.Peters@cern.ch>
9 * Author: Loic Dachary <loic@dachary.org>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
21 #include "crush/CrushWrapper.h"
22 #include "include/stringify.h"
23 #include "erasure-code/isa/ErasureCodeIsa.h"
24 #include "erasure-code/isa/xor_op.h"
25 #include "global/global_context.h"
26 #include "common/config.h"
27 #include "gtest/gtest.h"
31 ErasureCodeIsaTableCache tcache
;
33 class IsaErasureCodeTest
: public ::testing::Test
{
35 void compare_chunks(bufferlist
&in
, map
<int, bufferlist
> &encoded
);
36 void encode_decode(unsigned object_size
);
39 void IsaErasureCodeTest::compare_chunks(bufferlist
&in
, map
<int, bufferlist
> &encoded
)
41 unsigned object_size
= in
.length();
42 unsigned chunk_size
= encoded
[0].length();
43 for (unsigned i
= 0; i
< encoded
.size(); i
++) {
44 if (i
* chunk_size
>= object_size
)
46 int chunk_length
= object_size
> (i
+ 1) * chunk_size
? chunk_size
: object_size
- i
* chunk_size
;
47 EXPECT_EQ(0, memcmp(encoded
[i
].c_str(), in
.c_str() + i
* chunk_size
, chunk_length
));
51 void IsaErasureCodeTest::encode_decode(unsigned object_size
)
53 ErasureCodeIsaDefault
Isa(tcache
);
55 ErasureCodeProfile profile
;
58 Isa
.init(profile
, &cerr
);
60 string
payload(object_size
, 'X');
62 // may be multiple bufferptr if object_size is larger than CEPH_PAGE_SIZE
63 in
.append(payload
.c_str(), payload
.length());
64 int want_to_encode
[] = {0, 1, 2, 3};
65 map
<int, bufferlist
> encoded
;
66 EXPECT_EQ(0, Isa
.encode(set
<int>(want_to_encode
, want_to_encode
+ 4),
69 EXPECT_EQ(4u, encoded
.size());
70 unsigned chunk_size
= encoded
[0].length();
71 EXPECT_EQ(chunk_size
, Isa
.get_chunk_size(object_size
));
72 compare_chunks(in
, encoded
);
74 // all chunks are available
76 int want_to_decode
[] = {0, 1};
77 map
<int, bufferlist
> decoded
;
78 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 2),
81 EXPECT_EQ(2u, decoded
.size());
82 EXPECT_EQ(chunk_size
, decoded
[0].length());
83 compare_chunks(in
, decoded
);
86 // one data chunk is missing
88 map
<int, bufferlist
> degraded
= encoded
;
90 string
enc1(encoded
[1].c_str(), chunk_size
);
93 EXPECT_EQ(3u, degraded
.size());
94 int want_to_decode
[] = {1};
95 map
<int, bufferlist
> decoded
;
96 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 1),
99 // always decode all, regardless of want_to_decode
100 EXPECT_EQ(4u, decoded
.size());
101 EXPECT_EQ(chunk_size
, decoded
[1].length());
102 EXPECT_EQ(0, memcmp(decoded
[1].c_str(), enc1
.c_str(), chunk_size
));
105 // non-xor coding chunk is missing
107 map
<int, bufferlist
> degraded
= encoded
;
109 string
enc3(encoded
[3].c_str(), chunk_size
);
112 EXPECT_EQ(3u, degraded
.size());
113 int want_to_decode
[] = {3};
114 map
<int, bufferlist
> decoded
;
115 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 1),
118 // always decode all, regardless of want_to_decode
119 EXPECT_EQ(4u, decoded
.size());
120 EXPECT_EQ(chunk_size
, decoded
[3].length());
121 EXPECT_EQ(0, memcmp(decoded
[3].c_str(), enc3
.c_str(), chunk_size
));
124 // xor coding chunk is missing
126 map
<int, bufferlist
> degraded
= encoded
;
128 string
enc2(encoded
[2].c_str(), chunk_size
);
131 EXPECT_EQ(3u, degraded
.size());
132 int want_to_decode
[] = {2};
133 map
<int, bufferlist
> decoded
;
134 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 1),
137 // always decode all, regardless of want_to_decode
138 EXPECT_EQ(4u, decoded
.size());
139 EXPECT_EQ(chunk_size
, decoded
[2].length());
140 EXPECT_EQ(0, memcmp(decoded
[2].c_str(), enc2
.c_str(), chunk_size
));
143 // one data and one coding chunk is missing
145 map
<int, bufferlist
> degraded
= encoded
;
147 string
enc3(encoded
[3].c_str(), chunk_size
);
151 EXPECT_EQ(2u, degraded
.size());
152 int want_to_decode
[] = {1, 3};
153 map
<int, bufferlist
> decoded
;
154 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 2),
157 // always decode all, regardless of want_to_decode
158 EXPECT_EQ(4u, decoded
.size());
159 EXPECT_EQ(chunk_size
, decoded
[1].length());
160 EXPECT_EQ(0, memcmp(decoded
[3].c_str(), enc3
.c_str(), chunk_size
));
163 // two data chunks are missing
165 map
<int, bufferlist
> degraded
= encoded
;
168 EXPECT_EQ(2u, degraded
.size());
169 int want_to_decode
[] = {0, 1};
170 map
<int, bufferlist
> decoded
;
171 EXPECT_EQ(0, Isa
._decode(set
<int>(want_to_decode
, want_to_decode
+ 2),
174 // always decode all, regardless of want_to_decode
175 EXPECT_EQ(4u, decoded
.size());
176 EXPECT_EQ(chunk_size
, decoded
[0].length());
177 compare_chunks(in
, decoded
);
182 TEST_F(IsaErasureCodeTest
, encode_decode
)
185 encode_decode(EC_ISA_ADDRESS_ALIGNMENT
);
186 encode_decode(EC_ISA_ADDRESS_ALIGNMENT
+ 1);
189 encode_decode(4096 + 1);
192 TEST_F(IsaErasureCodeTest
, minimum_to_decode
)
194 ErasureCodeIsaDefault
Isa(tcache
);
195 ErasureCodeProfile profile
;
198 Isa
.init(profile
, &cerr
);
201 // If trying to read nothing, the minimum is empty.
204 set
<int> want_to_read
;
205 set
<int> available_chunks
;
208 EXPECT_EQ(0, Isa
._minimum_to_decode(want_to_read
,
211 EXPECT_TRUE(minimum
.empty());
214 // There is no way to read a chunk if none are available.
217 set
<int> want_to_read
;
218 set
<int> available_chunks
;
221 want_to_read
.insert(0);
223 EXPECT_EQ(-EIO
, Isa
._minimum_to_decode(want_to_read
,
228 // Reading a subset of the available chunks is always possible.
231 set
<int> want_to_read
;
232 set
<int> available_chunks
;
235 want_to_read
.insert(0);
236 available_chunks
.insert(0);
238 EXPECT_EQ(0, Isa
._minimum_to_decode(want_to_read
,
241 EXPECT_EQ(want_to_read
, minimum
);
244 // There is no way to read a missing chunk if there is less than k
248 set
<int> want_to_read
;
249 set
<int> available_chunks
;
252 want_to_read
.insert(0);
253 want_to_read
.insert(1);
254 available_chunks
.insert(0);
256 EXPECT_EQ(-EIO
, Isa
._minimum_to_decode(want_to_read
,
261 // When chunks are not available, the minimum can be made of any
262 // chunks. For instance, to read 1 and 3 below the minimum could be
263 // 2 and 3 which may seem better because it contains one of the
264 // chunks to be read. But it won't be more efficient than retrieving
265 // 0 and 2 instead because, in both cases, the decode function will
266 // need to run the same recovery operation and use the same amount
267 // of CPU and memory.
270 set
<int> want_to_read
;
271 set
<int> available_chunks
;
274 want_to_read
.insert(1);
275 want_to_read
.insert(3);
276 available_chunks
.insert(0);
277 available_chunks
.insert(2);
278 available_chunks
.insert(3);
280 EXPECT_EQ(0, Isa
._minimum_to_decode(want_to_read
,
283 EXPECT_EQ(2u, minimum
.size());
284 EXPECT_EQ(0u, minimum
.count(3));
288 TEST_F(IsaErasureCodeTest
, chunk_size
)
291 ErasureCodeIsaDefault
Isa(tcache
);
292 ErasureCodeProfile profile
;
295 Isa
.init(profile
, &cerr
);
298 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
, Isa
.get_chunk_size(1));
299 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
, Isa
.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT
* k
- 1));
300 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
* 2, Isa
.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT
* k
+ 1));
303 ErasureCodeIsaDefault
Isa(tcache
);
304 ErasureCodeProfile profile
;
307 Isa
.init(profile
, &cerr
);
310 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
, Isa
.get_chunk_size(1));
311 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
, Isa
.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT
* k
- 1));
312 ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT
* 2, Isa
.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT
* k
+ 1));
313 unsigned object_size
= EC_ISA_ADDRESS_ALIGNMENT
* k
* 1024 + 1;
314 ASSERT_NE(0u, object_size
% k
);
315 ASSERT_NE(0u, object_size
% EC_ISA_ADDRESS_ALIGNMENT
);
316 unsigned chunk_size
= Isa
.get_chunk_size(object_size
);
317 ASSERT_EQ(0u, chunk_size
% EC_ISA_ADDRESS_ALIGNMENT
);
318 ASSERT_GT(chunk_size
, (chunk_size
* k
) - object_size
);
322 TEST_F(IsaErasureCodeTest
, encode
)
324 ErasureCodeIsaDefault
Isa(tcache
);
325 ErasureCodeProfile profile
;
328 Isa
.init(profile
, &cerr
);
330 unsigned aligned_object_size
= Isa
.get_alignment() * 2;
333 // When the input bufferlist needs to be padded because
334 // it is not properly aligned, it is padded with zeros.
337 map
<int,bufferlist
> encoded
;
338 int want_to_encode
[] = { 0, 1, 2, 3 };
339 int trail_length
= 1;
340 in
.append(string(aligned_object_size
+ trail_length
, 'X'));
341 EXPECT_EQ(0, Isa
.encode(set
<int>(want_to_encode
, want_to_encode
+4),
344 EXPECT_EQ(4u, encoded
.size());
345 char *last_chunk
= encoded
[1].c_str();
346 int length
=encoded
[1].length();
347 EXPECT_EQ('X', last_chunk
[0]);
348 EXPECT_EQ('\0', last_chunk
[length
- trail_length
]);
353 // When only the first chunk is required, the encoded map only
354 // contains the first chunk. Although the Isa encode
355 // internally allocated a buffer because of padding requirements
356 // and also computes the coding chunks, they are released before
357 // the return of the method, as shown when running the tests thru
358 // valgrind (there is no leak).
361 map
<int,bufferlist
> encoded
;
362 set
<int> want_to_encode
;
363 want_to_encode
.insert(0);
364 int trail_length
= 1;
365 in
.append(string(aligned_object_size
+ trail_length
, 'X'));
366 EXPECT_EQ(0, Isa
.encode(want_to_encode
, in
, &encoded
));
367 EXPECT_EQ(1u, encoded
.size());
371 TEST_F(IsaErasureCodeTest
, sanity_check_k
)
373 ErasureCodeIsaDefault
Isa(tcache
);
374 ErasureCodeProfile profile
;
377 ostringstream errors
;
378 EXPECT_EQ(-EINVAL
, Isa
.init(profile
, &errors
));
379 EXPECT_NE(std::string::npos
, errors
.str().find("must be >= 2"));
383 DecodeAndVerify(ErasureCodeIsaDefault
& Isa
, map
<int, bufferlist
> °raded
, set
<int> want_to_decode
, buffer::ptr
* enc
, int length
)
385 map
<int, bufferlist
> decoded
;
388 // decode as requested
389 ok
= Isa
._decode(want_to_decode
,
393 for (int i
= 0; i
< (int) decoded
.size(); i
++) {
394 // compare all the buffers with their original
395 ok
|= memcmp(decoded
[i
].c_str(), enc
[i
].c_str(), length
);
401 TEST_F(IsaErasureCodeTest
, isa_vandermonde_exhaustive
)
403 // Test all possible failure scenarios and reconstruction cases for
404 // a (12,4) configuration using the vandermonde matrix
406 ErasureCodeIsaDefault
Isa(tcache
);
407 ErasureCodeProfile profile
;
410 Isa
.init(profile
, &cerr
);
415 #define LARGE_ENOUGH 2048
416 bufferptr
in_ptr(buffer::create_page_aligned(LARGE_ENOUGH
));
418 in_ptr
.set_length(0);
419 const char *payload
=
420 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
421 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
422 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
423 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
424 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
425 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
426 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
427 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
428 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
429 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
430 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
431 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
432 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
433 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
434 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
435 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
436 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
437 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
438 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
439 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
440 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
441 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
442 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
443 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
444 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
445 in_ptr
.append(payload
, strlen(payload
));
447 in
.push_back(in_ptr
);
449 set
<int>want_to_encode
;
451 map
<int, bufferlist
> encoded
;
452 for (int i
= 0; i
< (k
+ m
); i
++) {
453 want_to_encode
.insert(i
);
457 EXPECT_EQ(0, Isa
.encode(want_to_encode
,
461 EXPECT_EQ((unsigned) (k
+ m
), encoded
.size());
463 unsigned length
= encoded
[0].length();
465 for (int i
= 0; i
< k
; i
++) {
466 EXPECT_EQ(0, memcmp(encoded
[i
].c_str(), in
.c_str() + (i
* length
), length
));
469 buffer::ptr enc
[k
+ m
];
470 // create buffers with a copy of the original data to be able to compare it after decoding
472 for (int i
= 0; i
< (k
+ m
); i
++) {
473 buffer::ptr
newenc(buffer::create_page_aligned(LARGE_ENOUGH
));
476 enc
[i
].set_length(0);
477 enc
[i
].append(encoded
[i
].c_str(), length
);
481 // loop through all possible loss scenarios
484 for (int l1
= 0; l1
< (k
+ m
); l1
++) {
485 map
<int, bufferlist
> degraded
= encoded
;
486 set
<int> want_to_decode
;
489 want_to_decode
.insert(l1
);
490 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
493 for (int l2
= l1
+ 1; l2
< (k
+ m
); l2
++) {
495 want_to_decode
.insert(l2
);
496 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
499 for (int l3
= l2
+ 1; l3
< (k
+ m
); l3
++) {
501 want_to_decode
.insert(l3
);
502 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
505 for (int l4
= l3
+ 1; l4
< (k
+ m
); l4
++) {
507 want_to_decode
.insert(l4
);
508 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
510 degraded
[l4
] = encoded
[l4
];
511 want_to_decode
.erase(l4
);
514 degraded
[l3
] = encoded
[l3
];
515 want_to_decode
.erase(l3
);
517 degraded
[l2
] = encoded
[l2
];
518 want_to_decode
.erase(l2
);
520 degraded
[l1
] = encoded
[l1
];
521 want_to_decode
.erase(l1
);
523 EXPECT_EQ(2516, cnt_cf
);
524 EXPECT_EQ(2506, tcache
.getDecodingTableCacheSize()); // 3 entries from (2,2) test and 2503 from (12,4)
527 TEST_F(IsaErasureCodeTest
, isa_cauchy_exhaustive
)
529 // Test all possible failure scenarios and reconstruction cases for
530 // a (12,4) configuration using the cauchy matrix
531 ErasureCodeIsaDefault
Isa(tcache
,ErasureCodeIsaDefault::kCauchy
);
532 ErasureCodeProfile profile
;
535 profile
["technique"] = "cauchy";
537 Isa
.init(profile
, &cerr
);
542 #define LARGE_ENOUGH 2048
543 bufferptr
in_ptr(buffer::create_page_aligned(LARGE_ENOUGH
));
545 in_ptr
.set_length(0);
546 const char *payload
=
547 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
548 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
549 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
550 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
551 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
552 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
553 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
554 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
555 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
556 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
557 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
558 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
559 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
560 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
561 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
562 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
563 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
564 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
565 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
566 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
567 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
568 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
569 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
570 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
571 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
572 in_ptr
.append(payload
, strlen(payload
));
574 in
.push_back(in_ptr
);
576 set
<int>want_to_encode
;
578 map
<int, bufferlist
> encoded
;
579 for (int i
= 0; i
< (k
+ m
); i
++) {
580 want_to_encode
.insert(i
);
584 EXPECT_EQ(0, Isa
.encode(want_to_encode
,
588 EXPECT_EQ((unsigned) (k
+ m
), encoded
.size());
590 unsigned length
= encoded
[0].length();
592 for (int i
= 0; i
< k
; i
++) {
593 EXPECT_EQ(0, memcmp(encoded
[i
].c_str(), in
.c_str() + (i
* length
), length
));
596 buffer::ptr enc
[k
+ m
];
597 // create buffers with a copy of the original data to be able to compare it after decoding
599 for (int i
= 0; i
< (k
+ m
); i
++) {
600 buffer::ptr
newenc(buffer::create_page_aligned(LARGE_ENOUGH
));
603 enc
[i
].set_length(0);
604 enc
[i
].append(encoded
[i
].c_str(), length
);
608 // loop through all possible loss scenarios
611 for (int l1
= 0; l1
< (k
+ m
); l1
++) {
612 map
<int, bufferlist
> degraded
= encoded
;
613 set
<int> want_to_decode
;
616 want_to_decode
.insert(l1
);
617 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
620 for (int l2
= l1
+ 1; l2
< (k
+ m
); l2
++) {
622 want_to_decode
.insert(l2
);
623 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
626 for (int l3
= l2
+ 1; l3
< (k
+ m
); l3
++) {
628 want_to_decode
.insert(l3
);
629 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
632 for (int l4
= l3
+ 1; l4
< (k
+ m
); l4
++) {
634 want_to_decode
.insert(l4
);
635 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
637 degraded
[l4
] = encoded
[l4
];
638 want_to_decode
.erase(l4
);
641 degraded
[l3
] = encoded
[l3
];
642 want_to_decode
.erase(l3
);
644 degraded
[l2
] = encoded
[l2
];
645 want_to_decode
.erase(l2
);
647 degraded
[l1
] = encoded
[l1
];
648 want_to_decode
.erase(l1
);
650 EXPECT_EQ(2516, cnt_cf
);
651 EXPECT_EQ(2516, tcache
.getDecodingTableCacheSize(ErasureCodeIsaDefault::kCauchy
));
654 TEST_F(IsaErasureCodeTest
, isa_cauchy_cache_trash
)
656 // Test all possible failure scenarios and reconstruction cases for
657 // a (12,4) configuration using the cauchy matrix
658 ErasureCodeIsaDefault
Isa(tcache
,ErasureCodeIsaDefault::kCauchy
);
659 ErasureCodeProfile profile
;
662 profile
["technique"] = "cauchy";
664 Isa
.init(profile
, &cerr
);
669 #define LARGE_ENOUGH 2048
670 bufferptr
in_ptr(buffer::create_page_aligned(LARGE_ENOUGH
));
672 in_ptr
.set_length(0);
673 const char *payload
=
674 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
675 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
676 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
677 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
678 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
679 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
680 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
681 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
682 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
683 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
684 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
685 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
686 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
687 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
688 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
689 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
690 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
691 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
692 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
693 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
694 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
695 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
696 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
697 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
698 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
699 in_ptr
.append(payload
, strlen(payload
));
701 in
.push_back(in_ptr
);
703 set
<int>want_to_encode
;
705 map
<int, bufferlist
> encoded
;
706 for (int i
= 0; i
< (k
+ m
); i
++) {
707 want_to_encode
.insert(i
);
711 EXPECT_EQ(0, Isa
.encode(want_to_encode
,
715 EXPECT_EQ((unsigned) (k
+ m
), encoded
.size());
717 unsigned length
= encoded
[0].length();
719 for (int i
= 0; i
< k
; i
++) {
720 EXPECT_EQ(0, memcmp(encoded
[i
].c_str(), in
.c_str() + (i
* length
), length
));
723 buffer::ptr enc
[k
+ m
];
724 // create buffers with a copy of the original data to be able to compare it after decoding
726 for (int i
= 0; i
< (k
+ m
); i
++) {
727 buffer::ptr
newenc(buffer::create_page_aligned(LARGE_ENOUGH
));
730 enc
[i
].set_length(0);
731 enc
[i
].append(encoded
[i
].c_str(), length
);
735 // loop through all possible loss scenarios
738 for (int l1
= 0; l1
< (k
+ m
); l1
++) {
739 map
<int, bufferlist
> degraded
= encoded
;
740 set
<int> want_to_decode
;
743 want_to_decode
.insert(l1
);
744 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
747 for (int l2
= l1
+ 1; l2
< (k
+ m
); l2
++) {
749 want_to_decode
.insert(l2
);
750 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
753 for (int l3
= l2
+ 1; l3
< (k
+ m
); l3
++) {
755 want_to_decode
.insert(l3
);
756 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
759 for (int l4
= l3
+ 1; l4
< (k
+ m
); l4
++) {
761 want_to_decode
.insert(l4
);
762 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
764 degraded
[l4
] = encoded
[l4
];
765 want_to_decode
.erase(l4
);
768 degraded
[l3
] = encoded
[l3
];
769 want_to_decode
.erase(l3
);
771 degraded
[l2
] = encoded
[l2
];
772 want_to_decode
.erase(l2
);
774 degraded
[l1
] = encoded
[l1
];
775 want_to_decode
.erase(l1
);
777 EXPECT_EQ(6195, cnt_cf
);
778 EXPECT_EQ(2516, tcache
.getDecodingTableCacheSize(ErasureCodeIsaDefault::kCauchy
));
781 TEST_F(IsaErasureCodeTest
, isa_xor_codec
)
783 // Test all possible failure scenarios and reconstruction cases for
784 // a (4,1) RAID-5 like configuration
786 ErasureCodeIsaDefault
Isa(tcache
);
787 ErasureCodeProfile profile
;
790 Isa
.init(profile
, &cerr
);
795 #define LARGE_ENOUGH 2048
796 bufferptr
in_ptr(buffer::create_page_aligned(LARGE_ENOUGH
));
798 in_ptr
.set_length(0);
799 const char *payload
=
800 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
801 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
802 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
803 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
804 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
805 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
806 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
807 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
808 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
809 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
810 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
811 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
812 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
813 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
814 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
815 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
816 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
817 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
818 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
819 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
820 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
821 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
822 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
823 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
824 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
825 in_ptr
.append(payload
, strlen(payload
));
827 in
.push_back(in_ptr
);
829 set
<int>want_to_encode
;
831 map
<int, bufferlist
> encoded
;
832 for (int i
= 0; i
< (k
+ m
); i
++) {
833 want_to_encode
.insert(i
);
837 EXPECT_EQ(0, Isa
.encode(want_to_encode
,
841 EXPECT_EQ((unsigned) (k
+ m
), encoded
.size());
843 unsigned length
= encoded
[0].length();
845 for (int i
= 0; i
< k
; i
++) {
846 EXPECT_EQ(0, memcmp(encoded
[i
].c_str(), in
.c_str() + (i
* length
), length
));
849 buffer::ptr enc
[k
+ m
];
850 // create buffers with a copy of the original data to be able to compare it after decoding
852 for (int i
= 0; i
< (k
+ m
); i
++) {
853 buffer::ptr
newenc(buffer::create_page_aligned(LARGE_ENOUGH
));
856 enc
[i
].set_length(0);
857 enc
[i
].append(encoded
[i
].c_str(), length
);
861 // loop through all possible loss scenarios
864 for (int l1
= 0; l1
< (k
+ m
); l1
++) {
865 map
<int, bufferlist
> degraded
= encoded
;
866 set
<int> want_to_decode
;
869 want_to_decode
.insert(l1
);
870 err
= DecodeAndVerify(Isa
, degraded
, want_to_decode
, enc
, length
);
873 degraded
[l1
] = encoded
[l1
];
874 want_to_decode
.erase(l1
);
876 EXPECT_EQ(5, cnt_cf
);
879 TEST_F(IsaErasureCodeTest
, create_rule
)
881 std::unique_ptr
<CrushWrapper
> c
= std::make_unique
<CrushWrapper
>();
884 c
->set_type_name(root_type
, "root");
886 c
->set_type_name(host_type
, "host");
888 c
->set_type_name(osd_type
, "osd");
891 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
892 root_type
, 0, NULL
, NULL
, &rootno
);
893 c
->set_item_name(rootno
, "default");
895 map
<string
,string
> loc
;
896 loc
["root"] = "default";
901 for (int h
=0; h
<num_host
; ++h
) {
902 loc
["host"] = string("host-") + stringify(h
);
903 for (int o
=0; o
<num_osd
; ++o
, ++osd
) {
904 c
->insert_item(g_ceph_context
, osd
, 1.0, string("osd.") + stringify(osd
), loc
);
912 ErasureCodeIsaDefault
isa(tcache
);
913 ErasureCodeProfile profile
;
917 isa
.init(profile
, &cerr
);
918 int rule
= isa
.create_rule("myrule", *c
, &ss
);
920 EXPECT_EQ(-EEXIST
, isa
.create_rule("myrule", *c
, &ss
));
922 // the minimum that is expected from the created rule is to
923 // successfully map get_chunk_count() devices from the crushmap,
926 vector
<__u32
> weight(c
->get_max_devices(), 0x10000);
929 c
->do_rule(rule
, x
, out
, isa
.get_chunk_count(), weight
, 0);
930 ASSERT_EQ(out
.size(), isa
.get_chunk_count());
931 for (unsigned i
=0; i
<out
.size(); ++i
)
932 ASSERT_NE(CRUSH_ITEM_NONE
, out
[i
]);
936 ErasureCodeIsaDefault
isa(tcache
);
937 ErasureCodeProfile profile
;
941 profile
["crush-root"] = "BAD";
942 isa
.init(profile
, &cerr
);
943 EXPECT_EQ(-ENOENT
, isa
.create_rule("otherrule", *c
, &ss
));
944 EXPECT_EQ("root item BAD does not exist", ss
.str());
948 ErasureCodeIsaDefault
isa(tcache
);
949 ErasureCodeProfile profile
;
953 profile
["crush-failure-domain"] = "WORSE";
954 isa
.init(profile
, &cerr
);
955 EXPECT_EQ(-EINVAL
, isa
.create_rule("otherrule", *c
, &ss
));
956 EXPECT_EQ("unknown type WORSE", ss
.str());
962 * compile-command: "cd ../.. ; make -j4 unittest_erasure_code_isa &&
963 * libtool --mode=execute valgrind --tool=memcheck \
964 * ./unittest_erasure_code_isa \
965 * --gtest_filter=*.* --log-to-stderr=true --debug-osd=20"