]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_bit_vector.cc
update sources to 12.2.2
[ceph.git] / ceph / src / test / common / test_bit_vector.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 - scalable distributed file system
5 *
6 * Copyright (C) 2014 Red Hat <contact@redhat.com>
7 *
8 * LGPL2.1 (see COPYING-LGPL2.1) or later
9 */
10
11 #include <gtest/gtest.h>
12 #include <cmath>
13 #include "common/bit_vector.hpp"
14 #include <boost/assign/list_of.hpp>
15
16 using namespace ceph;
17
18 template <uint8_t _bit_count>
19 class TestParams {
20 public:
21 static const uint8_t BIT_COUNT = _bit_count;
22 };
23
24 template <typename T>
25 class BitVectorTest : public ::testing::Test {
26 public:
27 typedef BitVector<T::BIT_COUNT> bit_vector_t;
28 };
29
30 typedef ::testing::Types<TestParams<2> > BitVectorTypes;
31 TYPED_TEST_CASE(BitVectorTest, BitVectorTypes);
32
33 TYPED_TEST(BitVectorTest, resize) {
34 typename TestFixture::bit_vector_t bit_vector;
35
36 size_t size = 2357;
37
38 double elements_per_byte = 8 / bit_vector.BIT_COUNT;
39
40 bit_vector.resize(size);
41 ASSERT_EQ(bit_vector.size(), size);
42 ASSERT_EQ(bit_vector.get_data().length(), static_cast<uint64_t>(std::ceil(
43 size / elements_per_byte)));
44 }
45
46 TYPED_TEST(BitVectorTest, clear) {
47 typename TestFixture::bit_vector_t bit_vector;
48
49 bit_vector.resize(123);
50 bit_vector.clear();
51 ASSERT_EQ(0ull, bit_vector.size());
52 ASSERT_EQ(0ull, bit_vector.get_data().length());
53 }
54
55 TYPED_TEST(BitVectorTest, bit_order) {
56 typename TestFixture::bit_vector_t bit_vector;
57 bit_vector.resize(1);
58
59 uint8_t value = 1;
60 bit_vector[0] = value;
61
62 value <<= (8 - bit_vector.BIT_COUNT);
63 ASSERT_EQ(value, bit_vector.get_data()[0]);
64 }
65
66 TYPED_TEST(BitVectorTest, get_set) {
67 typename TestFixture::bit_vector_t bit_vector;
68 std::vector<uint64_t> ref;
69
70 uint64_t radix = 1 << bit_vector.BIT_COUNT;
71
72 size_t size = 1024;
73 bit_vector.resize(size);
74 ref.resize(size);
75 for (size_t i = 0; i < size; ++i) {
76 uint64_t v = rand() % radix;
77 ref[i] = v;
78 bit_vector[i] = v;
79 }
80
81 const typename TestFixture::bit_vector_t &const_bit_vector(bit_vector);
82 for (size_t i = 0; i < size; ++i) {
83 ASSERT_EQ(ref[i], bit_vector[i]);
84 ASSERT_EQ(ref[i], const_bit_vector[i]);
85 }
86 }
87
88 TYPED_TEST(BitVectorTest, get_buffer_extents) {
89 typename TestFixture::bit_vector_t bit_vector;
90
91 uint64_t element_count = 2 * bit_vector.BLOCK_SIZE + 51;
92 uint64_t elements_per_byte = 8 / bit_vector.BIT_COUNT;
93 bit_vector.resize(element_count * elements_per_byte);
94
95 uint64_t offset = (bit_vector.BLOCK_SIZE + 11) * elements_per_byte;
96 uint64_t length = (bit_vector.BLOCK_SIZE + 31) * elements_per_byte;
97 uint64_t byte_offset;
98 uint64_t byte_length;
99 bit_vector.get_data_extents(offset, length, &byte_offset, &byte_length);
100 ASSERT_EQ(bit_vector.BLOCK_SIZE, byte_offset);
101 ASSERT_EQ(bit_vector.BLOCK_SIZE + (element_count % bit_vector.BLOCK_SIZE),
102 byte_length);
103
104 bit_vector.get_data_extents(1, 1, &byte_offset, &byte_length);
105 ASSERT_EQ(0U, byte_offset);
106 ASSERT_EQ(bit_vector.BLOCK_SIZE, byte_length);
107 }
108
109 TYPED_TEST(BitVectorTest, get_header_length) {
110 typename TestFixture::bit_vector_t bit_vector;
111
112 bufferlist bl;
113 bit_vector.encode_header(bl);
114 ASSERT_EQ(bl.length(), bit_vector.get_header_length());
115 }
116
117 TYPED_TEST(BitVectorTest, get_footer_offset) {
118 typename TestFixture::bit_vector_t bit_vector;
119
120 bit_vector.resize(5111);
121
122 uint64_t byte_offset;
123 uint64_t byte_length;
124 bit_vector.get_data_extents(0, bit_vector.size(), &byte_offset, &byte_length);
125
126 ASSERT_EQ(bit_vector.get_header_length() + byte_length,
127 bit_vector.get_footer_offset());
128 }
129
130 TYPED_TEST(BitVectorTest, partial_decode_encode) {
131 typename TestFixture::bit_vector_t bit_vector;
132
133 uint64_t elements_per_byte = 8 / bit_vector.BIT_COUNT;
134 bit_vector.resize(9161 * elements_per_byte);
135 for (uint64_t i = 0; i < bit_vector.size(); ++i) {
136 bit_vector[i] = i % 4;
137 }
138
139 bufferlist bl;
140 ::encode(bit_vector, bl);
141 bit_vector.clear();
142
143 bufferlist header_bl;
144 header_bl.substr_of(bl, 0, bit_vector.get_header_length());
145 bufferlist::iterator header_it = header_bl.begin();
146 bit_vector.decode_header(header_it);
147
148 bufferlist footer_bl;
149 footer_bl.substr_of(bl, bit_vector.get_footer_offset(),
150 bl.length() - bit_vector.get_footer_offset());
151 bufferlist::iterator footer_it = footer_bl.begin();
152 bit_vector.decode_footer(footer_it);
153
154 typedef std::pair<uint64_t, uint64_t> Extent;
155 typedef std::list<Extent> Extents;
156
157 Extents extents = boost::assign::list_of(
158 std::make_pair(0, 1))(
159 std::make_pair((bit_vector.BLOCK_SIZE * elements_per_byte) - 2, 4))(
160 std::make_pair((bit_vector.BLOCK_SIZE * elements_per_byte) + 2, 2))(
161 std::make_pair((2 * bit_vector.BLOCK_SIZE * elements_per_byte) - 2, 4))(
162 std::make_pair((2 * bit_vector.BLOCK_SIZE * elements_per_byte) + 2, 2))(
163 std::make_pair(2, 2 * bit_vector.BLOCK_SIZE));
164 for (Extents::iterator it = extents.begin(); it != extents.end(); ++it) {
165 uint64_t element_offset = it->first;
166 uint64_t element_length = it->second;
167 uint64_t byte_offset;
168 uint64_t byte_length;
169 bit_vector.get_data_extents(element_offset, element_length, &byte_offset,
170 &byte_length);
171
172 bufferlist data_bl;
173 data_bl.substr_of(bl, bit_vector.get_header_length() + byte_offset,
174 byte_length);
175 bufferlist::iterator data_it = data_bl.begin();
176 bit_vector.decode_data(data_it, byte_offset);
177
178 data_bl.clear();
179 bit_vector.encode_data(data_bl, byte_offset, byte_length);
180
181 footer_bl.clear();
182 bit_vector.encode_footer(footer_bl);
183
184 bufferlist updated_bl;
185 updated_bl.substr_of(bl, 0, bit_vector.get_header_length() + byte_offset);
186 updated_bl.append(data_bl);
187
188 if (byte_offset + byte_length < bit_vector.get_footer_offset()) {
189 uint64_t tail_data_offset = bit_vector.get_header_length() + byte_offset +
190 byte_length;
191 data_bl.substr_of(bl, tail_data_offset,
192 bit_vector.get_footer_offset() - tail_data_offset);
193 updated_bl.append(data_bl);
194 }
195
196 updated_bl.append(footer_bl);
197 ASSERT_EQ(bl, updated_bl);
198
199 bufferlist::iterator updated_it = updated_bl.begin();
200 ::decode(bit_vector, updated_it);
201 }
202 }
203
204 TYPED_TEST(BitVectorTest, header_crc) {
205 typename TestFixture::bit_vector_t bit_vector;
206
207 bufferlist header;
208 bit_vector.encode_header(header);
209
210 bufferlist footer;
211 bit_vector.encode_footer(footer);
212
213 bufferlist::iterator it = footer.begin();
214 bit_vector.decode_footer(it);
215
216 bit_vector.resize(1);
217 bit_vector.encode_header(header);
218
219 it = footer.begin();
220 ASSERT_THROW(bit_vector.decode_footer(it), buffer::malformed_input);
221 }
222
223 TYPED_TEST(BitVectorTest, data_crc) {
224 typename TestFixture::bit_vector_t bit_vector1;
225 typename TestFixture::bit_vector_t bit_vector2;
226
227 uint64_t elements_per_byte = 8 / bit_vector1.BIT_COUNT;
228 bit_vector1.resize((bit_vector1.BLOCK_SIZE + 1) * elements_per_byte);
229 bit_vector2.resize((bit_vector2.BLOCK_SIZE + 1) * elements_per_byte);
230
231 uint64_t byte_offset;
232 uint64_t byte_length;
233 bit_vector1.get_data_extents(0, bit_vector1.size(), &byte_offset,
234 &byte_length);
235
236 bufferlist data;
237 bit_vector1.encode_data(data, byte_offset, byte_length);
238
239 bufferlist::iterator data_it = data.begin();
240 bit_vector1.decode_data(data_it, byte_offset);
241
242 bit_vector2[bit_vector2.size() - 1] = 1;
243
244 bufferlist dummy_data;
245 bit_vector2.encode_data(dummy_data, byte_offset, byte_length);
246
247 data_it = data.begin();
248 ASSERT_THROW(bit_vector2.decode_data(data_it, byte_offset),
249 buffer::malformed_input);
250 }
251
252 TYPED_TEST(BitVectorTest, iterator) {
253 typename TestFixture::bit_vector_t bit_vector;
254
255 uint64_t radix = 1 << bit_vector.BIT_COUNT;
256 uint64_t size = 25 * (1ULL << 20);
257 uint64_t offset = 0;
258
259 // create fragmented in-memory bufferlist layout
260 uint64_t resize = 0;
261 while (resize < size) {
262 resize += 4096;
263 if (resize > size) {
264 resize = size;
265 }
266 bit_vector.resize(resize);
267 }
268
269 for (auto it = bit_vector.begin(); it != bit_vector.end(); ++it, ++offset) {
270 *it = offset % radix;
271 }
272
273 offset = 123;
274 auto end_it = bit_vector.begin() + (size - 1024);
275 for (auto it = bit_vector.begin() + offset; it != end_it; ++it, ++offset) {
276 ASSERT_EQ(offset % radix, *it);
277 }
278 }