1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
2 // vim: ts=8 sw=2 smarttab
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"
14 #include "gtest/gtest.h"
15 #include "crimson_utils.h"
19 typedef RadosTest LibRadosIo
;
20 typedef RadosTestEC LibRadosIoEC
;
22 TEST_F(LibRadosIo
, SimpleWrite
) {
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));
30 TEST_F(LibRadosIo
, TooBig
) {
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));
38 TEST_F(LibRadosIo
, ReadTimeout
) {
40 memset(buf
, 'a', sizeof(buf
));
41 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
44 // set up a second client
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());
56 // then we show that the buffer is changed after rados_read returned
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);
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
]) {
72 // wait some time to give librados a change to do something
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
]);
83 printf("no timeout :/\n");
86 rados_ioctx_destroy(ioctx
);
87 rados_shutdown(cluster
);
92 TEST_F(LibRadosIo
, RoundTrip
) {
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
)));
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
)));
109 TEST_F(LibRadosIo
, Checksum
) {
111 memset(buf
, 0xcc, sizeof(buf
));
112 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
114 uint32_t expected_crc
= ceph_crc32c(-1, reinterpret_cast<const uint8_t*>(buf
),
116 ceph_le32
init_value(-1);
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]);
126 TEST_F(LibRadosIo
, OverlappingWriteRoundTrip
) {
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
)));
140 TEST_F(LibRadosIo
, WriteFullRoundTrip
) {
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
)));
153 TEST_F(LibRadosIo
, AppendRoundTrip
) {
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
)));
167 TEST_F(LibRadosIo
, ZeroLenZero
) {
168 rados_write_op_t op
= rados_create_write_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
);
175 TEST_F(LibRadosIo
, TruncTest
) {
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));
186 TEST_F(LibRadosIo
, RemoveTest
) {
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));
196 TEST_F(LibRadosIo
, XattrsRoundTrip
) {
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
)));
209 TEST_F(LibRadosIo
, RmXattr
) {
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
)));
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
)));
220 // Test rmxattr on a removed object
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));
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
));
232 TEST_F(LibRadosIo
, XattrIter
) {
234 char attr1
[] = "attr1";
235 char attr1_buf
[] = "foo bar baz";
236 char attr2
[] = "attr2";
238 for (size_t j
= 0; j
< sizeof(attr2_buf
); ++j
) {
239 attr2_buf
[j
] = j
% 0xff;
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
));
252 ASSERT_EQ(0, rados_getxattrs_next(iter
, &name
, &val
, &len
));
256 ASSERT_LT(num_seen
, 2);
257 if ((strcmp(name
, attr1
) == 0) && (val
!= NULL
) && (memcmp(val
, attr1_buf
, len
) == 0)) {
261 else if ((strcmp(name
, attr2
) == 0) && (val
!= NULL
) && (memcmp(val
, attr2_buf
, len
) == 0)) {
269 rados_getxattrs_end(iter
);
272 TEST_F(LibRadosIoEC
, SimpleWrite
) {
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));
281 TEST_F(LibRadosIoEC
, RoundTrip
) {
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
)));
292 ASSERT_EQ(-EOPNOTSUPP
, rados_write(ioctx
, "bar", buf
, sizeof(buf
), off
));
295 TEST_F(LibRadosIoEC
, OverlappingWriteRoundTrip
) {
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
];
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
));
318 TEST_F(LibRadosIoEC
, WriteFullRoundTrip
) {
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
)));
332 TEST_F(LibRadosIoEC
, AppendRoundTrip
) {
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
];
343 delete[] unalignedbuf
;
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
));
359 TEST_F(LibRadosIoEC
, TruncTest
) {
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
));
368 ASSERT_EQ((int)sizeof(buf
), rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
370 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)));
373 TEST_F(LibRadosIoEC
, RemoveTest
) {
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));
384 TEST_F(LibRadosIoEC
, XattrsRoundTrip
) {
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
)));
398 TEST_F(LibRadosIoEC
, RmXattr
) {
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
)));
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
)));
410 // Test rmxattr on a removed object
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));
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
));
422 TEST_F(LibRadosIoEC
, XattrIter
) {
425 char attr1
[] = "attr1";
426 char attr1_buf
[] = "foo bar baz";
427 char attr2
[] = "attr2";
429 for (size_t j
= 0; j
< sizeof(attr2_buf
); ++j
) {
430 attr2_buf
[j
] = j
% 0xff;
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
));
443 ASSERT_EQ(0, rados_getxattrs_next(iter
, &name
, &val
, &len
));
447 ASSERT_LT(num_seen
, 2);
448 if ((strcmp(name
, attr1
) == 0) && (val
!= NULL
) && (memcmp(val
, attr1_buf
, len
) == 0)) {
452 else if ((strcmp(name
, attr2
) == 0) && (val
!= NULL
) && (memcmp(val
, attr2_buf
, len
) == 0)) {
460 rados_getxattrs_end(iter
);