]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph distributed storage system | |
5 | * | |
6 | * Copyright (C) 2014 Red Hat <contact@redhat.com> | |
7 | * | |
8 | * Author: Loic Dachary <loic@dachary.org> | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <errno.h> | |
18 | #include <stdlib.h> | |
19 | ||
20 | #include "erasure-code/ErasureCode.h" | |
21 | #include "global/global_context.h" | |
22 | #include "common/config.h" | |
23 | #include "gtest/gtest.h" | |
24 | ||
25 | class ErasureCodeTest : public ErasureCode { | |
26 | public: | |
27 | map<int, bufferlist> encode_chunks_encoded; | |
28 | unsigned int k; | |
29 | unsigned int m; | |
30 | unsigned int chunk_size; | |
31 | ||
32 | ErasureCodeTest(unsigned int _k, unsigned int _m, unsigned int _chunk_size) : | |
33 | k(_k), m(_m), chunk_size(_chunk_size) {} | |
34 | ~ErasureCodeTest() override {} | |
35 | ||
36 | int init(ErasureCodeProfile &profile, ostream *ss) override { | |
37 | return 0; | |
38 | } | |
39 | ||
40 | unsigned int get_chunk_count() const override { return k + m; } | |
41 | unsigned int get_data_chunk_count() const override { return k; } | |
42 | unsigned int get_chunk_size(unsigned int object_size) const override { | |
43 | return chunk_size; | |
44 | } | |
45 | int encode_chunks(const set<int> &want_to_encode, | |
46 | map<int, bufferlist> *encoded) override { | |
47 | encode_chunks_encoded = *encoded; | |
48 | return 0; | |
49 | } | |
224ce89b WB |
50 | int create_rule(const string &name, |
51 | CrushWrapper &crush, | |
52 | ostream *ss) const override { return 0; } | |
7c673cae FG |
53 | }; |
54 | ||
55 | /* | |
56 | * If we have a buffer of 5 bytes (X below) and a chunk size of 3 | |
57 | * bytes, for k=3, m=1 an additional 7 bytes (P and C below) will | |
58 | * need to be allocated for padding (P) and the 3 coding bytes (C). | |
59 | * | |
60 | * X -+ +----------+ +-X | |
61 | * X | | data 0 | | X | |
62 | * X | +----------+ | X | |
63 | * X | +----------+ | X -> +-X | |
64 | * X -+ | data 1 | +-X -> | X | |
65 | * P -+ +----------+ | P | |
66 | * P | +----------+ | P | |
67 | * P | | data 2 | | P | |
68 | * P | +----------+ | P | |
69 | * C | +----------+ | C | |
70 | * C | | coding 3 | | C | |
71 | * C -+ +----------+ +-C | |
72 | * | |
73 | * The data chunks 1 and 2 (data 1 and data 2 above) overflow the | |
74 | * original buffer because it needs padding. A new buffer will | |
75 | * be allocated to contain the chunk that overflows and all other | |
76 | * chunks after it, including the coding chunk(s). | |
77 | * | |
78 | * The following test creates a siguation where the buffer provided | |
79 | * for encoding is not memory aligned. After encoding it asserts that: | |
80 | * | |
81 | * a) each chunk is SIMD aligned | |
82 | * b) the data 1 chunk content is as expected which implies that its | |
83 | * content has been copied over. | |
84 | * | |
85 | * It is possible for a flawed implementation to pas the test because the | |
86 | * underlying allocation function enforces it. | |
87 | */ | |
88 | TEST(ErasureCodeTest, encode_memory_align) | |
89 | { | |
90 | int k = 3; | |
91 | int m = 1; | |
92 | unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7; | |
93 | ErasureCodeTest erasure_code(k, m, chunk_size); | |
94 | ||
95 | set<int> want_to_encode; | |
96 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
97 | want_to_encode.insert(i); | |
98 | string data(chunk_size + chunk_size / 2, 'X'); // uses 1.5 chunks out of 3 | |
99 | // make sure nothing is memory aligned | |
100 | bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN)); | |
101 | ptr.copy_in(1, data.length(), data.c_str()); | |
102 | ptr.set_offset(1); | |
103 | ptr.set_length(data.length()); | |
104 | bufferlist in; | |
105 | in.append(ptr); | |
106 | map<int, bufferlist> encoded; | |
107 | ||
108 | ASSERT_FALSE(in.is_aligned(ErasureCode::SIMD_ALIGN)); | |
109 | ASSERT_EQ(0, erasure_code.encode(want_to_encode, in, &encoded)); | |
110 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
111 | ASSERT_TRUE(encoded[i].is_aligned(ErasureCode::SIMD_ALIGN)); | |
112 | for (unsigned i = 0; i < chunk_size / 2; i++) | |
113 | ASSERT_EQ(encoded[1][i], 'X'); | |
114 | ASSERT_NE(encoded[1][chunk_size / 2], 'X'); | |
115 | } | |
116 | ||
117 | TEST(ErasureCodeTest, encode_misaligned_non_contiguous) | |
118 | { | |
119 | int k = 3; | |
120 | int m = 1; | |
121 | unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7; | |
122 | ErasureCodeTest erasure_code(k, m, chunk_size); | |
123 | ||
124 | set<int> want_to_encode; | |
125 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
126 | want_to_encode.insert(i); | |
127 | string data(chunk_size, 'X'); | |
128 | // create a non contiguous bufferlist where the frist and the second | |
129 | // bufferptr are not size aligned although they are memory aligned | |
130 | bufferlist in; | |
131 | { | |
132 | bufferptr ptr(buffer::create_aligned(data.length() - 1, ErasureCode::SIMD_ALIGN)); | |
133 | in.append(ptr); | |
134 | } | |
135 | { | |
136 | bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN)); | |
137 | in.append(ptr); | |
138 | } | |
139 | map<int, bufferlist> encoded; | |
140 | ||
141 | ASSERT_FALSE(in.is_contiguous()); | |
142 | ASSERT_TRUE(in.front().is_aligned(ErasureCode::SIMD_ALIGN)); | |
143 | ASSERT_FALSE(in.front().is_n_align_sized(chunk_size)); | |
144 | ASSERT_TRUE(in.back().is_aligned(ErasureCode::SIMD_ALIGN)); | |
145 | ASSERT_FALSE(in.back().is_n_align_sized(chunk_size)); | |
146 | ASSERT_EQ(0, erasure_code.encode(want_to_encode, in, &encoded)); | |
147 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) { | |
148 | ASSERT_TRUE(encoded[i].is_aligned(ErasureCode::SIMD_ALIGN)); | |
149 | ASSERT_TRUE(encoded[i].is_n_align_sized(chunk_size)); | |
150 | } | |
151 | } | |
152 | ||
153 | /* | |
154 | * Local Variables: | |
155 | * compile-command: "cd ../.. ; | |
156 | * make -j4 unittest_erasure_code && | |
157 | * valgrind --tool=memcheck --leak-check=full \ | |
158 | * ./unittest_erasure_code \ | |
159 | * --gtest_filter=*.* --log-to-stderr=true" | |
160 | * End: | |
161 | */ |