1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
7 * Copyright (C) 2014 Red Hat <contact@redhat.com>
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/lrc/ErasureCodeLrc.h"
24 #include "global/global_context.h"
25 #include "common/config_proxy.h"
26 #include "gtest/gtest.h"
30 TEST(ErasureCodeLrc
, parse_rule
)
32 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
33 EXPECT_EQ("default", lrc
.rule_root
);
34 EXPECT_EQ("host", lrc
.rule_steps
.front().type
);
36 ErasureCodeProfile profile
;
37 profile
["crush-root"] = "other";
38 EXPECT_EQ(0, lrc
.parse_rule(profile
, &cerr
));
39 EXPECT_EQ("other", lrc
.rule_root
);
41 profile
["crush-steps"] = "[]";
42 EXPECT_EQ(0, lrc
.parse_rule(profile
, &cerr
));
43 EXPECT_TRUE(lrc
.rule_steps
.empty());
45 profile
["crush-steps"] = "0";
46 EXPECT_EQ(ERROR_LRC_ARRAY
, lrc
.parse_rule(profile
, &cerr
));
48 profile
["crush-steps"] = "{";
49 EXPECT_EQ(ERROR_LRC_PARSE_JSON
, lrc
.parse_rule(profile
, &cerr
));
51 profile
["crush-steps"] = "[0]";
52 EXPECT_EQ(ERROR_LRC_ARRAY
, lrc
.parse_rule(profile
, &cerr
));
54 profile
["crush-steps"] = "[[0]]";
55 EXPECT_EQ(ERROR_LRC_RULE_OP
, lrc
.parse_rule(profile
, &cerr
));
57 profile
["crush-steps"] = "[[\"choose\", 0]]";
58 EXPECT_EQ(ERROR_LRC_RULE_TYPE
, lrc
.parse_rule(profile
, &cerr
));
60 profile
["crush-steps"] = "[[\"choose\", \"host\", []]]";
61 EXPECT_EQ(ERROR_LRC_RULE_N
, lrc
.parse_rule(profile
, &cerr
));
63 profile
["crush-steps"] = "[[\"choose\", \"host\", 2]]";
64 EXPECT_EQ(0, lrc
.parse_rule(profile
, &cerr
));
66 const ErasureCodeLrc::Step
&step
= lrc
.rule_steps
.front();
67 EXPECT_EQ("choose", step
.op
);
68 EXPECT_EQ("host", step
.type
);
71 profile
["crush-steps"] =
73 " [\"choose\", \"rack\", 2], "
74 " [\"chooseleaf\", \"host\", 5], "
76 EXPECT_EQ(0, lrc
.parse_rule(profile
, &cerr
));
77 EXPECT_EQ(2U, lrc
.rule_steps
.size());
79 const ErasureCodeLrc::Step
&step
= lrc
.rule_steps
[0];
80 EXPECT_EQ("choose", step
.op
);
81 EXPECT_EQ("rack", step
.type
);
85 const ErasureCodeLrc::Step
&step
= lrc
.rule_steps
[1];
86 EXPECT_EQ("chooseleaf", step
.op
);
87 EXPECT_EQ("host", step
.type
);
92 TEST(ErasureCodeTest
, create_rule
)
94 CrushWrapper
*c
= new CrushWrapper
;
97 c
->set_type_name(root_type
, "root");
99 c
->set_type_name(rack_type
, "rack");
101 c
->set_type_name(host_type
, "host");
103 c
->set_type_name(osd_type
, "osd");
106 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
107 root_type
, 0, NULL
, NULL
, &rootno
);
108 c
->set_item_name(rootno
, "default");
110 map
<string
,string
> loc
;
111 loc
["root"] = "default";
114 // Set all to 10 so that the item number it trivial to decompose
115 // into rack/host/osd.
120 num_rack
= num_host
= num_osd
= 10;
122 for (int r
=0; r
<num_rack
; ++r
) {
123 loc
["rack"] = string("rack-") + stringify(r
);
124 for (int h
=0; h
<num_host
; ++h
) {
125 loc
["host"] = string("host-") + stringify(r
) + string("-") + stringify(h
);
126 for (int o
=0; o
<num_osd
; ++o
, ++osd
) {
127 c
->insert_item(g_ceph_context
, osd
, 1.0, string("osd.") + stringify(osd
), loc
);
134 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
135 EXPECT_EQ(0, lrc
.create_rule("rule1", *c
, &cerr
));
137 ErasureCodeProfile profile
;
138 unsigned int racks
= 2;
139 unsigned int hosts
= 5;
140 profile
["crush-steps"] =
142 " [\"choose\", \"rack\", " + stringify(racks
) + "], "
143 " [\"chooseleaf\", \"host\", " + stringify(hosts
) + "], "
145 const char *rule_name
= "rule2";
146 EXPECT_EQ(0, lrc
.parse_rule(profile
, &cerr
));
147 EXPECT_EQ(1, lrc
.create_rule(rule_name
, *c
, &cerr
));
149 vector
<__u32
> weight
;
150 for (int o
= 0; o
< c
->get_max_devices(); o
++)
151 weight
.push_back(0x10000);
152 int rule
= c
->get_rule_id(rule_name
);
154 unsigned int n
= racks
* hosts
;
155 c
->do_rule(rule
, 1, out
, n
, weight
, 0);
156 EXPECT_EQ(n
, out
.size());
158 // check that the first five are in the same rack and the next five
161 int first_rack
= out
[0] / num_host
/ num_osd
;
162 EXPECT_EQ(first_rack
, out
[1] / num_host
/ num_osd
);
163 EXPECT_EQ(first_rack
, out
[2] / num_host
/ num_osd
);
164 EXPECT_EQ(first_rack
, out
[3] / num_host
/ num_osd
);
165 EXPECT_EQ(first_rack
, out
[4] / num_host
/ num_osd
);
166 int second_rack
= out
[5] / num_host
/ num_osd
;
167 EXPECT_EQ(second_rack
, out
[6] / num_host
/ num_osd
);
168 EXPECT_EQ(second_rack
, out
[7] / num_host
/ num_osd
);
169 EXPECT_EQ(second_rack
, out
[8] / num_host
/ num_osd
);
170 EXPECT_EQ(second_rack
, out
[9] / num_host
/ num_osd
);
173 TEST(ErasureCodeLrc
, parse_kml
)
175 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
176 ErasureCodeProfile profile
;
177 EXPECT_EQ(0, lrc
.parse_kml(profile
, &cerr
));
179 EXPECT_EQ(ERROR_LRC_ALL_OR_NOTHING
, lrc
.parse_kml(profile
, &cerr
));
180 const char *generated
[] = { "mapping",
186 for (int i
= 0; i
< 3; i
++) {
187 profile
[generated
[i
]] = "SET";
188 EXPECT_EQ(ERROR_LRC_GENERATED
, lrc
.parse_kml(profile
, &cerr
));
189 profile
.erase(profile
.find(generated
[i
]));
195 EXPECT_EQ(ERROR_LRC_K_M_MODULO
, lrc
.parse_kml(profile
, &cerr
));
200 EXPECT_EQ(ERROR_LRC_K_MODULO
, lrc
.parse_kml(profile
, &cerr
));
205 EXPECT_EQ(0, lrc
.parse_kml(profile
, &cerr
));
207 " [ \"DDc_DDc_\", \"\" ],"
208 " [ \"DDDc____\", \"\" ],"
209 " [ \"____DDDc\", \"\" ],"
210 "]", profile
["layers"]);
211 EXPECT_EQ("DD__DD__", profile
["mapping"]);
212 EXPECT_EQ("chooseleaf", lrc
.rule_steps
[0].op
);
213 EXPECT_EQ("host", lrc
.rule_steps
[0].type
);
214 EXPECT_EQ(0, lrc
.rule_steps
[0].n
);
215 EXPECT_EQ(1U, lrc
.rule_steps
.size());
216 profile
.erase(profile
.find("mapping"));
217 profile
.erase(profile
.find("layers"));
222 profile
["crush-failure-domain"] = "osd";
223 EXPECT_EQ(0, lrc
.parse_kml(profile
, &cerr
));
224 EXPECT_EQ("chooseleaf", lrc
.rule_steps
[0].op
);
225 EXPECT_EQ("osd", lrc
.rule_steps
[0].type
);
226 EXPECT_EQ(0, lrc
.rule_steps
[0].n
);
227 EXPECT_EQ(1U, lrc
.rule_steps
.size());
228 profile
.erase(profile
.find("mapping"));
229 profile
.erase(profile
.find("layers"));
234 profile
["crush-failure-domain"] = "osd";
235 profile
["crush-locality"] = "rack";
236 EXPECT_EQ(0, lrc
.parse_kml(profile
, &cerr
));
237 EXPECT_EQ("choose", lrc
.rule_steps
[0].op
);
238 EXPECT_EQ("rack", lrc
.rule_steps
[0].type
);
239 EXPECT_EQ(2, lrc
.rule_steps
[0].n
);
240 EXPECT_EQ("chooseleaf", lrc
.rule_steps
[1].op
);
241 EXPECT_EQ("osd", lrc
.rule_steps
[1].type
);
242 EXPECT_EQ(4, lrc
.rule_steps
[1].n
);
243 EXPECT_EQ(2U, lrc
.rule_steps
.size());
244 profile
.erase(profile
.find("mapping"));
245 profile
.erase(profile
.find("layers"));
248 TEST(ErasureCodeLrc
, layers_description
)
250 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
251 ErasureCodeProfile profile
;
253 json_spirit::mArray description
;
254 EXPECT_EQ(ERROR_LRC_DESCRIPTION
,
255 lrc
.layers_description(profile
, &description
, &cerr
));
258 const char *description_string
= "\"not an array\"";
259 profile
["layers"] = description_string
;
260 EXPECT_EQ(ERROR_LRC_ARRAY
,
261 lrc
.layers_description(profile
, &description
, &cerr
));
264 const char *description_string
= "invalid json";
265 profile
["layers"] = description_string
;
266 EXPECT_EQ(ERROR_LRC_PARSE_JSON
,
267 lrc
.layers_description(profile
, &description
, &cerr
));
270 const char *description_string
= "[]";
271 profile
["layers"] = description_string
;
272 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
276 TEST(ErasureCodeLrc
, layers_parse
)
279 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
280 ErasureCodeProfile profile
;
282 const char *description_string
="[ 0 ]";
283 profile
["layers"] = description_string
;
284 json_spirit::mArray description
;
285 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
286 EXPECT_EQ(ERROR_LRC_ARRAY
,
287 lrc
.layers_parse(description_string
, description
, &cerr
));
291 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
292 ErasureCodeProfile profile
;
294 const char *description_string
="[ [ 0 ] ]";
295 profile
["layers"] = description_string
;
296 json_spirit::mArray description
;
297 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
298 EXPECT_EQ(ERROR_LRC_STR
,
299 lrc
.layers_parse(description_string
, description
, &cerr
));
303 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
304 ErasureCodeProfile profile
;
306 const char *description_string
="[ [ \"\", 0 ] ]";
307 profile
["layers"] = description_string
;
308 json_spirit::mArray description
;
309 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
310 EXPECT_EQ(ERROR_LRC_CONFIG_OPTIONS
,
311 lrc
.layers_parse(description_string
, description
, &cerr
));
315 // The second element can be an object describing the plugin
319 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
320 ErasureCodeProfile profile
;
322 const char *description_string
="[ [ \"\", { \"a\": \"b\" }, \"ignored\" ] ]";
323 profile
["layers"] = description_string
;
324 json_spirit::mArray description
;
325 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
326 EXPECT_EQ(0, lrc
.layers_parse(description_string
, description
, &cerr
));
327 EXPECT_EQ("b", lrc
.layers
.front().profile
["a"]);
331 // The second element can be a str_map parseable string describing the plugin
335 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
336 ErasureCodeProfile profile
;
338 const char *description_string
="[ [ \"\", \"a=b c=d\" ] ]";
339 profile
["layers"] = description_string
;
340 json_spirit::mArray description
;
341 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
342 EXPECT_EQ(0, lrc
.layers_parse(description_string
, description
, &cerr
));
343 EXPECT_EQ("b", lrc
.layers
.front().profile
["a"]);
344 EXPECT_EQ("d", lrc
.layers
.front().profile
["c"]);
349 TEST(ErasureCodeLrc
, layers_sanity_checks
)
352 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
353 ErasureCodeProfile profile
;
356 const char *description_string
=
358 " [ \"_cDDD_cDD\", \"\" ],"
359 " [ \"c_DDD____\", \"\" ],"
360 " [ \"_____cDDD\", \"\" ],"
362 profile
["layers"] = description_string
;
363 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
366 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
367 ErasureCodeProfile profile
;
368 const char *description_string
=
371 profile
["layers"] = description_string
;
372 EXPECT_EQ(ERROR_LRC_MAPPING
, lrc
.init(profile
, &cerr
));
375 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
376 ErasureCodeProfile profile
;
377 profile
["mapping"] = "";
378 const char *description_string
=
381 profile
["layers"] = description_string
;
382 EXPECT_EQ(ERROR_LRC_LAYERS_COUNT
, lrc
.init(profile
, &cerr
));
385 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
386 ErasureCodeProfile profile
;
389 const char *description_string
=
391 " [ \"DD??\", \"\" ], "
392 " [ \"DD\", \"\" ], "
393 " [ \"DD\", \"\" ], "
395 profile
["layers"] = description_string
;
396 EXPECT_EQ(-EINVAL
, lrc
.init(profile
, &cerr
));
400 TEST(ErasureCodeLrc
, layers_init
)
403 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
404 ErasureCodeProfile profile
;
406 const char* env
= getenv("CEPH_LIB");
407 string
directory(env
? env
: "lib");
408 string description_string
=
410 " [ \"_cDDD_cDD_\", \"directory=" + directory
+ "\" ],"
412 profile
["layers"] = description_string
;
413 json_spirit::mArray description
;
414 EXPECT_EQ(0, lrc
.layers_description(profile
, &description
, &cerr
));
415 EXPECT_EQ(0, lrc
.layers_parse(description_string
, description
, &cerr
));
416 EXPECT_EQ(0, lrc
.layers_init(&cerr
));
417 EXPECT_EQ("5", lrc
.layers
.front().profile
["k"]);
418 EXPECT_EQ("2", lrc
.layers
.front().profile
["m"]);
419 EXPECT_EQ("jerasure", lrc
.layers
.front().profile
["plugin"]);
420 EXPECT_EQ("reed_sol_van", lrc
.layers
.front().profile
["technique"]);
424 TEST(ErasureCodeLrc
, init
)
426 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
427 ErasureCodeProfile profile
;
430 const char *description_string
=
432 " [ \"_cDDD_cDD\", \"\" ],"
433 " [ \"c_DDD____\", \"\" ],"
434 " [ \"_____cDDD\", \"\" ],"
436 profile
["layers"] = description_string
;
437 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
440 TEST(ErasureCodeLrc
, init_kml
)
442 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
443 ErasureCodeProfile profile
;
447 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
448 EXPECT_EQ((unsigned int)(4 + 2 + (4 + 2) / 3), lrc
.get_chunk_count());
451 TEST(ErasureCodeLrc
, minimum_to_decode
)
453 // trivial : no erasures, the minimum is want_to_read
455 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
456 ErasureCodeProfile profile
;
459 const char *description_string
=
461 " [ \"_cDDD_cDD\", \"\" ],"
462 " [ \"c_DDD____\", \"\" ],"
463 " [ \"_____cDDD\", \"\" ],"
465 profile
["layers"] = description_string
;
466 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
467 set
<int> want_to_read
;
468 want_to_read
.insert(1);
469 set
<int> available_chunks
;
470 available_chunks
.insert(1);
471 available_chunks
.insert(2);
473 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
474 EXPECT_EQ(want_to_read
, minimum
);
476 // locally repairable erasure
478 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
479 ErasureCodeProfile profile
;
482 const char *description_string
=
484 " [ \"_cDDD_cDD_\", \"\" ],"
485 " [ \"c_DDD_____\", \"\" ],"
486 " [ \"_____cDDD_\", \"\" ],"
487 " [ \"_____DDDDc\", \"\" ],"
489 profile
["layers"] = description_string
;
490 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
491 EXPECT_EQ(profile
["mapping"].length(),
492 lrc
.get_chunk_count());
494 // want to read the last chunk
495 set
<int> want_to_read
;
496 want_to_read
.insert(lrc
.get_chunk_count() - 1);
497 // all chunks are available except the last chunk
498 set
<int> available_chunks
;
499 for (int i
= 0; i
< (int)lrc
.get_chunk_count() - 1; i
++)
500 available_chunks
.insert(i
);
501 // _____DDDDc can recover c
503 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
504 set
<int> expected_minimum
;
505 expected_minimum
.insert(5);
506 expected_minimum
.insert(6);
507 expected_minimum
.insert(7);
508 expected_minimum
.insert(8);
509 EXPECT_EQ(expected_minimum
, minimum
);
512 set
<int> want_to_read
;
513 want_to_read
.insert(0);
514 set
<int> available_chunks
;
515 for (int i
= 1; i
< (int)lrc
.get_chunk_count(); i
++)
516 available_chunks
.insert(i
);
518 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
519 set
<int> expected_minimum
;
520 expected_minimum
.insert(2);
521 expected_minimum
.insert(3);
522 expected_minimum
.insert(4);
523 EXPECT_EQ(expected_minimum
, minimum
);
526 // implicit parity required
528 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
529 ErasureCodeProfile profile
;
532 const char *description_string
=
534 " [ \"_cDDD_cDD\", \"\" ],"
535 " [ \"c_DDD____\", \"\" ],"
536 " [ \"_____cDDD\", \"\" ],"
538 profile
["layers"] = description_string
;
539 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
540 EXPECT_EQ(profile
["mapping"].length(),
541 lrc
.get_chunk_count());
542 set
<int> want_to_read
;
543 want_to_read
.insert(8);
545 // unable to recover, too many chunks missing
548 set
<int> available_chunks
;
549 available_chunks
.insert(0);
550 available_chunks
.insert(1);
553 available_chunks
.insert(4);
554 available_chunks
.insert(5);
555 available_chunks
.insert(6);
559 EXPECT_EQ(-EIO
, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
562 // We want to read chunk 8 and encoding was done with
568 // First strategy fails:
571 // xxXXXxxXX initial chunks
572 // xx.XXxx.. missing (2, 7, 8)
573 // _____cDDD fail : can recover 1 but 2 are missing
574 // c_DDD____ ignored because 8 is not used (i.e. _)
575 // _cDDD_cDD fail : can recover 2 but 3 are missing
577 // Second strategy succeeds:
580 // xxXXXxxXX initial chunks
581 // xx.XXxx.. missing (2, 7, 8)
582 // _____cDDD fail : can recover 1 but 2 are missing
583 // c_DDD____ success: recovers chunk 2
584 // _cDDD_cDD success: recovers chunk 7, 8
587 set
<int> available_chunks
;
588 available_chunks
.insert(0);
589 available_chunks
.insert(1);
591 available_chunks
.insert(3);
592 available_chunks
.insert(4);
593 available_chunks
.insert(5);
594 available_chunks
.insert(6);
598 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
599 EXPECT_EQ(available_chunks
, minimum
);
604 TEST(ErasureCodeLrc
, encode_decode
)
606 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
607 ErasureCodeProfile profile
;
610 const char *description_string
=
612 " [ \"_cDD_cDD\", \"\" ]," // global layer
613 " [ \"c_DD____\", \"\" ]," // first local layer
614 " [ \"____cDDD\", \"\" ]," // second local layer
616 profile
["layers"] = description_string
;
617 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
618 EXPECT_EQ(4U, lrc
.get_data_chunk_count());
619 unsigned int chunk_size
= g_conf().get_val
<Option::size_t>("osd_pool_erasure_code_stripe_unit");
620 unsigned int stripe_width
= lrc
.get_data_chunk_count() * chunk_size
;
621 EXPECT_EQ(chunk_size
, lrc
.get_chunk_size(stripe_width
));
622 set
<int> want_to_encode
;
623 map
<int, bufferlist
> encoded
;
624 for (unsigned int i
= 0; i
< lrc
.get_chunk_count(); ++i
) {
625 want_to_encode
.insert(i
);
626 bufferptr
ptr(buffer::create_page_aligned(chunk_size
));
629 tmp
.claim_append(encoded
[i
]);
630 encoded
[i
].swap(tmp
);
632 const vector
<int> &mapping
= lrc
.get_chunk_mapping();
634 for (unsigned int i
= 0; i
< lrc
.get_data_chunk_count(); i
++) {
636 string
s(chunk_size
, c
);
638 encoded
[j
].append(s
);
641 EXPECT_EQ(0, lrc
.encode_chunks(want_to_encode
, &encoded
));
644 map
<int, bufferlist
> chunks
;
645 chunks
[4] = encoded
[4];
646 chunks
[5] = encoded
[5];
647 chunks
[6] = encoded
[6];
648 set
<int> want_to_read
;
649 want_to_read
.insert(7);
650 set
<int> available_chunks
;
651 available_chunks
.insert(4);
652 available_chunks
.insert(5);
653 available_chunks
.insert(6);
655 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
656 // only need three chunks from the second local layer
657 EXPECT_EQ(3U, minimum
.size());
658 EXPECT_EQ(1U, minimum
.count(4));
659 EXPECT_EQ(1U, minimum
.count(5));
660 EXPECT_EQ(1U, minimum
.count(6));
661 map
<int, bufferlist
> decoded
;
662 EXPECT_EQ(0, lrc
._decode(want_to_read
, chunks
, &decoded
));
663 string
s(chunk_size
, 'D');
664 EXPECT_EQ(s
, string(decoded
[7].c_str(), chunk_size
));
667 set
<int> want_to_read
;
668 want_to_read
.insert(2);
669 map
<int, bufferlist
> chunks
;
670 chunks
[1] = encoded
[1];
671 chunks
[3] = encoded
[3];
672 chunks
[5] = encoded
[5];
673 chunks
[6] = encoded
[6];
674 chunks
[7] = encoded
[7];
675 set
<int> available_chunks
;
676 available_chunks
.insert(1);
677 available_chunks
.insert(3);
678 available_chunks
.insert(5);
679 available_chunks
.insert(6);
680 available_chunks
.insert(7);
682 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
683 EXPECT_EQ(5U, minimum
.size());
684 EXPECT_EQ(available_chunks
, minimum
);
686 map
<int, bufferlist
> decoded
;
687 EXPECT_EQ(0, lrc
._decode(want_to_read
, encoded
, &decoded
));
688 string
s(chunk_size
, 'A');
689 EXPECT_EQ(s
, string(decoded
[2].c_str(), chunk_size
));
692 set
<int> want_to_read
;
693 want_to_read
.insert(3);
694 want_to_read
.insert(6);
695 want_to_read
.insert(7);
696 set
<int> available_chunks
;
697 available_chunks
.insert(0);
698 available_chunks
.insert(1);
699 available_chunks
.insert(2);
700 // available_chunks.insert(3);
701 available_chunks
.insert(4);
702 available_chunks
.insert(5);
703 // available_chunks.insert(6);
704 // available_chunks.insert(7);
708 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
709 EXPECT_EQ(4U, minimum
.size());
710 // only need two chunks from the first local layer
711 EXPECT_EQ(1U, minimum
.count(0));
712 EXPECT_EQ(1U, minimum
.count(2));
713 // the above chunks will rebuild chunk 3 and the global layer only needs
714 // three more chunks to reach the required amount of chunks (4) to recover
716 EXPECT_EQ(1U, minimum
.count(1));
717 EXPECT_EQ(1U, minimum
.count(2));
718 EXPECT_EQ(1U, minimum
.count(5));
720 map
<int, bufferlist
> decoded
;
721 EXPECT_EQ(0, lrc
._decode(want_to_read
, encoded
, &decoded
));
723 string
s(chunk_size
, 'B');
724 EXPECT_EQ(s
, string(decoded
[3].c_str(), chunk_size
));
727 string
s(chunk_size
, 'C');
728 EXPECT_EQ(s
, string(decoded
[6].c_str(), chunk_size
));
731 string
s(chunk_size
, 'D');
732 EXPECT_EQ(s
, string(decoded
[7].c_str(), chunk_size
));
737 TEST(ErasureCodeLrc
, encode_decode_2
)
739 ErasureCodeLrc
lrc(g_conf().get_val
<std::string
>("erasure_code_dir"));
740 ErasureCodeProfile profile
;
743 const char *description_string
=
745 " [ \"DDc_DDc_\", \"\" ],"
746 " [ \"DDDc____\", \"\" ],"
747 " [ \"____DDDc\", \"\" ],"
749 profile
["layers"] = description_string
;
750 EXPECT_EQ(0, lrc
.init(profile
, &cerr
));
751 EXPECT_EQ(4U, lrc
.get_data_chunk_count());
752 unsigned int chunk_size
= g_conf().get_val
<Option::size_t>("osd_pool_erasure_code_stripe_unit");
753 unsigned int stripe_width
= lrc
.get_data_chunk_count() * chunk_size
;
754 EXPECT_EQ(chunk_size
, lrc
.get_chunk_size(stripe_width
));
755 set
<int> want_to_encode
;
756 map
<int, bufferlist
> encoded
;
757 for (unsigned int i
= 0; i
< lrc
.get_chunk_count(); ++i
) {
758 want_to_encode
.insert(i
);
759 bufferptr
ptr(buffer::create_page_aligned(chunk_size
));
762 tmp
.claim_append(encoded
[i
]);
763 encoded
[i
].swap(tmp
);
765 const vector
<int> &mapping
= lrc
.get_chunk_mapping();
767 for (unsigned int i
= 0; i
< lrc
.get_data_chunk_count(); i
++) {
769 string
s(chunk_size
, c
);
771 encoded
[j
].append(s
);
774 EXPECT_EQ(0, lrc
.encode_chunks(want_to_encode
, &encoded
));
777 set
<int> want_to_read
;
778 want_to_read
.insert(0);
779 map
<int, bufferlist
> chunks
;
780 chunks
[1] = encoded
[1];
781 chunks
[3] = encoded
[3];
782 chunks
[4] = encoded
[4];
783 chunks
[5] = encoded
[5];
784 chunks
[6] = encoded
[6];
785 chunks
[7] = encoded
[7];
786 set
<int> available_chunks
;
787 available_chunks
.insert(1);
788 available_chunks
.insert(3);
789 available_chunks
.insert(4);
790 available_chunks
.insert(5);
791 available_chunks
.insert(6);
792 available_chunks
.insert(7);
794 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
795 EXPECT_EQ(4U, minimum
.size());
796 EXPECT_EQ(1U, minimum
.count(1));
797 EXPECT_EQ(1U, minimum
.count(4));
798 EXPECT_EQ(1U, minimum
.count(5));
799 EXPECT_EQ(1U, minimum
.count(6));
801 map
<int, bufferlist
> decoded
;
802 EXPECT_EQ(0, lrc
._decode(want_to_read
, chunks
, &decoded
));
803 string
s(chunk_size
, 'A');
804 EXPECT_EQ(s
, string(decoded
[0].c_str(), chunk_size
));
807 set
<int> want_to_read
;
808 for (unsigned int i
= 0; i
< lrc
.get_chunk_count(); i
++)
809 want_to_read
.insert(i
);
810 map
<int, bufferlist
> chunks
;
811 chunks
[1] = encoded
[1];
812 chunks
[3] = encoded
[3];
813 chunks
[5] = encoded
[5];
814 chunks
[6] = encoded
[6];
815 chunks
[7] = encoded
[7];
816 set
<int> available_chunks
;
817 available_chunks
.insert(1);
818 available_chunks
.insert(3);
819 available_chunks
.insert(5);
820 available_chunks
.insert(6);
821 available_chunks
.insert(7);
823 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
824 EXPECT_EQ(5U, minimum
.size());
825 EXPECT_EQ(1U, minimum
.count(1));
826 EXPECT_EQ(1U, minimum
.count(3));
827 EXPECT_EQ(1U, minimum
.count(5));
828 EXPECT_EQ(1U, minimum
.count(6));
829 EXPECT_EQ(1U, minimum
.count(7));
831 map
<int, bufferlist
> decoded
;
832 EXPECT_EQ(0, lrc
._decode(want_to_read
, chunks
, &decoded
));
834 string
s(chunk_size
, 'A');
835 EXPECT_EQ(s
, string(decoded
[0].c_str(), chunk_size
));
838 string
s(chunk_size
, 'B');
839 EXPECT_EQ(s
, string(decoded
[1].c_str(), chunk_size
));
842 string
s(chunk_size
, 'C');
843 EXPECT_EQ(s
, string(decoded
[4].c_str(), chunk_size
));
846 string
s(chunk_size
, 'D');
847 EXPECT_EQ(s
, string(decoded
[5].c_str(), chunk_size
));
851 set
<int> want_to_read
;
852 for (unsigned int i
= 0; i
< lrc
.get_chunk_count(); i
++)
853 want_to_read
.insert(i
);
854 map
<int, bufferlist
> chunks
;
855 chunks
[1] = encoded
[1];
856 chunks
[3] = encoded
[3];
857 chunks
[5] = encoded
[5];
858 chunks
[6] = encoded
[6];
859 chunks
[7] = encoded
[7];
860 set
<int> available_chunks
;
861 available_chunks
.insert(1);
862 available_chunks
.insert(3);
863 available_chunks
.insert(5);
864 available_chunks
.insert(6);
865 available_chunks
.insert(7);
867 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
868 EXPECT_EQ(5U, minimum
.size());
869 EXPECT_EQ(1U, minimum
.count(1));
870 EXPECT_EQ(1U, minimum
.count(3));
871 EXPECT_EQ(1U, minimum
.count(5));
872 EXPECT_EQ(1U, minimum
.count(6));
873 EXPECT_EQ(1U, minimum
.count(7));
875 map
<int, bufferlist
> decoded
;
876 EXPECT_EQ(0, lrc
._decode(want_to_read
, chunks
, &decoded
));
878 string
s(chunk_size
, 'A');
879 EXPECT_EQ(s
, string(decoded
[0].c_str(), chunk_size
));
882 string
s(chunk_size
, 'B');
883 EXPECT_EQ(s
, string(decoded
[1].c_str(), chunk_size
));
886 string
s(chunk_size
, 'C');
887 EXPECT_EQ(s
, string(decoded
[4].c_str(), chunk_size
));
890 string
s(chunk_size
, 'D');
891 EXPECT_EQ(s
, string(decoded
[5].c_str(), chunk_size
));
895 set
<int> want_to_read
;
896 want_to_read
.insert(6);
897 map
<int, bufferlist
> chunks
;
898 chunks
[0] = encoded
[0];
899 chunks
[1] = encoded
[1];
900 chunks
[3] = encoded
[3];
901 chunks
[5] = encoded
[5];
902 chunks
[7] = encoded
[7];
903 set
<int> available_chunks
;
904 available_chunks
.insert(0);
905 available_chunks
.insert(1);
906 available_chunks
.insert(3);
907 available_chunks
.insert(5);
908 available_chunks
.insert(7);
910 EXPECT_EQ(0, lrc
._minimum_to_decode(want_to_read
, available_chunks
, &minimum
));
911 EXPECT_EQ(available_chunks
, minimum
);
913 map
<int, bufferlist
> decoded
;
914 EXPECT_EQ(0, lrc
._decode(want_to_read
, chunks
, &decoded
));
920 * compile-command: "cd ../.. ;
921 * make -j4 unittest_erasure_code_lrc && valgrind --tool=memcheck \
922 * ./unittest_erasure_code_lrc \
923 * --gtest_filter=*.* --log-to-stderr=true --debug-osd=20"