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 Red Hat <contact@redhat.com>
8 * Author: Loic Dachary <loic@dachary.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
20 #include "erasure-code/ErasureCode.h"
21 #include "global/global_context.h"
22 #include "common/config.h"
23 #include "gtest/gtest.h"
27 class ErasureCodeTest
: public ErasureCode
{
29 map
<int, bufferlist
> encode_chunks_encoded
;
32 unsigned int chunk_size
;
34 ErasureCodeTest(unsigned int _k
, unsigned int _m
, unsigned int _chunk_size
) :
35 k(_k
), m(_m
), chunk_size(_chunk_size
) {}
36 ~ErasureCodeTest() override
{}
38 int init(ErasureCodeProfile
&profile
, ostream
*ss
) override
{
42 unsigned int get_chunk_count() const override
{ return k
+ m
; }
43 unsigned int get_data_chunk_count() const override
{ return k
; }
44 unsigned int get_chunk_size(unsigned int object_size
) const override
{
47 int encode_chunks(const set
<int> &want_to_encode
,
48 map
<int, bufferlist
> *encoded
) override
{
49 encode_chunks_encoded
= *encoded
;
52 int decode_chunks(const set
<int> &want_to_read
,
53 const map
<int, bufferlist
> &chunks
,
54 map
<int, bufferlist
> *decoded
) override
{
55 ceph_abort_msg("ErasureCode::decode_chunks not implemented");
58 int create_rule(const string
&name
,
60 ostream
*ss
) const override
{ return 0; }
64 * If we have a buffer of 5 bytes (X below) and a chunk size of 3
65 * bytes, for k=3, m=1 an additional 7 bytes (P and C below) will
66 * need to be allocated for padding (P) and the 3 coding bytes (C).
68 * X -+ +----------+ +-X
70 * X | +----------+ | X
71 * X | +----------+ | X -> +-X
72 * X -+ | data 1 | +-X -> | X
73 * P -+ +----------+ | P
74 * P | +----------+ | P
76 * P | +----------+ | P
77 * C | +----------+ | C
78 * C | | coding 3 | | C
79 * C -+ +----------+ +-C
81 * The data chunks 1 and 2 (data 1 and data 2 above) overflow the
82 * original buffer because it needs padding. A new buffer will
83 * be allocated to contain the chunk that overflows and all other
84 * chunks after it, including the coding chunk(s).
86 * The following test creates a siguation where the buffer provided
87 * for encoding is not memory aligned. After encoding it asserts that:
89 * a) each chunk is SIMD aligned
90 * b) the data 1 chunk content is as expected which implies that its
91 * content has been copied over.
93 * It is possible for a flawed implementation to pas the test because the
94 * underlying allocation function enforces it.
96 TEST(ErasureCodeTest
, encode_memory_align
)
100 unsigned chunk_size
= ErasureCode::SIMD_ALIGN
* 7;
101 ErasureCodeTest
erasure_code(k
, m
, chunk_size
);
103 set
<int> want_to_encode
;
104 for (unsigned int i
= 0; i
< erasure_code
.get_chunk_count(); i
++)
105 want_to_encode
.insert(i
);
106 string
data(chunk_size
+ chunk_size
/ 2, 'X'); // uses 1.5 chunks out of 3
107 // make sure nothing is memory aligned
108 bufferptr
ptr(buffer::create_aligned(data
.length() + 1, ErasureCode::SIMD_ALIGN
));
109 ptr
.copy_in(1, data
.length(), data
.c_str());
111 ptr
.set_length(data
.length());
114 map
<int, bufferlist
> encoded
;
116 ASSERT_FALSE(in
.is_aligned(ErasureCode::SIMD_ALIGN
));
117 ASSERT_EQ(0, erasure_code
.encode(want_to_encode
, in
, &encoded
));
118 for (unsigned int i
= 0; i
< erasure_code
.get_chunk_count(); i
++)
119 ASSERT_TRUE(encoded
[i
].is_aligned(ErasureCode::SIMD_ALIGN
));
120 for (unsigned i
= 0; i
< chunk_size
/ 2; i
++)
121 ASSERT_EQ(encoded
[1][i
], 'X');
122 ASSERT_NE(encoded
[1][chunk_size
/ 2], 'X');
125 TEST(ErasureCodeTest
, encode_misaligned_non_contiguous
)
129 unsigned chunk_size
= ErasureCode::SIMD_ALIGN
* 7;
130 ErasureCodeTest
erasure_code(k
, m
, chunk_size
);
132 set
<int> want_to_encode
;
133 for (unsigned int i
= 0; i
< erasure_code
.get_chunk_count(); i
++)
134 want_to_encode
.insert(i
);
135 string
data(chunk_size
, 'X');
136 // create a non contiguous bufferlist where the frist and the second
137 // bufferptr are not size aligned although they are memory aligned
140 bufferptr
ptr(buffer::create_aligned(data
.length() - 1, ErasureCode::SIMD_ALIGN
));
144 bufferptr
ptr(buffer::create_aligned(data
.length() + 1, ErasureCode::SIMD_ALIGN
));
147 map
<int, bufferlist
> encoded
;
149 ASSERT_FALSE(in
.is_contiguous());
150 ASSERT_TRUE(in
.front().is_aligned(ErasureCode::SIMD_ALIGN
));
151 ASSERT_FALSE(in
.front().is_n_align_sized(chunk_size
));
152 ASSERT_TRUE(in
.back().is_aligned(ErasureCode::SIMD_ALIGN
));
153 ASSERT_FALSE(in
.back().is_n_align_sized(chunk_size
));
154 ASSERT_EQ(0, erasure_code
.encode(want_to_encode
, in
, &encoded
));
155 for (unsigned int i
= 0; i
< erasure_code
.get_chunk_count(); i
++) {
156 ASSERT_TRUE(encoded
[i
].is_aligned(ErasureCode::SIMD_ALIGN
));
157 ASSERT_TRUE(encoded
[i
].is_n_align_sized(chunk_size
));
163 * compile-command: "cd ../.. ;
164 * make -j4 unittest_erasure_code &&
165 * valgrind --tool=memcheck --leak-check=full \
166 * ./unittest_erasure_code \
167 * --gtest_filter=*.* --log-to-stderr=true"