]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
9 | ||
10 | #include "include/types.h" | |
11 | #include "common/hobject.h" | |
12 | #include "gtest/gtest.h" | |
13 | #include <errno.h> | |
14 | #include <string> | |
15 | #include <stdexcept> | |
16 | ||
17 | using namespace librados; | |
18 | ||
19 | typedef RadosTestNSCleanup LibRadosList; | |
20 | typedef RadosTestPPNSCleanup LibRadosListPP; | |
21 | typedef RadosTestECNSCleanup LibRadosListEC; | |
22 | typedef RadosTestECPPNSCleanup LibRadosListECPP; | |
23 | typedef RadosTestNP LibRadosListNP; | |
24 | ||
25 | ||
26 | TEST_F(LibRadosList, ListObjects) { | |
27 | char buf[128]; | |
28 | memset(buf, 0xcc, sizeof(buf)); | |
29 | ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); | |
30 | rados_list_ctx_t ctx; | |
31 | ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx)); | |
32 | const char *entry; | |
33 | bool foundit = false; | |
34 | while (rados_nobjects_list_next(ctx, &entry, NULL, NULL) != -ENOENT) { | |
35 | foundit = true; | |
36 | ASSERT_EQ(std::string(entry), "foo"); | |
37 | } | |
38 | ASSERT_TRUE(foundit); | |
39 | rados_nobjects_list_close(ctx); | |
40 | } | |
41 | ||
42 | TEST_F(LibRadosListPP, ListObjectsPP) { | |
43 | char buf[128]; | |
44 | memset(buf, 0xcc, sizeof(buf)); | |
45 | bufferlist bl1; | |
46 | bl1.append(buf, sizeof(buf)); | |
47 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
48 | NObjectIterator iter(ioctx.nobjects_begin()); | |
49 | bool foundit = false; | |
50 | while (iter != ioctx.nobjects_end()) { | |
51 | foundit = true; | |
52 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
53 | ++iter; | |
54 | } | |
55 | ASSERT_TRUE(foundit); | |
56 | } | |
57 | ||
58 | TEST_F(LibRadosListPP, ListObjectsTwicePP) { | |
59 | char buf[128]; | |
60 | memset(buf, 0xcc, sizeof(buf)); | |
61 | bufferlist bl1; | |
62 | bl1.append(buf, sizeof(buf)); | |
63 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
64 | NObjectIterator iter(ioctx.nobjects_begin()); | |
65 | bool foundit = false; | |
66 | while (iter != ioctx.nobjects_end()) { | |
67 | foundit = true; | |
68 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
69 | ++iter; | |
70 | } | |
71 | ASSERT_TRUE(foundit); | |
72 | ++iter; | |
73 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
74 | foundit = false; | |
75 | iter.seek(0); | |
76 | while (iter != ioctx.nobjects_end()) { | |
77 | foundit = true; | |
78 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
79 | ++iter; | |
80 | } | |
81 | ASSERT_TRUE(foundit); | |
82 | } | |
83 | ||
84 | TEST_F(LibRadosListPP, ListObjectsCopyIterPP) { | |
85 | char buf[128]; | |
86 | memset(buf, 0xcc, sizeof(buf)); | |
87 | bufferlist bl1; | |
88 | bl1.append(buf, sizeof(buf)); | |
89 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
90 | ||
91 | // make sure this is still valid after the original iterators are gone | |
92 | NObjectIterator iter3; | |
93 | { | |
94 | NObjectIterator iter(ioctx.nobjects_begin()); | |
95 | NObjectIterator iter2(iter); | |
96 | iter3 = iter2; | |
97 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
98 | ++iter; | |
99 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
100 | ++iter; | |
101 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
102 | ||
103 | ASSERT_EQ(iter2->get_oid(), "foo"); | |
104 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
105 | ++iter2; | |
106 | ASSERT_TRUE(iter2 == ioctx.nobjects_end()); | |
107 | } | |
108 | ||
109 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
110 | iter3 = iter3; | |
111 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
112 | ++iter3; | |
113 | ASSERT_TRUE(iter3 == ioctx.nobjects_end()); | |
114 | } | |
115 | ||
116 | TEST_F(LibRadosListPP, ListObjectsEndIter) { | |
117 | char buf[128]; | |
118 | memset(buf, 0xcc, sizeof(buf)); | |
119 | bufferlist bl1; | |
120 | bl1.append(buf, sizeof(buf)); | |
121 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
122 | ||
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()); | |
129 | ||
130 | ASSERT_EQ(iter->get_oid(), "foo"); | |
131 | ++iter; | |
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); | |
139 | } | |
140 | ||
141 | static void check_list( | |
142 | std::set<std::string>& myset, | |
143 | rados_list_ctx_t& ctx, | |
144 | std::string check_nspace) | |
145 | { | |
146 | const char *entry, *nspace; | |
147 | cout << "myset " << myset << std::endl; | |
148 | // we should see every item exactly once. | |
149 | int ret; | |
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); | |
154 | } else { | |
155 | ASSERT_TRUE(std::string(nspace) == check_nspace); | |
156 | test_name = std::string(entry); | |
157 | } | |
158 | cout << test_name << std::endl; | |
159 | ||
160 | ASSERT_TRUE(myset.end() != myset.find(test_name)); | |
161 | myset.erase(test_name); | |
162 | } | |
163 | ASSERT_EQ(-ENOENT, ret); | |
164 | ASSERT_TRUE(myset.empty()); | |
165 | } | |
166 | ||
167 | TEST_F(LibRadosList, ListObjectsNS) { | |
168 | char buf[128]; | |
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)); | |
184 | ||
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")); | |
202 | ||
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); | |
209 | ||
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); | |
215 | ||
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); | |
221 | ||
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); | |
227 | } | |
228 | ||
229 | static void check_listpp(std::set<std::string>& myset, IoCtx& ioctx, std::string check_nspace) | |
230 | { | |
231 | NObjectIterator iter(ioctx.nobjects_begin()); | |
232 | std::set<std::string> orig_set(myset); | |
233 | /** | |
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 | |
237 | * at least once. | |
238 | */ | |
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(); | |
243 | } else { | |
244 | ASSERT_TRUE(iter->get_nspace() == check_nspace); | |
245 | test_name = iter->get_oid(); | |
246 | } | |
247 | ASSERT_TRUE(orig_set.end() != orig_set.find(test_name)); | |
248 | myset.erase(test_name); | |
249 | ++iter; | |
250 | } | |
251 | ASSERT_TRUE(myset.empty()); | |
252 | } | |
253 | ||
254 | TEST_F(LibRadosListPP, ListObjectsPPNS) { | |
255 | char buf[128]; | |
256 | memset(buf, 0xcc, sizeof(buf)); | |
257 | bufferlist bl1; | |
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)); | |
273 | ||
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")); | |
291 | ||
292 | ioctx.set_namespace(""); | |
293 | check_listpp(def, ioctx, ""); | |
294 | ||
295 | ioctx.set_namespace("ns1"); | |
296 | check_listpp(ns1, ioctx, "ns1"); | |
297 | ||
298 | ioctx.set_namespace("ns2"); | |
299 | check_listpp(ns2, ioctx, "ns2"); | |
300 | ||
301 | ioctx.set_namespace(all_nspaces); | |
302 | check_listpp(all, ioctx, all_nspaces); | |
303 | } | |
304 | ||
305 | TEST_F(LibRadosListPP, ListObjectsManyPP) { | |
306 | char buf[128]; | |
307 | memset(buf, 0xcc, sizeof(buf)); | |
308 | bufferlist bl; | |
309 | bl.append(buf, sizeof(buf)); | |
310 | ||
311 | for (int i=0; i<256; ++i) { | |
312 | ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); | |
313 | } | |
314 | ||
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()); | |
323 | } | |
324 | std::cout << "saw " << saw_pg.size() << " pgs " << std::endl; | |
325 | ||
326 | // make sure they are 0..n | |
327 | for (unsigned i = 0; i < saw_pg.size(); ++i) | |
328 | ASSERT_TRUE(saw_pg.count(i)); | |
329 | } | |
330 | ||
331 | TEST_F(LibRadosList, ListObjectsStart) { | |
332 | char buf[128]; | |
333 | memset(buf, 0xcc, sizeof(buf)); | |
334 | ||
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)); | |
338 | } | |
339 | ||
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; | |
343 | const char *entry; | |
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); | |
348 | } | |
349 | rados_nobjects_list_close(ctx); | |
350 | ||
351 | std::map<int, std::set<std::string> >::reverse_iterator p = | |
352 | pg_to_obj.rbegin(); | |
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)); | |
359 | ++p; | |
360 | } | |
361 | rados_nobjects_list_close(ctx); | |
362 | } | |
363 | ||
364 | TEST_F(LibRadosListPP, ListObjectsStartPP) { | |
365 | char buf[128]; | |
366 | memset(buf, 0xcc, sizeof(buf)); | |
367 | bufferlist bl; | |
368 | bl.append(buf, sizeof(buf)); | |
369 | ||
370 | for (int i=0; i<16; ++i) { | |
371 | ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); | |
372 | } | |
373 | ||
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()); | |
379 | } | |
380 | ||
381 | std::map<int, std::set<std::string> >::reverse_iterator p = | |
382 | pg_to_obj.rbegin(); | |
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())); | |
388 | ++p; | |
389 | } | |
390 | } | |
391 | ||
392 | TEST_F(LibRadosListPP, ListObjectsCursorNSPP) { | |
393 | char buf[128]; | |
394 | memset(buf, 0xcc, sizeof(buf)); | |
395 | bufferlist bl; | |
396 | bl.append(buf, sizeof(buf)); | |
397 | ||
398 | const int max_objs = 16; | |
399 | ||
400 | map<string, string> oid_to_ns; | |
401 | ||
402 | for (int i=0; i<max_objs; ++i) { | |
403 | stringstream ss; | |
404 | ss << "ns" << i / 4; | |
405 | ioctx.set_namespace(ss.str()); | |
406 | string oid = stringify(i); | |
407 | ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0)); | |
408 | ||
409 | oid_to_ns[oid] = ss.str(); | |
410 | } | |
411 | ||
412 | ioctx.set_namespace(all_nspaces); | |
413 | ||
414 | librados::NObjectIterator it = ioctx.nobjects_begin(); | |
415 | std::map<librados::ObjectCursor, string> cursor_to_obj; | |
416 | ||
417 | int count = 0; | |
418 | ||
419 | librados::ObjectCursor seek_cursor; | |
420 | ||
421 | map<string, list<librados::ObjectCursor> > ns_to_cursors; | |
422 | ||
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; | |
427 | } | |
428 | ||
429 | vector<string> objs_order; | |
430 | ||
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; | |
437 | ||
438 | ASSERT_EQ(oid_to_ns[oid], it->get_nspace()); | |
439 | ||
440 | it.seek(cursor); | |
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 */ | |
444 | ||
445 | ns_to_cursors[it->get_nspace()].push_back(cursor); | |
446 | ||
447 | if (count == max_objs/2) { | |
448 | seek_cursor = cursor; | |
449 | } | |
450 | objs_order.push_back(it->get_oid()); | |
451 | } | |
452 | ||
453 | ASSERT_EQ(count, max_objs); | |
454 | ||
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()); | |
460 | } | |
461 | ||
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; | |
466 | ||
467 | for (auto& cursor : cursors) { | |
468 | cout << ": seek to " << cursor << std::endl; | |
469 | it.seek(cursor); | |
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); | |
477 | } | |
478 | } | |
479 | } | |
480 | ||
481 | TEST_F(LibRadosListPP, ListObjectsCursorPP) { | |
482 | char buf[128]; | |
483 | memset(buf, 0xcc, sizeof(buf)); | |
484 | bufferlist bl; | |
485 | bl.append(buf, sizeof(buf)); | |
486 | ||
487 | const int max_objs = 16; | |
488 | ||
489 | for (int i=0; i<max_objs; ++i) { | |
490 | stringstream ss; | |
491 | ss << "ns" << i / 4; | |
492 | ioctx.set_namespace(ss.str()); | |
493 | ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); | |
494 | } | |
495 | ||
496 | ioctx.set_namespace(all_nspaces); | |
497 | ||
498 | librados::NObjectIterator it = ioctx.nobjects_begin(); | |
499 | std::map<librados::ObjectCursor, string> cursor_to_obj; | |
500 | ||
501 | int count = 0; | |
502 | ||
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; | |
509 | ||
510 | it.seek(cursor); | |
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 */ | |
514 | } | |
515 | ||
516 | ASSERT_EQ(count, max_objs); | |
517 | ||
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; | |
522 | it.seek(p->first); | |
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()); | |
527 | ||
528 | librados::NObjectIterator it2 = ioctx.nobjects_begin(it.get_cursor()); | |
529 | ASSERT_EQ(it2->get_oid(), it->get_oid()); | |
530 | ||
531 | ++p; | |
532 | } | |
533 | } | |
534 | ||
535 | TEST_F(LibRadosList, ListObjectsCursor) { | |
536 | char buf[128]; | |
537 | memset(buf, 0xcc, sizeof(buf)); | |
538 | ||
539 | const int max_objs = 16; | |
540 | ||
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)); | |
544 | } | |
545 | ||
546 | { | |
547 | rados_list_ctx_t ctx; | |
548 | const char *entry; | |
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) { | |
555 | string oid = entry; | |
556 | ASSERT_EQ(rados_nobjects_list_get_cursor(ctx, &cursor), 0); | |
557 | cout << "> oid=" << oid << " cursor=" << ObjectCursor(cursor) << std::endl; | |
558 | } | |
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; | |
562 | } | |
563 | rados_list_ctx_t ctx; | |
564 | ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx)); | |
565 | ||
566 | std::map<rados_object_list_cursor, string> cursor_to_obj; | |
567 | int count = 0; | |
568 | ||
569 | const char *entry; | |
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); | |
573 | string oid = entry; | |
574 | cout << ": oid=" << oid << " cursor=" << ObjectCursor(cursor) << std::endl; | |
575 | cursor_to_obj[cursor] = oid; | |
576 | ||
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 */ | |
583 | ||
584 | ++count; | |
585 | } | |
586 | ||
587 | ASSERT_EQ(count, max_objs); | |
588 | ||
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)); | |
603 | ||
604 | ++p; | |
605 | ||
606 | rados_object_list_cursor_free(ctx, cursor); | |
607 | } | |
608 | } | |
609 | ||
610 | TEST_F(LibRadosListEC, ListObjects) { | |
611 | char buf[128]; | |
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)); | |
616 | const char *entry; | |
617 | bool foundit = false; | |
618 | while (rados_nobjects_list_next(ctx, &entry, NULL, NULL) != -ENOENT) { | |
619 | foundit = true; | |
620 | ASSERT_EQ(std::string(entry), "foo"); | |
621 | } | |
622 | ASSERT_TRUE(foundit); | |
623 | rados_nobjects_list_close(ctx); | |
624 | } | |
625 | ||
626 | TEST_F(LibRadosListECPP, ListObjectsPP) { | |
627 | char buf[128]; | |
628 | memset(buf, 0xcc, sizeof(buf)); | |
629 | bufferlist bl1; | |
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()) { | |
635 | foundit = true; | |
636 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
637 | ++iter; | |
638 | } | |
639 | ASSERT_TRUE(foundit); | |
640 | } | |
641 | ||
642 | TEST_F(LibRadosListECPP, ListObjectsTwicePP) { | |
643 | char buf[128]; | |
644 | memset(buf, 0xcc, sizeof(buf)); | |
645 | bufferlist bl1; | |
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()) { | |
651 | foundit = true; | |
652 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
653 | ++iter; | |
654 | } | |
655 | ASSERT_TRUE(foundit); | |
656 | ++iter; | |
657 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
658 | foundit = false; | |
659 | iter.seek(0); | |
660 | while (iter != ioctx.nobjects_end()) { | |
661 | foundit = true; | |
662 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
663 | ++iter; | |
664 | } | |
665 | ASSERT_TRUE(foundit); | |
666 | } | |
667 | ||
668 | TEST_F(LibRadosListECPP, ListObjectsCopyIterPP) { | |
669 | char buf[128]; | |
670 | memset(buf, 0xcc, sizeof(buf)); | |
671 | bufferlist bl1; | |
672 | bl1.append(buf, sizeof(buf)); | |
673 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
674 | ||
675 | // make sure this is still valid after the original iterators are gone | |
676 | NObjectIterator iter3; | |
677 | { | |
678 | NObjectIterator iter(ioctx.nobjects_begin()); | |
679 | NObjectIterator iter2(iter); | |
680 | iter3 = iter2; | |
681 | ASSERT_EQ((*iter).get_oid(), "foo"); | |
682 | ++iter; | |
683 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
684 | ++iter; | |
685 | ASSERT_TRUE(iter == ioctx.nobjects_end()); | |
686 | ||
687 | ASSERT_EQ(iter2->get_oid(), "foo"); | |
688 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
689 | ++iter2; | |
690 | ASSERT_TRUE(iter2 == ioctx.nobjects_end()); | |
691 | } | |
692 | ||
693 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
694 | iter3 = iter3; | |
695 | ASSERT_EQ(iter3->get_oid(), "foo"); | |
696 | ++iter3; | |
697 | ASSERT_TRUE(iter3 == ioctx.nobjects_end()); | |
698 | } | |
699 | ||
700 | TEST_F(LibRadosListECPP, ListObjectsEndIter) { | |
701 | char buf[128]; | |
702 | memset(buf, 0xcc, sizeof(buf)); | |
703 | bufferlist bl1; | |
704 | bl1.append(buf, sizeof(buf)); | |
705 | ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); | |
706 | ||
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()); | |
713 | ||
714 | ASSERT_EQ(iter->get_oid(), "foo"); | |
715 | ++iter; | |
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); | |
723 | } | |
724 | ||
725 | TEST_F(LibRadosListEC, ListObjectsNS) { | |
726 | char buf[128]; | |
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)); | |
742 | ||
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")); | |
760 | ||
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); | |
767 | ||
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); | |
773 | ||
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); | |
779 | ||
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); | |
785 | } | |
786 | ||
787 | TEST_F(LibRadosListECPP, ListObjectsPPNS) { | |
788 | char buf[128]; | |
789 | memset(buf, 0xcc, sizeof(buf)); | |
790 | bufferlist bl1; | |
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)); | |
806 | ||
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")); | |
816 | ||
817 | ioctx.set_namespace(""); | |
818 | check_listpp(def, ioctx, ""); | |
819 | ||
820 | ioctx.set_namespace("ns1"); | |
821 | check_listpp(ns1, ioctx, "ns1"); | |
822 | ||
823 | ioctx.set_namespace("ns2"); | |
824 | check_listpp(ns2, ioctx, "ns2"); | |
825 | } | |
826 | ||
827 | TEST_F(LibRadosListECPP, ListObjectsManyPP) { | |
828 | char buf[128]; | |
829 | memset(buf, 0xcc, sizeof(buf)); | |
830 | bufferlist bl; | |
831 | bl.append(buf, sizeof(buf)); | |
832 | ||
833 | for (int i=0; i<256; ++i) { | |
834 | ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); | |
835 | } | |
836 | ||
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()); | |
845 | } | |
846 | std::cout << "saw " << saw_pg.size() << " pgs " << std::endl; | |
847 | ||
848 | // make sure they are 0..n | |
849 | for (unsigned i = 0; i < saw_pg.size(); ++i) | |
850 | ASSERT_TRUE(saw_pg.count(i)); | |
851 | } | |
852 | ||
853 | TEST_F(LibRadosListEC, ListObjectsStart) { | |
854 | char buf[128]; | |
855 | memset(buf, 0xcc, sizeof(buf)); | |
856 | ||
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)); | |
860 | } | |
861 | ||
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; | |
865 | const char *entry; | |
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); | |
870 | } | |
871 | rados_nobjects_list_close(ctx); | |
872 | ||
873 | std::map<int, std::set<std::string> >::reverse_iterator p = | |
874 | pg_to_obj.rbegin(); | |
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)); | |
881 | ++p; | |
882 | } | |
883 | rados_nobjects_list_close(ctx); | |
884 | } | |
885 | ||
886 | TEST_F(LibRadosListECPP, ListObjectsStartPP) { | |
887 | char buf[128]; | |
888 | memset(buf, 0xcc, sizeof(buf)); | |
889 | bufferlist bl; | |
890 | bl.append(buf, sizeof(buf)); | |
891 | ||
892 | for (int i=0; i<16; ++i) { | |
893 | ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); | |
894 | } | |
895 | ||
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()); | |
901 | } | |
902 | ||
903 | std::map<int, std::set<std::string> >::reverse_iterator p = | |
904 | pg_to_obj.rbegin(); | |
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())); | |
910 | ++p; | |
911 | } | |
912 | } | |
913 | ||
914 | TEST_F(LibRadosListPP, ListObjectsFilterPP) { | |
915 | char buf[128]; | |
916 | memset(buf, 0xcc, sizeof(buf)); | |
917 | bufferlist obj_content; | |
918 | obj_content.append(buf, sizeof(buf)); | |
919 | ||
920 | std::string target_str = "content"; | |
921 | ||
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"); | |
927 | ||
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)); | |
931 | ||
932 | ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val)); | |
933 | ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val)); | |
934 | ||
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); | |
940 | ||
941 | NObjectIterator iter(ioctx.nobjects_begin(filter_bl)); | |
942 | bool foundit = false; | |
943 | int k = 0; | |
944 | while (iter != ioctx.nobjects_end()) { | |
945 | foundit = true; | |
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 | |
949 | ASSERT_EQ(k, 0); | |
950 | ++iter; | |
951 | ++k; | |
952 | } | |
953 | ASSERT_TRUE(foundit); | |
954 | } | |
955 | ||
956 | TEST_F(LibRadosListNP, ListObjectsError) { | |
957 | std::string pool_name; | |
958 | rados_t cluster; | |
959 | rados_ioctx_t ioctx; | |
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)); | |
963 | char buf[128]; | |
964 | memset(buf, 0xcc, sizeof(buf)); | |
965 | rados_ioctx_set_namespace(ioctx, ""); | |
966 | ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); | |
967 | ||
968 | //ASSERT_EQ(0, rados_pool_delete(cluster, pool_name.c_str())); | |
969 | { | |
970 | char *buf, *st; | |
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)); | |
977 | } | |
978 | ||
979 | rados_list_ctx_t ctx; | |
980 | ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx)); | |
981 | const char *entry; | |
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); | |
986 | } | |
987 | ||
988 | ||
989 | ||
990 | // --------------------------------------------- | |
991 | ||
992 | TEST_F(LibRadosList, EnumerateObjects) { | |
993 | char buf[128]; | |
994 | memset(buf, 0xcc, sizeof(buf)); | |
995 | ||
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)); | |
999 | } | |
1000 | ||
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()); | |
1005 | ||
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)) | |
1010 | { | |
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); | |
1017 | ASSERT_GE(r, 0); | |
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; | |
1022 | } | |
1023 | ASSERT_FALSE(saw_obj.count(oid)); | |
1024 | saw_obj.insert(oid); | |
1025 | } | |
1026 | rados_object_list_free(12, results); | |
1027 | } | |
1028 | rados_object_list_cursor_free(ioctx, c); | |
1029 | rados_object_list_cursor_free(ioctx, end); | |
1030 | ||
1031 | for (unsigned i=0; i<n_objects; ++i) { | |
1032 | if (!saw_obj.count(stringify(i))) { | |
1033 | std::cerr << "missing object " << i << std::endl; | |
1034 | } | |
1035 | ASSERT_TRUE(saw_obj.count(stringify(i))); | |
1036 | } | |
1037 | ASSERT_EQ(n_objects, saw_obj.size()); | |
1038 | } | |
1039 | ||
1040 | TEST_F(LibRadosList, EnumerateObjectsSplit) { | |
1041 | char buf[128]; | |
1042 | memset(buf, 0xcc, sizeof(buf)); | |
1043 | ||
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)); | |
1047 | } | |
1048 | ||
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()); | |
1053 | ||
1054 | rados_object_list_cursor begin = rados_object_list_begin(ioctx); | |
1055 | rados_object_list_cursor end = rados_object_list_end(ioctx); | |
1056 | ||
1057 | // Step through an odd number of shards | |
1058 | unsigned m = 5; | |
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);; | |
1063 | ||
1064 | rados_object_list_slice( | |
1065 | ioctx, | |
1066 | begin, | |
1067 | end, | |
1068 | n, | |
1069 | m, | |
1070 | &shard_start, | |
1071 | &shard_end); | |
1072 | std::cout << "split " << n << "/" << m << " -> " | |
1073 | << *(hobject_t*)shard_start << " " | |
1074 | << *(hobject_t*)shard_end << std::endl; | |
1075 | ||
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) | |
1079 | { | |
1080 | rados_object_list_item results[12]; | |
1081 | memset(results, 0, sizeof(rados_object_list_item) * 12); | |
1082 | int r = rados_object_list(ioctx, | |
1083 | c, shard_end, | |
1084 | 12, NULL, 0, results, &c); | |
1085 | ASSERT_GE(r, 0); | |
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; | |
1090 | } | |
1091 | ASSERT_FALSE(saw_obj.count(oid)); | |
1092 | saw_obj.insert(oid); | |
1093 | } | |
1094 | rados_object_list_free(12, results); | |
1095 | } | |
1096 | rados_object_list_cursor_free(ioctx, shard_start); | |
1097 | rados_object_list_cursor_free(ioctx, shard_end); | |
1098 | } | |
1099 | ||
1100 | rados_object_list_cursor_free(ioctx, begin); | |
1101 | rados_object_list_cursor_free(ioctx, end); | |
1102 | ||
1103 | for (unsigned i=0; i<n_objects; ++i) { | |
1104 | if (!saw_obj.count(stringify(i))) { | |
1105 | std::cerr << "missing object " << i << std::endl; | |
1106 | } | |
1107 | ASSERT_TRUE(saw_obj.count(stringify(i))); | |
1108 | } | |
1109 | ASSERT_EQ(n_objects, saw_obj.size()); | |
1110 | } | |
1111 | ||
1112 | TEST_F(LibRadosListPP, EnumerateObjectsPP) { | |
1113 | char buf[128]; | |
1114 | memset(buf, 0xcc, sizeof(buf)); | |
1115 | bufferlist bl; | |
1116 | bl.append(buf, sizeof(buf)); | |
1117 | ||
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)); | |
1121 | } | |
1122 | ||
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)) | |
1127 | { | |
1128 | std::vector<ObjectItem> result; | |
1129 | int r = ioctx.object_list(c, end, 12, {}, &result, &c); | |
1130 | ASSERT_GE(r, 0); | |
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; | |
1136 | } | |
1137 | ASSERT_FALSE(saw_obj.count(oid)); | |
1138 | saw_obj.insert(oid); | |
1139 | } | |
1140 | } | |
1141 | ||
1142 | for (unsigned i=0; i<n_objects; ++i) { | |
1143 | if (!saw_obj.count(stringify(i))) { | |
1144 | std::cerr << "missing object " << i << std::endl; | |
1145 | } | |
1146 | ASSERT_TRUE(saw_obj.count(stringify(i))); | |
1147 | } | |
1148 | ASSERT_EQ(n_objects, saw_obj.size()); | |
1149 | } | |
1150 | ||
1151 | TEST_F(LibRadosListPP, EnumerateObjectsSplitPP) { | |
1152 | char buf[128]; | |
1153 | memset(buf, 0xcc, sizeof(buf)); | |
1154 | bufferlist bl; | |
1155 | bl.append(buf, sizeof(buf)); | |
1156 | ||
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)); | |
1160 | } | |
1161 | ||
1162 | ObjectCursor begin = ioctx.object_list_begin(); | |
1163 | ObjectCursor end = ioctx.object_list_end(); | |
1164 | ||
1165 | // Step through an odd number of shards | |
1166 | unsigned m = 5; | |
1167 | std::set<std::string> saw_obj; | |
1168 | for (unsigned n = 0; n < m; ++n) { | |
1169 | ObjectCursor shard_start; | |
1170 | ObjectCursor shard_end; | |
1171 | ||
1172 | ioctx.object_list_slice( | |
1173 | begin, | |
1174 | end, | |
1175 | n, | |
1176 | m, | |
1177 | &shard_start, | |
1178 | &shard_end); | |
1179 | ||
1180 | ObjectCursor c(shard_start); | |
1181 | while(c < shard_end) | |
1182 | { | |
1183 | std::vector<ObjectItem> result; | |
1184 | int r = ioctx.object_list(c, shard_end, 12, {}, &result, &c); | |
1185 | ASSERT_GE(r, 0); | |
1186 | ||
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; | |
1191 | } | |
1192 | ASSERT_FALSE(saw_obj.count(oid)); | |
1193 | saw_obj.insert(oid); | |
1194 | } | |
1195 | } | |
1196 | } | |
1197 | ||
1198 | for (unsigned i=0; i<n_objects; ++i) { | |
1199 | if (!saw_obj.count(stringify(i))) { | |
1200 | std::cerr << "missing object " << i << std::endl; | |
1201 | } | |
1202 | ASSERT_TRUE(saw_obj.count(stringify(i))); | |
1203 | } | |
1204 | ASSERT_EQ(n_objects, saw_obj.size()); | |
1205 | } | |
1206 | ||
1207 | ||
1208 | TEST_F(LibRadosListPP, EnumerateObjectsFilterPP) { | |
1209 | char buf[128]; | |
1210 | memset(buf, 0xcc, sizeof(buf)); | |
1211 | bufferlist obj_content; | |
1212 | obj_content.append(buf, sizeof(buf)); | |
1213 | ||
1214 | std::string target_str = "content"; | |
1215 | ||
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"); | |
1221 | ||
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)); | |
1225 | ||
1226 | ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val)); | |
1227 | ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val)); | |
1228 | ||
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); | |
1234 | ||
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)) | |
1239 | { | |
1240 | std::vector<ObjectItem> result; | |
1241 | int r = ioctx.object_list(c, end, 12, filter_bl, &result, &c); | |
1242 | ASSERT_GE(r, 0); | |
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); | |
1250 | foundit = true; | |
1251 | } | |
1252 | } | |
1253 | ASSERT_TRUE(foundit); | |
1254 | } |