1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // Tests for the C API coverage of atomic read operations
4 #include <cstring> // For memcpy
8 #include "include/buffer.h"
9 #include "include/denc.h"
10 #include "include/err.h"
11 #include "include/rados/librados.h"
12 #include "include/rbd/features.h" // For RBD_FEATURES_ALL
13 #include "include/scope_guard.h"
14 #include "test/librados/TestCase.h"
15 #include "test/librados/test.h"
17 const char *data
= "testdata";
18 const char *obj
= "testobj";
19 const size_t len
= strlen(data
);
21 class CReadOpsTest
: public RadosTest
{
24 // Create an object and write to it
25 ASSERT_EQ(0, rados_write(ioctx
, obj
, data
, len
, 0));
27 void remove_object() {
28 ASSERT_EQ(0, rados_remove(ioctx
, obj
));
30 int cmp_xattr(const char *xattr
, const char *value
, size_t value_len
,
33 rados_read_op_t op
= rados_create_read_op();
34 rados_read_op_cmpxattr(op
, xattr
, cmp_op
, value
, value_len
);
35 int r
= rados_read_op_operate(op
, ioctx
, obj
, 0);
36 rados_release_read_op(op
);
40 void fetch_and_verify_omap_vals(char const* const* keys
,
41 char const* const* vals
,
45 rados_omap_iter_t iter_vals
, iter_keys
, iter_vals_by_key
;
46 int r_vals
, r_keys
, r_vals_by_key
;
47 rados_read_op_t op
= rados_create_read_op();
48 rados_read_op_omap_get_vals2(op
, NULL
, NULL
, 100, &iter_vals
, NULL
, &r_vals
);
49 rados_read_op_omap_get_keys2(op
, NULL
, 100, &iter_keys
, NULL
, &r_keys
);
50 rados_read_op_omap_get_vals_by_keys(op
, keys
, len
,
51 &iter_vals_by_key
, &r_vals_by_key
);
52 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
53 rados_release_read_op(op
);
56 ASSERT_EQ(0, r_vals_by_key
);
58 const char *zeros
[len
];
59 size_t zero_lens
[len
];
60 memset(zeros
, 0, sizeof(zeros
));
61 memset(zero_lens
, 0, sizeof(zero_lens
));
62 compare_omap_vals(keys
, vals
, lens
, len
, iter_vals
);
63 compare_omap_vals(keys
, zeros
, zero_lens
, len
, iter_keys
);
64 compare_omap_vals(keys
, vals
, lens
, len
, iter_vals_by_key
);
67 void compare_omap_vals(char const* const* keys
,
68 char const* const* vals
,
71 rados_omap_iter_t iter
)
77 ASSERT_EQ(len
, rados_omap_iter_size(iter
));
79 ASSERT_EQ(0, rados_omap_get_next(iter
, &key
, &val
, &val_len
));
80 if (val_len
== 0 && key
== NULL
&& val
== NULL
)
83 EXPECT_EQ(std::string(keys
[i
]), std::string(key
));
85 EXPECT_EQ(keys
[i
], key
);
86 ASSERT_EQ(0, memcmp(vals
[i
], val
, val_len
));
87 ASSERT_EQ(lens
[i
], val_len
);
91 ASSERT_EQ(0, rados_omap_get_next(iter
, &key
, &val
, &val_len
));
92 ASSERT_EQ((char*)NULL
, key
);
93 ASSERT_EQ((char*)NULL
, val
);
94 ASSERT_EQ(0u, val_len
);
95 rados_omap_get_end(iter
);
98 // these two used to test omap funcs that accept length for both keys and vals
99 void fetch_and_verify_omap_vals2(char const* const* keys
,
100 char const* const* vals
,
101 const size_t *keylens
,
102 const size_t *vallens
,
105 rados_omap_iter_t iter_vals_by_key
;
107 rados_read_op_t op
= rados_create_read_op();
108 rados_read_op_omap_get_vals_by_keys2(op
, keys
, len
, keylens
,
109 &iter_vals_by_key
, &r_vals_by_key
);
110 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
111 rados_release_read_op(op
);
112 ASSERT_EQ(0, r_vals_by_key
);
114 compare_omap_vals2(keys
, vals
, keylens
, vallens
, len
, iter_vals_by_key
);
117 void compare_omap_vals2(char const* const* keys
,
118 char const* const* vals
,
119 const size_t *keylens
,
120 const size_t *vallens
,
122 rados_omap_iter_t iter
)
129 ASSERT_EQ(len
, rados_omap_iter_size(iter
));
131 ASSERT_EQ(0, rados_omap_get_next2(iter
, &key
, &val
, &key_len
, &val_len
));
132 if (key_len
== 0 && val_len
== 0 && key
== NULL
&& val
== NULL
)
135 EXPECT_EQ(std::string(keys
[i
], keylens
[i
]), std::string(key
, key_len
));
137 EXPECT_EQ(keys
[i
], key
);
138 ASSERT_EQ(val_len
, vallens
[i
]);
139 ASSERT_EQ(key_len
, keylens
[i
]);
140 ASSERT_EQ(0, memcmp(vals
[i
], val
, val_len
));
144 ASSERT_EQ(0, rados_omap_get_next2(iter
, &key
, &val
, &key_len
, &val_len
));
145 ASSERT_EQ((char*)NULL
, key
);
146 ASSERT_EQ((char*)NULL
, val
);
147 ASSERT_EQ(0u, key_len
);
148 ASSERT_EQ(0u, val_len
);
149 rados_omap_get_end(iter
);
152 void compare_xattrs(char const* const* keys
,
153 char const* const* vals
,
156 rados_xattrs_iter_t iter
)
163 ASSERT_EQ(0, rados_getxattrs_next(iter
, (const char**) &key
,
164 (const char**) &val
, &val_len
));
167 EXPECT_EQ(std::string(keys
[i
]), std::string(key
));
169 EXPECT_EQ(0, memcmp(vals
[i
], val
, val_len
));
171 EXPECT_EQ(lens
[i
], val_len
);
175 ASSERT_EQ(0, rados_getxattrs_next(iter
, (const char**)&key
,
176 (const char**)&val
, &val_len
));
177 ASSERT_EQ((char*)NULL
, key
);
178 ASSERT_EQ((char*)NULL
, val
);
179 ASSERT_EQ(0u, val_len
);
180 rados_getxattrs_end(iter
);
184 TEST_F(CReadOpsTest
, NewDelete
) {
185 rados_read_op_t op
= rados_create_read_op();
187 rados_release_read_op(op
);
190 TEST_F(CReadOpsTest
, SetOpFlags
) {
193 rados_read_op_t op
= rados_create_read_op();
194 size_t bytes_read
= 0;
197 rados_read_op_exec(op
, "rbd", "get_id", NULL
, 0, &out
,
199 rados_read_op_set_flags(op
, LIBRADOS_OP_FLAG_FAILOK
);
200 EXPECT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
201 EXPECT_EQ(-EIO
, rval
);
202 EXPECT_EQ(0u, bytes_read
);
203 EXPECT_EQ((char*)NULL
, out
);
204 rados_release_read_op(op
);
209 TEST_F(CReadOpsTest
, AssertExists
) {
210 rados_read_op_t op
= rados_create_read_op();
211 rados_read_op_assert_exists(op
);
213 ASSERT_EQ(-ENOENT
, rados_read_op_operate(op
, ioctx
, obj
, 0));
214 rados_release_read_op(op
);
216 op
= rados_create_read_op();
217 rados_read_op_assert_exists(op
);
219 rados_completion_t completion
;
220 ASSERT_EQ(0, rados_aio_create_completion(NULL
, NULL
, NULL
, &completion
));
221 auto sg
= make_scope_guard([&] { rados_aio_release(completion
); });
222 ASSERT_EQ(0, rados_aio_read_op_operate(op
, ioctx
, completion
, obj
, 0));
223 rados_aio_wait_for_complete(completion
);
224 ASSERT_EQ(-ENOENT
, rados_aio_get_return_value(completion
));
225 rados_release_read_op(op
);
229 op
= rados_create_read_op();
230 rados_read_op_assert_exists(op
);
231 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
232 rados_release_read_op(op
);
237 TEST_F(CReadOpsTest
, AssertVersion
) {
239 // Write to the object a second time to guarantee that its
240 // version number is greater than 0
242 uint64_t v
= rados_get_last_version(ioctx
);
244 rados_read_op_t op
= rados_create_read_op();
245 rados_read_op_assert_version(op
, v
+1);
246 ASSERT_EQ(-EOVERFLOW
, rados_read_op_operate(op
, ioctx
, obj
, 0));
247 rados_release_read_op(op
);
249 op
= rados_create_read_op();
250 rados_read_op_assert_version(op
, v
-1);
251 ASSERT_EQ(-ERANGE
, rados_read_op_operate(op
, ioctx
, obj
, 0));
252 rados_release_read_op(op
);
254 op
= rados_create_read_op();
255 rados_read_op_assert_version(op
, v
);
256 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
257 rados_release_read_op(op
);
262 TEST_F(CReadOpsTest
, CmpXattr
) {
266 memset(buf
, 0xcc, sizeof(buf
));
268 const char *xattr
= "test";
269 rados_setxattr(ioctx
, obj
, xattr
, buf
, sizeof(buf
));
272 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_EQ
));
273 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_NE
));
274 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_GT
));
275 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_GTE
));
276 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_LT
));
277 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_LTE
));
280 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_EQ
));
281 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_NE
));
282 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_GT
));
283 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_GTE
));
284 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_LT
));
285 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
) - 1, LIBRADOS_CMPXATTR_OP_LTE
));
288 memset(buf
, 0xcd, sizeof(buf
));
289 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_EQ
));
290 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_NE
));
291 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_GT
));
292 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_GTE
));
293 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_LT
));
294 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, sizeof(buf
), LIBRADOS_CMPXATTR_OP_LTE
));
296 // check that null bytes are compared correctly
297 rados_setxattr(ioctx
, obj
, xattr
, "\0\0", 2);
299 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_EQ
));
300 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_NE
));
301 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_GT
));
302 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_GTE
));
303 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_LT
));
304 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_LTE
));
307 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_EQ
));
308 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_NE
));
309 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_GT
));
310 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_GTE
));
311 EXPECT_EQ(-ECANCELED
, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_LT
));
312 EXPECT_EQ(1, cmp_xattr(xattr
, buf
, 2, LIBRADOS_CMPXATTR_OP_LTE
));
317 TEST_F(CReadOpsTest
, Read
) {
321 // check that using read_ops returns the same data with
322 // or without bytes_read and rval out params
324 rados_read_op_t op
= rados_create_read_op();
325 rados_read_op_read(op
, 0, len
, buf
, NULL
, NULL
);
326 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
327 ASSERT_EQ(0, memcmp(data
, buf
, len
));
328 rados_release_read_op(op
);
332 rados_read_op_t op
= rados_create_read_op();
334 rados_read_op_read(op
, 0, len
, buf
, NULL
, &rval
);
335 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
337 ASSERT_EQ(0, memcmp(data
, buf
, len
));
338 rados_release_read_op(op
);
342 rados_read_op_t op
= rados_create_read_op();
343 size_t bytes_read
= 0;
344 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, NULL
);
345 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
346 ASSERT_EQ(len
, bytes_read
);
347 ASSERT_EQ(0, memcmp(data
, buf
, len
));
348 rados_release_read_op(op
);
352 rados_read_op_t op
= rados_create_read_op();
353 size_t bytes_read
= 0;
355 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, &rval
);
356 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
357 ASSERT_EQ(len
, bytes_read
);
359 ASSERT_EQ(0, memcmp(data
, buf
, len
));
360 rados_release_read_op(op
);
364 rados_read_op_t op
= rados_create_read_op();
365 size_t bytes_read
= 0;
367 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, &rval
);
368 rados_read_op_set_flags(op
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
369 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
370 ASSERT_EQ(len
, bytes_read
);
372 ASSERT_EQ(0, memcmp(data
, buf
, len
));
373 rados_release_read_op(op
);
379 TEST_F(CReadOpsTest
, Checksum
) {
383 rados_read_op_t op
= rados_create_read_op();
384 ceph_le64
init_value(-1);
385 rados_read_op_checksum(op
, LIBRADOS_CHECKSUM_TYPE_XXHASH64
,
386 reinterpret_cast<char *>(&init_value
),
387 sizeof(init_value
), 0, len
, 0, NULL
, 0, NULL
);
388 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
389 rados_release_read_op(op
);
393 ceph_le32
init_value(-1);
395 rados_read_op_t op
= rados_create_read_op();
396 rados_read_op_checksum(op
, LIBRADOS_CHECKSUM_TYPE_CRC32C
,
397 reinterpret_cast<char *>(&init_value
),
398 sizeof(init_value
), 0, len
, 0,
399 reinterpret_cast<char *>(&crc
), sizeof(crc
),
401 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
402 ASSERT_EQ(1U, crc
[0]);
403 uint32_t expected_crc
= ceph_crc32c(
404 -1, reinterpret_cast<const uint8_t*>(data
), static_cast<uint32_t>(len
));
405 ASSERT_EQ(expected_crc
, crc
[1]);
406 rados_release_read_op(op
);
410 ceph_le32
init_value(-1);
412 rados_read_op_t op
= rados_create_read_op();
413 rados_read_op_checksum(op
, LIBRADOS_CHECKSUM_TYPE_XXHASH32
,
414 reinterpret_cast<char *>(&init_value
),
415 sizeof(init_value
), 0, len
, 0, nullptr, 0, &rval
);
416 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
418 rados_release_read_op(op
);
422 ceph_le32
init_value(-1);
425 rados_read_op_t op
= rados_create_read_op();
426 rados_read_op_checksum(op
, LIBRADOS_CHECKSUM_TYPE_CRC32C
,
427 reinterpret_cast<char *>(&init_value
),
428 sizeof(init_value
), 0, len
, 4,
429 reinterpret_cast<char *>(&crc
), sizeof(crc
), &rval
);
430 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
431 ASSERT_EQ(2U, crc
[0]);
432 uint32_t expected_crc
[2];
433 expected_crc
[0] = ceph_crc32c(
434 -1, reinterpret_cast<const uint8_t*>(data
), 4U);
435 expected_crc
[1] = ceph_crc32c(
436 -1, reinterpret_cast<const uint8_t*>(data
+ 4), 4U);
437 ASSERT_EQ(expected_crc
[0], crc
[1]);
438 ASSERT_EQ(expected_crc
[1], crc
[2]);
440 rados_release_read_op(op
);
446 TEST_F(CReadOpsTest
, RWOrderedRead
) {
450 rados_read_op_t op
= rados_create_read_op();
451 size_t bytes_read
= 0;
453 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, &rval
);
454 rados_read_op_set_flags(op
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
455 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
,
456 LIBRADOS_OPERATION_ORDER_READS_WRITES
));
457 ASSERT_EQ(len
, bytes_read
);
459 ASSERT_EQ(0, memcmp(data
, buf
, len
));
460 rados_release_read_op(op
);
465 TEST_F(CReadOpsTest
, ShortRead
) {
469 // check that using read_ops returns the same data with
470 // or without bytes_read and rval out params
472 rados_read_op_t op
= rados_create_read_op();
473 rados_read_op_read(op
, 0, len
* 2, buf
, NULL
, NULL
);
474 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
475 ASSERT_EQ(0, memcmp(data
, buf
, len
));
476 rados_release_read_op(op
);
480 rados_read_op_t op
= rados_create_read_op();
482 rados_read_op_read(op
, 0, len
* 2, buf
, NULL
, &rval
);
483 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
485 ASSERT_EQ(0, memcmp(data
, buf
, len
));
486 rados_release_read_op(op
);
490 rados_read_op_t op
= rados_create_read_op();
491 size_t bytes_read
= 0;
492 rados_read_op_read(op
, 0, len
* 2, buf
, &bytes_read
, NULL
);
493 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
494 ASSERT_EQ(len
, bytes_read
);
495 ASSERT_EQ(0, memcmp(data
, buf
, len
));
496 rados_release_read_op(op
);
500 rados_read_op_t op
= rados_create_read_op();
501 size_t bytes_read
= 0;
503 rados_read_op_read(op
, 0, len
* 2, buf
, &bytes_read
, &rval
);
504 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
505 ASSERT_EQ(len
, bytes_read
);
507 ASSERT_EQ(0, memcmp(data
, buf
, len
));
508 rados_release_read_op(op
);
514 TEST_F(CReadOpsTest
, Exec
) {
515 // create object so we don't get -ENOENT
518 rados_read_op_t op
= rados_create_read_op();
520 size_t bytes_read
= 0;
523 rados_read_op_exec(op
, "rbd", "get_all_features", NULL
, 0, &out
,
525 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
526 rados_release_read_op(op
);
530 EXPECT_EQ(sizeof(features
), bytes_read
);
531 // make sure buffer is at least as long as it claims
533 bl
.append(out
, bytes_read
);
534 auto it
= bl
.cbegin();
535 ceph::decode(features
, it
);
536 ASSERT_EQ(RBD_FEATURES_ALL
, features
);
537 rados_buffer_free(out
);
542 TEST_F(CReadOpsTest
, ExecUserBuf
) {
543 // create object so we don't get -ENOENT
546 rados_read_op_t op
= rados_create_read_op();
547 size_t bytes_read
= 0;
549 char out
[sizeof(features
)];
551 rados_read_op_exec_user_buf(op
, "rbd", "get_all_features", NULL
, 0, out
,
552 sizeof(out
), &bytes_read
, &rval
);
553 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
554 rados_release_read_op(op
);
556 EXPECT_EQ(sizeof(features
), bytes_read
);
560 op
= rados_create_read_op();
561 rados_read_op_exec_user_buf(op
, "rbd", "get_all_features", NULL
, 0, out
,
562 sizeof(features
) - 1, &bytes_read
, &rval
);
563 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
564 rados_release_read_op(op
);
565 EXPECT_EQ(0u, bytes_read
);
566 EXPECT_EQ(-ERANGE
, rval
);
568 // input buffer and no rval or bytes_read
569 op
= rados_create_read_op();
570 rados_read_op_exec_user_buf(op
, "rbd", "get_all_features", out
, sizeof(out
),
571 out
, sizeof(out
), NULL
, NULL
);
572 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
573 rados_release_read_op(op
);
578 TEST_F(CReadOpsTest
, Stat
) {
579 rados_read_op_t op
= rados_create_read_op();
582 rados_read_op_stat(op
, &size
, NULL
, &rval
);
583 EXPECT_EQ(-ENOENT
, rados_read_op_operate(op
, ioctx
, obj
, 0));
584 EXPECT_EQ(-EIO
, rval
);
586 rados_release_read_op(op
);
590 op
= rados_create_read_op();
591 rados_read_op_stat(op
, &size
, NULL
, &rval
);
592 EXPECT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
594 EXPECT_EQ(len
, size
);
595 rados_release_read_op(op
);
597 op
= rados_create_read_op();
598 rados_read_op_stat(op
, NULL
, NULL
, NULL
);
599 EXPECT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
600 rados_release_read_op(op
);
604 op
= rados_create_read_op();
605 rados_read_op_stat(op
, NULL
, NULL
, NULL
);
606 EXPECT_EQ(-ENOENT
, rados_read_op_operate(op
, ioctx
, obj
, 0));
607 rados_release_read_op(op
);
610 TEST_F(CReadOpsTest
, Omap
) {
611 char *keys
[] = {(char*)"bar",
615 char *vals
[] = {(char*)"",
619 size_t lens
[] = {0, 1, 3, 6};
621 // check for -ENOENT before the object exists and when it exists
622 // with no omap entries
623 rados_omap_iter_t iter_vals
;
624 rados_read_op_t rop
= rados_create_read_op();
625 rados_read_op_omap_get_vals2(rop
, "", "", 10, &iter_vals
, NULL
, NULL
);
626 ASSERT_EQ(-ENOENT
, rados_read_op_operate(rop
, ioctx
, obj
, 0));
627 rados_release_read_op(rop
);
628 compare_omap_vals(NULL
, NULL
, NULL
, 0, iter_vals
);
632 fetch_and_verify_omap_vals(NULL
, NULL
, NULL
, 0);
634 // write and check for the k/v pairs
635 rados_write_op_t op
= rados_create_write_op();
636 rados_write_op_omap_set(op
, keys
, vals
, lens
, 4);
637 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
638 rados_release_write_op(op
);
640 fetch_and_verify_omap_vals(keys
, vals
, lens
, 4);
642 rados_omap_iter_t iter_keys
;
643 int r_vals
= -1, r_keys
= -1;
644 rop
= rados_create_read_op();
645 rados_read_op_omap_get_vals2(rop
, "", "test", 1, &iter_vals
, NULL
, &r_vals
);
646 rados_read_op_omap_get_keys2(rop
, "test", 1, &iter_keys
, NULL
, &r_keys
);
647 ASSERT_EQ(0, rados_read_op_operate(rop
, ioctx
, obj
, 0));
648 rados_release_read_op(rop
);
649 EXPECT_EQ(0, r_vals
);
650 EXPECT_EQ(0, r_keys
);
651 EXPECT_EQ(1u, rados_omap_iter_size(iter_vals
));
652 EXPECT_EQ(1u, rados_omap_iter_size(iter_keys
));
654 compare_omap_vals(&keys
[2], &vals
[2], &lens
[2], 1, iter_vals
);
655 compare_omap_vals(&keys
[2], &vals
[0], &lens
[0], 1, iter_keys
);
657 // check omap_cmp finds all expected values
658 rop
= rados_create_read_op();
660 for (int i
= 0; i
< 4; ++i
)
661 rados_read_op_omap_cmp(rop
, keys
[i
], LIBRADOS_CMPXATTR_OP_EQ
,
662 vals
[i
], lens
[i
], &rvals
[i
]);
663 EXPECT_EQ(0, rados_read_op_operate(rop
, ioctx
, obj
, 0));
664 rados_release_read_op(rop
);
665 for (int i
= 0; i
< 4; ++i
)
666 EXPECT_EQ(0, rvals
[i
]);
668 // try to remove keys with a guard that should fail
669 op
= rados_create_write_op();
670 rados_write_op_omap_cmp(op
, keys
[2], LIBRADOS_CMPXATTR_OP_LT
,
671 vals
[2], lens
[2], &r_vals
);
672 rados_write_op_omap_rm_keys(op
, keys
, 2);
673 EXPECT_EQ(-ECANCELED
, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
674 rados_release_write_op(op
);
676 // see http://tracker.ceph.com/issues/19518
677 //ASSERT_EQ(-ECANCELED, r_vals);
679 // verifying the keys are still there, and then remove them
680 op
= rados_create_write_op();
681 rados_write_op_omap_cmp(op
, keys
[0], LIBRADOS_CMPXATTR_OP_EQ
,
682 vals
[0], lens
[0], NULL
);
683 rados_write_op_omap_cmp(op
, keys
[1], LIBRADOS_CMPXATTR_OP_EQ
,
684 vals
[1], lens
[1], NULL
);
685 rados_write_op_omap_rm_keys(op
, keys
, 2);
686 EXPECT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
687 rados_release_write_op(op
);
689 fetch_and_verify_omap_vals(&keys
[2], &vals
[2], &lens
[2], 2);
691 // clear the rest and check there are none left
692 op
= rados_create_write_op();
693 rados_write_op_omap_clear(op
);
694 EXPECT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
695 rados_release_write_op(op
);
697 fetch_and_verify_omap_vals(NULL
, NULL
, NULL
, 0);
702 TEST_F(CReadOpsTest
, OmapNuls
) {
703 char *keys
[] = {(char*)"1\0bar",
706 char *vals
[] = {(char*)"_\0var",
709 size_t nklens
[] = {5, 6, 7};
710 size_t nvlens
[] = {5, 6, 8};
711 const int paircount
= 3;
713 // check for -ENOENT before the object exists and when it exists
714 // with no omap entries
715 rados_omap_iter_t iter_vals
;
716 rados_read_op_t rop
= rados_create_read_op();
717 rados_read_op_omap_get_vals2(rop
, "", "", 10, &iter_vals
, NULL
, NULL
);
718 ASSERT_EQ(-ENOENT
, rados_read_op_operate(rop
, ioctx
, obj
, 0));
719 rados_release_read_op(rop
);
720 compare_omap_vals(NULL
, NULL
, NULL
, 0, iter_vals
);
724 fetch_and_verify_omap_vals(NULL
, NULL
, NULL
, 0);
726 // write and check for the k/v pairs
727 rados_write_op_t op
= rados_create_write_op();
728 rados_write_op_omap_set2(op
, keys
, vals
, nklens
, nvlens
, paircount
);
729 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
730 rados_release_write_op(op
);
732 fetch_and_verify_omap_vals2(keys
, vals
, nklens
, nvlens
, paircount
);
734 // check omap_cmp finds all expected values
735 rop
= rados_create_read_op();
737 for (int i
= 0; i
< paircount
; ++i
)
738 rados_read_op_omap_cmp2(rop
, keys
[i
], LIBRADOS_CMPXATTR_OP_EQ
,
739 vals
[i
], nklens
[i
], nvlens
[i
], &rvals
[i
]);
740 EXPECT_EQ(0, rados_read_op_operate(rop
, ioctx
, obj
, 0));
741 rados_release_read_op(rop
);
742 for (int i
= 0; i
< paircount
; ++i
)
743 EXPECT_EQ(0, rvals
[i
]);
745 // try to remove keys with a guard that should fail
747 op
= rados_create_write_op();
748 rados_write_op_omap_cmp2(op
, keys
[2], LIBRADOS_CMPXATTR_OP_LT
,
749 vals
[2], nklens
[2], nvlens
[2], &r_vals
);
750 rados_write_op_omap_rm_keys(op
, keys
, 2);
751 EXPECT_EQ(-ECANCELED
, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
752 rados_release_write_op(op
);
754 // verifying the keys are still there, and then remove them
755 op
= rados_create_write_op();
756 rados_write_op_omap_cmp2(op
, keys
[0], LIBRADOS_CMPXATTR_OP_EQ
,
757 vals
[0], nklens
[0], nvlens
[0], NULL
);
758 rados_write_op_omap_cmp2(op
, keys
[1], LIBRADOS_CMPXATTR_OP_EQ
,
759 vals
[1], nklens
[1], nvlens
[1], NULL
);
760 rados_write_op_omap_rm_keys2(op
, keys
, nklens
, 2);
761 EXPECT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
762 rados_release_write_op(op
);
764 fetch_and_verify_omap_vals2(&keys
[2], &vals
[2], &nklens
[2], &nvlens
[2], 1);
766 // clear the rest and check there are none left
767 op
= rados_create_write_op();
768 rados_write_op_omap_clear(op
);
769 EXPECT_EQ(0, rados_write_op_operate(op
, ioctx
, obj
, NULL
, 0));
770 rados_release_write_op(op
);
772 fetch_and_verify_omap_vals(NULL
, NULL
, NULL
, 0);
776 TEST_F(CReadOpsTest
, GetXattrs
) {
779 char *keys
[] = {(char*)"bar",
783 char *vals
[] = {(char*)"",
787 size_t lens
[] = {0, 1, 3, 6};
790 rados_read_op_t op
= rados_create_read_op();
791 rados_xattrs_iter_t it
;
792 rados_read_op_getxattrs(op
, &it
, &rval
);
793 EXPECT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
795 rados_release_read_op(op
);
796 compare_xattrs(keys
, vals
, lens
, 0, it
);
798 for (int i
= 0; i
< 4; ++i
)
799 rados_setxattr(ioctx
, obj
, keys
[i
], vals
[i
], lens
[i
]);
802 op
= rados_create_read_op();
803 rados_read_op_getxattrs(op
, &it
, &rval
);
804 EXPECT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
806 rados_release_read_op(op
);
807 compare_xattrs(keys
, vals
, lens
, 4, it
);
812 TEST_F(CReadOpsTest
, CmpExt
) {
814 size_t bytes_read
= 0;
820 // cmpext with match should ensure that the following read is successful
821 rados_read_op_t op
= rados_create_read_op();
823 // @obj, @data and @len correspond to object initialised by write_object()
824 rados_read_op_cmpext(op
, data
, len
, 0, &cmpext_val
);
825 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, &read_val
);
826 ASSERT_EQ(0, rados_read_op_operate(op
, ioctx
, obj
, 0));
827 ASSERT_EQ(len
, bytes_read
);
828 ASSERT_EQ(0, memcmp(data
, buf
, len
));
829 ASSERT_EQ(cmpext_val
, 0);
830 rados_release_read_op(op
);
832 // cmpext with mismatch should fail and fill mismatch_buf accordingly
833 memset(buf
, 0, sizeof(buf
));
837 op
= rados_create_read_op();
839 // @obj, @data and @len correspond to object initialised by write_object()
840 rados_read_op_cmpext(op
, "mismatch", strlen("mismatch"), 0, &cmpext_val
);
841 rados_read_op_read(op
, 0, len
, buf
, &bytes_read
, &read_val
);
842 ASSERT_EQ(-MAX_ERRNO
, rados_read_op_operate(op
, ioctx
, obj
, 0));
843 rados_release_read_op(op
);
845 ASSERT_EQ(-MAX_ERRNO
, cmpext_val
);