]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/libradosstriper/striping.cc
update sources to v12.1.1
[ceph.git] / ceph / src / test / libradosstriper / striping.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
31f18b77 4#include "include/compat.h"
7c673cae
FG
5#include "include/types.h"
6#include "include/rados/librados.h"
7#include "include/rados/librados.hpp"
8#include "include/radosstriper/libradosstriper.h"
9#include "include/radosstriper/libradosstriper.hpp"
10#include "include/ceph_fs.h"
224ce89b 11#include "common/backport14.h"
7c673cae
FG
12#include "test/librados/test.h"
13#include "test/libradosstriper/TestCase.h"
14
15#include <string>
16#include <errno.h>
17using namespace librados;
18using namespace libradosstriper;
19
20class StriperTestRT : public StriperTestParam {
21public:
22 StriperTestRT() : StriperTestParam() {}
23protected:
24 char* getObjName(const std::string& soid, uint64_t nb)
25 {
26 char name[soid.size()+18];
27 sprintf(name, "%s.%016llx", soid.c_str(), (long long unsigned int)nb);
28 return strdup(name);
29 }
30
31 void checkObjectFromRados(const std::string& soid, bufferlist &bl,
32 uint64_t exp_stripe_unit, uint64_t exp_stripe_count,
33 uint64_t exp_object_size, size_t size)
34 {
35 checkObjectFromRados(soid, bl, exp_stripe_unit, exp_stripe_count, exp_object_size, size, size);
36 }
37
38 void checkObjectFromRados(const std::string& soid, bufferlist &bl,
39 uint64_t exp_stripe_unit, uint64_t exp_stripe_count,
40 uint64_t exp_object_size, size_t size,
41 size_t actual_size_if_sparse)
42 {
43 // checking first object's rados xattrs
44 bufferlist xattrbl;
45 char* firstOid = getObjName(soid, 0);
46 ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.stripe_unit", xattrbl));
47 std::string s_xattr(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
48 uint64_t stripe_unit = strtoll(s_xattr.c_str(), NULL, 10);
49 ASSERT_LT((unsigned)0, stripe_unit);
50 ASSERT_EQ(stripe_unit, exp_stripe_unit);
51 xattrbl.clear();
52 ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.stripe_count", xattrbl));
53 s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
54 uint64_t stripe_count = strtoll(s_xattr.c_str(), NULL, 10);
55 ASSERT_LT(0U, stripe_count);
56 ASSERT_EQ(stripe_count, exp_stripe_count);
57 xattrbl.clear();
58 ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.object_size", xattrbl));
59 s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
60 uint64_t object_size = strtoll(s_xattr.c_str(), NULL, 10);
61 ASSERT_EQ(object_size, exp_object_size);
62 xattrbl.clear();
63 ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.size", xattrbl));
64 s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
65 uint64_t xa_size = strtoll(s_xattr.c_str(), NULL, 10);
66 ASSERT_EQ(xa_size, size);
67 // checking object content from rados point of view
68 // we will go stripe by stripe, read the content of each of them and
69 // check with expectations
70 uint64_t stripe_per_object = object_size / stripe_unit;
71 uint64_t stripe_per_objectset = stripe_per_object * stripe_count;
72 uint64_t nb_stripes_in_object = (size+stripe_unit-1)/stripe_unit;
73 for (uint64_t stripe_nb = 0;
74 stripe_nb < nb_stripes_in_object;
75 stripe_nb++) {
76 // find out where this stripe is stored
77 uint64_t objectset = stripe_nb / stripe_per_objectset;
78 uint64_t stripe_in_object_set = stripe_nb % stripe_per_objectset;
79 uint64_t object_in_set = stripe_in_object_set % stripe_count;
80 uint64_t stripe_in_object = stripe_in_object_set / stripe_count;
81 uint64_t object_nb = objectset * stripe_count + object_in_set;
82 uint64_t start = stripe_in_object * stripe_unit;
83 uint64_t len = stripe_unit;
84 if (stripe_nb == nb_stripes_in_object-1 and size % stripe_unit != 0) {
85 len = size % stripe_unit;
86 }
87 // handle case of sparse object (can only be sparse at the end in our tests)
88 if (actual_size_if_sparse < size and
89 ((actual_size_if_sparse+stripe_unit-1)/stripe_unit)-1 == stripe_nb) {
90 len = actual_size_if_sparse % stripe_unit;
91 if (0 == len) len = stripe_unit;
92 }
93 bufferlist stripe_data;
94 // check object content
95 char* oid = getObjName(soid, object_nb);
96 int rc = ioctx.read(oid, stripe_data, len, start);
97 if (actual_size_if_sparse < size and
98 (actual_size_if_sparse+stripe_unit-1)/stripe_unit <= stripe_nb) {
99 // sparse object case : the stripe does not exist, but the rados object may
100 uint64_t object_start = (object_in_set + objectset*stripe_per_objectset) * stripe_unit;
101 if (actual_size_if_sparse <= object_start) {
102 ASSERT_EQ(rc, -ENOENT);
103 } else {
104 ASSERT_EQ(rc, 0);
105 }
106 } else {
107 ASSERT_EQ((uint64_t)rc, len);
108 bufferlist original_data;
109 original_data.substr_of(bl, stripe_nb*stripe_unit, len);
110 ASSERT_EQ(0, memcmp(original_data.c_str(), stripe_data.c_str(), len));
111 }
112 free(oid);
113 }
114 // checking rados object sizes; we go object by object
115 uint64_t nb_full_object_sets = nb_stripes_in_object / stripe_per_objectset;
116 uint64_t nb_extra_objects = nb_stripes_in_object % stripe_per_objectset;
117 if (nb_extra_objects > stripe_count) nb_extra_objects = stripe_count;
118 uint64_t nb_objects = nb_full_object_sets * stripe_count + nb_extra_objects;
119 for (uint64_t object_nb = 0; object_nb < nb_objects; object_nb++) {
120 uint64_t rados_size;
121 time_t mtime;
122 char* oid = getObjName(soid, object_nb);
123 uint64_t nb_full_object_set = object_nb / stripe_count;
124 uint64_t object_index_in_set = object_nb % stripe_count;
125 uint64_t object_start_stripe = nb_full_object_set * stripe_per_objectset + object_index_in_set;
126 uint64_t object_start_off = object_start_stripe * stripe_unit;
127 if (actual_size_if_sparse < size and actual_size_if_sparse <= object_start_off) {
128 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &rados_size, &mtime));
129 } else {
130 ASSERT_EQ(0, ioctx.stat(oid, &rados_size, &mtime));
131 uint64_t offset;
132 uint64_t stripe_size = stripe_count * stripe_unit;
133 uint64_t set_size = stripe_count * object_size;
134 uint64_t len = 0;
135 for (offset = object_start_off;
136 (offset < (object_start_off) + set_size) && (offset < actual_size_if_sparse);
137 offset += stripe_size) {
138 if (offset + stripe_unit > actual_size_if_sparse) {
139 len += actual_size_if_sparse-offset;
140 } else {
141 len += stripe_unit;
142 }
143 }
144 ASSERT_EQ(len, rados_size);
145 }
146 free(oid);
147 }
148 // check we do not have an extra object behind
149 uint64_t rados_size;
150 time_t mtime;
151 char* oid = getObjName(soid, nb_objects);
152 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &rados_size, &mtime));
153 free(oid);
154 free(firstOid);
155 }
156};
157
158TEST_P(StriperTestRT, StripedRoundtrip) {
159 // get striping parameters and apply them
160 TestData testData = GetParam();
161 ASSERT_EQ(0, striper.set_object_layout_stripe_unit(testData.stripe_unit));
162 ASSERT_EQ(0, striper.set_object_layout_stripe_count(testData.stripe_count));
163 ASSERT_EQ(0, striper.set_object_layout_object_size(testData.object_size));
164 std::ostringstream oss;
165 oss << "StripedRoundtrip_" << testData.stripe_unit << "_"
166 << testData.stripe_count << "_" << testData.object_size
167 << "_" << testData.size;
168 std::string soid = oss.str();
169 // writing striped data
224ce89b 170 std::unique_ptr<char[]> buf1;
7c673cae
FG
171 bufferlist bl1;
172 {
173 SCOPED_TRACE("Writing initial object");
224ce89b 174 buf1 = ceph::make_unique<char[]>(testData.size);
7c673cae 175 for (unsigned int i = 0; i < testData.size; i++) buf1[i] = 13*((unsigned char)i);
224ce89b 176 bl1.append(buf1.get(), testData.size);
7c673cae
FG
177 ASSERT_EQ(0, striper.write(soid, bl1, testData.size, 0));
178 // checking object state from Rados point of view
179 ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
180 testData.stripe_count, testData.object_size,
181 testData.size));
182 }
183 // adding more data to object and checking again
224ce89b 184 std::unique_ptr<char[]> buf2;
7c673cae
FG
185 bufferlist bl2;
186 {
187 SCOPED_TRACE("Testing append");
224ce89b 188 buf2 = ceph::make_unique<char[]>(testData.size);
7c673cae 189 for (unsigned int i = 0; i < testData.size; i++) buf2[i] = 17*((unsigned char)i);
224ce89b 190 bl2.append(buf2.get(), testData.size);
7c673cae 191 ASSERT_EQ(0, striper.append(soid, bl2, testData.size));
224ce89b 192 bl1.append(buf2.get(), testData.size);
7c673cae
FG
193 ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
194 testData.stripe_count, testData.object_size,
195 testData.size*2));
196 }
197 // truncating to half original size and checking again
198 {
199 SCOPED_TRACE("Testing trunc to truncate object");
200 ASSERT_EQ(0, striper.trunc(soid, testData.size/2));
201 ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
202 testData.stripe_count, testData.object_size,
203 testData.size/2));
204 }
205 // truncating back to original size and checking again (especially for 0s)
206 {
207 SCOPED_TRACE("Testing trunc to extend object with 0s");
208 ASSERT_EQ(0, striper.trunc(soid, testData.size));
209 bufferlist bl3;
210 bl3.substr_of(bl1, 0, testData.size/2);
211 bl3.append_zero(testData.size - testData.size/2);
212 ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl3, testData.stripe_unit,
213 testData.stripe_count, testData.object_size,
214 testData.size, testData.size/2));
215 }
216 {
217 SCOPED_TRACE("Testing write_full");
218 // using write_full and checking again
219 ASSERT_EQ(0, striper.write_full(soid, bl2));
220 checkObjectFromRados(soid, bl2, testData.stripe_unit,
221 testData.stripe_count, testData.object_size,
222 testData.size);
223 }
224 {
225 SCOPED_TRACE("Testing standard remove");
226 // call remove
227 ASSERT_EQ(0, striper.remove(soid));
228 // check that the removal was successful
229 uint64_t size;
230 time_t mtime;
231 for (uint64_t object_nb = 0;
232 object_nb < testData.size*2/testData.object_size + testData.stripe_count;
233 object_nb++) {
234 char* oid = getObjName(soid, object_nb);
235 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &size, &mtime));
236 free(oid);
237 }
238 }
239 {
240 SCOPED_TRACE("Testing remove when no object size");
241 // recreate object
242 ASSERT_EQ(0, striper.write(soid, bl1, testData.size*2, 0));
243 // remove the object size attribute from the striped object
244 char* firstOid = getObjName(soid, 0);
245 ASSERT_EQ(0, ioctx.rmxattr(firstOid, "striper.size"));
246 free(firstOid);
247 // check that stat fails
248 uint64_t size;
249 time_t mtime;
250 ASSERT_EQ(-ENODATA, striper.stat(soid, &size, &mtime));
251 // call remove
252 ASSERT_EQ(0, striper.remove(soid));
253 // check that the removal was successful
254 for (uint64_t object_nb = 0;
255 object_nb < testData.size*2/testData.object_size + testData.stripe_count;
256 object_nb++) {
257 char* oid = getObjName(soid, object_nb);
258 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &size, &mtime));
259 free(oid);
260 }
261 }
7c673cae
FG
262}
263
264const TestData simple_stripe_schemes[] = {
265 // stripe_unit, stripe_count, object_size, size
266 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 2},
267 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT},
268 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT-1},
269 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT},
270 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT},
271 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT-1},
272 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT-1},
273 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
274 {CEPH_MIN_STRIPE_UNIT, 5, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
275 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
276 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
277 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
278 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
279 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
280 {CEPH_MIN_STRIPE_UNIT, 5, 3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100},
281 {262144, 5, 262144, 2},
282 {262144, 5, 262144, 262144},
283 {262144, 5, 262144, 262144-1},
284 {262144, 5, 262144, 2*262144},
285 {262144, 5, 262144, 12*262144},
286 {262144, 5, 262144, 2*262144-1},
287 {262144, 5, 262144, 12*262144-1},
288 {262144, 5, 262144, 2*262144+100},
289 {262144, 5, 262144, 12*262144+100},
290 {262144, 5, 3*262144, 2*262144+100},
291 {262144, 5, 3*262144, 8*262144+100},
292 {262144, 5, 3*262144, 12*262144+100},
293 {262144, 5, 3*262144, 15*262144+100},
294 {262144, 5, 3*262144, 25*262144+100},
295 {262144, 5, 3*262144, 45*262144+100},
296 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 2},
297 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT},
298 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT-1},
299 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT},
300 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT},
301 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT-1},
302 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT-1},
303 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
304 {CEPH_MIN_STRIPE_UNIT, 1, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
305 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
306 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
307 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
308 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
309 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
310 {CEPH_MIN_STRIPE_UNIT, 1, 3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100},
311 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 2},
312 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT},
313 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, CEPH_MIN_STRIPE_UNIT-1},
314 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT},
315 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT},
316 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT-1},
317 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT-1},
318 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
319 {CEPH_MIN_STRIPE_UNIT, 50, CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
320 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
321 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
322 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
323 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
324 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
325 {CEPH_MIN_STRIPE_UNIT, 50, 3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100}
326};
327
328INSTANTIATE_TEST_CASE_P(SimpleStriping,
329 StriperTestRT,
330 ::testing::ValuesIn(simple_stripe_schemes));