1 // Tests for the C API coverage of atomic write operations
4 #include "include/err.h"
5 #include "include/rados/librados.h"
6 #include "test/librados/test.h"
7 #include "gtest/gtest.h"
9 TEST(LibradosCWriteOps
, NewDelete
) {
10 rados_write_op_t op
= rados_create_write_op();
12 rados_release_write_op(op
);
15 TEST(LibRadosCWriteOps
, assertExists
) {
18 std::string pool_name
= get_temp_pool_name();
19 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
20 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
22 rados_write_op_t op
= rados_create_write_op();
24 rados_write_op_assert_exists(op
);
27 ASSERT_EQ(-2, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
28 rados_release_write_op(op
);
30 rados_write_op_t op2
= rados_create_write_op();
32 rados_write_op_assert_exists(op2
);
34 rados_completion_t completion
;
35 ASSERT_EQ(0, rados_aio_create_completion(NULL
, NULL
, NULL
, &completion
));
36 ASSERT_EQ(0, rados_aio_write_op_operate(op2
, ioctx
, completion
, "test", NULL
, 0));
37 rados_aio_wait_for_complete(completion
);
38 ASSERT_EQ(-2, rados_aio_get_return_value(completion
));
39 rados_aio_release(completion
);
41 rados_ioctx_destroy(ioctx
);
42 rados_release_write_op(op2
);
43 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
46 TEST(LibRadosCWriteOps
, WriteOpAssertVersion
) {
49 std::string pool_name
= get_temp_pool_name();
50 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
51 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
53 rados_write_op_t op
= rados_create_write_op();
55 rados_write_op_create(op
, LIBRADOS_CREATE_EXCLUSIVE
, NULL
);
56 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
57 rados_release_write_op(op
);
59 // Write to the object a second time to guarantee that its
60 // version number is greater than 0
61 op
= rados_create_write_op();
63 rados_write_op_write_full(op
, "hi", 2);
64 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
65 rados_release_write_op(op
);
67 uint64_t v
= rados_get_last_version(ioctx
);
69 op
= rados_create_write_op();
71 rados_write_op_assert_version(op
, v
+1);
72 ASSERT_EQ(-EOVERFLOW
, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
73 rados_release_write_op(op
);
75 op
= rados_create_write_op();
77 rados_write_op_assert_version(op
, v
-1);
78 ASSERT_EQ(-ERANGE
, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
79 rados_release_write_op(op
);
81 op
= rados_create_write_op();
83 rados_write_op_assert_version(op
, v
);
84 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
85 rados_release_write_op(op
);
87 rados_ioctx_destroy(ioctx
);
88 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
91 TEST(LibRadosCWriteOps
, Xattrs
) {
94 std::string pool_name
= get_temp_pool_name();
95 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
96 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
98 // Create an object with an xattr
99 rados_write_op_t op
= rados_create_write_op();
101 rados_write_op_create(op
, LIBRADOS_CREATE_EXCLUSIVE
, NULL
);
102 rados_write_op_setxattr(op
, "key", "value", 5);
103 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
104 rados_release_write_op(op
);
106 // Check that xattr exists, if it does, delete it.
107 op
= rados_create_write_op();
109 rados_write_op_create(op
, LIBRADOS_CREATE_IDEMPOTENT
, NULL
);
110 rados_write_op_cmpxattr(op
, "key", LIBRADOS_CMPXATTR_OP_EQ
, "value", 5);
111 rados_write_op_rmxattr(op
, "key");
112 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
113 rados_release_write_op(op
);
115 // Check the xattr exits, if it does, add it again (will fail) with -125
117 op
= rados_create_write_op();
119 rados_write_op_cmpxattr(op
, "key", LIBRADOS_CMPXATTR_OP_EQ
, "value", 5);
120 rados_write_op_setxattr(op
, "key", "value", 5);
121 ASSERT_EQ(-ECANCELED
, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
123 rados_release_write_op(op
);
124 rados_ioctx_destroy(ioctx
);
125 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
128 TEST(LibRadosCWriteOps
, Write
) {
131 std::string pool_name
= get_temp_pool_name();
132 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
133 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
135 // Create an object, write and write full to it
136 rados_write_op_t op
= rados_create_write_op();
138 rados_write_op_create(op
, LIBRADOS_CREATE_EXCLUSIVE
, NULL
);
139 rados_write_op_write(op
, "four", 4, 0);
140 rados_write_op_write_full(op
, "hi", 2);
141 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
143 ASSERT_EQ(2, rados_read(ioctx
, "test", hi
, 4, 0));
144 rados_release_write_op(op
);
146 //create write op with iohint
147 op
= rados_create_write_op();
149 rados_write_op_write_full(op
, "ceph", 4);
150 rados_write_op_set_flags(op
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
151 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
152 ASSERT_EQ(4, rados_read(ioctx
, "test", hi
, 4, 0));
153 rados_release_write_op(op
);
155 // Truncate and append
156 op
= rados_create_write_op();
158 rados_write_op_truncate(op
, 1);
159 rados_write_op_append(op
, "hi", 2);
160 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
161 ASSERT_EQ(3, rados_read(ioctx
, "test", hi
, 4, 0));
162 rados_release_write_op(op
);
165 op
= rados_create_write_op();
167 rados_write_op_zero(op
, 0, 3);
168 rados_write_op_remove(op
);
169 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
171 ASSERT_EQ(-2, rados_read(ioctx
, "test", hi
, 4, 0));
172 rados_release_write_op(op
);
174 rados_ioctx_destroy(ioctx
);
175 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
178 TEST(LibRadosCWriteOps
, Exec
) {
181 std::string pool_name
= get_temp_pool_name();
182 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
183 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
186 rados_write_op_t op
= rados_create_write_op();
187 rados_write_op_exec(op
, "hello", "record_hello", "test", 4, &rval
);
188 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
189 rados_release_write_op(op
);
193 ASSERT_EQ(12, rados_read(ioctx
, "test", hi
, 100, 0));
195 ASSERT_EQ(0, strcmp("Hello, test!", hi
));
197 rados_ioctx_destroy(ioctx
);
198 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
201 TEST(LibRadosCWriteOps
, WriteSame
) {
204 std::string pool_name
= get_temp_pool_name();
205 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
206 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
208 // Create an object, write to it using writesame
209 rados_write_op_t op
= rados_create_write_op();
211 rados_write_op_create(op
, LIBRADOS_CREATE_EXCLUSIVE
, NULL
);
212 rados_write_op_writesame(op
, "four", 4, 4 * 4, 0);
213 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
215 ASSERT_EQ(sizeof(hi
), static_cast<std::size_t>(
216 rados_read(ioctx
, "test", hi
,sizeof(hi
), 0)));
217 rados_release_write_op(op
);
218 ASSERT_EQ(0, memcmp("fourfourfourfour", hi
, sizeof(hi
)));
221 op
= rados_create_write_op();
223 rados_write_op_remove(op
);
224 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
225 rados_release_write_op(op
);
227 rados_ioctx_destroy(ioctx
);
228 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));
231 TEST(LibRadosCWriteOps
, CmpExt
) {
234 std::string pool_name
= get_temp_pool_name();
235 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
236 rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
);
238 // create an object, write to it using writesame
239 rados_write_op_t op
= rados_create_write_op();
241 rados_write_op_create(op
, LIBRADOS_CREATE_EXCLUSIVE
, NULL
);
242 rados_write_op_write(op
, "four", 4, 0);
243 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
244 rados_release_write_op(op
);
246 ASSERT_EQ(sizeof(hi
), static_cast<std::size_t>(rados_read(ioctx
, "test", hi
, sizeof(hi
), 0)));
247 ASSERT_EQ(0, memcmp("four", hi
, sizeof(hi
)));
249 // compare and overwrite on (expected) match
251 op
= rados_create_write_op();
253 rados_write_op_cmpext(op
, "four", 4, 0, &val
);
254 rados_write_op_write(op
, "five", 4, 0);
255 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
257 rados_release_write_op(op
);
258 ASSERT_EQ(sizeof(hi
), static_cast<std::size_t>(rados_read(ioctx
, "test", hi
, sizeof(hi
), 0)));
259 ASSERT_EQ(0, memcmp("five", hi
, sizeof(hi
)));
261 // compare and bail before write due to mismatch
263 op
= rados_create_write_op();
265 rados_write_op_cmpext(op
, "four", 4, 0, &val
);
266 rados_write_op_write(op
, "six ", 4, 0);
267 ASSERT_EQ(-MAX_ERRNO
- 1, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
269 ASSERT_EQ(-MAX_ERRNO
- 1, val
);
272 op
= rados_create_write_op();
274 rados_write_op_remove(op
);
275 ASSERT_EQ(0, rados_write_op_operate(op
, ioctx
, "test", NULL
, 0));
277 rados_ioctx_destroy(ioctx
);
278 ASSERT_EQ(0, destroy_one_pool(pool_name
, &cluster
));