]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/erasure-code/TestErasureCode.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / erasure-code / TestErasureCode.cc
CommitLineData
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
20effc67
TL
25using namespace std;
26
7c673cae
FG
27class ErasureCodeTest : public ErasureCode {
28public:
29 map<int, bufferlist> encode_chunks_encoded;
30 unsigned int k;
31 unsigned int m;
32 unsigned int chunk_size;
33
34 ErasureCodeTest(unsigned int _k, unsigned int _m, unsigned int _chunk_size) :
35 k(_k), m(_m), chunk_size(_chunk_size) {}
36 ~ErasureCodeTest() override {}
37
38 int init(ErasureCodeProfile &profile, ostream *ss) override {
39 return 0;
40 }
41
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 {
45 return chunk_size;
46 }
47 int encode_chunks(const set<int> &want_to_encode,
48 map<int, bufferlist> *encoded) override {
49 encode_chunks_encoded = *encoded;
50 return 0;
51 }
f67539c2
TL
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");
56 }
57
224ce89b
WB
58 int create_rule(const string &name,
59 CrushWrapper &crush,
60 ostream *ss) const override { return 0; }
7c673cae
FG
61};
62
63/*
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).
67 *
68 * X -+ +----------+ +-X
69 * X | | data 0 | | X
70 * X | +----------+ | X
71 * X | +----------+ | X -> +-X
72 * X -+ | data 1 | +-X -> | X
73 * P -+ +----------+ | P
74 * P | +----------+ | P
75 * P | | data 2 | | P
76 * P | +----------+ | P
77 * C | +----------+ | C
78 * C | | coding 3 | | C
79 * C -+ +----------+ +-C
80 *
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).
85 *
86 * The following test creates a siguation where the buffer provided
87 * for encoding is not memory aligned. After encoding it asserts that:
88 *
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.
92 *
93 * It is possible for a flawed implementation to pas the test because the
94 * underlying allocation function enforces it.
95 */
96TEST(ErasureCodeTest, encode_memory_align)
97{
98 int k = 3;
99 int m = 1;
100 unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7;
101 ErasureCodeTest erasure_code(k, m, chunk_size);
102
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());
110 ptr.set_offset(1);
111 ptr.set_length(data.length());
112 bufferlist in;
113 in.append(ptr);
114 map<int, bufferlist> encoded;
115
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');
123}
124
125TEST(ErasureCodeTest, encode_misaligned_non_contiguous)
126{
127 int k = 3;
128 int m = 1;
129 unsigned chunk_size = ErasureCode::SIMD_ALIGN * 7;
130 ErasureCodeTest erasure_code(k, m, chunk_size);
131
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
138 bufferlist in;
139 {
140 bufferptr ptr(buffer::create_aligned(data.length() - 1, ErasureCode::SIMD_ALIGN));
141 in.append(ptr);
142 }
143 {
144 bufferptr ptr(buffer::create_aligned(data.length() + 1, ErasureCode::SIMD_ALIGN));
145 in.append(ptr);
146 }
147 map<int, bufferlist> encoded;
148
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));
158 }
159}
160
161/*
162 * Local Variables:
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"
168 * End:
169 */