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"
25 class ErasureCodeTest : public ErasureCode {
27 map<int, bufferlist> encode_chunks_encoded;
30 unsigned int chunk_size;
32 ErasureCodeTest(unsigned int _k, unsigned int _m, unsigned int _chunk_size) :
33 k(_k), m(_m), chunk_size(_chunk_size) {}
34 ~ErasureCodeTest() override {}
36 int init(ErasureCodeProfile &profile, ostream *ss) override {
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 {
45 int encode_chunks(const set<int> &want_to_encode,
46 map<int, bufferlist> *encoded) override {
47 encode_chunks_encoded = *encoded;
50 int create_rule(const string &name,
52 ostream *ss) const override { return 0; }
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).
60 * X -+ +----------+ +-X
62 * X | +----------+ | X
63 * X | +----------+ | X -> +-X
64 * X -+ | data 1 | +-X -> | X
65 * P -+ +----------+ | P
66 * P | +----------+ | P
68 * P | +----------+ | P
69 * C | +----------+ | C
70 * C | | coding 3 | | C
71 * C -+ +----------+ +-C
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).
78 * The following test creates a siguation where the buffer provided
79 * for encoding is not memory aligned. After encoding it asserts that:
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.
85 * It is possible for a flawed implementation to pas the test because the
86 * underlying allocation function enforces it.
88 TEST(ErasureCodeTest, encode_memory_align)
92 unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7;
93 ErasureCodeTest erasure_code(k, m, chunk_size);
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());
103 ptr.set_length(data.length());
106 map<int, bufferlist> encoded;
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');
117 TEST(ErasureCodeTest, encode_misaligned_non_contiguous)
121 unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7;
122 ErasureCodeTest erasure_code(k, m, chunk_size);
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
132 bufferptr ptr(buffer::create_aligned(data.length() - 1, ErasureCode::SIMD_ALIGN));
136 bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN));
139 map<int, bufferlist> encoded;
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));
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"