]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados/c_read_operations.cc
d3d8e772cbcfe96e213b81b6cc0bae44c366758b
[ceph.git] / ceph / src / test / librados / c_read_operations.cc
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
3
4 #include <cstring> // For memcpy
5 #include <errno.h>
6 #include <string>
7
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"
16
17 const char *data = "testdata";
18 const char *obj = "testobj";
19 const size_t len = strlen(data);
20
21 class CReadOpsTest : public RadosTest {
22 protected:
23 void write_object() {
24 // Create an object and write to it
25 ASSERT_EQ(0, rados_write(ioctx, obj, data, len, 0));
26 }
27 void remove_object() {
28 ASSERT_EQ(0, rados_remove(ioctx, obj));
29 }
30 int cmp_xattr(const char *xattr, const char *value, size_t value_len,
31 uint8_t cmp_op)
32 {
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);
37 return r;
38 }
39
40 void fetch_and_verify_omap_vals(char const* const* keys,
41 char const* const* vals,
42 const size_t *lens,
43 size_t len)
44 {
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);
54 ASSERT_EQ(0, r_vals);
55 ASSERT_EQ(0, r_keys);
56 ASSERT_EQ(0, r_vals_by_key);
57
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);
65 }
66
67 void compare_omap_vals(char const* const* keys,
68 char const* const* vals,
69 const size_t *lens,
70 size_t len,
71 rados_omap_iter_t iter)
72 {
73 size_t i = 0;
74 char *key = NULL;
75 char *val = NULL;
76 size_t val_len = 0;
77 ASSERT_EQ(len, rados_omap_iter_size(iter));
78 while (i < len) {
79 ASSERT_EQ(0, rados_omap_get_next(iter, &key, &val, &val_len));
80 if (val_len == 0 && key == NULL && val == NULL)
81 break;
82 if (key)
83 EXPECT_EQ(std::string(keys[i]), std::string(key));
84 else
85 EXPECT_EQ(keys[i], key);
86 ASSERT_EQ(0, memcmp(vals[i], val, val_len));
87 ASSERT_EQ(lens[i], val_len);
88 ++i;
89 }
90 ASSERT_EQ(i, 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);
96 }
97
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,
103 size_t len)
104 {
105 rados_omap_iter_t iter_vals_by_key;
106 int r_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);
113
114 compare_omap_vals2(keys, vals, keylens, vallens, len, iter_vals_by_key);
115 }
116
117 void compare_omap_vals2(char const* const* keys,
118 char const* const* vals,
119 const size_t *keylens,
120 const size_t *vallens,
121 size_t len,
122 rados_omap_iter_t iter)
123 {
124 size_t i = 0;
125 char *key = NULL;
126 char *val = NULL;
127 size_t key_len = 0;
128 size_t val_len = 0;
129 ASSERT_EQ(len, rados_omap_iter_size(iter));
130 while (i < len) {
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)
133 break;
134 if (key)
135 EXPECT_EQ(std::string(keys[i], keylens[i]), std::string(key, key_len));
136 else
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));
141 ++i;
142 }
143 ASSERT_EQ(i, 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);
150 }
151
152 void compare_xattrs(char const* const* keys,
153 char const* const* vals,
154 const size_t *lens,
155 size_t len,
156 rados_xattrs_iter_t iter)
157 {
158 size_t i = 0;
159 char *key = NULL;
160 char *val = NULL;
161 size_t val_len = 0;
162 while (i < len) {
163 ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**) &key,
164 (const char**) &val, &val_len));
165 if (key == NULL)
166 break;
167 EXPECT_EQ(std::string(keys[i]), std::string(key));
168 if (val != NULL) {
169 EXPECT_EQ(0, memcmp(vals[i], val, val_len));
170 }
171 EXPECT_EQ(lens[i], val_len);
172 ++i;
173 }
174 ASSERT_EQ(i, 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);
181 }
182 };
183
184 TEST_F(CReadOpsTest, NewDelete) {
185 rados_read_op_t op = rados_create_read_op();
186 ASSERT_TRUE(op);
187 rados_release_read_op(op);
188 }
189
190 TEST_F(CReadOpsTest, SetOpFlags) {
191 write_object();
192
193 rados_read_op_t op = rados_create_read_op();
194 size_t bytes_read = 0;
195 char *out = NULL;
196 int rval = 0;
197 rados_read_op_exec(op, "rbd", "get_id", NULL, 0, &out,
198 &bytes_read, &rval);
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);
205
206 remove_object();
207 }
208
209 TEST_F(CReadOpsTest, AssertExists) {
210 rados_read_op_t op = rados_create_read_op();
211 rados_read_op_assert_exists(op);
212
213 ASSERT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0));
214 rados_release_read_op(op);
215
216 op = rados_create_read_op();
217 rados_read_op_assert_exists(op);
218
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);
226
227 write_object();
228
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);
233
234 remove_object();
235 }
236
237 TEST_F(CReadOpsTest, AssertVersion) {
238 write_object();
239 // Write to the object a second time to guarantee that its
240 // version number is greater than 0
241 write_object();
242 uint64_t v = rados_get_last_version(ioctx);
243
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);
248
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);
253
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);
258
259 remove_object();
260 }
261
262 TEST_F(CReadOpsTest, CmpXattr) {
263 write_object();
264
265 char buf[len];
266 memset(buf, 0xcc, sizeof(buf));
267
268 const char *xattr = "test";
269 rados_setxattr(ioctx, obj, xattr, buf, sizeof(buf));
270
271 // equal value
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));
278
279 // < value
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));
286
287 // > value
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));
295
296 // check that null bytes are compared correctly
297 rados_setxattr(ioctx, obj, xattr, "\0\0", 2);
298 buf[0] = '\0';
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));
305
306 buf[1] = '\0';
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));
313
314 remove_object();
315 }
316
317 TEST_F(CReadOpsTest, Read) {
318 write_object();
319
320 char buf[len];
321 // check that using read_ops returns the same data with
322 // or without bytes_read and rval out params
323 {
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);
329 }
330
331 {
332 rados_read_op_t op = rados_create_read_op();
333 int rval;
334 rados_read_op_read(op, 0, len, buf, NULL, &rval);
335 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
336 ASSERT_EQ(0, rval);
337 ASSERT_EQ(0, memcmp(data, buf, len));
338 rados_release_read_op(op);
339 }
340
341 {
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);
349 }
350
351 {
352 rados_read_op_t op = rados_create_read_op();
353 size_t bytes_read = 0;
354 int rval;
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);
358 ASSERT_EQ(0, rval);
359 ASSERT_EQ(0, memcmp(data, buf, len));
360 rados_release_read_op(op);
361 }
362
363 {
364 rados_read_op_t op = rados_create_read_op();
365 size_t bytes_read = 0;
366 int rval;
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);
371 ASSERT_EQ(0, rval);
372 ASSERT_EQ(0, memcmp(data, buf, len));
373 rados_release_read_op(op);
374 }
375
376 remove_object();
377 }
378
379 TEST_F(CReadOpsTest, Checksum) {
380 write_object();
381
382 {
383 rados_read_op_t op = rados_create_read_op();
384 uint64_t 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);
390 }
391
392 {
393 uint32_t init_value = -1;
394 uint32_t crc[2];
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),
400 nullptr);
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);
407 }
408
409 {
410 uint32_t init_value = -1;
411 int rval;
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));
417 ASSERT_EQ(0, rval);
418 rados_release_read_op(op);
419 }
420
421 {
422 uint32_t init_value = -1;
423 uint32_t crc[3];
424 int rval;
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]);
439 ASSERT_EQ(0, rval);
440 rados_release_read_op(op);
441 }
442
443 remove_object();
444 }
445
446 TEST_F(CReadOpsTest, RWOrderedRead) {
447 write_object();
448
449 char buf[len];
450 rados_read_op_t op = rados_create_read_op();
451 size_t bytes_read = 0;
452 int rval;
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);
458 ASSERT_EQ(0, rval);
459 ASSERT_EQ(0, memcmp(data, buf, len));
460 rados_release_read_op(op);
461
462 remove_object();
463 }
464
465 TEST_F(CReadOpsTest, ShortRead) {
466 write_object();
467
468 char buf[len * 2];
469 // check that using read_ops returns the same data with
470 // or without bytes_read and rval out params
471 {
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);
477 }
478
479 {
480 rados_read_op_t op = rados_create_read_op();
481 int rval;
482 rados_read_op_read(op, 0, len * 2, buf, NULL, &rval);
483 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
484 ASSERT_EQ(0, rval);
485 ASSERT_EQ(0, memcmp(data, buf, len));
486 rados_release_read_op(op);
487 }
488
489 {
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);
497 }
498
499 {
500 rados_read_op_t op = rados_create_read_op();
501 size_t bytes_read = 0;
502 int rval;
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);
506 ASSERT_EQ(0, rval);
507 ASSERT_EQ(0, memcmp(data, buf, len));
508 rados_release_read_op(op);
509 }
510
511 remove_object();
512 }
513
514 TEST_F(CReadOpsTest, Exec) {
515 // create object so we don't get -ENOENT
516 write_object();
517
518 rados_read_op_t op = rados_create_read_op();
519 ASSERT_TRUE(op);
520 size_t bytes_read = 0;
521 char *out = NULL;
522 int rval = 0;
523 rados_read_op_exec(op, "rbd", "get_all_features", NULL, 0, &out,
524 &bytes_read, &rval);
525 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
526 rados_release_read_op(op);
527 EXPECT_EQ(0, rval);
528 EXPECT_TRUE(out);
529 uint64_t features;
530 EXPECT_EQ(sizeof(features), bytes_read);
531 // make sure buffer is at least as long as it claims
532 bufferlist bl;
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);
538
539 remove_object();
540 }
541
542 TEST_F(CReadOpsTest, ExecUserBuf) {
543 // create object so we don't get -ENOENT
544 write_object();
545
546 rados_read_op_t op = rados_create_read_op();
547 size_t bytes_read = 0;
548 uint64_t features;
549 char out[sizeof(features)];
550 int rval = 0;
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);
555 EXPECT_EQ(0, rval);
556 EXPECT_EQ(sizeof(features), bytes_read);
557
558 // buffer too short
559 bytes_read = 1024;
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);
567
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);
574
575 remove_object();
576 }
577
578 TEST_F(CReadOpsTest, Stat) {
579 rados_read_op_t op = rados_create_read_op();
580 uint64_t size = 1;
581 int rval;
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);
585 EXPECT_EQ(1u, size);
586 rados_release_read_op(op);
587
588 write_object();
589
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));
593 EXPECT_EQ(0, rval);
594 EXPECT_EQ(len, size);
595 rados_release_read_op(op);
596
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);
601
602 remove_object();
603
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);
608 }
609
610 TEST_F(CReadOpsTest, Omap) {
611 char *keys[] = {(char*)"bar",
612 (char*)"foo",
613 (char*)"test1",
614 (char*)"test2"};
615 char *vals[] = {(char*)"",
616 (char*)"\0",
617 (char*)"abc",
618 (char*)"va\0lue"};
619 size_t lens[] = {0, 1, 3, 6};
620
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);
629
630 write_object();
631
632 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
633
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);
639
640 fetch_and_verify_omap_vals(keys, vals, lens, 4);
641
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));
653
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);
656
657 // check omap_cmp finds all expected values
658 rop = rados_create_read_op();
659 int rvals[4];
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]);
667
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);
675
676 // see http://tracker.ceph.com/issues/19518
677 //ASSERT_EQ(-ECANCELED, r_vals);
678
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);
688
689 fetch_and_verify_omap_vals(&keys[2], &vals[2], &lens[2], 2);
690
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);
696
697 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
698
699 remove_object();
700 }
701
702 TEST_F(CReadOpsTest, OmapNuls) {
703 char *keys[] = {(char*)"1\0bar",
704 (char*)"2baar\0",
705 (char*)"3baa\0rr"};
706 char *vals[] = {(char*)"_\0var",
707 (char*)"_vaar\0",
708 (char*)"__vaa\0rr"};
709 size_t nklens[] = {5, 6, 7};
710 size_t nvlens[] = {5, 6, 8};
711 const int paircount = 3;
712
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);
721
722 write_object();
723
724 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
725
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);
731
732 fetch_and_verify_omap_vals2(keys, vals, nklens, nvlens, paircount);
733
734 // check omap_cmp finds all expected values
735 rop = rados_create_read_op();
736 int rvals[4];
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]);
744
745 // try to remove keys with a guard that should fail
746 int r_vals = -1;
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);
753
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);
763
764 fetch_and_verify_omap_vals2(&keys[2], &vals[2], &nklens[2], &nvlens[2], 1);
765
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);
771
772 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
773
774 remove_object();
775 }
776 TEST_F(CReadOpsTest, GetXattrs) {
777 write_object();
778
779 char *keys[] = {(char*)"bar",
780 (char*)"foo",
781 (char*)"test1",
782 (char*)"test2"};
783 char *vals[] = {(char*)"",
784 (char*)"\0",
785 (char*)"abc",
786 (char*)"va\0lue"};
787 size_t lens[] = {0, 1, 3, 6};
788
789 int rval = 1;
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));
794 EXPECT_EQ(0, rval);
795 rados_release_read_op(op);
796 compare_xattrs(keys, vals, lens, 0, it);
797
798 for (int i = 0; i < 4; ++i)
799 rados_setxattr(ioctx, obj, keys[i], vals[i], lens[i]);
800
801 rval = 1;
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));
805 EXPECT_EQ(0, rval);
806 rados_release_read_op(op);
807 compare_xattrs(keys, vals, lens, 4, it);
808
809 remove_object();
810 }
811
812 TEST_F(CReadOpsTest, CmpExt) {
813 char buf[len];
814 size_t bytes_read = 0;
815 int cmpext_val = 0;
816 int read_val = 0;
817
818 write_object();
819
820 // cmpext with match should ensure that the following read is successful
821 rados_read_op_t op = rados_create_read_op();
822 ASSERT_TRUE(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);
831
832 // cmpext with mismatch should fail and fill mismatch_buf accordingly
833 memset(buf, 0, sizeof(buf));
834 bytes_read = 0;
835 cmpext_val = 0;
836 read_val = 0;
837 op = rados_create_read_op();
838 ASSERT_TRUE(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);
844
845 ASSERT_EQ(-MAX_ERRNO, cmpext_val);
846
847 remove_object();
848 }