1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "include/rados/librados.h"
4 #include "include/rados/librados.hpp"
5 #include "include/stringify.h"
6 #include "test/librados/test.h"
7 #include "test/librados/test_common.h"
8 #include "test/librados/TestCase.h"
9 #include "global/global_context.h"
11 #include "include/types.h"
12 #include "common/hobject.h"
13 #include "gtest/gtest.h"
18 using namespace librados
;
20 typedef RadosTestNSCleanup LibRadosList
;
21 typedef RadosTestPPNSCleanup LibRadosListPP
;
22 typedef RadosTestECNSCleanup LibRadosListEC
;
23 typedef RadosTestECPPNSCleanup LibRadosListECPP
;
24 typedef RadosTestNP LibRadosListNP
;
27 TEST_F(LibRadosList
, ListObjects
) {
29 memset(buf
, 0xcc, sizeof(buf
));
30 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
32 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
35 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
37 ASSERT_EQ(std::string(entry
), "foo");
40 rados_nobjects_list_close(ctx
);
43 TEST_F(LibRadosListPP
, ListObjectsPP
) {
45 memset(buf
, 0xcc, sizeof(buf
));
47 bl1
.append(buf
, sizeof(buf
));
48 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
49 NObjectIterator
iter(ioctx
.nobjects_begin());
51 while (iter
!= ioctx
.nobjects_end()) {
53 ASSERT_EQ((*iter
).get_oid(), "foo");
59 TEST_F(LibRadosListPP
, ListObjectsTwicePP
) {
61 memset(buf
, 0xcc, sizeof(buf
));
63 bl1
.append(buf
, sizeof(buf
));
64 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
65 NObjectIterator
iter(ioctx
.nobjects_begin());
67 while (iter
!= ioctx
.nobjects_end()) {
69 ASSERT_EQ((*iter
).get_oid(), "foo");
74 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
77 while (iter
!= ioctx
.nobjects_end()) {
79 ASSERT_EQ((*iter
).get_oid(), "foo");
85 TEST_F(LibRadosListPP
, ListObjectsCopyIterPP
) {
87 memset(buf
, 0xcc, sizeof(buf
));
89 bl1
.append(buf
, sizeof(buf
));
90 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
92 // make sure this is still valid after the original iterators are gone
93 NObjectIterator iter3
;
95 NObjectIterator
iter(ioctx
.nobjects_begin());
96 NObjectIterator
iter2(iter
);
98 ASSERT_EQ((*iter
).get_oid(), "foo");
100 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
102 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
104 ASSERT_EQ(iter2
->get_oid(), "foo");
105 ASSERT_EQ(iter3
->get_oid(), "foo");
107 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
110 ASSERT_EQ(iter3
->get_oid(), "foo");
112 ASSERT_EQ(iter3
->get_oid(), "foo");
114 ASSERT_TRUE(iter3
== ioctx
.nobjects_end());
117 TEST_F(LibRadosListPP
, ListObjectsEndIter
) {
119 memset(buf
, 0xcc, sizeof(buf
));
121 bl1
.append(buf
, sizeof(buf
));
122 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
124 NObjectIterator
iter(ioctx
.nobjects_begin());
125 NObjectIterator
iter_end(ioctx
.nobjects_end());
126 NObjectIterator iter_end2
= ioctx
.nobjects_end();
127 ASSERT_TRUE(iter_end
== iter_end2
);
128 ASSERT_TRUE(iter_end
== ioctx
.nobjects_end());
129 ASSERT_TRUE(iter_end2
== ioctx
.nobjects_end());
131 ASSERT_EQ(iter
->get_oid(), "foo");
133 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
134 ASSERT_TRUE(iter
== iter_end
);
135 ASSERT_TRUE(iter
== iter_end2
);
136 NObjectIterator iter2
= iter
;
137 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
138 ASSERT_TRUE(iter2
== iter_end
);
139 ASSERT_TRUE(iter2
== iter_end2
);
142 static void check_list(
143 std::set
<std::string
>& myset
,
144 rados_list_ctx_t
& ctx
,
145 std::string check_nspace
)
147 const char *entry
, *nspace
;
148 cout
<< "myset " << myset
<< std::endl
;
149 // we should see every item exactly once.
151 while ((ret
= rados_nobjects_list_next(ctx
, &entry
, NULL
, &nspace
)) == 0) {
152 std::string test_name
;
153 if (check_nspace
== all_nspaces
) {
154 test_name
= std::string(nspace
) + ":" + std::string(entry
);
156 ASSERT_TRUE(std::string(nspace
) == check_nspace
);
157 test_name
= std::string(entry
);
159 cout
<< test_name
<< std::endl
;
161 ASSERT_TRUE(myset
.end() != myset
.find(test_name
));
162 myset
.erase(test_name
);
164 ASSERT_EQ(-ENOENT
, ret
);
165 ASSERT_TRUE(myset
.empty());
168 TEST_F(LibRadosList
, ListObjectsNS
) {
170 memset(buf
, 0xcc, sizeof(buf
));
171 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
172 rados_ioctx_set_namespace(ioctx
, "");
173 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
174 rados_ioctx_set_namespace(ioctx
, "ns1");
175 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
176 rados_ioctx_set_namespace(ioctx
, "");
177 ASSERT_EQ(0, rados_write(ioctx
, "foo2", buf
, sizeof(buf
), 0));
178 ASSERT_EQ(0, rados_write(ioctx
, "foo3", buf
, sizeof(buf
), 0));
179 rados_ioctx_set_namespace(ioctx
, "ns1");
180 ASSERT_EQ(0, rados_write(ioctx
, "foo4", buf
, sizeof(buf
), 0));
181 ASSERT_EQ(0, rados_write(ioctx
, "foo5", buf
, sizeof(buf
), 0));
182 rados_ioctx_set_namespace(ioctx
, "ns2");
183 ASSERT_EQ(0, rados_write(ioctx
, "foo6", buf
, sizeof(buf
), 0));
184 ASSERT_EQ(0, rados_write(ioctx
, "foo7", buf
, sizeof(buf
), 0));
186 std::set
<std::string
> def
, ns1
, ns2
, all
;
187 def
.insert(std::string("foo1"));
188 def
.insert(std::string("foo2"));
189 def
.insert(std::string("foo3"));
190 ns1
.insert(std::string("foo1"));
191 ns1
.insert(std::string("foo4"));
192 ns1
.insert(std::string("foo5"));
193 ns2
.insert(std::string("foo6"));
194 ns2
.insert(std::string("foo7"));
195 all
.insert(std::string(":foo1"));
196 all
.insert(std::string(":foo2"));
197 all
.insert(std::string(":foo3"));
198 all
.insert(std::string("ns1:foo1"));
199 all
.insert(std::string("ns1:foo4"));
200 all
.insert(std::string("ns1:foo5"));
201 all
.insert(std::string("ns2:foo6"));
202 all
.insert(std::string("ns2:foo7"));
204 rados_list_ctx_t ctx
;
205 // Check default namespace ""
206 rados_ioctx_set_namespace(ioctx
, "");
207 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
208 check_list(def
, ctx
, "");
209 rados_nobjects_list_close(ctx
);
211 // Check namespace "ns1"
212 rados_ioctx_set_namespace(ioctx
, "ns1");
213 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
214 check_list(ns1
, ctx
, "ns1");
215 rados_nobjects_list_close(ctx
);
217 // Check namespace "ns2"
218 rados_ioctx_set_namespace(ioctx
, "ns2");
219 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
220 check_list(ns2
, ctx
, "ns2");
221 rados_nobjects_list_close(ctx
);
223 // Check ALL namespaces
224 rados_ioctx_set_namespace(ioctx
, LIBRADOS_ALL_NSPACES
);
225 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
226 check_list(all
, ctx
, all_nspaces
);
227 rados_nobjects_list_close(ctx
);
230 static void check_listpp(std::set
<std::string
>& myset
, IoCtx
& ioctx
, std::string check_nspace
)
232 NObjectIterator
iter(ioctx
.nobjects_begin());
233 std::set
<std::string
> orig_set(myset
);
235 * During splitting, we might see duplicate items.
236 * We assert that every object returned is in myset and that
237 * we don't hit ENOENT until we have hit every item in myset
240 while (iter
!= ioctx
.nobjects_end()) {
241 std::string test_name
;
242 if (check_nspace
== all_nspaces
) {
243 test_name
= iter
->get_nspace() + ":" + iter
->get_oid();
245 ASSERT_TRUE(iter
->get_nspace() == check_nspace
);
246 test_name
= iter
->get_oid();
248 ASSERT_TRUE(orig_set
.end() != orig_set
.find(test_name
));
249 myset
.erase(test_name
);
252 ASSERT_TRUE(myset
.empty());
255 TEST_F(LibRadosListPP
, ListObjectsPPNS
) {
257 memset(buf
, 0xcc, sizeof(buf
));
259 bl1
.append(buf
, sizeof(buf
));
260 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
261 ioctx
.set_namespace("");
262 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
263 ioctx
.set_namespace("ns1");
264 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
265 ioctx
.set_namespace("");
266 ASSERT_EQ(0, ioctx
.write("foo2", bl1
, sizeof(buf
), 0));
267 ASSERT_EQ(0, ioctx
.write("foo3", bl1
, sizeof(buf
), 0));
268 ioctx
.set_namespace("ns1");
269 ASSERT_EQ(0, ioctx
.write("foo4", bl1
, sizeof(buf
), 0));
270 ASSERT_EQ(0, ioctx
.write("foo5", bl1
, sizeof(buf
), 0));
271 ioctx
.set_namespace("ns2");
272 ASSERT_EQ(0, ioctx
.write("foo6", bl1
, sizeof(buf
), 0));
273 ASSERT_EQ(0, ioctx
.write("foo7", bl1
, sizeof(buf
), 0));
275 std::set
<std::string
> def
, ns1
, ns2
, all
;
276 def
.insert(std::string("foo1"));
277 def
.insert(std::string("foo2"));
278 def
.insert(std::string("foo3"));
279 ns1
.insert(std::string("foo1"));
280 ns1
.insert(std::string("foo4"));
281 ns1
.insert(std::string("foo5"));
282 ns2
.insert(std::string("foo6"));
283 ns2
.insert(std::string("foo7"));
284 all
.insert(std::string(":foo1"));
285 all
.insert(std::string(":foo2"));
286 all
.insert(std::string(":foo3"));
287 all
.insert(std::string("ns1:foo1"));
288 all
.insert(std::string("ns1:foo4"));
289 all
.insert(std::string("ns1:foo5"));
290 all
.insert(std::string("ns2:foo6"));
291 all
.insert(std::string("ns2:foo7"));
293 ioctx
.set_namespace("");
294 check_listpp(def
, ioctx
, "");
296 ioctx
.set_namespace("ns1");
297 check_listpp(ns1
, ioctx
, "ns1");
299 ioctx
.set_namespace("ns2");
300 check_listpp(ns2
, ioctx
, "ns2");
302 ioctx
.set_namespace(all_nspaces
);
303 check_listpp(all
, ioctx
, all_nspaces
);
306 TEST_F(LibRadosListPP
, ListObjectsManyPP
) {
308 memset(buf
, 0xcc, sizeof(buf
));
310 bl
.append(buf
, sizeof(buf
));
312 for (int i
=0; i
<256; ++i
) {
313 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
316 librados::NObjectIterator it
= ioctx
.nobjects_begin();
317 std::set
<std::string
> saw_obj
;
318 std::set
<int> saw_pg
;
319 for (; it
!= ioctx
.nobjects_end(); ++it
) {
320 std::cout
<< it
->get_oid()
321 << " " << it
.get_pg_hash_position() << std::endl
;
322 saw_obj
.insert(it
->get_oid());
323 saw_pg
.insert(it
.get_pg_hash_position());
325 std::cout
<< "saw " << saw_pg
.size() << " pgs " << std::endl
;
327 // make sure they are 0..n
328 for (unsigned i
= 0; i
< saw_pg
.size(); ++i
)
329 ASSERT_TRUE(saw_pg
.count(i
));
332 TEST_F(LibRadosList
, ListObjectsStart
) {
334 memset(buf
, 0xcc, sizeof(buf
));
336 for (int i
=0; i
<16; ++i
) {
337 string n
= stringify(i
);
338 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
341 rados_list_ctx_t ctx
;
342 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
343 std::map
<int, std::set
<std::string
> > pg_to_obj
;
345 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
346 uint32_t pos
= rados_nobjects_list_get_pg_hash_position(ctx
);
347 std::cout
<< entry
<< " " << pos
<< std::endl
;
348 pg_to_obj
[pos
].insert(entry
);
350 rados_nobjects_list_close(ctx
);
352 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
354 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
355 while (p
!= pg_to_obj
.rend()) {
356 ASSERT_EQ((uint32_t)p
->first
, rados_nobjects_list_seek(ctx
, p
->first
));
357 ASSERT_EQ(0, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
358 std::cout
<< "have " << entry
<< " expect one of " << p
->second
<< std::endl
;
359 ASSERT_TRUE(p
->second
.count(entry
));
362 rados_nobjects_list_close(ctx
);
365 TEST_F(LibRadosListPP
, ListObjectsStartPP
) {
367 memset(buf
, 0xcc, sizeof(buf
));
369 bl
.append(buf
, sizeof(buf
));
371 for (int i
=0; i
<16; ++i
) {
372 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
375 librados::NObjectIterator it
= ioctx
.nobjects_begin();
376 std::map
<int, std::set
<std::string
> > pg_to_obj
;
377 for (; it
!= ioctx
.nobjects_end(); ++it
) {
378 std::cout
<< it
->get_oid() << " " << it
.get_pg_hash_position() << std::endl
;
379 pg_to_obj
[it
.get_pg_hash_position()].insert(it
->get_oid());
382 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
384 it
= ioctx
.nobjects_begin(p
->first
);
385 while (p
!= pg_to_obj
.rend()) {
386 ASSERT_EQ((uint32_t)p
->first
, it
.seek(p
->first
));
387 std::cout
<< "have " << it
->get_oid() << " expect one of " << p
->second
<< std::endl
;
388 ASSERT_TRUE(p
->second
.count(it
->get_oid()));
393 TEST_F(LibRadosListPP
, ListObjectsCursorNSPP
) {
395 memset(buf
, 0xcc, sizeof(buf
));
397 bl
.append(buf
, sizeof(buf
));
399 const int max_objs
= 16;
401 map
<string
, string
> oid_to_ns
;
403 for (int i
=0; i
<max_objs
; ++i
) {
406 ioctx
.set_namespace(ss
.str());
407 string oid
= stringify(i
);
408 ASSERT_EQ(0, ioctx
.write(oid
, bl
, bl
.length(), 0));
410 oid_to_ns
[oid
] = ss
.str();
413 ioctx
.set_namespace(all_nspaces
);
415 librados::NObjectIterator it
= ioctx
.nobjects_begin();
416 std::map
<librados::ObjectCursor
, string
> cursor_to_obj
;
420 librados::ObjectCursor seek_cursor
;
422 map
<string
, list
<librados::ObjectCursor
> > ns_to_cursors
;
424 for (it
= ioctx
.nobjects_begin(); it
!= ioctx
.nobjects_end(); ++it
) {
425 librados::ObjectCursor cursor
= it
.get_cursor();
426 string oid
= it
->get_oid();
427 cout
<< "> oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
430 vector
<string
> objs_order
;
432 for (it
= ioctx
.nobjects_begin(); it
!= ioctx
.nobjects_end(); ++it
, ++count
) {
433 librados::ObjectCursor cursor
= it
.get_cursor();
434 string oid
= it
->get_oid();
435 std::cout
<< oid
<< " " << it
.get_pg_hash_position() << std::endl
;
436 cout
<< ": oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
437 cursor_to_obj
[cursor
] = oid
;
439 ASSERT_EQ(oid_to_ns
[oid
], it
->get_nspace());
442 cout
<< ": seek to " << cursor
<< " it.cursor=" << it
.get_cursor() << std::endl
;
443 ASSERT_EQ(oid
, it
->get_oid());
444 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
446 ns_to_cursors
[it
->get_nspace()].push_back(cursor
);
448 if (count
== max_objs
/2) {
449 seek_cursor
= cursor
;
451 objs_order
.push_back(it
->get_oid());
454 ASSERT_EQ(count
, max_objs
);
456 /* check that reading past seek also works */
457 cout
<< "seek_cursor=" << seek_cursor
<< std::endl
;
458 it
.seek(seek_cursor
);
459 for (count
= max_objs
/2; count
< max_objs
; ++count
, ++it
) {
460 ASSERT_EQ(objs_order
[count
], it
->get_oid());
463 /* seek to all cursors, check that we get expected obj */
464 for (auto& niter
: ns_to_cursors
) {
465 const string
& ns
= niter
.first
;
466 list
<librados::ObjectCursor
>& cursors
= niter
.second
;
468 for (auto& cursor
: cursors
) {
469 cout
<< ": seek to " << cursor
<< std::endl
;
471 ASSERT_EQ(cursor
, it
.get_cursor());
472 string
& expected_oid
= cursor_to_obj
[cursor
];
473 cout
<< ": it->get_cursor()=" << it
.get_cursor() << " expected=" << cursor
<< std::endl
;
474 cout
<< ": it->get_oid()=" << it
->get_oid() << " expected=" << expected_oid
<< std::endl
;
475 cout
<< ": it->get_nspace()=" << it
->get_oid() << " expected=" << ns
<< std::endl
;
476 ASSERT_EQ(expected_oid
, it
->get_oid());
477 ASSERT_EQ(it
->get_nspace(), ns
);
482 TEST_F(LibRadosListPP
, ListObjectsCursorPP
) {
484 memset(buf
, 0xcc, sizeof(buf
));
486 bl
.append(buf
, sizeof(buf
));
488 const int max_objs
= 16;
490 for (int i
=0; i
<max_objs
; ++i
) {
493 ioctx
.set_namespace(ss
.str());
494 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
497 ioctx
.set_namespace(all_nspaces
);
499 librados::NObjectIterator it
= ioctx
.nobjects_begin();
500 std::map
<librados::ObjectCursor
, string
> cursor_to_obj
;
504 for (; it
!= ioctx
.nobjects_end(); ++it
, ++count
) {
505 librados::ObjectCursor cursor
= it
.get_cursor();
506 string oid
= it
->get_oid();
507 std::cout
<< oid
<< " " << it
.get_pg_hash_position() << std::endl
;
508 cout
<< ": oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
509 cursor_to_obj
[cursor
] = oid
;
512 cout
<< ": seek to " << cursor
<< std::endl
;
513 ASSERT_EQ(oid
, it
->get_oid());
514 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
517 ASSERT_EQ(count
, max_objs
);
519 auto p
= cursor_to_obj
.rbegin();
520 it
= ioctx
.nobjects_begin();
521 while (p
!= cursor_to_obj
.rend()) {
522 cout
<< ": seek to " << p
->first
<< std::endl
;
524 ASSERT_EQ(p
->first
, it
.get_cursor());
525 cout
<< ": it->get_cursor()=" << it
.get_cursor() << " expected=" << p
->first
<< std::endl
;
526 cout
<< ": it->get_oid()=" << it
->get_oid() << " expected=" << p
->second
<< std::endl
;
527 ASSERT_EQ(p
->second
, it
->get_oid());
529 librados::NObjectIterator it2
= ioctx
.nobjects_begin(it
.get_cursor());
530 ASSERT_EQ(it2
->get_oid(), it
->get_oid());
536 TEST_F(LibRadosList
, ListObjectsCursor
) {
538 memset(buf
, 0xcc, sizeof(buf
));
540 const int max_objs
= 16;
542 for (int i
=0; i
<max_objs
; ++i
) {
543 string n
= stringify(i
);
544 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
548 rados_list_ctx_t ctx
;
550 rados_object_list_cursor cursor
;
551 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
552 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
553 rados_object_list_cursor first_cursor
= cursor
;
554 cout
<< "x cursor=" << ObjectCursor(cursor
) << std::endl
;
555 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
557 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
558 cout
<< "> oid=" << oid
<< " cursor=" << ObjectCursor(cursor
) << std::endl
;
560 rados_nobjects_list_seek_cursor(ctx
, first_cursor
);
561 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
562 cout
<< "FIRST> seek to " << ObjectCursor(first_cursor
) << " oid=" << string(entry
) << std::endl
;
564 rados_list_ctx_t ctx
;
565 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
567 std::map
<rados_object_list_cursor
, string
> cursor_to_obj
;
571 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
572 rados_object_list_cursor cursor
;
573 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
575 cout
<< ": oid=" << oid
<< " cursor=" << ObjectCursor(cursor
) << std::endl
;
576 cursor_to_obj
[cursor
] = oid
;
578 rados_nobjects_list_seek_cursor(ctx
, cursor
);
579 cout
<< ": seek to " << ObjectCursor(cursor
) << std::endl
;
580 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
581 cout
<< "> " << ObjectCursor(cursor
) << " -> " << entry
<< std::endl
;
582 ASSERT_EQ(string(entry
), oid
);
583 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
588 ASSERT_EQ(count
, max_objs
);
590 auto p
= cursor_to_obj
.rbegin();
591 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
592 while (p
!= cursor_to_obj
.rend()) {
593 cout
<< ": seek to " << ObjectCursor(p
->first
) << std::endl
;
594 rados_object_list_cursor cursor
;
595 rados_object_list_cursor
oid(p
->first
);
596 rados_nobjects_list_seek_cursor(ctx
, oid
);
597 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
598 cout
<< ": cursor()=" << ObjectCursor(cursor
) << " expected=" << oid
<< std::endl
;
599 // ASSERT_EQ(ObjectCursor(oid), ObjectCursor(cursor));
600 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
601 cout
<< "> " << ObjectCursor(cursor
) << " -> " << entry
<< std::endl
;
602 cout
<< ": entry=" << entry
<< " expected=" << p
->second
<< std::endl
;
603 ASSERT_EQ(p
->second
, string(entry
));
607 rados_object_list_cursor_free(ctx
, cursor
);
611 TEST_F(LibRadosListEC
, ListObjects
) {
613 memset(buf
, 0xcc, sizeof(buf
));
614 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
615 rados_list_ctx_t ctx
;
616 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
618 bool foundit
= false;
619 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
621 ASSERT_EQ(std::string(entry
), "foo");
623 ASSERT_TRUE(foundit
);
624 rados_nobjects_list_close(ctx
);
627 TEST_F(LibRadosListECPP
, ListObjectsPP
) {
629 memset(buf
, 0xcc, sizeof(buf
));
631 bl1
.append(buf
, sizeof(buf
));
632 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
633 NObjectIterator
iter(ioctx
.nobjects_begin());
634 bool foundit
= false;
635 while (iter
!= ioctx
.nobjects_end()) {
637 ASSERT_EQ((*iter
).get_oid(), "foo");
640 ASSERT_TRUE(foundit
);
643 TEST_F(LibRadosListECPP
, ListObjectsTwicePP
) {
645 memset(buf
, 0xcc, sizeof(buf
));
647 bl1
.append(buf
, sizeof(buf
));
648 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
649 NObjectIterator
iter(ioctx
.nobjects_begin());
650 bool foundit
= false;
651 while (iter
!= ioctx
.nobjects_end()) {
653 ASSERT_EQ((*iter
).get_oid(), "foo");
656 ASSERT_TRUE(foundit
);
658 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
661 while (iter
!= ioctx
.nobjects_end()) {
663 ASSERT_EQ((*iter
).get_oid(), "foo");
666 ASSERT_TRUE(foundit
);
669 TEST_F(LibRadosListECPP
, ListObjectsCopyIterPP
) {
671 memset(buf
, 0xcc, sizeof(buf
));
673 bl1
.append(buf
, sizeof(buf
));
674 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
676 // make sure this is still valid after the original iterators are gone
677 NObjectIterator iter3
;
679 NObjectIterator
iter(ioctx
.nobjects_begin());
680 NObjectIterator
iter2(iter
);
682 ASSERT_EQ((*iter
).get_oid(), "foo");
684 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
686 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
688 ASSERT_EQ(iter2
->get_oid(), "foo");
689 ASSERT_EQ(iter3
->get_oid(), "foo");
691 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
694 ASSERT_EQ(iter3
->get_oid(), "foo");
696 ASSERT_EQ(iter3
->get_oid(), "foo");
698 ASSERT_TRUE(iter3
== ioctx
.nobjects_end());
701 TEST_F(LibRadosListECPP
, ListObjectsEndIter
) {
703 memset(buf
, 0xcc, sizeof(buf
));
705 bl1
.append(buf
, sizeof(buf
));
706 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
708 NObjectIterator
iter(ioctx
.nobjects_begin());
709 NObjectIterator
iter_end(ioctx
.nobjects_end());
710 NObjectIterator iter_end2
= ioctx
.nobjects_end();
711 ASSERT_TRUE(iter_end
== iter_end2
);
712 ASSERT_TRUE(iter_end
== ioctx
.nobjects_end());
713 ASSERT_TRUE(iter_end2
== ioctx
.nobjects_end());
715 ASSERT_EQ(iter
->get_oid(), "foo");
717 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
718 ASSERT_TRUE(iter
== iter_end
);
719 ASSERT_TRUE(iter
== iter_end2
);
720 NObjectIterator iter2
= iter
;
721 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
722 ASSERT_TRUE(iter2
== iter_end
);
723 ASSERT_TRUE(iter2
== iter_end2
);
726 TEST_F(LibRadosListEC
, ListObjectsNS
) {
728 memset(buf
, 0xcc, sizeof(buf
));
729 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
730 rados_ioctx_set_namespace(ioctx
, "");
731 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
732 rados_ioctx_set_namespace(ioctx
, "ns1");
733 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
734 rados_ioctx_set_namespace(ioctx
, "");
735 ASSERT_EQ(0, rados_write(ioctx
, "foo2", buf
, sizeof(buf
), 0));
736 ASSERT_EQ(0, rados_write(ioctx
, "foo3", buf
, sizeof(buf
), 0));
737 rados_ioctx_set_namespace(ioctx
, "ns1");
738 ASSERT_EQ(0, rados_write(ioctx
, "foo4", buf
, sizeof(buf
), 0));
739 ASSERT_EQ(0, rados_write(ioctx
, "foo5", buf
, sizeof(buf
), 0));
740 rados_ioctx_set_namespace(ioctx
, "ns2");
741 ASSERT_EQ(0, rados_write(ioctx
, "foo6", buf
, sizeof(buf
), 0));
742 ASSERT_EQ(0, rados_write(ioctx
, "foo7", buf
, sizeof(buf
), 0));
744 std::set
<std::string
> def
, ns1
, ns2
, all
;
745 def
.insert(std::string("foo1"));
746 def
.insert(std::string("foo2"));
747 def
.insert(std::string("foo3"));
748 ns1
.insert(std::string("foo1"));
749 ns1
.insert(std::string("foo4"));
750 ns1
.insert(std::string("foo5"));
751 ns2
.insert(std::string("foo6"));
752 ns2
.insert(std::string("foo7"));
753 all
.insert(std::string(":foo1"));
754 all
.insert(std::string(":foo2"));
755 all
.insert(std::string(":foo3"));
756 all
.insert(std::string("ns1:foo1"));
757 all
.insert(std::string("ns1:foo4"));
758 all
.insert(std::string("ns1:foo5"));
759 all
.insert(std::string("ns2:foo6"));
760 all
.insert(std::string("ns2:foo7"));
762 rados_list_ctx_t ctx
;
763 // Check default namespace ""
764 rados_ioctx_set_namespace(ioctx
, "");
765 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
766 check_list(def
, ctx
, "");
767 rados_nobjects_list_close(ctx
);
769 // Check default namespace "ns1"
770 rados_ioctx_set_namespace(ioctx
, "ns1");
771 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
772 check_list(ns1
, ctx
, "ns1");
773 rados_nobjects_list_close(ctx
);
775 // Check default namespace "ns2"
776 rados_ioctx_set_namespace(ioctx
, "ns2");
777 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
778 check_list(ns2
, ctx
, "ns2");
779 rados_nobjects_list_close(ctx
);
781 // Check all namespaces
782 rados_ioctx_set_namespace(ioctx
, LIBRADOS_ALL_NSPACES
);
783 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
784 check_list(all
, ctx
, all_nspaces
);
785 rados_nobjects_list_close(ctx
);
788 TEST_F(LibRadosListECPP
, ListObjectsPPNS
) {
790 memset(buf
, 0xcc, sizeof(buf
));
792 bl1
.append(buf
, sizeof(buf
));
793 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
794 ioctx
.set_namespace("");
795 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
796 ioctx
.set_namespace("ns1");
797 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
798 ioctx
.set_namespace("");
799 ASSERT_EQ(0, ioctx
.write("foo2", bl1
, sizeof(buf
), 0));
800 ASSERT_EQ(0, ioctx
.write("foo3", bl1
, sizeof(buf
), 0));
801 ioctx
.set_namespace("ns1");
802 ASSERT_EQ(0, ioctx
.write("foo4", bl1
, sizeof(buf
), 0));
803 ASSERT_EQ(0, ioctx
.write("foo5", bl1
, sizeof(buf
), 0));
804 ioctx
.set_namespace("ns2");
805 ASSERT_EQ(0, ioctx
.write("foo6", bl1
, sizeof(buf
), 0));
806 ASSERT_EQ(0, ioctx
.write("foo7", bl1
, sizeof(buf
), 0));
808 std::set
<std::string
> def
, ns1
, ns2
;
809 def
.insert(std::string("foo1"));
810 def
.insert(std::string("foo2"));
811 def
.insert(std::string("foo3"));
812 ns1
.insert(std::string("foo1"));
813 ns1
.insert(std::string("foo4"));
814 ns1
.insert(std::string("foo5"));
815 ns2
.insert(std::string("foo6"));
816 ns2
.insert(std::string("foo7"));
818 ioctx
.set_namespace("");
819 check_listpp(def
, ioctx
, "");
821 ioctx
.set_namespace("ns1");
822 check_listpp(ns1
, ioctx
, "ns1");
824 ioctx
.set_namespace("ns2");
825 check_listpp(ns2
, ioctx
, "ns2");
828 TEST_F(LibRadosListECPP
, ListObjectsManyPP
) {
830 memset(buf
, 0xcc, sizeof(buf
));
832 bl
.append(buf
, sizeof(buf
));
834 for (int i
=0; i
<256; ++i
) {
835 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
838 librados::NObjectIterator it
= ioctx
.nobjects_begin();
839 std::set
<std::string
> saw_obj
;
840 std::set
<int> saw_pg
;
841 for (; it
!= ioctx
.nobjects_end(); ++it
) {
842 std::cout
<< it
->get_oid()
843 << " " << it
.get_pg_hash_position() << std::endl
;
844 saw_obj
.insert(it
->get_oid());
845 saw_pg
.insert(it
.get_pg_hash_position());
847 std::cout
<< "saw " << saw_pg
.size() << " pgs " << std::endl
;
849 // make sure they are 0..n
850 for (unsigned i
= 0; i
< saw_pg
.size(); ++i
)
851 ASSERT_TRUE(saw_pg
.count(i
));
854 TEST_F(LibRadosListEC
, ListObjectsStart
) {
856 memset(buf
, 0xcc, sizeof(buf
));
858 for (int i
=0; i
<16; ++i
) {
859 string n
= stringify(i
);
860 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
863 rados_list_ctx_t ctx
;
864 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
865 std::map
<int, std::set
<std::string
> > pg_to_obj
;
867 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
868 uint32_t pos
= rados_nobjects_list_get_pg_hash_position(ctx
);
869 std::cout
<< entry
<< " " << pos
<< std::endl
;
870 pg_to_obj
[pos
].insert(entry
);
872 rados_nobjects_list_close(ctx
);
874 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
876 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
877 while (p
!= pg_to_obj
.rend()) {
878 ASSERT_EQ((uint32_t)p
->first
, rados_nobjects_list_seek(ctx
, p
->first
));
879 ASSERT_EQ(0, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
880 std::cout
<< "have " << entry
<< " expect one of " << p
->second
<< std::endl
;
881 ASSERT_TRUE(p
->second
.count(entry
));
884 rados_nobjects_list_close(ctx
);
887 TEST_F(LibRadosListECPP
, ListObjectsStartPP
) {
889 memset(buf
, 0xcc, sizeof(buf
));
891 bl
.append(buf
, sizeof(buf
));
893 for (int i
=0; i
<16; ++i
) {
894 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
897 librados::NObjectIterator it
= ioctx
.nobjects_begin();
898 std::map
<int, std::set
<std::string
> > pg_to_obj
;
899 for (; it
!= ioctx
.nobjects_end(); ++it
) {
900 std::cout
<< it
->get_oid() << " " << it
.get_pg_hash_position() << std::endl
;
901 pg_to_obj
[it
.get_pg_hash_position()].insert(it
->get_oid());
904 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
906 it
= ioctx
.nobjects_begin(p
->first
);
907 while (p
!= pg_to_obj
.rend()) {
908 ASSERT_EQ((uint32_t)p
->first
, it
.seek(p
->first
));
909 std::cout
<< "have " << it
->get_oid() << " expect one of " << p
->second
<< std::endl
;
910 ASSERT_TRUE(p
->second
.count(it
->get_oid()));
915 TEST_F(LibRadosListPP
, ListObjectsFilterPP
) {
917 memset(buf
, 0xcc, sizeof(buf
));
918 bufferlist obj_content
;
919 obj_content
.append(buf
, sizeof(buf
));
921 std::string target_str
= "content";
923 // Write xattr bare, no ::encod'ing
924 bufferlist target_val
;
925 target_val
.append(target_str
);
926 bufferlist nontarget_val
;
927 nontarget_val
.append("rhubarb");
929 ASSERT_EQ(0, ioctx
.write("has_xattr", obj_content
, obj_content
.length(), 0));
930 ASSERT_EQ(0, ioctx
.write("has_wrong_xattr", obj_content
, obj_content
.length(), 0));
931 ASSERT_EQ(0, ioctx
.write("no_xattr", obj_content
, obj_content
.length(), 0));
933 ASSERT_EQ(0, ioctx
.setxattr("has_xattr", "theattr", target_val
));
934 ASSERT_EQ(0, ioctx
.setxattr("has_wrong_xattr", "theattr", nontarget_val
));
936 bufferlist filter_bl
;
937 std::string filter_name
= "plain";
938 ::encode(filter_name
, filter_bl
);
939 ::encode("_theattr", filter_bl
);
940 ::encode(target_str
, filter_bl
);
942 NObjectIterator
iter(ioctx
.nobjects_begin(filter_bl
));
943 bool foundit
= false;
945 while (iter
!= ioctx
.nobjects_end()) {
947 // We should only see the object that matches the filter
948 ASSERT_EQ((*iter
).get_oid(), "has_xattr");
949 // We should only see it once
954 ASSERT_TRUE(foundit
);
957 TEST_F(LibRadosListNP
, ListObjectsError
) {
958 std::string pool_name
;
961 pool_name
= get_temp_pool_name();
962 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
963 ASSERT_EQ(0, rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
));
965 memset(buf
, 0xcc, sizeof(buf
));
966 rados_ioctx_set_namespace(ioctx
, "");
967 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
969 //ASSERT_EQ(0, rados_pool_delete(cluster, pool_name.c_str()));
972 size_t buflen
, stlen
;
973 string c
= "{\"prefix\":\"osd pool rm\",\"pool\": \"" + pool_name
+
974 "\",\"pool2\":\"" + pool_name
+
975 "\",\"sure\": \"--yes-i-really-really-mean-it-not-faking\"}";
976 const char *cmd
[2] = { c
.c_str(), 0 };
977 ASSERT_EQ(0, rados_mon_command(cluster
, (const char **)cmd
, 1, "", 0, &buf
, &buflen
, &st
, &stlen
));
978 ASSERT_EQ(0, rados_wait_for_latest_osdmap(cluster
));
981 rados_list_ctx_t ctx
;
982 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
984 ASSERT_EQ(-ENOENT
, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
985 rados_nobjects_list_close(ctx
);
986 rados_ioctx_destroy(ioctx
);
987 rados_shutdown(cluster
);
992 // ---------------------------------------------
994 TEST_F(LibRadosList
, EnumerateObjects
) {
996 memset(buf
, 0xcc, sizeof(buf
));
998 const uint32_t n_objects
= 16;
999 for (unsigned i
=0; i
<n_objects
; ++i
) {
1000 ASSERT_EQ(0, rados_write(ioctx
, stringify(i
).c_str(), buf
, sizeof(buf
), 0));
1003 // Ensure a non-power-of-two PG count to avoid only
1004 // touching the easy path.
1005 std::string err_str
= set_pg_num(&s_cluster
, pool_name
, 11);
1006 ASSERT_TRUE(err_str
.empty());
1008 std::set
<std::string
> saw_obj
;
1009 rados_object_list_cursor c
= rados_object_list_begin(ioctx
);
1010 rados_object_list_cursor end
= rados_object_list_end(ioctx
);
1011 while(!rados_object_list_is_end(ioctx
, c
))
1013 rados_object_list_item results
[12];
1014 memset(results
, 0, sizeof(rados_object_list_item
) * 12);
1015 rados_object_list_cursor temp_end
= rados_object_list_end(ioctx
);
1016 int r
= rados_object_list(ioctx
, c
, temp_end
,
1017 12, NULL
, 0, results
, &c
);
1018 rados_object_list_cursor_free(ioctx
, temp_end
);
1020 for (int i
= 0; i
< r
; ++i
) {
1021 std::string
oid(results
[i
].oid
, results
[i
].oid_length
);
1022 if (saw_obj
.count(oid
)) {
1023 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1025 ASSERT_FALSE(saw_obj
.count(oid
));
1026 saw_obj
.insert(oid
);
1028 rados_object_list_free(12, results
);
1030 rados_object_list_cursor_free(ioctx
, c
);
1031 rados_object_list_cursor_free(ioctx
, end
);
1033 for (unsigned i
=0; i
<n_objects
; ++i
) {
1034 if (!saw_obj
.count(stringify(i
))) {
1035 std::cerr
<< "missing object " << i
<< std::endl
;
1037 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1039 ASSERT_EQ(n_objects
, saw_obj
.size());
1042 TEST_F(LibRadosList
, EnumerateObjectsSplit
) {
1044 memset(buf
, 0xcc, sizeof(buf
));
1046 const uint32_t n_objects
= 16;
1047 for (unsigned i
=0; i
<n_objects
; ++i
) {
1048 ASSERT_EQ(0, rados_write(ioctx
, stringify(i
).c_str(), buf
, sizeof(buf
), 0));
1051 // Ensure a non-power-of-two PG count to avoid only
1052 // touching the easy path.
1053 std::string err_str
= set_pg_num(&s_cluster
, pool_name
, 11);
1054 ASSERT_TRUE(err_str
.empty());
1056 rados_object_list_cursor begin
= rados_object_list_begin(ioctx
);
1057 rados_object_list_cursor end
= rados_object_list_end(ioctx
);
1059 // Step through an odd number of shards
1061 std::set
<std::string
> saw_obj
;
1062 for (unsigned n
= 0; n
< m
; ++n
) {
1063 rados_object_list_cursor shard_start
= rados_object_list_begin(ioctx
);;
1064 rados_object_list_cursor shard_end
= rados_object_list_end(ioctx
);;
1066 rados_object_list_slice(
1074 std::cout
<< "split " << n
<< "/" << m
<< " -> "
1075 << *(hobject_t
*)shard_start
<< " "
1076 << *(hobject_t
*)shard_end
<< std::endl
;
1078 rados_object_list_cursor c
= shard_start
;
1079 //while(c < shard_end)
1080 while(rados_object_list_cursor_cmp(ioctx
, c
, shard_end
) == -1)
1082 rados_object_list_item results
[12];
1083 memset(results
, 0, sizeof(rados_object_list_item
) * 12);
1084 int r
= rados_object_list(ioctx
,
1086 12, NULL
, 0, results
, &c
);
1088 for (int i
= 0; i
< r
; ++i
) {
1089 std::string
oid(results
[i
].oid
, results
[i
].oid_length
);
1090 if (saw_obj
.count(oid
)) {
1091 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1093 ASSERT_FALSE(saw_obj
.count(oid
));
1094 saw_obj
.insert(oid
);
1096 rados_object_list_free(12, results
);
1098 rados_object_list_cursor_free(ioctx
, shard_start
);
1099 rados_object_list_cursor_free(ioctx
, shard_end
);
1102 rados_object_list_cursor_free(ioctx
, begin
);
1103 rados_object_list_cursor_free(ioctx
, end
);
1105 for (unsigned i
=0; i
<n_objects
; ++i
) {
1106 if (!saw_obj
.count(stringify(i
))) {
1107 std::cerr
<< "missing object " << i
<< std::endl
;
1109 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1111 ASSERT_EQ(n_objects
, saw_obj
.size());
1114 TEST_F(LibRadosListPP
, EnumerateObjectsPP
) {
1116 memset(buf
, 0xcc, sizeof(buf
));
1118 bl
.append(buf
, sizeof(buf
));
1120 const uint32_t n_objects
= 16;
1121 for (unsigned i
=0; i
<n_objects
; ++i
) {
1122 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, sizeof(buf
), 0));
1125 std::set
<std::string
> saw_obj
;
1126 ObjectCursor c
= ioctx
.object_list_begin();
1127 ObjectCursor end
= ioctx
.object_list_end();
1128 while(!ioctx
.object_list_is_end(c
))
1130 std::vector
<ObjectItem
> result
;
1131 int r
= ioctx
.object_list(c
, end
, 12, {}, &result
, &c
);
1133 ASSERT_EQ(r
, (int)result
.size());
1134 for (int i
= 0; i
< r
; ++i
) {
1135 auto oid
= result
[i
].oid
;
1136 if (saw_obj
.count(oid
)) {
1137 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1139 ASSERT_FALSE(saw_obj
.count(oid
));
1140 saw_obj
.insert(oid
);
1144 for (unsigned i
=0; i
<n_objects
; ++i
) {
1145 if (!saw_obj
.count(stringify(i
))) {
1146 std::cerr
<< "missing object " << i
<< std::endl
;
1148 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1150 ASSERT_EQ(n_objects
, saw_obj
.size());
1153 TEST_F(LibRadosListPP
, EnumerateObjectsSplitPP
) {
1155 memset(buf
, 0xcc, sizeof(buf
));
1157 bl
.append(buf
, sizeof(buf
));
1159 const uint32_t n_objects
= 16;
1160 for (unsigned i
=0; i
<n_objects
; ++i
) {
1161 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, sizeof(buf
), 0));
1164 ObjectCursor begin
= ioctx
.object_list_begin();
1165 ObjectCursor end
= ioctx
.object_list_end();
1167 // Step through an odd number of shards
1169 std::set
<std::string
> saw_obj
;
1170 for (unsigned n
= 0; n
< m
; ++n
) {
1171 ObjectCursor shard_start
;
1172 ObjectCursor shard_end
;
1174 ioctx
.object_list_slice(
1182 ObjectCursor
c(shard_start
);
1183 while(c
< shard_end
)
1185 std::vector
<ObjectItem
> result
;
1186 int r
= ioctx
.object_list(c
, shard_end
, 12, {}, &result
, &c
);
1189 for (const auto & i
: result
) {
1190 const auto &oid
= i
.oid
;
1191 if (saw_obj
.count(oid
)) {
1192 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1194 ASSERT_FALSE(saw_obj
.count(oid
));
1195 saw_obj
.insert(oid
);
1200 for (unsigned i
=0; i
<n_objects
; ++i
) {
1201 if (!saw_obj
.count(stringify(i
))) {
1202 std::cerr
<< "missing object " << i
<< std::endl
;
1204 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1206 ASSERT_EQ(n_objects
, saw_obj
.size());
1210 TEST_F(LibRadosListPP
, EnumerateObjectsFilterPP
) {
1212 memset(buf
, 0xcc, sizeof(buf
));
1213 bufferlist obj_content
;
1214 obj_content
.append(buf
, sizeof(buf
));
1216 std::string target_str
= "content";
1218 // Write xattr bare, no ::encod'ing
1219 bufferlist target_val
;
1220 target_val
.append(target_str
);
1221 bufferlist nontarget_val
;
1222 nontarget_val
.append("rhubarb");
1224 ASSERT_EQ(0, ioctx
.write("has_xattr", obj_content
, obj_content
.length(), 0));
1225 ASSERT_EQ(0, ioctx
.write("has_wrong_xattr", obj_content
, obj_content
.length(), 0));
1226 ASSERT_EQ(0, ioctx
.write("no_xattr", obj_content
, obj_content
.length(), 0));
1228 ASSERT_EQ(0, ioctx
.setxattr("has_xattr", "theattr", target_val
));
1229 ASSERT_EQ(0, ioctx
.setxattr("has_wrong_xattr", "theattr", nontarget_val
));
1231 bufferlist filter_bl
;
1232 std::string filter_name
= "plain";
1233 ::encode(filter_name
, filter_bl
);
1234 ::encode("_theattr", filter_bl
);
1235 ::encode(target_str
, filter_bl
);
1237 ObjectCursor c
= ioctx
.object_list_begin();
1238 ObjectCursor end
= ioctx
.object_list_end();
1239 bool foundit
= false;
1240 while(!ioctx
.object_list_is_end(c
))
1242 std::vector
<ObjectItem
> result
;
1243 int r
= ioctx
.object_list(c
, end
, 12, filter_bl
, &result
, &c
);
1245 ASSERT_EQ(r
, (int)result
.size());
1246 for (int i
= 0; i
< r
; ++i
) {
1247 auto oid
= result
[i
].oid
;
1248 // We should only see the object that matches the filter
1249 ASSERT_EQ(oid
, "has_xattr");
1250 // We should only see it once
1251 ASSERT_FALSE(foundit
);
1255 ASSERT_TRUE(foundit
);