]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | /* | |
3 | * Ceph - scalable distributed file system | |
4 | * | |
5 | * Copyright (C) 2014 CERN (Switzerland) | |
6 | * Copyright (C) 2014 Red Hat <contact@redhat.com> | |
7 | * | |
8 | * Author: Andreas-Joachim Peters <Andreas.Joachim.Peters@cern.ch> | |
9 | * Author: Loic Dachary <loic@dachary.org> | |
10 | * | |
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. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <errno.h> | |
19 | #include <stdlib.h> | |
20 | ||
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" | |
28 | ||
29 | ErasureCodeIsaTableCache tcache; | |
30 | ||
31 | class IsaErasureCodeTest : public ::testing::Test { | |
32 | public: | |
33 | void compare_chunks(bufferlist &in, map<int, bufferlist> &encoded); | |
34 | void encode_decode(unsigned object_size); | |
35 | }; | |
36 | ||
37 | void IsaErasureCodeTest::compare_chunks(bufferlist &in, map<int, bufferlist> &encoded) | |
38 | { | |
39 | unsigned object_size = in.length(); | |
40 | unsigned chunk_size = encoded[0].length(); | |
41 | for (unsigned i = 0; i < encoded.size(); i++) { | |
42 | if (i * chunk_size >= object_size) | |
43 | break; | |
44 | int chunk_length = object_size > (i + 1) * chunk_size ? chunk_size : object_size - i * chunk_size; | |
45 | EXPECT_EQ(0, memcmp(encoded[i].c_str(), in.c_str() + i * chunk_size, chunk_length)); | |
46 | } | |
47 | } | |
48 | ||
49 | void IsaErasureCodeTest::encode_decode(unsigned object_size) | |
50 | { | |
51 | ErasureCodeIsaDefault Isa(tcache); | |
52 | ||
53 | ErasureCodeProfile profile; | |
54 | profile["k"] = "2"; | |
55 | profile["m"] = "2"; | |
56 | Isa.init(profile, &cerr); | |
57 | ||
58 | string payload(object_size, 'X'); | |
59 | bufferlist in; | |
60 | // may be multiple bufferptr if object_size is larger than CEPH_PAGE_SIZE | |
61 | in.append(payload.c_str(), payload.length()); | |
62 | int want_to_encode[] = {0, 1, 2, 3}; | |
63 | map<int, bufferlist> encoded; | |
64 | EXPECT_EQ(0, Isa.encode(set<int>(want_to_encode, want_to_encode + 4), | |
65 | in, | |
66 | &encoded)); | |
67 | EXPECT_EQ(4u, encoded.size()); | |
68 | unsigned chunk_size = encoded[0].length(); | |
69 | EXPECT_EQ(chunk_size, Isa.get_chunk_size(object_size)); | |
70 | compare_chunks(in, encoded); | |
71 | ||
72 | // all chunks are available | |
73 | { | |
74 | int want_to_decode[] = {0, 1}; | |
75 | map<int, bufferlist> decoded; | |
76 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 2), | |
77 | encoded, | |
78 | &decoded)); | |
79 | EXPECT_EQ(2u, decoded.size()); | |
80 | EXPECT_EQ(chunk_size, decoded[0].length()); | |
81 | compare_chunks(in, decoded); | |
82 | } | |
83 | ||
84 | // one data chunk is missing | |
85 | { | |
86 | map<int, bufferlist> degraded = encoded; | |
87 | ||
88 | string enc1(encoded[1].c_str(), chunk_size); | |
89 | ||
90 | degraded.erase(1); | |
91 | EXPECT_EQ(3u, degraded.size()); | |
92 | int want_to_decode[] = {1}; | |
93 | map<int, bufferlist> decoded; | |
94 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 1), | |
95 | degraded, | |
96 | &decoded)); | |
97 | // always decode all, regardless of want_to_decode | |
98 | EXPECT_EQ(4u, decoded.size()); | |
99 | EXPECT_EQ(chunk_size, decoded[1].length()); | |
100 | EXPECT_EQ(0, memcmp(decoded[1].c_str(), enc1.c_str(), chunk_size)); | |
101 | } | |
102 | ||
103 | // non-xor coding chunk is missing | |
104 | { | |
105 | map<int, bufferlist> degraded = encoded; | |
106 | ||
107 | string enc3(encoded[3].c_str(), chunk_size); | |
108 | ||
109 | degraded.erase(3); | |
110 | EXPECT_EQ(3u, degraded.size()); | |
111 | int want_to_decode[] = {3}; | |
112 | map<int, bufferlist> decoded; | |
113 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 1), | |
114 | degraded, | |
115 | &decoded)); | |
116 | // always decode all, regardless of want_to_decode | |
117 | EXPECT_EQ(4u, decoded.size()); | |
118 | EXPECT_EQ(chunk_size, decoded[3].length()); | |
119 | EXPECT_EQ(0, memcmp(decoded[3].c_str(), enc3.c_str(), chunk_size)); | |
120 | } | |
121 | ||
122 | // xor coding chunk is missing | |
123 | { | |
124 | map<int, bufferlist> degraded = encoded; | |
125 | ||
126 | string enc2(encoded[2].c_str(), chunk_size); | |
127 | ||
128 | degraded.erase(2); | |
129 | EXPECT_EQ(3u, degraded.size()); | |
130 | int want_to_decode[] = {2}; | |
131 | map<int, bufferlist> decoded; | |
132 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 1), | |
133 | degraded, | |
134 | &decoded)); | |
135 | // always decode all, regardless of want_to_decode | |
136 | EXPECT_EQ(4u, decoded.size()); | |
137 | EXPECT_EQ(chunk_size, decoded[2].length()); | |
138 | EXPECT_EQ(0, memcmp(decoded[2].c_str(), enc2.c_str(), chunk_size)); | |
139 | } | |
140 | ||
141 | // one data and one coding chunk is missing | |
142 | { | |
143 | map<int, bufferlist> degraded = encoded; | |
144 | ||
145 | string enc3(encoded[3].c_str(), chunk_size); | |
146 | ||
147 | degraded.erase(1); | |
148 | degraded.erase(3); | |
149 | EXPECT_EQ(2u, degraded.size()); | |
150 | int want_to_decode[] = {1, 3}; | |
151 | map<int, bufferlist> decoded; | |
152 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 2), | |
153 | degraded, | |
154 | &decoded)); | |
155 | // always decode all, regardless of want_to_decode | |
156 | EXPECT_EQ(4u, decoded.size()); | |
157 | EXPECT_EQ(chunk_size, decoded[1].length()); | |
158 | EXPECT_EQ(0, memcmp(decoded[3].c_str(), enc3.c_str(), chunk_size)); | |
159 | } | |
160 | ||
161 | // two data chunks are missing | |
162 | { | |
163 | map<int, bufferlist> degraded = encoded; | |
164 | degraded.erase(0); | |
165 | degraded.erase(1); | |
166 | EXPECT_EQ(2u, degraded.size()); | |
167 | int want_to_decode[] = {0, 1}; | |
168 | map<int, bufferlist> decoded; | |
169 | EXPECT_EQ(0, Isa.decode(set<int>(want_to_decode, want_to_decode + 2), | |
170 | degraded, | |
171 | &decoded)); | |
172 | // always decode all, regardless of want_to_decode | |
173 | EXPECT_EQ(4u, decoded.size()); | |
174 | EXPECT_EQ(chunk_size, decoded[0].length()); | |
175 | compare_chunks(in, decoded); | |
176 | } | |
177 | ||
178 | } | |
179 | ||
180 | TEST_F(IsaErasureCodeTest, encode_decode) | |
181 | { | |
182 | encode_decode(1); | |
183 | encode_decode(EC_ISA_ADDRESS_ALIGNMENT); | |
184 | encode_decode(EC_ISA_ADDRESS_ALIGNMENT + 1); | |
185 | encode_decode(2048); | |
186 | encode_decode(4096); | |
187 | encode_decode(4096 + 1); | |
188 | } | |
189 | ||
190 | TEST_F(IsaErasureCodeTest, minimum_to_decode) | |
191 | { | |
192 | ErasureCodeIsaDefault Isa(tcache); | |
193 | ErasureCodeProfile profile; | |
194 | profile["k"] = "2"; | |
195 | profile["m"] = "2"; | |
196 | Isa.init(profile, &cerr); | |
197 | ||
198 | // | |
199 | // If trying to read nothing, the minimum is empty. | |
200 | // | |
201 | { | |
202 | set<int> want_to_read; | |
203 | set<int> available_chunks; | |
204 | set<int> minimum; | |
205 | ||
206 | EXPECT_EQ(0, Isa.minimum_to_decode(want_to_read, | |
207 | available_chunks, | |
208 | &minimum)); | |
209 | EXPECT_TRUE(minimum.empty()); | |
210 | } | |
211 | // | |
212 | // There is no way to read a chunk if none are available. | |
213 | // | |
214 | { | |
215 | set<int> want_to_read; | |
216 | set<int> available_chunks; | |
217 | set<int> minimum; | |
218 | ||
219 | want_to_read.insert(0); | |
220 | ||
221 | EXPECT_EQ(-EIO, Isa.minimum_to_decode(want_to_read, | |
222 | available_chunks, | |
223 | &minimum)); | |
224 | } | |
225 | // | |
226 | // Reading a subset of the available chunks is always possible. | |
227 | // | |
228 | { | |
229 | set<int> want_to_read; | |
230 | set<int> available_chunks; | |
231 | set<int> minimum; | |
232 | ||
233 | want_to_read.insert(0); | |
234 | available_chunks.insert(0); | |
235 | ||
236 | EXPECT_EQ(0, Isa.minimum_to_decode(want_to_read, | |
237 | available_chunks, | |
238 | &minimum)); | |
239 | EXPECT_EQ(want_to_read, minimum); | |
240 | } | |
241 | // | |
242 | // There is no way to read a missing chunk if there is less than k | |
243 | // chunks available. | |
244 | // | |
245 | { | |
246 | set<int> want_to_read; | |
247 | set<int> available_chunks; | |
248 | set<int> minimum; | |
249 | ||
250 | want_to_read.insert(0); | |
251 | want_to_read.insert(1); | |
252 | available_chunks.insert(0); | |
253 | ||
254 | EXPECT_EQ(-EIO, Isa.minimum_to_decode(want_to_read, | |
255 | available_chunks, | |
256 | &minimum)); | |
257 | } | |
258 | // | |
259 | // When chunks are not available, the minimum can be made of any | |
260 | // chunks. For instance, to read 1 and 3 below the minimum could be | |
261 | // 2 and 3 which may seem better because it contains one of the | |
262 | // chunks to be read. But it won't be more efficient than retrieving | |
263 | // 0 and 2 instead because, in both cases, the decode function will | |
264 | // need to run the same recovery operation and use the same amount | |
265 | // of CPU and memory. | |
266 | // | |
267 | { | |
268 | set<int> want_to_read; | |
269 | set<int> available_chunks; | |
270 | set<int> minimum; | |
271 | ||
272 | want_to_read.insert(1); | |
273 | want_to_read.insert(3); | |
274 | available_chunks.insert(0); | |
275 | available_chunks.insert(2); | |
276 | available_chunks.insert(3); | |
277 | ||
278 | EXPECT_EQ(0, Isa.minimum_to_decode(want_to_read, | |
279 | available_chunks, | |
280 | &minimum)); | |
281 | EXPECT_EQ(2u, minimum.size()); | |
282 | EXPECT_EQ(0u, minimum.count(3)); | |
283 | } | |
284 | } | |
285 | ||
286 | TEST_F(IsaErasureCodeTest, chunk_size) | |
287 | { | |
288 | { | |
289 | ErasureCodeIsaDefault Isa(tcache); | |
290 | ErasureCodeProfile profile; | |
291 | profile["k"] = "2"; | |
292 | profile["m"] = "1"; | |
293 | Isa.init(profile, &cerr); | |
294 | const int k = 2; | |
295 | ||
296 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT, Isa.get_chunk_size(1)); | |
297 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT, Isa.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT * k - 1)); | |
298 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT * 2, Isa.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT * k + 1)); | |
299 | } | |
300 | { | |
301 | ErasureCodeIsaDefault Isa(tcache); | |
302 | ErasureCodeProfile profile; | |
303 | profile["k"] = "3"; | |
304 | profile["m"] = "1"; | |
305 | Isa.init(profile, &cerr); | |
306 | const int k = 3; | |
307 | ||
308 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT, Isa.get_chunk_size(1)); | |
309 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT, Isa.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT * k - 1)); | |
310 | ASSERT_EQ(EC_ISA_ADDRESS_ALIGNMENT * 2, Isa.get_chunk_size(EC_ISA_ADDRESS_ALIGNMENT * k + 1)); | |
311 | unsigned object_size = EC_ISA_ADDRESS_ALIGNMENT * k * 1024 + 1; | |
312 | ASSERT_NE(0u, object_size % k); | |
313 | ASSERT_NE(0u, object_size % EC_ISA_ADDRESS_ALIGNMENT); | |
314 | unsigned chunk_size = Isa.get_chunk_size(object_size); | |
315 | ASSERT_EQ(0u, chunk_size % EC_ISA_ADDRESS_ALIGNMENT); | |
316 | ASSERT_GT(chunk_size, (chunk_size * k) - object_size); | |
317 | } | |
318 | } | |
319 | ||
320 | TEST_F(IsaErasureCodeTest, encode) | |
321 | { | |
322 | ErasureCodeIsaDefault Isa(tcache); | |
323 | ErasureCodeProfile profile; | |
324 | profile["k"] = "2"; | |
325 | profile["m"] = "2"; | |
326 | Isa.init(profile, &cerr); | |
327 | ||
328 | unsigned aligned_object_size = Isa.get_alignment() * 2; | |
329 | { | |
330 | // | |
331 | // When the input bufferlist needs to be padded because | |
332 | // it is not properly aligned, it is padded with zeros. | |
333 | // | |
334 | bufferlist in; | |
335 | map<int,bufferlist> encoded; | |
336 | int want_to_encode[] = { 0, 1, 2, 3 }; | |
337 | int trail_length = 1; | |
338 | in.append(string(aligned_object_size + trail_length, 'X')); | |
339 | EXPECT_EQ(0, Isa.encode(set<int>(want_to_encode, want_to_encode+4), | |
340 | in, | |
341 | &encoded)); | |
342 | EXPECT_EQ(4u, encoded.size()); | |
343 | char *last_chunk = encoded[1].c_str(); | |
344 | int length =encoded[1].length(); | |
345 | EXPECT_EQ('X', last_chunk[0]); | |
346 | EXPECT_EQ('\0', last_chunk[length - trail_length]); | |
347 | } | |
348 | ||
349 | { | |
350 | // | |
351 | // When only the first chunk is required, the encoded map only | |
352 | // contains the first chunk. Although the Isa encode | |
353 | // internally allocated a buffer because of padding requirements | |
354 | // and also computes the coding chunks, they are released before | |
355 | // the return of the method, as shown when running the tests thru | |
356 | // valgrind (there is no leak). | |
357 | // | |
358 | bufferlist in; | |
359 | map<int,bufferlist> encoded; | |
360 | set<int> want_to_encode; | |
361 | want_to_encode.insert(0); | |
362 | int trail_length = 1; | |
363 | in.append(string(aligned_object_size + trail_length, 'X')); | |
364 | EXPECT_EQ(0, Isa.encode(want_to_encode, in, &encoded)); | |
365 | EXPECT_EQ(1u, encoded.size()); | |
366 | } | |
367 | } | |
368 | ||
369 | TEST_F(IsaErasureCodeTest, sanity_check_k) | |
370 | { | |
371 | ErasureCodeIsaDefault Isa(tcache); | |
372 | ErasureCodeProfile profile; | |
373 | profile["k"] = "1"; | |
374 | profile["m"] = "1"; | |
375 | ostringstream errors; | |
376 | EXPECT_EQ(-EINVAL, Isa.init(profile, &errors)); | |
377 | EXPECT_NE(std::string::npos, errors.str().find("must be >= 2")); | |
378 | } | |
379 | ||
380 | bool | |
381 | DecodeAndVerify(ErasureCodeIsaDefault& Isa, map<int, bufferlist> °raded, set<int> want_to_decode, buffer::ptr* enc, int length) | |
382 | { | |
383 | map<int, bufferlist> decoded; | |
384 | bool ok; | |
385 | ||
386 | // decode as requested | |
387 | ok = Isa.decode(want_to_decode, | |
388 | degraded, | |
389 | &decoded); | |
390 | ||
391 | for (int i = 0; i < (int) decoded.size(); i++) { | |
392 | // compare all the buffers with their original | |
393 | ok |= memcmp(decoded[i].c_str(), enc[i].c_str(), length); | |
394 | } | |
395 | ||
396 | return ok; | |
397 | } | |
398 | ||
399 | TEST_F(IsaErasureCodeTest, isa_vandermonde_exhaustive) | |
400 | { | |
401 | // Test all possible failure scenarios and reconstruction cases for | |
402 | // a (12,4) configuration using the vandermonde matrix | |
403 | ||
404 | ErasureCodeIsaDefault Isa(tcache); | |
405 | ErasureCodeProfile profile; | |
406 | profile["k"] = "12"; | |
407 | profile["m"] = "4"; | |
408 | Isa.init(profile, &cerr); | |
409 | ||
410 | const int k = 12; | |
411 | const int m = 4; | |
412 | ||
413 | #define LARGE_ENOUGH 2048 | |
414 | bufferptr in_ptr(buffer::create_page_aligned(LARGE_ENOUGH)); | |
415 | in_ptr.zero(); | |
416 | in_ptr.set_length(0); | |
417 | const char *payload = | |
418 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
419 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
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 | in_ptr.append(payload, strlen(payload)); | |
444 | bufferlist in; | |
445 | in.push_front(in_ptr); | |
446 | ||
447 | set<int>want_to_encode; | |
448 | ||
449 | map<int, bufferlist> encoded; | |
450 | for (int i = 0; i < (k + m); i++) { | |
451 | want_to_encode.insert(i); | |
452 | } | |
453 | ||
454 | ||
455 | EXPECT_EQ(0, Isa.encode(want_to_encode, | |
456 | in, | |
457 | &encoded)); | |
458 | ||
459 | EXPECT_EQ((unsigned) (k + m), encoded.size()); | |
460 | ||
461 | unsigned length = encoded[0].length(); | |
462 | ||
463 | for (int i = 0; i < k; i++) { | |
464 | EXPECT_EQ(0, memcmp(encoded[i].c_str(), in.c_str() + (i * length), length)); | |
465 | } | |
466 | ||
467 | buffer::ptr enc[k + m]; | |
468 | // create buffers with a copy of the original data to be able to compare it after decoding | |
469 | { | |
470 | for (int i = 0; i < (k + m); i++) { | |
471 | buffer::ptr newenc(buffer::create_page_aligned(LARGE_ENOUGH)); | |
472 | enc[i] = newenc; | |
473 | enc[i].zero(); | |
474 | enc[i].set_length(0); | |
475 | enc[i].append(encoded[i].c_str(), length); | |
476 | } | |
477 | } | |
478 | ||
479 | // loop through all possible loss scenarios | |
480 | int cnt_cf = 0; | |
481 | ||
482 | for (int l1 = 0; l1 < (k + m); l1++) { | |
483 | map<int, bufferlist> degraded = encoded; | |
484 | set<int> want_to_decode; | |
485 | bool err; | |
486 | degraded.erase(l1); | |
487 | want_to_decode.insert(l1); | |
488 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
489 | EXPECT_EQ(0, err); | |
490 | cnt_cf++; | |
491 | for (int l2 = l1 + 1; l2 < (k + m); l2++) { | |
492 | degraded.erase(l2); | |
493 | want_to_decode.insert(l2); | |
494 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
495 | EXPECT_EQ(0, err); | |
496 | cnt_cf++; | |
497 | for (int l3 = l2 + 1; l3 < (k + m); l3++) { | |
498 | degraded.erase(l3); | |
499 | want_to_decode.insert(l3); | |
500 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
501 | EXPECT_EQ(0, err); | |
502 | cnt_cf++; | |
503 | for (int l4 = l3 + 1; l4 < (k + m); l4++) { | |
504 | degraded.erase(l4); | |
505 | want_to_decode.insert(l4); | |
506 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
507 | EXPECT_EQ(0, err); | |
508 | degraded[l4] = encoded[l4]; | |
509 | want_to_decode.erase(l4); | |
510 | cnt_cf++; | |
511 | } | |
512 | degraded[l3] = encoded[l3]; | |
513 | want_to_decode.erase(l3); | |
514 | } | |
515 | degraded[l2] = encoded[l2]; | |
516 | want_to_decode.erase(l2); | |
517 | } | |
518 | degraded[l1] = encoded[l1]; | |
519 | want_to_decode.erase(l1); | |
520 | } | |
521 | EXPECT_EQ(2516, cnt_cf); | |
522 | EXPECT_EQ(2506, tcache.getDecodingTableCacheSize()); // 3 entries from (2,2) test and 2503 from (12,4) | |
523 | } | |
524 | ||
525 | TEST_F(IsaErasureCodeTest, isa_cauchy_exhaustive) | |
526 | { | |
527 | // Test all possible failure scenarios and reconstruction cases for | |
528 | // a (12,4) configuration using the cauchy matrix | |
529 | ErasureCodeIsaDefault Isa(tcache,ErasureCodeIsaDefault::kCauchy); | |
530 | ErasureCodeProfile profile; | |
531 | profile["k"] = "12"; | |
532 | profile["m"] = "4"; | |
533 | profile["technique"] = "cauchy"; | |
534 | ||
535 | Isa.init(profile, &cerr); | |
536 | ||
537 | const int k = 12; | |
538 | const int m = 4; | |
539 | ||
540 | #define LARGE_ENOUGH 2048 | |
541 | bufferptr in_ptr(buffer::create_page_aligned(LARGE_ENOUGH)); | |
542 | in_ptr.zero(); | |
543 | in_ptr.set_length(0); | |
544 | const char *payload = | |
545 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
546 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
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 | in_ptr.append(payload, strlen(payload)); | |
571 | bufferlist in; | |
572 | in.push_front(in_ptr); | |
573 | ||
574 | set<int>want_to_encode; | |
575 | ||
576 | map<int, bufferlist> encoded; | |
577 | for (int i = 0; i < (k + m); i++) { | |
578 | want_to_encode.insert(i); | |
579 | } | |
580 | ||
581 | ||
582 | EXPECT_EQ(0, Isa.encode(want_to_encode, | |
583 | in, | |
584 | &encoded)); | |
585 | ||
586 | EXPECT_EQ((unsigned) (k + m), encoded.size()); | |
587 | ||
588 | unsigned length = encoded[0].length(); | |
589 | ||
590 | for (int i = 0; i < k; i++) { | |
591 | EXPECT_EQ(0, memcmp(encoded[i].c_str(), in.c_str() + (i * length), length)); | |
592 | } | |
593 | ||
594 | buffer::ptr enc[k + m]; | |
595 | // create buffers with a copy of the original data to be able to compare it after decoding | |
596 | { | |
597 | for (int i = 0; i < (k + m); i++) { | |
598 | buffer::ptr newenc(buffer::create_page_aligned(LARGE_ENOUGH)); | |
599 | enc[i] = newenc; | |
600 | enc[i].zero(); | |
601 | enc[i].set_length(0); | |
602 | enc[i].append(encoded[i].c_str(), length); | |
603 | } | |
604 | } | |
605 | ||
606 | // loop through all possible loss scenarios | |
607 | int cnt_cf = 0; | |
608 | ||
609 | for (int l1 = 0; l1 < (k + m); l1++) { | |
610 | map<int, bufferlist> degraded = encoded; | |
611 | set<int> want_to_decode; | |
612 | bool err; | |
613 | degraded.erase(l1); | |
614 | want_to_decode.insert(l1); | |
615 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
616 | EXPECT_EQ(0, err); | |
617 | cnt_cf++; | |
618 | for (int l2 = l1 + 1; l2 < (k + m); l2++) { | |
619 | degraded.erase(l2); | |
620 | want_to_decode.insert(l2); | |
621 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
622 | EXPECT_EQ(0, err); | |
623 | cnt_cf++; | |
624 | for (int l3 = l2 + 1; l3 < (k + m); l3++) { | |
625 | degraded.erase(l3); | |
626 | want_to_decode.insert(l3); | |
627 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
628 | EXPECT_EQ(0, err); | |
629 | cnt_cf++; | |
630 | for (int l4 = l3 + 1; l4 < (k + m); l4++) { | |
631 | degraded.erase(l4); | |
632 | want_to_decode.insert(l4); | |
633 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
634 | EXPECT_EQ(0, err); | |
635 | degraded[l4] = encoded[l4]; | |
636 | want_to_decode.erase(l4); | |
637 | cnt_cf++; | |
638 | } | |
639 | degraded[l3] = encoded[l3]; | |
640 | want_to_decode.erase(l3); | |
641 | } | |
642 | degraded[l2] = encoded[l2]; | |
643 | want_to_decode.erase(l2); | |
644 | } | |
645 | degraded[l1] = encoded[l1]; | |
646 | want_to_decode.erase(l1); | |
647 | } | |
648 | EXPECT_EQ(2516, cnt_cf); | |
649 | EXPECT_EQ(2516, tcache.getDecodingTableCacheSize(ErasureCodeIsaDefault::kCauchy)); | |
650 | } | |
651 | ||
652 | TEST_F(IsaErasureCodeTest, isa_cauchy_cache_trash) | |
653 | { | |
654 | // Test all possible failure scenarios and reconstruction cases for | |
655 | // a (12,4) configuration using the cauchy matrix | |
656 | ErasureCodeIsaDefault Isa(tcache,ErasureCodeIsaDefault::kCauchy); | |
657 | ErasureCodeProfile profile; | |
658 | profile["k"] = "16"; | |
659 | profile["m"] = "4"; | |
660 | profile["technique"] = "cauchy"; | |
661 | ||
662 | Isa.init(profile, &cerr); | |
663 | ||
664 | const int k = 16; | |
665 | const int m = 4; | |
666 | ||
667 | #define LARGE_ENOUGH 2048 | |
668 | bufferptr in_ptr(buffer::create_page_aligned(LARGE_ENOUGH)); | |
669 | in_ptr.zero(); | |
670 | in_ptr.set_length(0); | |
671 | const char *payload = | |
672 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
673 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
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 | in_ptr.append(payload, strlen(payload)); | |
698 | bufferlist in; | |
699 | in.push_front(in_ptr); | |
700 | ||
701 | set<int>want_to_encode; | |
702 | ||
703 | map<int, bufferlist> encoded; | |
704 | for (int i = 0; i < (k + m); i++) { | |
705 | want_to_encode.insert(i); | |
706 | } | |
707 | ||
708 | ||
709 | EXPECT_EQ(0, Isa.encode(want_to_encode, | |
710 | in, | |
711 | &encoded)); | |
712 | ||
713 | EXPECT_EQ((unsigned) (k + m), encoded.size()); | |
714 | ||
715 | unsigned length = encoded[0].length(); | |
716 | ||
717 | for (int i = 0; i < k; i++) { | |
718 | EXPECT_EQ(0, memcmp(encoded[i].c_str(), in.c_str() + (i * length), length)); | |
719 | } | |
720 | ||
721 | buffer::ptr enc[k + m]; | |
722 | // create buffers with a copy of the original data to be able to compare it after decoding | |
723 | { | |
724 | for (int i = 0; i < (k + m); i++) { | |
725 | buffer::ptr newenc(buffer::create_page_aligned(LARGE_ENOUGH)); | |
726 | enc[i] = newenc; | |
727 | enc[i].zero(); | |
728 | enc[i].set_length(0); | |
729 | enc[i].append(encoded[i].c_str(), length); | |
730 | } | |
731 | } | |
732 | ||
733 | // loop through all possible loss scenarios | |
734 | int cnt_cf = 0; | |
735 | ||
736 | for (int l1 = 0; l1 < (k + m); l1++) { | |
737 | map<int, bufferlist> degraded = encoded; | |
738 | set<int> want_to_decode; | |
739 | bool err; | |
740 | degraded.erase(l1); | |
741 | want_to_decode.insert(l1); | |
742 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
743 | EXPECT_EQ(0, err); | |
744 | cnt_cf++; | |
745 | for (int l2 = l1 + 1; l2 < (k + m); l2++) { | |
746 | degraded.erase(l2); | |
747 | want_to_decode.insert(l2); | |
748 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
749 | EXPECT_EQ(0, err); | |
750 | cnt_cf++; | |
751 | for (int l3 = l2 + 1; l3 < (k + m); l3++) { | |
752 | degraded.erase(l3); | |
753 | want_to_decode.insert(l3); | |
754 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
755 | EXPECT_EQ(0, err); | |
756 | cnt_cf++; | |
757 | for (int l4 = l3 + 1; l4 < (k + m); l4++) { | |
758 | degraded.erase(l4); | |
759 | want_to_decode.insert(l4); | |
760 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
761 | EXPECT_EQ(0, err); | |
762 | degraded[l4] = encoded[l4]; | |
763 | want_to_decode.erase(l4); | |
764 | cnt_cf++; | |
765 | } | |
766 | degraded[l3] = encoded[l3]; | |
767 | want_to_decode.erase(l3); | |
768 | } | |
769 | degraded[l2] = encoded[l2]; | |
770 | want_to_decode.erase(l2); | |
771 | } | |
772 | degraded[l1] = encoded[l1]; | |
773 | want_to_decode.erase(l1); | |
774 | } | |
775 | EXPECT_EQ(6195, cnt_cf); | |
776 | EXPECT_EQ(2516, tcache.getDecodingTableCacheSize(ErasureCodeIsaDefault::kCauchy)); | |
777 | } | |
778 | ||
779 | TEST_F(IsaErasureCodeTest, isa_xor_codec) | |
780 | { | |
781 | // Test all possible failure scenarios and reconstruction cases for | |
782 | // a (4,1) RAID-5 like configuration | |
783 | ||
784 | ErasureCodeIsaDefault Isa(tcache); | |
785 | ErasureCodeProfile profile; | |
786 | profile["k"] = "4"; | |
787 | profile["m"] = "1"; | |
788 | Isa.init(profile, &cerr); | |
789 | ||
790 | const int k = 4; | |
791 | const int m = 1; | |
792 | ||
793 | #define LARGE_ENOUGH 2048 | |
794 | bufferptr in_ptr(buffer::create_page_aligned(LARGE_ENOUGH)); | |
795 | in_ptr.zero(); | |
796 | in_ptr.set_length(0); | |
797 | const char *payload = | |
798 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
799 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
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 | in_ptr.append(payload, strlen(payload)); | |
824 | bufferlist in; | |
825 | in.push_front(in_ptr); | |
826 | ||
827 | set<int>want_to_encode; | |
828 | ||
829 | map<int, bufferlist> encoded; | |
830 | for (int i = 0; i < (k + m); i++) { | |
831 | want_to_encode.insert(i); | |
832 | } | |
833 | ||
834 | ||
835 | EXPECT_EQ(0, Isa.encode(want_to_encode, | |
836 | in, | |
837 | &encoded)); | |
838 | ||
839 | EXPECT_EQ((unsigned) (k + m), encoded.size()); | |
840 | ||
841 | unsigned length = encoded[0].length(); | |
842 | ||
843 | for (int i = 0; i < k; i++) { | |
844 | EXPECT_EQ(0, memcmp(encoded[i].c_str(), in.c_str() + (i * length), length)); | |
845 | } | |
846 | ||
847 | buffer::ptr enc[k + m]; | |
848 | // create buffers with a copy of the original data to be able to compare it after decoding | |
849 | { | |
850 | for (int i = 0; i < (k + m); i++) { | |
851 | buffer::ptr newenc(buffer::create_page_aligned(LARGE_ENOUGH)); | |
852 | enc[i] = newenc; | |
853 | enc[i].zero(); | |
854 | enc[i].set_length(0); | |
855 | enc[i].append(encoded[i].c_str(), length); | |
856 | } | |
857 | } | |
858 | ||
859 | // loop through all possible loss scenarios | |
860 | int cnt_cf = 0; | |
861 | ||
862 | for (int l1 = 0; l1 < (k + m); l1++) { | |
863 | map<int, bufferlist> degraded = encoded; | |
864 | set<int> want_to_decode; | |
865 | bool err; | |
866 | degraded.erase(l1); | |
867 | want_to_decode.insert(l1); | |
868 | err = DecodeAndVerify(Isa, degraded, want_to_decode, enc, length); | |
869 | EXPECT_EQ(0, err); | |
870 | cnt_cf++; | |
871 | degraded[l1] = encoded[l1]; | |
872 | want_to_decode.erase(l1); | |
873 | } | |
874 | EXPECT_EQ(5, cnt_cf); | |
875 | } | |
876 | ||
224ce89b | 877 | TEST_F(IsaErasureCodeTest, create_rule) |
7c673cae FG |
878 | { |
879 | CrushWrapper *c = new CrushWrapper; | |
880 | c->create(); | |
881 | int root_type = 2; | |
882 | c->set_type_name(root_type, "root"); | |
883 | int host_type = 1; | |
884 | c->set_type_name(host_type, "host"); | |
885 | int osd_type = 0; | |
886 | c->set_type_name(osd_type, "osd"); | |
887 | ||
888 | int rootno; | |
889 | c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, | |
890 | root_type, 0, NULL, NULL, &rootno); | |
891 | c->set_item_name(rootno, "default"); | |
892 | ||
893 | map<string,string> loc; | |
894 | loc["root"] = "default"; | |
895 | ||
896 | int num_host = 4; | |
897 | int num_osd = 5; | |
898 | int osd = 0; | |
899 | for (int h=0; h<num_host; ++h) { | |
900 | loc["host"] = string("host-") + stringify(h); | |
901 | for (int o=0; o<num_osd; ++o, ++osd) { | |
902 | c->insert_item(g_ceph_context, osd, 1.0, string("osd.") + stringify(osd), loc); | |
903 | } | |
904 | } | |
905 | ||
906 | c->finalize(); | |
907 | ||
908 | { | |
909 | stringstream ss; | |
910 | ErasureCodeIsaDefault isa(tcache); | |
911 | ErasureCodeProfile profile; | |
912 | profile["k"] = "2"; | |
913 | profile["m"] = "2"; | |
914 | profile["w"] = "8"; | |
915 | isa.init(profile, &cerr); | |
224ce89b | 916 | int ruleset = isa.create_rule("myrule", *c, &ss); |
7c673cae | 917 | EXPECT_EQ(0, ruleset); |
224ce89b | 918 | EXPECT_EQ(-EEXIST, isa.create_rule("myrule", *c, &ss)); |
7c673cae FG |
919 | // |
920 | // the minimum that is expected from the created ruleset is to | |
921 | // successfully map get_chunk_count() devices from the crushmap, | |
922 | // at least once. | |
923 | // | |
924 | vector<__u32> weight(c->get_max_devices(), 0x10000); | |
925 | vector<int> out; | |
926 | int x = 0; | |
927 | c->do_rule(ruleset, x, out, isa.get_chunk_count(), weight, 0); | |
928 | ASSERT_EQ(out.size(), isa.get_chunk_count()); | |
929 | for (unsigned i=0; i<out.size(); ++i) | |
930 | ASSERT_NE(CRUSH_ITEM_NONE, out[i]); | |
931 | } | |
932 | { | |
933 | stringstream ss; | |
934 | ErasureCodeIsaDefault isa(tcache); | |
935 | ErasureCodeProfile profile; | |
936 | profile["k"] = "2"; | |
937 | profile["m"] = "2"; | |
938 | profile["w"] = "8"; | |
224ce89b | 939 | profile["crush-root"] = "BAD"; |
7c673cae | 940 | isa.init(profile, &cerr); |
224ce89b | 941 | EXPECT_EQ(-ENOENT, isa.create_rule("otherrule", *c, &ss)); |
7c673cae FG |
942 | EXPECT_EQ("root item BAD does not exist", ss.str()); |
943 | } | |
944 | { | |
945 | stringstream ss; | |
946 | ErasureCodeIsaDefault isa(tcache); | |
947 | ErasureCodeProfile profile; | |
948 | profile["k"] = "2"; | |
949 | profile["m"] = "2"; | |
950 | profile["w"] = "8"; | |
224ce89b | 951 | profile["crush-failure-domain"] = "WORSE"; |
7c673cae | 952 | isa.init(profile, &cerr); |
224ce89b | 953 | EXPECT_EQ(-EINVAL, isa.create_rule("otherrule", *c, &ss)); |
7c673cae FG |
954 | EXPECT_EQ("unknown type WORSE", ss.str()); |
955 | } | |
956 | } | |
957 | ||
958 | /* | |
959 | * Local Variables: | |
960 | * compile-command: "cd ../.. ; make -j4 unittest_erasure_code_isa && | |
961 | * libtool --mode=execute valgrind --tool=memcheck \ | |
962 | * ./unittest_erasure_code_isa \ | |
963 | * --gtest_filter=*.* --log-to-stderr=true --debug-osd=20" | |
964 | * End: | |
965 | */ |