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/TestCase.h"
8 #include "global/global_context.h"
10 #include "include/types.h"
11 #include "common/hobject.h"
12 #include "gtest/gtest.h"
17 using namespace librados
;
19 typedef RadosTestNSCleanup LibRadosList
;
20 typedef RadosTestPPNSCleanup LibRadosListPP
;
21 typedef RadosTestECNSCleanup LibRadosListEC
;
22 typedef RadosTestECPPNSCleanup LibRadosListECPP
;
23 typedef RadosTestNP LibRadosListNP
;
26 TEST_F(LibRadosList
, ListObjects
) {
28 memset(buf
, 0xcc, sizeof(buf
));
29 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
31 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
34 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
36 ASSERT_EQ(std::string(entry
), "foo");
39 rados_nobjects_list_close(ctx
);
42 TEST_F(LibRadosListPP
, ListObjectsPP
) {
44 memset(buf
, 0xcc, sizeof(buf
));
46 bl1
.append(buf
, sizeof(buf
));
47 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
48 NObjectIterator
iter(ioctx
.nobjects_begin());
50 while (iter
!= ioctx
.nobjects_end()) {
52 ASSERT_EQ((*iter
).get_oid(), "foo");
58 TEST_F(LibRadosListPP
, ListObjectsTwicePP
) {
60 memset(buf
, 0xcc, sizeof(buf
));
62 bl1
.append(buf
, sizeof(buf
));
63 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
64 NObjectIterator
iter(ioctx
.nobjects_begin());
66 while (iter
!= ioctx
.nobjects_end()) {
68 ASSERT_EQ((*iter
).get_oid(), "foo");
73 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
76 while (iter
!= ioctx
.nobjects_end()) {
78 ASSERT_EQ((*iter
).get_oid(), "foo");
84 TEST_F(LibRadosListPP
, ListObjectsCopyIterPP
) {
86 memset(buf
, 0xcc, sizeof(buf
));
88 bl1
.append(buf
, sizeof(buf
));
89 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
91 // make sure this is still valid after the original iterators are gone
92 NObjectIterator iter3
;
94 NObjectIterator
iter(ioctx
.nobjects_begin());
95 NObjectIterator
iter2(iter
);
97 ASSERT_EQ((*iter
).get_oid(), "foo");
99 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
101 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
103 ASSERT_EQ(iter2
->get_oid(), "foo");
104 ASSERT_EQ(iter3
->get_oid(), "foo");
106 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
109 ASSERT_EQ(iter3
->get_oid(), "foo");
111 ASSERT_EQ(iter3
->get_oid(), "foo");
113 ASSERT_TRUE(iter3
== ioctx
.nobjects_end());
116 TEST_F(LibRadosListPP
, ListObjectsEndIter
) {
118 memset(buf
, 0xcc, sizeof(buf
));
120 bl1
.append(buf
, sizeof(buf
));
121 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
123 NObjectIterator
iter(ioctx
.nobjects_begin());
124 NObjectIterator
iter_end(ioctx
.nobjects_end());
125 NObjectIterator iter_end2
= ioctx
.nobjects_end();
126 ASSERT_TRUE(iter_end
== iter_end2
);
127 ASSERT_TRUE(iter_end
== ioctx
.nobjects_end());
128 ASSERT_TRUE(iter_end2
== ioctx
.nobjects_end());
130 ASSERT_EQ(iter
->get_oid(), "foo");
132 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
133 ASSERT_TRUE(iter
== iter_end
);
134 ASSERT_TRUE(iter
== iter_end2
);
135 NObjectIterator iter2
= iter
;
136 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
137 ASSERT_TRUE(iter2
== iter_end
);
138 ASSERT_TRUE(iter2
== iter_end2
);
141 static void check_list(
142 std::set
<std::string
>& myset
,
143 rados_list_ctx_t
& ctx
,
144 std::string check_nspace
)
146 const char *entry
, *nspace
;
147 cout
<< "myset " << myset
<< std::endl
;
148 // we should see every item exactly once.
150 while ((ret
= rados_nobjects_list_next(ctx
, &entry
, NULL
, &nspace
)) == 0) {
151 std::string test_name
;
152 if (check_nspace
== all_nspaces
) {
153 test_name
= std::string(nspace
) + ":" + std::string(entry
);
155 ASSERT_TRUE(std::string(nspace
) == check_nspace
);
156 test_name
= std::string(entry
);
158 cout
<< test_name
<< std::endl
;
160 ASSERT_TRUE(myset
.end() != myset
.find(test_name
));
161 myset
.erase(test_name
);
163 ASSERT_EQ(-ENOENT
, ret
);
164 ASSERT_TRUE(myset
.empty());
167 TEST_F(LibRadosList
, ListObjectsNS
) {
169 memset(buf
, 0xcc, sizeof(buf
));
170 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
171 rados_ioctx_set_namespace(ioctx
, "");
172 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
173 rados_ioctx_set_namespace(ioctx
, "ns1");
174 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
175 rados_ioctx_set_namespace(ioctx
, "");
176 ASSERT_EQ(0, rados_write(ioctx
, "foo2", buf
, sizeof(buf
), 0));
177 ASSERT_EQ(0, rados_write(ioctx
, "foo3", buf
, sizeof(buf
), 0));
178 rados_ioctx_set_namespace(ioctx
, "ns1");
179 ASSERT_EQ(0, rados_write(ioctx
, "foo4", buf
, sizeof(buf
), 0));
180 ASSERT_EQ(0, rados_write(ioctx
, "foo5", buf
, sizeof(buf
), 0));
181 rados_ioctx_set_namespace(ioctx
, "ns2");
182 ASSERT_EQ(0, rados_write(ioctx
, "foo6", buf
, sizeof(buf
), 0));
183 ASSERT_EQ(0, rados_write(ioctx
, "foo7", buf
, sizeof(buf
), 0));
185 std::set
<std::string
> def
, ns1
, ns2
, all
;
186 def
.insert(std::string("foo1"));
187 def
.insert(std::string("foo2"));
188 def
.insert(std::string("foo3"));
189 ns1
.insert(std::string("foo1"));
190 ns1
.insert(std::string("foo4"));
191 ns1
.insert(std::string("foo5"));
192 ns2
.insert(std::string("foo6"));
193 ns2
.insert(std::string("foo7"));
194 all
.insert(std::string(":foo1"));
195 all
.insert(std::string(":foo2"));
196 all
.insert(std::string(":foo3"));
197 all
.insert(std::string("ns1:foo1"));
198 all
.insert(std::string("ns1:foo4"));
199 all
.insert(std::string("ns1:foo5"));
200 all
.insert(std::string("ns2:foo6"));
201 all
.insert(std::string("ns2:foo7"));
203 rados_list_ctx_t ctx
;
204 // Check default namespace ""
205 rados_ioctx_set_namespace(ioctx
, "");
206 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
207 check_list(def
, ctx
, "");
208 rados_nobjects_list_close(ctx
);
210 // Check namespace "ns1"
211 rados_ioctx_set_namespace(ioctx
, "ns1");
212 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
213 check_list(ns1
, ctx
, "ns1");
214 rados_nobjects_list_close(ctx
);
216 // Check namespace "ns2"
217 rados_ioctx_set_namespace(ioctx
, "ns2");
218 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
219 check_list(ns2
, ctx
, "ns2");
220 rados_nobjects_list_close(ctx
);
222 // Check ALL namespaces
223 rados_ioctx_set_namespace(ioctx
, LIBRADOS_ALL_NSPACES
);
224 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
225 check_list(all
, ctx
, all_nspaces
);
226 rados_nobjects_list_close(ctx
);
229 static void check_listpp(std::set
<std::string
>& myset
, IoCtx
& ioctx
, std::string check_nspace
)
231 NObjectIterator
iter(ioctx
.nobjects_begin());
232 std::set
<std::string
> orig_set(myset
);
234 * During splitting, we might see duplicate items.
235 * We assert that every object returned is in myset and that
236 * we don't hit ENOENT until we have hit every item in myset
239 while (iter
!= ioctx
.nobjects_end()) {
240 std::string test_name
;
241 if (check_nspace
== all_nspaces
) {
242 test_name
= iter
->get_nspace() + ":" + iter
->get_oid();
244 ASSERT_TRUE(iter
->get_nspace() == check_nspace
);
245 test_name
= iter
->get_oid();
247 ASSERT_TRUE(orig_set
.end() != orig_set
.find(test_name
));
248 myset
.erase(test_name
);
251 ASSERT_TRUE(myset
.empty());
254 TEST_F(LibRadosListPP
, ListObjectsPPNS
) {
256 memset(buf
, 0xcc, sizeof(buf
));
258 bl1
.append(buf
, sizeof(buf
));
259 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
260 ioctx
.set_namespace("");
261 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
262 ioctx
.set_namespace("ns1");
263 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
264 ioctx
.set_namespace("");
265 ASSERT_EQ(0, ioctx
.write("foo2", bl1
, sizeof(buf
), 0));
266 ASSERT_EQ(0, ioctx
.write("foo3", bl1
, sizeof(buf
), 0));
267 ioctx
.set_namespace("ns1");
268 ASSERT_EQ(0, ioctx
.write("foo4", bl1
, sizeof(buf
), 0));
269 ASSERT_EQ(0, ioctx
.write("foo5", bl1
, sizeof(buf
), 0));
270 ioctx
.set_namespace("ns2");
271 ASSERT_EQ(0, ioctx
.write("foo6", bl1
, sizeof(buf
), 0));
272 ASSERT_EQ(0, ioctx
.write("foo7", bl1
, sizeof(buf
), 0));
274 std::set
<std::string
> def
, ns1
, ns2
, all
;
275 def
.insert(std::string("foo1"));
276 def
.insert(std::string("foo2"));
277 def
.insert(std::string("foo3"));
278 ns1
.insert(std::string("foo1"));
279 ns1
.insert(std::string("foo4"));
280 ns1
.insert(std::string("foo5"));
281 ns2
.insert(std::string("foo6"));
282 ns2
.insert(std::string("foo7"));
283 all
.insert(std::string(":foo1"));
284 all
.insert(std::string(":foo2"));
285 all
.insert(std::string(":foo3"));
286 all
.insert(std::string("ns1:foo1"));
287 all
.insert(std::string("ns1:foo4"));
288 all
.insert(std::string("ns1:foo5"));
289 all
.insert(std::string("ns2:foo6"));
290 all
.insert(std::string("ns2:foo7"));
292 ioctx
.set_namespace("");
293 check_listpp(def
, ioctx
, "");
295 ioctx
.set_namespace("ns1");
296 check_listpp(ns1
, ioctx
, "ns1");
298 ioctx
.set_namespace("ns2");
299 check_listpp(ns2
, ioctx
, "ns2");
301 ioctx
.set_namespace(all_nspaces
);
302 check_listpp(all
, ioctx
, all_nspaces
);
305 TEST_F(LibRadosListPP
, ListObjectsManyPP
) {
307 memset(buf
, 0xcc, sizeof(buf
));
309 bl
.append(buf
, sizeof(buf
));
311 for (int i
=0; i
<256; ++i
) {
312 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
315 librados::NObjectIterator it
= ioctx
.nobjects_begin();
316 std::set
<std::string
> saw_obj
;
317 std::set
<int> saw_pg
;
318 for (; it
!= ioctx
.nobjects_end(); ++it
) {
319 std::cout
<< it
->get_oid()
320 << " " << it
.get_pg_hash_position() << std::endl
;
321 saw_obj
.insert(it
->get_oid());
322 saw_pg
.insert(it
.get_pg_hash_position());
324 std::cout
<< "saw " << saw_pg
.size() << " pgs " << std::endl
;
326 // make sure they are 0..n
327 for (unsigned i
= 0; i
< saw_pg
.size(); ++i
)
328 ASSERT_TRUE(saw_pg
.count(i
));
331 TEST_F(LibRadosList
, ListObjectsStart
) {
333 memset(buf
, 0xcc, sizeof(buf
));
335 for (int i
=0; i
<16; ++i
) {
336 string n
= stringify(i
);
337 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
340 rados_list_ctx_t ctx
;
341 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
342 std::map
<int, std::set
<std::string
> > pg_to_obj
;
344 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
345 uint32_t pos
= rados_nobjects_list_get_pg_hash_position(ctx
);
346 std::cout
<< entry
<< " " << pos
<< std::endl
;
347 pg_to_obj
[pos
].insert(entry
);
349 rados_nobjects_list_close(ctx
);
351 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
353 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
354 while (p
!= pg_to_obj
.rend()) {
355 ASSERT_EQ((uint32_t)p
->first
, rados_nobjects_list_seek(ctx
, p
->first
));
356 ASSERT_EQ(0, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
357 std::cout
<< "have " << entry
<< " expect one of " << p
->second
<< std::endl
;
358 ASSERT_TRUE(p
->second
.count(entry
));
361 rados_nobjects_list_close(ctx
);
364 TEST_F(LibRadosListPP
, ListObjectsStartPP
) {
366 memset(buf
, 0xcc, sizeof(buf
));
368 bl
.append(buf
, sizeof(buf
));
370 for (int i
=0; i
<16; ++i
) {
371 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
374 librados::NObjectIterator it
= ioctx
.nobjects_begin();
375 std::map
<int, std::set
<std::string
> > pg_to_obj
;
376 for (; it
!= ioctx
.nobjects_end(); ++it
) {
377 std::cout
<< it
->get_oid() << " " << it
.get_pg_hash_position() << std::endl
;
378 pg_to_obj
[it
.get_pg_hash_position()].insert(it
->get_oid());
381 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
383 it
= ioctx
.nobjects_begin(p
->first
);
384 while (p
!= pg_to_obj
.rend()) {
385 ASSERT_EQ((uint32_t)p
->first
, it
.seek(p
->first
));
386 std::cout
<< "have " << it
->get_oid() << " expect one of " << p
->second
<< std::endl
;
387 ASSERT_TRUE(p
->second
.count(it
->get_oid()));
392 TEST_F(LibRadosListPP
, ListObjectsCursorNSPP
) {
394 memset(buf
, 0xcc, sizeof(buf
));
396 bl
.append(buf
, sizeof(buf
));
398 const int max_objs
= 16;
400 map
<string
, string
> oid_to_ns
;
402 for (int i
=0; i
<max_objs
; ++i
) {
405 ioctx
.set_namespace(ss
.str());
406 string oid
= stringify(i
);
407 ASSERT_EQ(0, ioctx
.write(oid
, bl
, bl
.length(), 0));
409 oid_to_ns
[oid
] = ss
.str();
412 ioctx
.set_namespace(all_nspaces
);
414 librados::NObjectIterator it
= ioctx
.nobjects_begin();
415 std::map
<librados::ObjectCursor
, string
> cursor_to_obj
;
419 librados::ObjectCursor seek_cursor
;
421 map
<string
, list
<librados::ObjectCursor
> > ns_to_cursors
;
423 for (it
= ioctx
.nobjects_begin(); it
!= ioctx
.nobjects_end(); ++it
) {
424 librados::ObjectCursor cursor
= it
.get_cursor();
425 string oid
= it
->get_oid();
426 cout
<< "> oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
429 vector
<string
> objs_order
;
431 for (it
= ioctx
.nobjects_begin(); it
!= ioctx
.nobjects_end(); ++it
, ++count
) {
432 librados::ObjectCursor cursor
= it
.get_cursor();
433 string oid
= it
->get_oid();
434 std::cout
<< oid
<< " " << it
.get_pg_hash_position() << std::endl
;
435 cout
<< ": oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
436 cursor_to_obj
[cursor
] = oid
;
438 ASSERT_EQ(oid_to_ns
[oid
], it
->get_nspace());
441 cout
<< ": seek to " << cursor
<< " it.cursor=" << it
.get_cursor() << std::endl
;
442 ASSERT_EQ(oid
, it
->get_oid());
443 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
445 ns_to_cursors
[it
->get_nspace()].push_back(cursor
);
447 if (count
== max_objs
/2) {
448 seek_cursor
= cursor
;
450 objs_order
.push_back(it
->get_oid());
453 ASSERT_EQ(count
, max_objs
);
455 /* check that reading past seek also works */
456 cout
<< "seek_cursor=" << seek_cursor
<< std::endl
;
457 it
.seek(seek_cursor
);
458 for (count
= max_objs
/2; count
< max_objs
; ++count
, ++it
) {
459 ASSERT_EQ(objs_order
[count
], it
->get_oid());
462 /* seek to all cursors, check that we get expected obj */
463 for (auto& niter
: ns_to_cursors
) {
464 const string
& ns
= niter
.first
;
465 list
<librados::ObjectCursor
>& cursors
= niter
.second
;
467 for (auto& cursor
: cursors
) {
468 cout
<< ": seek to " << cursor
<< std::endl
;
470 ASSERT_EQ(cursor
, it
.get_cursor());
471 string
& expected_oid
= cursor_to_obj
[cursor
];
472 cout
<< ": it->get_cursor()=" << it
.get_cursor() << " expected=" << cursor
<< std::endl
;
473 cout
<< ": it->get_oid()=" << it
->get_oid() << " expected=" << expected_oid
<< std::endl
;
474 cout
<< ": it->get_nspace()=" << it
->get_oid() << " expected=" << ns
<< std::endl
;
475 ASSERT_EQ(expected_oid
, it
->get_oid());
476 ASSERT_EQ(it
->get_nspace(), ns
);
481 TEST_F(LibRadosListPP
, ListObjectsCursorPP
) {
483 memset(buf
, 0xcc, sizeof(buf
));
485 bl
.append(buf
, sizeof(buf
));
487 const int max_objs
= 16;
489 for (int i
=0; i
<max_objs
; ++i
) {
492 ioctx
.set_namespace(ss
.str());
493 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
496 ioctx
.set_namespace(all_nspaces
);
498 librados::NObjectIterator it
= ioctx
.nobjects_begin();
499 std::map
<librados::ObjectCursor
, string
> cursor_to_obj
;
503 for (; it
!= ioctx
.nobjects_end(); ++it
, ++count
) {
504 librados::ObjectCursor cursor
= it
.get_cursor();
505 string oid
= it
->get_oid();
506 std::cout
<< oid
<< " " << it
.get_pg_hash_position() << std::endl
;
507 cout
<< ": oid=" << oid
<< " cursor=" << it
.get_cursor() << std::endl
;
508 cursor_to_obj
[cursor
] = oid
;
511 cout
<< ": seek to " << cursor
<< std::endl
;
512 ASSERT_EQ(oid
, it
->get_oid());
513 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
516 ASSERT_EQ(count
, max_objs
);
518 auto p
= cursor_to_obj
.rbegin();
519 it
= ioctx
.nobjects_begin();
520 while (p
!= cursor_to_obj
.rend()) {
521 cout
<< ": seek to " << p
->first
<< std::endl
;
523 ASSERT_EQ(p
->first
, it
.get_cursor());
524 cout
<< ": it->get_cursor()=" << it
.get_cursor() << " expected=" << p
->first
<< std::endl
;
525 cout
<< ": it->get_oid()=" << it
->get_oid() << " expected=" << p
->second
<< std::endl
;
526 ASSERT_EQ(p
->second
, it
->get_oid());
528 librados::NObjectIterator it2
= ioctx
.nobjects_begin(it
.get_cursor());
529 ASSERT_EQ(it2
->get_oid(), it
->get_oid());
535 TEST_F(LibRadosList
, ListObjectsCursor
) {
537 memset(buf
, 0xcc, sizeof(buf
));
539 const int max_objs
= 16;
541 for (int i
=0; i
<max_objs
; ++i
) {
542 string n
= stringify(i
);
543 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
547 rados_list_ctx_t ctx
;
549 rados_object_list_cursor cursor
;
550 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
551 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
552 rados_object_list_cursor first_cursor
= cursor
;
553 cout
<< "x cursor=" << ObjectCursor(cursor
) << std::endl
;
554 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
556 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
557 cout
<< "> oid=" << oid
<< " cursor=" << ObjectCursor(cursor
) << std::endl
;
559 rados_nobjects_list_seek_cursor(ctx
, first_cursor
);
560 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
561 cout
<< "FIRST> seek to " << ObjectCursor(first_cursor
) << " oid=" << string(entry
) << std::endl
;
563 rados_list_ctx_t ctx
;
564 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
566 std::map
<rados_object_list_cursor
, string
> cursor_to_obj
;
570 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
571 rados_object_list_cursor cursor
;
572 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
574 cout
<< ": oid=" << oid
<< " cursor=" << ObjectCursor(cursor
) << std::endl
;
575 cursor_to_obj
[cursor
] = oid
;
577 rados_nobjects_list_seek_cursor(ctx
, cursor
);
578 cout
<< ": seek to " << ObjectCursor(cursor
) << std::endl
;
579 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
580 cout
<< "> " << ObjectCursor(cursor
) << " -> " << entry
<< std::endl
;
581 ASSERT_EQ(string(entry
), oid
);
582 ASSERT_LT(count
, max_objs
); /* avoid infinite loops due to bad seek */
587 ASSERT_EQ(count
, max_objs
);
589 auto p
= cursor_to_obj
.rbegin();
590 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
591 while (p
!= cursor_to_obj
.rend()) {
592 cout
<< ": seek to " << ObjectCursor(p
->first
) << std::endl
;
593 rados_object_list_cursor cursor
;
594 rados_object_list_cursor
oid(p
->first
);
595 rados_nobjects_list_seek_cursor(ctx
, oid
);
596 ASSERT_EQ(rados_nobjects_list_get_cursor(ctx
, &cursor
), 0);
597 cout
<< ": cursor()=" << ObjectCursor(cursor
) << " expected=" << oid
<< std::endl
;
598 // ASSERT_EQ(ObjectCursor(oid), ObjectCursor(cursor));
599 ASSERT_EQ(rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
), 0);
600 cout
<< "> " << ObjectCursor(cursor
) << " -> " << entry
<< std::endl
;
601 cout
<< ": entry=" << entry
<< " expected=" << p
->second
<< std::endl
;
602 ASSERT_EQ(p
->second
, string(entry
));
606 rados_object_list_cursor_free(ctx
, cursor
);
610 TEST_F(LibRadosListEC
, ListObjects
) {
612 memset(buf
, 0xcc, sizeof(buf
));
613 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
614 rados_list_ctx_t ctx
;
615 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
617 bool foundit
= false;
618 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
620 ASSERT_EQ(std::string(entry
), "foo");
622 ASSERT_TRUE(foundit
);
623 rados_nobjects_list_close(ctx
);
626 TEST_F(LibRadosListECPP
, ListObjectsPP
) {
628 memset(buf
, 0xcc, sizeof(buf
));
630 bl1
.append(buf
, sizeof(buf
));
631 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
632 NObjectIterator
iter(ioctx
.nobjects_begin());
633 bool foundit
= false;
634 while (iter
!= ioctx
.nobjects_end()) {
636 ASSERT_EQ((*iter
).get_oid(), "foo");
639 ASSERT_TRUE(foundit
);
642 TEST_F(LibRadosListECPP
, ListObjectsTwicePP
) {
644 memset(buf
, 0xcc, sizeof(buf
));
646 bl1
.append(buf
, sizeof(buf
));
647 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
648 NObjectIterator
iter(ioctx
.nobjects_begin());
649 bool foundit
= false;
650 while (iter
!= ioctx
.nobjects_end()) {
652 ASSERT_EQ((*iter
).get_oid(), "foo");
655 ASSERT_TRUE(foundit
);
657 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
660 while (iter
!= ioctx
.nobjects_end()) {
662 ASSERT_EQ((*iter
).get_oid(), "foo");
665 ASSERT_TRUE(foundit
);
668 TEST_F(LibRadosListECPP
, ListObjectsCopyIterPP
) {
670 memset(buf
, 0xcc, sizeof(buf
));
672 bl1
.append(buf
, sizeof(buf
));
673 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
675 // make sure this is still valid after the original iterators are gone
676 NObjectIterator iter3
;
678 NObjectIterator
iter(ioctx
.nobjects_begin());
679 NObjectIterator
iter2(iter
);
681 ASSERT_EQ((*iter
).get_oid(), "foo");
683 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
685 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
687 ASSERT_EQ(iter2
->get_oid(), "foo");
688 ASSERT_EQ(iter3
->get_oid(), "foo");
690 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
693 ASSERT_EQ(iter3
->get_oid(), "foo");
695 ASSERT_EQ(iter3
->get_oid(), "foo");
697 ASSERT_TRUE(iter3
== ioctx
.nobjects_end());
700 TEST_F(LibRadosListECPP
, ListObjectsEndIter
) {
702 memset(buf
, 0xcc, sizeof(buf
));
704 bl1
.append(buf
, sizeof(buf
));
705 ASSERT_EQ(0, ioctx
.write("foo", bl1
, sizeof(buf
), 0));
707 NObjectIterator
iter(ioctx
.nobjects_begin());
708 NObjectIterator
iter_end(ioctx
.nobjects_end());
709 NObjectIterator iter_end2
= ioctx
.nobjects_end();
710 ASSERT_TRUE(iter_end
== iter_end2
);
711 ASSERT_TRUE(iter_end
== ioctx
.nobjects_end());
712 ASSERT_TRUE(iter_end2
== ioctx
.nobjects_end());
714 ASSERT_EQ(iter
->get_oid(), "foo");
716 ASSERT_TRUE(iter
== ioctx
.nobjects_end());
717 ASSERT_TRUE(iter
== iter_end
);
718 ASSERT_TRUE(iter
== iter_end2
);
719 NObjectIterator iter2
= iter
;
720 ASSERT_TRUE(iter2
== ioctx
.nobjects_end());
721 ASSERT_TRUE(iter2
== iter_end
);
722 ASSERT_TRUE(iter2
== iter_end2
);
725 TEST_F(LibRadosListEC
, ListObjectsNS
) {
727 memset(buf
, 0xcc, sizeof(buf
));
728 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
729 rados_ioctx_set_namespace(ioctx
, "");
730 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
731 rados_ioctx_set_namespace(ioctx
, "ns1");
732 ASSERT_EQ(0, rados_write(ioctx
, "foo1", buf
, sizeof(buf
), 0));
733 rados_ioctx_set_namespace(ioctx
, "");
734 ASSERT_EQ(0, rados_write(ioctx
, "foo2", buf
, sizeof(buf
), 0));
735 ASSERT_EQ(0, rados_write(ioctx
, "foo3", buf
, sizeof(buf
), 0));
736 rados_ioctx_set_namespace(ioctx
, "ns1");
737 ASSERT_EQ(0, rados_write(ioctx
, "foo4", buf
, sizeof(buf
), 0));
738 ASSERT_EQ(0, rados_write(ioctx
, "foo5", buf
, sizeof(buf
), 0));
739 rados_ioctx_set_namespace(ioctx
, "ns2");
740 ASSERT_EQ(0, rados_write(ioctx
, "foo6", buf
, sizeof(buf
), 0));
741 ASSERT_EQ(0, rados_write(ioctx
, "foo7", buf
, sizeof(buf
), 0));
743 std::set
<std::string
> def
, ns1
, ns2
, all
;
744 def
.insert(std::string("foo1"));
745 def
.insert(std::string("foo2"));
746 def
.insert(std::string("foo3"));
747 ns1
.insert(std::string("foo1"));
748 ns1
.insert(std::string("foo4"));
749 ns1
.insert(std::string("foo5"));
750 ns2
.insert(std::string("foo6"));
751 ns2
.insert(std::string("foo7"));
752 all
.insert(std::string(":foo1"));
753 all
.insert(std::string(":foo2"));
754 all
.insert(std::string(":foo3"));
755 all
.insert(std::string("ns1:foo1"));
756 all
.insert(std::string("ns1:foo4"));
757 all
.insert(std::string("ns1:foo5"));
758 all
.insert(std::string("ns2:foo6"));
759 all
.insert(std::string("ns2:foo7"));
761 rados_list_ctx_t ctx
;
762 // Check default namespace ""
763 rados_ioctx_set_namespace(ioctx
, "");
764 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
765 check_list(def
, ctx
, "");
766 rados_nobjects_list_close(ctx
);
768 // Check default namespace "ns1"
769 rados_ioctx_set_namespace(ioctx
, "ns1");
770 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
771 check_list(ns1
, ctx
, "ns1");
772 rados_nobjects_list_close(ctx
);
774 // Check default namespace "ns2"
775 rados_ioctx_set_namespace(ioctx
, "ns2");
776 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
777 check_list(ns2
, ctx
, "ns2");
778 rados_nobjects_list_close(ctx
);
780 // Check all namespaces
781 rados_ioctx_set_namespace(ioctx
, LIBRADOS_ALL_NSPACES
);
782 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
783 check_list(all
, ctx
, all_nspaces
);
784 rados_nobjects_list_close(ctx
);
787 TEST_F(LibRadosListECPP
, ListObjectsPPNS
) {
789 memset(buf
, 0xcc, sizeof(buf
));
791 bl1
.append(buf
, sizeof(buf
));
792 // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
793 ioctx
.set_namespace("");
794 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
795 ioctx
.set_namespace("ns1");
796 ASSERT_EQ(0, ioctx
.write("foo1", bl1
, sizeof(buf
), 0));
797 ioctx
.set_namespace("");
798 ASSERT_EQ(0, ioctx
.write("foo2", bl1
, sizeof(buf
), 0));
799 ASSERT_EQ(0, ioctx
.write("foo3", bl1
, sizeof(buf
), 0));
800 ioctx
.set_namespace("ns1");
801 ASSERT_EQ(0, ioctx
.write("foo4", bl1
, sizeof(buf
), 0));
802 ASSERT_EQ(0, ioctx
.write("foo5", bl1
, sizeof(buf
), 0));
803 ioctx
.set_namespace("ns2");
804 ASSERT_EQ(0, ioctx
.write("foo6", bl1
, sizeof(buf
), 0));
805 ASSERT_EQ(0, ioctx
.write("foo7", bl1
, sizeof(buf
), 0));
807 std::set
<std::string
> def
, ns1
, ns2
;
808 def
.insert(std::string("foo1"));
809 def
.insert(std::string("foo2"));
810 def
.insert(std::string("foo3"));
811 ns1
.insert(std::string("foo1"));
812 ns1
.insert(std::string("foo4"));
813 ns1
.insert(std::string("foo5"));
814 ns2
.insert(std::string("foo6"));
815 ns2
.insert(std::string("foo7"));
817 ioctx
.set_namespace("");
818 check_listpp(def
, ioctx
, "");
820 ioctx
.set_namespace("ns1");
821 check_listpp(ns1
, ioctx
, "ns1");
823 ioctx
.set_namespace("ns2");
824 check_listpp(ns2
, ioctx
, "ns2");
827 TEST_F(LibRadosListECPP
, ListObjectsManyPP
) {
829 memset(buf
, 0xcc, sizeof(buf
));
831 bl
.append(buf
, sizeof(buf
));
833 for (int i
=0; i
<256; ++i
) {
834 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
837 librados::NObjectIterator it
= ioctx
.nobjects_begin();
838 std::set
<std::string
> saw_obj
;
839 std::set
<int> saw_pg
;
840 for (; it
!= ioctx
.nobjects_end(); ++it
) {
841 std::cout
<< it
->get_oid()
842 << " " << it
.get_pg_hash_position() << std::endl
;
843 saw_obj
.insert(it
->get_oid());
844 saw_pg
.insert(it
.get_pg_hash_position());
846 std::cout
<< "saw " << saw_pg
.size() << " pgs " << std::endl
;
848 // make sure they are 0..n
849 for (unsigned i
= 0; i
< saw_pg
.size(); ++i
)
850 ASSERT_TRUE(saw_pg
.count(i
));
853 TEST_F(LibRadosListEC
, ListObjectsStart
) {
855 memset(buf
, 0xcc, sizeof(buf
));
857 for (int i
=0; i
<16; ++i
) {
858 string n
= stringify(i
);
859 ASSERT_EQ(0, rados_write(ioctx
, n
.c_str(), buf
, sizeof(buf
), 0));
862 rados_list_ctx_t ctx
;
863 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
864 std::map
<int, std::set
<std::string
> > pg_to_obj
;
866 while (rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
) == 0) {
867 uint32_t pos
= rados_nobjects_list_get_pg_hash_position(ctx
);
868 std::cout
<< entry
<< " " << pos
<< std::endl
;
869 pg_to_obj
[pos
].insert(entry
);
871 rados_nobjects_list_close(ctx
);
873 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
875 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
876 while (p
!= pg_to_obj
.rend()) {
877 ASSERT_EQ((uint32_t)p
->first
, rados_nobjects_list_seek(ctx
, p
->first
));
878 ASSERT_EQ(0, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
879 std::cout
<< "have " << entry
<< " expect one of " << p
->second
<< std::endl
;
880 ASSERT_TRUE(p
->second
.count(entry
));
883 rados_nobjects_list_close(ctx
);
886 TEST_F(LibRadosListECPP
, ListObjectsStartPP
) {
888 memset(buf
, 0xcc, sizeof(buf
));
890 bl
.append(buf
, sizeof(buf
));
892 for (int i
=0; i
<16; ++i
) {
893 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, bl
.length(), 0));
896 librados::NObjectIterator it
= ioctx
.nobjects_begin();
897 std::map
<int, std::set
<std::string
> > pg_to_obj
;
898 for (; it
!= ioctx
.nobjects_end(); ++it
) {
899 std::cout
<< it
->get_oid() << " " << it
.get_pg_hash_position() << std::endl
;
900 pg_to_obj
[it
.get_pg_hash_position()].insert(it
->get_oid());
903 std::map
<int, std::set
<std::string
> >::reverse_iterator p
=
905 it
= ioctx
.nobjects_begin(p
->first
);
906 while (p
!= pg_to_obj
.rend()) {
907 ASSERT_EQ((uint32_t)p
->first
, it
.seek(p
->first
));
908 std::cout
<< "have " << it
->get_oid() << " expect one of " << p
->second
<< std::endl
;
909 ASSERT_TRUE(p
->second
.count(it
->get_oid()));
914 TEST_F(LibRadosListPP
, ListObjectsFilterPP
) {
916 memset(buf
, 0xcc, sizeof(buf
));
917 bufferlist obj_content
;
918 obj_content
.append(buf
, sizeof(buf
));
920 std::string target_str
= "content";
922 // Write xattr bare, no ::encod'ing
923 bufferlist target_val
;
924 target_val
.append(target_str
);
925 bufferlist nontarget_val
;
926 nontarget_val
.append("rhubarb");
928 ASSERT_EQ(0, ioctx
.write("has_xattr", obj_content
, obj_content
.length(), 0));
929 ASSERT_EQ(0, ioctx
.write("has_wrong_xattr", obj_content
, obj_content
.length(), 0));
930 ASSERT_EQ(0, ioctx
.write("no_xattr", obj_content
, obj_content
.length(), 0));
932 ASSERT_EQ(0, ioctx
.setxattr("has_xattr", "theattr", target_val
));
933 ASSERT_EQ(0, ioctx
.setxattr("has_wrong_xattr", "theattr", nontarget_val
));
935 bufferlist filter_bl
;
936 std::string filter_name
= "plain";
937 ::encode(filter_name
, filter_bl
);
938 ::encode("_theattr", filter_bl
);
939 ::encode(target_str
, filter_bl
);
941 NObjectIterator
iter(ioctx
.nobjects_begin(filter_bl
));
942 bool foundit
= false;
944 while (iter
!= ioctx
.nobjects_end()) {
946 // We should only see the object that matches the filter
947 ASSERT_EQ((*iter
).get_oid(), "has_xattr");
948 // We should only see it once
953 ASSERT_TRUE(foundit
);
956 TEST_F(LibRadosListNP
, ListObjectsError
) {
957 std::string pool_name
;
960 pool_name
= get_temp_pool_name();
961 ASSERT_EQ("", create_one_pool(pool_name
, &cluster
));
962 ASSERT_EQ(0, rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
));
964 memset(buf
, 0xcc, sizeof(buf
));
965 rados_ioctx_set_namespace(ioctx
, "");
966 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
968 //ASSERT_EQ(0, rados_pool_delete(cluster, pool_name.c_str()));
971 size_t buflen
, stlen
;
972 string c
= "{\"prefix\":\"osd pool rm\",\"pool\": \"" + pool_name
+
973 "\",\"pool2\":\"" + pool_name
+
974 "\",\"sure\": \"--yes-i-really-really-mean-it-not-faking\"}";
975 const char *cmd
[2] = { c
.c_str(), 0 };
976 ASSERT_EQ(0, rados_mon_command(cluster
, (const char **)cmd
, 1, "", 0, &buf
, &buflen
, &st
, &stlen
));
979 rados_list_ctx_t ctx
;
980 ASSERT_EQ(0, rados_nobjects_list_open(ioctx
, &ctx
));
982 ASSERT_EQ(-ENOENT
, rados_nobjects_list_next(ctx
, &entry
, NULL
, NULL
));
983 rados_nobjects_list_close(ctx
);
984 rados_ioctx_destroy(ioctx
);
985 rados_shutdown(cluster
);
990 // ---------------------------------------------
992 TEST_F(LibRadosList
, EnumerateObjects
) {
994 memset(buf
, 0xcc, sizeof(buf
));
996 const uint32_t n_objects
= 16;
997 for (unsigned i
=0; i
<n_objects
; ++i
) {
998 ASSERT_EQ(0, rados_write(ioctx
, stringify(i
).c_str(), buf
, sizeof(buf
), 0));
1001 // Ensure a non-power-of-two PG count to avoid only
1002 // touching the easy path.
1003 std::string err_str
= set_pg_num(&s_cluster
, pool_name
, 11);
1004 ASSERT_TRUE(err_str
.empty());
1006 std::set
<std::string
> saw_obj
;
1007 rados_object_list_cursor c
= rados_object_list_begin(ioctx
);
1008 rados_object_list_cursor end
= rados_object_list_end(ioctx
);
1009 while(!rados_object_list_is_end(ioctx
, c
))
1011 rados_object_list_item results
[12];
1012 memset(results
, 0, sizeof(rados_object_list_item
) * 12);
1013 rados_object_list_cursor temp_end
= rados_object_list_end(ioctx
);
1014 int r
= rados_object_list(ioctx
, c
, temp_end
,
1015 12, NULL
, 0, results
, &c
);
1016 rados_object_list_cursor_free(ioctx
, temp_end
);
1018 for (int i
= 0; i
< r
; ++i
) {
1019 std::string
oid(results
[i
].oid
, results
[i
].oid_length
);
1020 if (saw_obj
.count(oid
)) {
1021 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1023 ASSERT_FALSE(saw_obj
.count(oid
));
1024 saw_obj
.insert(oid
);
1026 rados_object_list_free(12, results
);
1028 rados_object_list_cursor_free(ioctx
, c
);
1029 rados_object_list_cursor_free(ioctx
, end
);
1031 for (unsigned i
=0; i
<n_objects
; ++i
) {
1032 if (!saw_obj
.count(stringify(i
))) {
1033 std::cerr
<< "missing object " << i
<< std::endl
;
1035 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1037 ASSERT_EQ(n_objects
, saw_obj
.size());
1040 TEST_F(LibRadosList
, EnumerateObjectsSplit
) {
1042 memset(buf
, 0xcc, sizeof(buf
));
1044 const uint32_t n_objects
= 16;
1045 for (unsigned i
=0; i
<n_objects
; ++i
) {
1046 ASSERT_EQ(0, rados_write(ioctx
, stringify(i
).c_str(), buf
, sizeof(buf
), 0));
1049 // Ensure a non-power-of-two PG count to avoid only
1050 // touching the easy path.
1051 std::string err_str
= set_pg_num(&s_cluster
, pool_name
, 11);
1052 ASSERT_TRUE(err_str
.empty());
1054 rados_object_list_cursor begin
= rados_object_list_begin(ioctx
);
1055 rados_object_list_cursor end
= rados_object_list_end(ioctx
);
1057 // Step through an odd number of shards
1059 std::set
<std::string
> saw_obj
;
1060 for (unsigned n
= 0; n
< m
; ++n
) {
1061 rados_object_list_cursor shard_start
= rados_object_list_begin(ioctx
);;
1062 rados_object_list_cursor shard_end
= rados_object_list_end(ioctx
);;
1064 rados_object_list_slice(
1072 std::cout
<< "split " << n
<< "/" << m
<< " -> "
1073 << *(hobject_t
*)shard_start
<< " "
1074 << *(hobject_t
*)shard_end
<< std::endl
;
1076 rados_object_list_cursor c
= shard_start
;
1077 //while(c < shard_end)
1078 while(rados_object_list_cursor_cmp(ioctx
, c
, shard_end
) == -1)
1080 rados_object_list_item results
[12];
1081 memset(results
, 0, sizeof(rados_object_list_item
) * 12);
1082 int r
= rados_object_list(ioctx
,
1084 12, NULL
, 0, results
, &c
);
1086 for (int i
= 0; i
< r
; ++i
) {
1087 std::string
oid(results
[i
].oid
, results
[i
].oid_length
);
1088 if (saw_obj
.count(oid
)) {
1089 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1091 ASSERT_FALSE(saw_obj
.count(oid
));
1092 saw_obj
.insert(oid
);
1094 rados_object_list_free(12, results
);
1096 rados_object_list_cursor_free(ioctx
, shard_start
);
1097 rados_object_list_cursor_free(ioctx
, shard_end
);
1100 rados_object_list_cursor_free(ioctx
, begin
);
1101 rados_object_list_cursor_free(ioctx
, end
);
1103 for (unsigned i
=0; i
<n_objects
; ++i
) {
1104 if (!saw_obj
.count(stringify(i
))) {
1105 std::cerr
<< "missing object " << i
<< std::endl
;
1107 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1109 ASSERT_EQ(n_objects
, saw_obj
.size());
1112 TEST_F(LibRadosListPP
, EnumerateObjectsPP
) {
1114 memset(buf
, 0xcc, sizeof(buf
));
1116 bl
.append(buf
, sizeof(buf
));
1118 const uint32_t n_objects
= 16;
1119 for (unsigned i
=0; i
<n_objects
; ++i
) {
1120 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, sizeof(buf
), 0));
1123 std::set
<std::string
> saw_obj
;
1124 ObjectCursor c
= ioctx
.object_list_begin();
1125 ObjectCursor end
= ioctx
.object_list_end();
1126 while(!ioctx
.object_list_is_end(c
))
1128 std::vector
<ObjectItem
> result
;
1129 int r
= ioctx
.object_list(c
, end
, 12, {}, &result
, &c
);
1131 ASSERT_EQ(r
, (int)result
.size());
1132 for (int i
= 0; i
< r
; ++i
) {
1133 auto oid
= result
[i
].oid
;
1134 if (saw_obj
.count(oid
)) {
1135 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1137 ASSERT_FALSE(saw_obj
.count(oid
));
1138 saw_obj
.insert(oid
);
1142 for (unsigned i
=0; i
<n_objects
; ++i
) {
1143 if (!saw_obj
.count(stringify(i
))) {
1144 std::cerr
<< "missing object " << i
<< std::endl
;
1146 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1148 ASSERT_EQ(n_objects
, saw_obj
.size());
1151 TEST_F(LibRadosListPP
, EnumerateObjectsSplitPP
) {
1153 memset(buf
, 0xcc, sizeof(buf
));
1155 bl
.append(buf
, sizeof(buf
));
1157 const uint32_t n_objects
= 16;
1158 for (unsigned i
=0; i
<n_objects
; ++i
) {
1159 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, sizeof(buf
), 0));
1162 ObjectCursor begin
= ioctx
.object_list_begin();
1163 ObjectCursor end
= ioctx
.object_list_end();
1165 // Step through an odd number of shards
1167 std::set
<std::string
> saw_obj
;
1168 for (unsigned n
= 0; n
< m
; ++n
) {
1169 ObjectCursor shard_start
;
1170 ObjectCursor shard_end
;
1172 ioctx
.object_list_slice(
1180 ObjectCursor
c(shard_start
);
1181 while(c
< shard_end
)
1183 std::vector
<ObjectItem
> result
;
1184 int r
= ioctx
.object_list(c
, shard_end
, 12, {}, &result
, &c
);
1187 for (const auto & i
: result
) {
1188 const auto &oid
= i
.oid
;
1189 if (saw_obj
.count(oid
)) {
1190 std::cerr
<< "duplicate obj " << oid
<< std::endl
;
1192 ASSERT_FALSE(saw_obj
.count(oid
));
1193 saw_obj
.insert(oid
);
1198 for (unsigned i
=0; i
<n_objects
; ++i
) {
1199 if (!saw_obj
.count(stringify(i
))) {
1200 std::cerr
<< "missing object " << i
<< std::endl
;
1202 ASSERT_TRUE(saw_obj
.count(stringify(i
)));
1204 ASSERT_EQ(n_objects
, saw_obj
.size());
1208 TEST_F(LibRadosListPP
, EnumerateObjectsFilterPP
) {
1210 memset(buf
, 0xcc, sizeof(buf
));
1211 bufferlist obj_content
;
1212 obj_content
.append(buf
, sizeof(buf
));
1214 std::string target_str
= "content";
1216 // Write xattr bare, no ::encod'ing
1217 bufferlist target_val
;
1218 target_val
.append(target_str
);
1219 bufferlist nontarget_val
;
1220 nontarget_val
.append("rhubarb");
1222 ASSERT_EQ(0, ioctx
.write("has_xattr", obj_content
, obj_content
.length(), 0));
1223 ASSERT_EQ(0, ioctx
.write("has_wrong_xattr", obj_content
, obj_content
.length(), 0));
1224 ASSERT_EQ(0, ioctx
.write("no_xattr", obj_content
, obj_content
.length(), 0));
1226 ASSERT_EQ(0, ioctx
.setxattr("has_xattr", "theattr", target_val
));
1227 ASSERT_EQ(0, ioctx
.setxattr("has_wrong_xattr", "theattr", nontarget_val
));
1229 bufferlist filter_bl
;
1230 std::string filter_name
= "plain";
1231 ::encode(filter_name
, filter_bl
);
1232 ::encode("_theattr", filter_bl
);
1233 ::encode(target_str
, filter_bl
);
1235 ObjectCursor c
= ioctx
.object_list_begin();
1236 ObjectCursor end
= ioctx
.object_list_end();
1237 bool foundit
= false;
1238 while(!ioctx
.object_list_is_end(c
))
1240 std::vector
<ObjectItem
> result
;
1241 int r
= ioctx
.object_list(c
, end
, 12, filter_bl
, &result
, &c
);
1243 ASSERT_EQ(r
, (int)result
.size());
1244 for (int i
= 0; i
< r
; ++i
) {
1245 auto oid
= result
[i
].oid
;
1246 // We should only see the object that matches the filter
1247 ASSERT_EQ(oid
, "has_xattr");
1248 // We should only see it once
1249 ASSERT_FALSE(foundit
);
1253 ASSERT_TRUE(foundit
);