]>
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 | } | |
50 | int create_ruleset(const string &name, | |
51 | CrushWrapper &crush, | |
52 | ostream *ss) const override { return 0; } | |
53 | ||
54 | }; | |
55 | ||
56 | /* | |
57 | * If we have a buffer of 5 bytes (X below) and a chunk size of 3 | |
58 | * bytes, for k=3, m=1 an additional 7 bytes (P and C below) will | |
59 | * need to be allocated for padding (P) and the 3 coding bytes (C). | |
60 | * | |
61 | * X -+ +----------+ +-X | |
62 | * X | | data 0 | | X | |
63 | * X | +----------+ | X | |
64 | * X | +----------+ | X -> +-X | |
65 | * X -+ | data 1 | +-X -> | X | |
66 | * P -+ +----------+ | P | |
67 | * P | +----------+ | P | |
68 | * P | | data 2 | | P | |
69 | * P | +----------+ | P | |
70 | * C | +----------+ | C | |
71 | * C | | coding 3 | | C | |
72 | * C -+ +----------+ +-C | |
73 | * | |
74 | * The data chunks 1 and 2 (data 1 and data 2 above) overflow the | |
75 | * original buffer because it needs padding. A new buffer will | |
76 | * be allocated to contain the chunk that overflows and all other | |
77 | * chunks after it, including the coding chunk(s). | |
78 | * | |
79 | * The following test creates a siguation where the buffer provided | |
80 | * for encoding is not memory aligned. After encoding it asserts that: | |
81 | * | |
82 | * a) each chunk is SIMD aligned | |
83 | * b) the data 1 chunk content is as expected which implies that its | |
84 | * content has been copied over. | |
85 | * | |
86 | * It is possible for a flawed implementation to pas the test because the | |
87 | * underlying allocation function enforces it. | |
88 | */ | |
89 | TEST(ErasureCodeTest, encode_memory_align) | |
90 | { | |
91 | int k = 3; | |
92 | int m = 1; | |
93 | unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7; | |
94 | ErasureCodeTest erasure_code(k, m, chunk_size); | |
95 | ||
96 | set<int> want_to_encode; | |
97 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
98 | want_to_encode.insert(i); | |
99 | string data(chunk_size + chunk_size / 2, 'X'); // uses 1.5 chunks out of 3 | |
100 | // make sure nothing is memory aligned | |
101 | bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN)); | |
102 | ptr.copy_in(1, data.length(), data.c_str()); | |
103 | ptr.set_offset(1); | |
104 | ptr.set_length(data.length()); | |
105 | bufferlist in; | |
106 | in.append(ptr); | |
107 | map<int, bufferlist> encoded; | |
108 | ||
109 | ASSERT_FALSE(in.is_aligned(ErasureCode::SIMD_ALIGN)); | |
110 | ASSERT_EQ(0, erasure_code.encode(want_to_encode, in, &encoded)); | |
111 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
112 | ASSERT_TRUE(encoded[i].is_aligned(ErasureCode::SIMD_ALIGN)); | |
113 | for (unsigned i = 0; i < chunk_size / 2; i++) | |
114 | ASSERT_EQ(encoded[1][i], 'X'); | |
115 | ASSERT_NE(encoded[1][chunk_size / 2], 'X'); | |
116 | } | |
117 | ||
118 | TEST(ErasureCodeTest, encode_misaligned_non_contiguous) | |
119 | { | |
120 | int k = 3; | |
121 | int m = 1; | |
122 | unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7; | |
123 | ErasureCodeTest erasure_code(k, m, chunk_size); | |
124 | ||
125 | set<int> want_to_encode; | |
126 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) | |
127 | want_to_encode.insert(i); | |
128 | string data(chunk_size, 'X'); | |
129 | // create a non contiguous bufferlist where the frist and the second | |
130 | // bufferptr are not size aligned although they are memory aligned | |
131 | bufferlist in; | |
132 | { | |
133 | bufferptr ptr(buffer::create_aligned(data.length() - 1, ErasureCode::SIMD_ALIGN)); | |
134 | in.append(ptr); | |
135 | } | |
136 | { | |
137 | bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN)); | |
138 | in.append(ptr); | |
139 | } | |
140 | map<int, bufferlist> encoded; | |
141 | ||
142 | ASSERT_FALSE(in.is_contiguous()); | |
143 | ASSERT_TRUE(in.front().is_aligned(ErasureCode::SIMD_ALIGN)); | |
144 | ASSERT_FALSE(in.front().is_n_align_sized(chunk_size)); | |
145 | ASSERT_TRUE(in.back().is_aligned(ErasureCode::SIMD_ALIGN)); | |
146 | ASSERT_FALSE(in.back().is_n_align_sized(chunk_size)); | |
147 | ASSERT_EQ(0, erasure_code.encode(want_to_encode, in, &encoded)); | |
148 | for (unsigned int i = 0; i < erasure_code.get_chunk_count(); i++) { | |
149 | ASSERT_TRUE(encoded[i].is_aligned(ErasureCode::SIMD_ALIGN)); | |
150 | ASSERT_TRUE(encoded[i].is_n_align_sized(chunk_size)); | |
151 | } | |
152 | } | |
153 | ||
154 | /* | |
155 | * Local Variables: | |
156 | * compile-command: "cd ../.. ; | |
157 | * make -j4 unittest_erasure_code && | |
158 | * valgrind --tool=memcheck --leak-check=full \ | |
159 | * ./unittest_erasure_code \ | |
160 | * --gtest_filter=*.* --log-to-stderr=true" | |
161 | * End: | |
162 | */ |