]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados/io.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librados / io.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
2 // vim: ts=8 sw=2 smarttab
3
4 #include <climits>
5
6 #include "include/rados/librados.h"
7 #include "include/encoding.h"
8 #include "include/err.h"
9 #include "include/scope_guard.h"
10 #include "test/librados/test.h"
11 #include "test/librados/TestCase.h"
12
13 #include <errno.h>
14 #include "gtest/gtest.h"
15 #include "crimson_utils.h"
16
17 using std::string;
18
19 typedef RadosTest LibRadosIo;
20 typedef RadosTestEC LibRadosIoEC;
21
22 TEST_F(LibRadosIo, SimpleWrite) {
23 char buf[128];
24 memset(buf, 0xcc, sizeof(buf));
25 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
26 rados_ioctx_set_namespace(ioctx, "nspace");
27 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
28 }
29
30 TEST_F(LibRadosIo, TooBig) {
31 char buf[1] = { 0 };
32 ASSERT_EQ(-E2BIG, rados_write(ioctx, "A", buf, UINT_MAX, 0));
33 ASSERT_EQ(-E2BIG, rados_append(ioctx, "A", buf, UINT_MAX));
34 ASSERT_EQ(-E2BIG, rados_write_full(ioctx, "A", buf, UINT_MAX));
35 ASSERT_EQ(-E2BIG, rados_writesame(ioctx, "A", buf, sizeof(buf), UINT_MAX, 0));
36 }
37
38 TEST_F(LibRadosIo, ReadTimeout) {
39 char buf[128];
40 memset(buf, 'a', sizeof(buf));
41 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
42
43 {
44 // set up a second client
45 rados_t cluster;
46 rados_ioctx_t ioctx;
47 ASSERT_EQ(0, rados_create(&cluster, "admin"));
48 ASSERT_EQ(0, rados_conf_read_file(cluster, NULL));
49 ASSERT_EQ(0, rados_conf_parse_env(cluster, NULL));
50 ASSERT_EQ(0, rados_conf_set(cluster, "rados_osd_op_timeout", "1")); // use any small value that will result in a timeout
51 ASSERT_EQ(0, rados_conf_set(cluster, "ms_inject_internal_delays", "2")); // create a 2 second delay
52 ASSERT_EQ(0, rados_connect(cluster));
53 ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx));
54 rados_ioctx_set_namespace(ioctx, nspace.c_str());
55
56 // then we show that the buffer is changed after rados_read returned
57 // with a timeout
58 for (int i=0; i<5; i++) {
59 char buf2[sizeof(buf)];
60 memset(buf2, 0, sizeof(buf2));
61 int err = rados_read(ioctx, "foo", buf2, sizeof(buf2), 0);
62 if (err == -110) {
63 int startIndex = 0;
64 // find the index until which librados already read the object before the timeout occurred
65 for (unsigned b=0; b<sizeof(buf); b++) {
66 if (buf2[b] != buf[b]) {
67 startIndex = b;
68 break;
69 }
70 }
71
72 // wait some time to give librados a change to do something
73 sleep(1);
74
75 // then check if the buffer was changed after the call
76 if (buf2[startIndex] == 'a') {
77 printf("byte at index %d was changed after the timeout to %d\n",
78 startIndex, (int)buf[startIndex]);
79 ASSERT_TRUE(0);
80 break;
81 }
82 } else {
83 printf("no timeout :/\n");
84 }
85 }
86 rados_ioctx_destroy(ioctx);
87 rados_shutdown(cluster);
88 }
89 }
90
91
92 TEST_F(LibRadosIo, RoundTrip) {
93 char buf[128];
94 char buf2[128];
95 memset(buf, 0xcc, sizeof(buf));
96 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
97 memset(buf2, 0, sizeof(buf2));
98 ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
99 ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
100
101 uint64_t off = 19;
102 memset(buf, 0xcc, sizeof(buf));
103 ASSERT_EQ(0, rados_write(ioctx, "bar", buf, sizeof(buf), off));
104 memset(buf2, 0, sizeof(buf2));
105 ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "bar", buf2, sizeof(buf2), off));
106 ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
107 }
108
109 TEST_F(LibRadosIo, Checksum) {
110 char buf[128];
111 memset(buf, 0xcc, sizeof(buf));
112 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
113
114 uint32_t expected_crc = ceph_crc32c(-1, reinterpret_cast<const uint8_t*>(buf),
115 sizeof(buf));
116 ceph_le32 init_value(-1);
117 ceph_le32 crc[2];
118 ASSERT_EQ(0, rados_checksum(ioctx, "foo", LIBRADOS_CHECKSUM_TYPE_CRC32C,
119 reinterpret_cast<char*>(&init_value),
120 sizeof(init_value), sizeof(buf), 0, 0,
121 reinterpret_cast<char*>(&crc), sizeof(crc)));
122 ASSERT_EQ(1U, crc[0]);
123 ASSERT_EQ(expected_crc, crc[1]);
124 }
125
126 TEST_F(LibRadosIo, OverlappingWriteRoundTrip) {
127 char buf[128];
128 char buf2[64];
129 char buf3[128];
130 memset(buf, 0xcc, sizeof(buf));
131 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
132 memset(buf2, 0xdd, sizeof(buf2));
133 ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0));
134 memset(buf3, 0xdd, sizeof(buf3));
135 ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
136 ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
137 ASSERT_EQ(0, memcmp(buf3 + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
138 }
139
140 TEST_F(LibRadosIo, WriteFullRoundTrip) {
141 char buf[128];
142 char buf2[64];
143 char buf3[128];
144 memset(buf, 0xcc, sizeof(buf));
145 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
146 memset(buf2, 0xdd, sizeof(buf2));
147 ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2)));
148 memset(buf3, 0x00, sizeof(buf3));
149 ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
150 ASSERT_EQ(0, memcmp(buf2, buf3, sizeof(buf2)));
151 }
152
153 TEST_F(LibRadosIo, AppendRoundTrip) {
154 char buf[64];
155 char buf2[64];
156 char buf3[sizeof(buf) + sizeof(buf2)];
157 memset(buf, 0xde, sizeof(buf));
158 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
159 memset(buf2, 0xad, sizeof(buf2));
160 ASSERT_EQ(0, rados_append(ioctx, "foo", buf2, sizeof(buf2)));
161 memset(buf3, 0, sizeof(buf3));
162 ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
163 ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf)));
164 ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2)));
165 }
166
167 TEST_F(LibRadosIo, ZeroLenZero) {
168 rados_write_op_t op = rados_create_write_op();
169 ASSERT_TRUE(op);
170 rados_write_op_zero(op, 0, 0);
171 ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "foo", NULL, 0));
172 rados_release_write_op(op);
173 }
174
175 TEST_F(LibRadosIo, TruncTest) {
176 char buf[128];
177 char buf2[sizeof(buf)];
178 memset(buf, 0xaa, sizeof(buf));
179 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
180 ASSERT_EQ(0, rados_trunc(ioctx, "foo", sizeof(buf) / 2));
181 memset(buf2, 0, sizeof(buf2));
182 ASSERT_EQ((int)(sizeof(buf)/2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
183 ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)/2));
184 }
185
186 TEST_F(LibRadosIo, RemoveTest) {
187 char buf[128];
188 char buf2[sizeof(buf)];
189 memset(buf, 0xaa, sizeof(buf));
190 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
191 ASSERT_EQ(0, rados_remove(ioctx, "foo"));
192 memset(buf2, 0, sizeof(buf2));
193 ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
194 }
195
196 TEST_F(LibRadosIo, XattrsRoundTrip) {
197 char buf[128];
198 char attr1[] = "attr1";
199 char attr1_buf[] = "foo bar baz";
200 memset(buf, 0xaa, sizeof(buf));
201 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
202 ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
203 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
204 ASSERT_EQ((int)sizeof(attr1_buf),
205 rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
206 ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
207 }
208
209 TEST_F(LibRadosIo, RmXattr) {
210 char buf[128];
211 char attr1[] = "attr1";
212 char attr1_buf[] = "foo bar baz";
213 memset(buf, 0xaa, sizeof(buf));
214 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
215 ASSERT_EQ(0,
216 rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
217 ASSERT_EQ(0, rados_rmxattr(ioctx, "foo", attr1));
218 ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
219
220 // Test rmxattr on a removed object
221 char buf2[128];
222 char attr2[] = "attr2";
223 char attr2_buf[] = "foo bar baz";
224 memset(buf2, 0xbb, sizeof(buf2));
225 ASSERT_EQ(0, rados_write(ioctx, "foo_rmxattr", buf2, sizeof(buf2), 0));
226 ASSERT_EQ(0,
227 rados_setxattr(ioctx, "foo_rmxattr", attr2, attr2_buf, sizeof(attr2_buf)));
228 ASSERT_EQ(0, rados_remove(ioctx, "foo_rmxattr"));
229 ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
230 }
231
232 TEST_F(LibRadosIo, XattrIter) {
233 char buf[128];
234 char attr1[] = "attr1";
235 char attr1_buf[] = "foo bar baz";
236 char attr2[] = "attr2";
237 char attr2_buf[256];
238 for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
239 attr2_buf[j] = j % 0xff;
240 }
241 memset(buf, 0xaa, sizeof(buf));
242 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
243 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
244 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf)));
245 rados_xattrs_iter_t iter;
246 ASSERT_EQ(0, rados_getxattrs(ioctx, "foo", &iter));
247 int num_seen = 0;
248 while (true) {
249 const char *name;
250 const char *val;
251 size_t len;
252 ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len));
253 if (name == NULL) {
254 break;
255 }
256 ASSERT_LT(num_seen, 2);
257 if ((strcmp(name, attr1) == 0) && (val != NULL) && (memcmp(val, attr1_buf, len) == 0)) {
258 num_seen++;
259 continue;
260 }
261 else if ((strcmp(name, attr2) == 0) && (val != NULL) && (memcmp(val, attr2_buf, len) == 0)) {
262 num_seen++;
263 continue;
264 }
265 else {
266 ASSERT_EQ(0, 1);
267 }
268 }
269 rados_getxattrs_end(iter);
270 }
271
272 TEST_F(LibRadosIoEC, SimpleWrite) {
273 SKIP_IF_CRIMSON();
274 char buf[128];
275 memset(buf, 0xcc, sizeof(buf));
276 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
277 rados_ioctx_set_namespace(ioctx, "nspace");
278 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
279 }
280
281 TEST_F(LibRadosIoEC, RoundTrip) {
282 SKIP_IF_CRIMSON();
283 char buf[128];
284 char buf2[128];
285 memset(buf, 0xcc, sizeof(buf));
286 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
287 memset(buf2, 0, sizeof(buf2));
288 ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
289 ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
290
291 uint64_t off = 19;
292 ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "bar", buf, sizeof(buf), off));
293 }
294
295 TEST_F(LibRadosIoEC, OverlappingWriteRoundTrip) {
296 SKIP_IF_CRIMSON();
297 int bsize = alignment;
298 int dbsize = bsize * 2;
299 char *buf = (char *)new char[dbsize];
300 char *buf2 = (char *)new char[bsize];
301 char *buf3 = (char *)new char[dbsize];
302 auto cleanup = [&] {
303 delete[] buf;
304 delete[] buf2;
305 delete[] buf3;
306 };
307 scope_guard<decltype(cleanup)> sg(std::move(cleanup));
308 memset(buf, 0xcc, dbsize);
309 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, dbsize, 0));
310 memset(buf2, 0xdd, bsize);
311 ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "foo", buf2, bsize, 0));
312 memset(buf3, 0xdd, dbsize);
313 ASSERT_EQ(dbsize, rados_read(ioctx, "foo", buf3, dbsize, 0));
314 // Read the same as first write
315 ASSERT_EQ(0, memcmp(buf3, buf, dbsize));
316 }
317
318 TEST_F(LibRadosIoEC, WriteFullRoundTrip) {
319 SKIP_IF_CRIMSON();
320 char buf[128];
321 char buf2[64];
322 char buf3[128];
323 memset(buf, 0xcc, sizeof(buf));
324 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
325 memset(buf2, 0xdd, sizeof(buf2));
326 ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2)));
327 memset(buf3, 0xee, sizeof(buf3));
328 ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
329 ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
330 }
331
332 TEST_F(LibRadosIoEC, AppendRoundTrip) {
333 SKIP_IF_CRIMSON();
334 char *buf = (char *)new char[alignment];
335 char *buf2 = (char *)new char[alignment];
336 char *buf3 = (char *)new char[alignment *2];
337 int uasize = alignment/2;
338 char *unalignedbuf = (char *)new char[uasize];
339 auto cleanup = [&] {
340 delete[] buf;
341 delete[] buf2;
342 delete[] buf3;
343 delete[] unalignedbuf;
344 };
345 scope_guard<decltype(cleanup)> sg(std::move(cleanup));
346 memset(buf, 0xde, alignment);
347 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, alignment));
348 memset(buf2, 0xad, alignment);
349 ASSERT_EQ(0, rados_append(ioctx, "foo", buf2, alignment));
350 memset(buf3, 0, alignment*2);
351 ASSERT_EQ((int)alignment*2, rados_read(ioctx, "foo", buf3, alignment*2, 0));
352 ASSERT_EQ(0, memcmp(buf3, buf, alignment));
353 ASSERT_EQ(0, memcmp(buf3 + alignment, buf2, alignment));
354 memset(unalignedbuf, 0, uasize);
355 ASSERT_EQ(0, rados_append(ioctx, "foo", unalignedbuf, uasize));
356 ASSERT_EQ(-EOPNOTSUPP, rados_append(ioctx, "foo", unalignedbuf, uasize));
357 }
358
359 TEST_F(LibRadosIoEC, TruncTest) {
360 SKIP_IF_CRIMSON();
361 char buf[128];
362 char buf2[sizeof(buf)];
363 memset(buf, 0xaa, sizeof(buf));
364 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
365 ASSERT_EQ(-EOPNOTSUPP, rados_trunc(ioctx, "foo", sizeof(buf) / 2));
366 memset(buf2, 0, sizeof(buf2));
367 // Same size
368 ASSERT_EQ((int)sizeof(buf), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
369 // No change
370 ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
371 }
372
373 TEST_F(LibRadosIoEC, RemoveTest) {
374 SKIP_IF_CRIMSON();
375 char buf[128];
376 char buf2[sizeof(buf)];
377 memset(buf, 0xaa, sizeof(buf));
378 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
379 ASSERT_EQ(0, rados_remove(ioctx, "foo"));
380 memset(buf2, 0, sizeof(buf2));
381 ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
382 }
383
384 TEST_F(LibRadosIoEC, XattrsRoundTrip) {
385 SKIP_IF_CRIMSON();
386 char buf[128];
387 char attr1[] = "attr1";
388 char attr1_buf[] = "foo bar baz";
389 memset(buf, 0xaa, sizeof(buf));
390 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
391 ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
392 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
393 ASSERT_EQ((int)sizeof(attr1_buf),
394 rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
395 ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
396 }
397
398 TEST_F(LibRadosIoEC, RmXattr) {
399 SKIP_IF_CRIMSON();
400 char buf[128];
401 char attr1[] = "attr1";
402 char attr1_buf[] = "foo bar baz";
403 memset(buf, 0xaa, sizeof(buf));
404 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
405 ASSERT_EQ(0,
406 rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
407 ASSERT_EQ(0, rados_rmxattr(ioctx, "foo", attr1));
408 ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
409
410 // Test rmxattr on a removed object
411 char buf2[128];
412 char attr2[] = "attr2";
413 char attr2_buf[] = "foo bar baz";
414 memset(buf2, 0xbb, sizeof(buf2));
415 ASSERT_EQ(0, rados_write(ioctx, "foo_rmxattr", buf2, sizeof(buf2), 0));
416 ASSERT_EQ(0,
417 rados_setxattr(ioctx, "foo_rmxattr", attr2, attr2_buf, sizeof(attr2_buf)));
418 ASSERT_EQ(0, rados_remove(ioctx, "foo_rmxattr"));
419 ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
420 }
421
422 TEST_F(LibRadosIoEC, XattrIter) {
423 SKIP_IF_CRIMSON();
424 char buf[128];
425 char attr1[] = "attr1";
426 char attr1_buf[] = "foo bar baz";
427 char attr2[] = "attr2";
428 char attr2_buf[256];
429 for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
430 attr2_buf[j] = j % 0xff;
431 }
432 memset(buf, 0xaa, sizeof(buf));
433 ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
434 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
435 ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf)));
436 rados_xattrs_iter_t iter;
437 ASSERT_EQ(0, rados_getxattrs(ioctx, "foo", &iter));
438 int num_seen = 0;
439 while (true) {
440 const char *name;
441 const char *val;
442 size_t len;
443 ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len));
444 if (name == NULL) {
445 break;
446 }
447 ASSERT_LT(num_seen, 2);
448 if ((strcmp(name, attr1) == 0) && (val != NULL) && (memcmp(val, attr1_buf, len) == 0)) {
449 num_seen++;
450 continue;
451 }
452 else if ((strcmp(name, attr2) == 0) && (val != NULL) && (memcmp(val, attr2_buf, len) == 0)) {
453 num_seen++;
454 continue;
455 }
456 else {
457 ASSERT_EQ(0, 1);
458 }
459 }
460 rados_getxattrs_end(iter);
461 }