Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / erasure-code / TestErasureCode.cc
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_rule(const string &name,
51                   CrushWrapper &crush,
52                   ostream *ss) const override { return 0; }
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  */