1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
7 #include "common/config.h"
8 #include "common/Formatter.h"
9 #include "common/errno.h"
12 #include "rgw_multi.h"
13 #include "rgw_orphan.h"
15 #include "rgw_bucket.h"
16 #include "rgw_sal_rados.h"
18 #include "services/svc_zone.h"
19 #include "services/svc_sys_obj.h"
21 #define dout_subsys ceph_subsys_rgw
23 #define DEFAULT_NUM_SHARDS 64
27 static string
obj_fingerprint(const string
& oid
, const char *force_ns
= NULL
)
29 ssize_t pos
= oid
.find('_');
31 cerr
<< "ERROR: object does not have a bucket marker: " << oid
<< std::endl
;
34 string obj_marker
= oid
.substr(0, pos
);
38 rgw_obj_key::parse_raw_oid(oid
.substr(pos
+ 1), &key
);
48 rgw_obj
new_obj(b
, key
);
49 s
= obj_marker
+ "_" + new_obj
.get_oid();
53 size_t i
= s
.size() - 1;
54 for (; i
>= s
.size() - 10; --i
) {
56 if (!isdigit(c
) && c
!= '.' && c
!= '_') {
61 return s
.substr(0, i
+ 1);
64 int RGWOrphanStore::read_job(const string
& job_name
, RGWOrphanSearchState
& state
)
67 map
<string
, bufferlist
> vals
;
68 keys
.insert(job_name
);
69 int r
= ioctx
.omap_get_vals_by_keys(oid
, keys
, &vals
);
74 map
<string
, bufferlist
>::iterator iter
= vals
.find(job_name
);
75 if (iter
== vals
.end()) {
80 bufferlist
& bl
= iter
->second
;
82 } catch (buffer::error
& err
) {
83 lderr(store
->ctx()) << "ERROR: could not decode buffer" << dendl
;
90 int RGWOrphanStore::write_job(const string
& job_name
, const RGWOrphanSearchState
& state
)
92 map
<string
, bufferlist
> vals
;
96 int r
= ioctx
.omap_set(oid
, vals
);
104 int RGWOrphanStore::remove_job(const string
& job_name
)
107 keys
.insert(job_name
);
109 int r
= ioctx
.omap_rm_keys(oid
, keys
);
117 int RGWOrphanStore::list_jobs(map
<string
,RGWOrphanSearchState
>& job_list
)
119 map
<string
,bufferlist
> vals
;
124 // loop through all the omap vals from index object, storing them to job_list,
125 // read in batches of 1024, we update the marker every iteration and exit the
126 // loop when we find that total size read out is less than batch size
128 r
= ioctx
.omap_get_vals(oid
, marker
, MAX_READ
, &vals
);
134 for (const auto &it
: vals
) {
136 RGWOrphanSearchState state
;
138 bufferlist bl
= it
.second
;
140 } catch (buffer::error
& err
) {
141 lderr(store
->ctx()) << "ERROR: could not decode buffer" << dendl
;
144 job_list
[it
.first
] = state
;
146 } while (r
== MAX_READ
);
151 int RGWOrphanStore::init(const DoutPrefixProvider
*dpp
)
153 const rgw_pool
& log_pool
= store
->get_zone()->get_params().log_pool
;
154 int r
= rgw_init_ioctx(dpp
, static_cast<rgw::sal::RadosStore
*>(store
)->getRados()->get_rados_handle(), log_pool
, ioctx
);
156 cerr
<< "ERROR: failed to open log pool (" << log_pool
<< " ret=" << r
<< std::endl
;
163 int RGWOrphanStore::store_entries(const DoutPrefixProvider
*dpp
, const string
& oid
, const map
<string
, bufferlist
>& entries
)
165 librados::ObjectWriteOperation op
;
166 op
.omap_set(entries
);
167 cout
<< "storing " << entries
.size() << " entries at " << oid
<< std::endl
;
168 ldpp_dout(dpp
, 20) << "storing " << entries
.size() << " entries at " << oid
<< ": " << dendl
;
169 for (map
<string
, bufferlist
>::const_iterator iter
= entries
.begin(); iter
!= entries
.end(); ++iter
) {
170 ldpp_dout(dpp
, 20) << " > " << iter
->first
<< dendl
;
172 int ret
= rgw_rados_operate(dpp
, ioctx
, oid
, &op
, null_yield
);
174 ldpp_dout(dpp
, -1) << "ERROR: " << __func__
<< "(" << oid
<< ") returned ret=" << ret
<< dendl
;
180 int RGWOrphanStore::read_entries(const string
& oid
, const string
& marker
, map
<string
, bufferlist
> *entries
, bool *truncated
)
182 #define MAX_OMAP_GET 100
183 int ret
= ioctx
.omap_get_vals(oid
, marker
, MAX_OMAP_GET
, entries
);
184 if (ret
< 0 && ret
!= -ENOENT
) {
185 cerr
<< "ERROR: " << __func__
<< "(" << oid
<< ") returned ret=" << cpp_strerror(-ret
) << std::endl
;
188 *truncated
= (entries
->size() == MAX_OMAP_GET
);
193 int RGWOrphanSearch::init(const DoutPrefixProvider
*dpp
, const string
& job_name
, RGWOrphanSearchInfo
*info
, bool _detailed_mode
)
195 int r
= orphan_store
.init(dpp
);
200 constexpr int64_t MAX_LIST_OBJS_ENTRIES
=100;
202 max_list_bucket_entries
= std::max(store
->ctx()->_conf
->rgw_list_bucket_min_readahead
,
203 MAX_LIST_OBJS_ENTRIES
);
205 detailed_mode
= _detailed_mode
;
206 RGWOrphanSearchState state
;
207 r
= orphan_store
.read_job(job_name
, state
);
208 if (r
< 0 && r
!= -ENOENT
) {
209 ldpp_dout(dpp
, -1) << "ERROR: failed to read state ret=" << r
<< dendl
;
214 search_info
= state
.info
;
215 search_stage
= state
.stage
;
216 } else if (info
) { /* r == -ENOENT, initiate a new job if info was provided */
218 search_info
.job_name
= job_name
;
219 search_info
.num_shards
= (info
->num_shards
? info
->num_shards
: DEFAULT_NUM_SHARDS
);
220 search_info
.start_time
= ceph_clock_now();
221 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_INIT
);
225 ldpp_dout(dpp
, -1) << "ERROR: failed to write state ret=" << r
<< dendl
;
229 ldpp_dout(dpp
, -1) << "ERROR: job not found" << dendl
;
233 index_objs_prefix
= RGW_ORPHAN_INDEX_PREFIX
+ string(".");
234 index_objs_prefix
+= job_name
;
236 for (int i
= 0; i
< search_info
.num_shards
; i
++) {
239 snprintf(buf
, sizeof(buf
), "%s.rados.%d", index_objs_prefix
.c_str(), i
);
240 all_objs_index
[i
] = buf
;
242 snprintf(buf
, sizeof(buf
), "%s.buckets.%d", index_objs_prefix
.c_str(), i
);
243 buckets_instance_index
[i
] = buf
;
245 snprintf(buf
, sizeof(buf
), "%s.linked.%d", index_objs_prefix
.c_str(), i
);
246 linked_objs_index
[i
] = buf
;
251 int RGWOrphanSearch::log_oids(const DoutPrefixProvider
*dpp
, map
<int, string
>& log_shards
, map
<int, list
<string
> >& oids
)
253 map
<int, list
<string
> >::iterator miter
= oids
.begin();
255 list
<log_iter_info
> liters
; /* a list of iterator pairs for begin and end */
257 for (; miter
!= oids
.end(); ++miter
) {
259 info
.oid
= log_shards
[miter
->first
];
260 info
.cur
= miter
->second
.begin();
261 info
.end
= miter
->second
.end();
262 liters
.push_back(info
);
265 list
<log_iter_info
>::iterator list_iter
;
266 while (!liters
.empty()) {
267 list_iter
= liters
.begin();
269 while (list_iter
!= liters
.end()) {
270 log_iter_info
& cur_info
= *list_iter
;
272 list
<string
>::iterator
& cur
= cur_info
.cur
;
273 list
<string
>::iterator
& end
= cur_info
.end
;
275 map
<string
, bufferlist
> entries
;
276 #define MAX_OMAP_SET_ENTRIES 100
277 for (int j
= 0; cur
!= end
&& j
!= MAX_OMAP_SET_ENTRIES
; ++cur
, ++j
) {
278 ldpp_dout(dpp
, 20) << "adding obj: " << *cur
<< dendl
;
279 entries
[*cur
] = bufferlist();
282 int ret
= orphan_store
.store_entries(dpp
, cur_info
.oid
, entries
);
286 list
<log_iter_info
>::iterator tmp
= list_iter
;
296 int RGWOrphanSearch::build_all_oids_index(const DoutPrefixProvider
*dpp
)
298 librados::IoCtx ioctx
;
300 int ret
= rgw_init_ioctx(dpp
, static_cast<rgw::sal::RadosStore
*>(store
)->getRados()->get_rados_handle(), search_info
.pool
, ioctx
);
302 ldpp_dout(dpp
, -1) << __func__
<< ": rgw_init_ioctx() returned ret=" << ret
<< dendl
;
306 ioctx
.set_namespace(librados::all_nspaces
);
307 librados::NObjectIterator i
= ioctx
.nobjects_begin();
308 librados::NObjectIterator i_end
= ioctx
.nobjects_end();
310 map
<int, list
<string
> > oids
;
315 cout
<< "logging all objects in the pool" << std::endl
;
317 for (; i
!= i_end
; ++i
) {
318 string nspace
= i
->get_nspace();
319 string oid
= i
->get_oid();
320 string locator
= i
->get_locator();
322 ssize_t pos
= oid
.find('_');
324 cout
<< "unidentified oid: " << oid
<< ", skipping" << std::endl
;
325 /* what is this object, oids should be in the format of <bucket marker>_<obj>,
330 string stripped_oid
= oid
.substr(pos
+ 1);
332 if (!rgw_obj_key::parse_raw_oid(stripped_oid
, &key
)) {
333 cout
<< "cannot parse oid: " << oid
<< ", skipping" << std::endl
;
337 if (key
.ns
.empty()) {
338 /* skipping head objects, we don't want to remove these as they are mutable and
339 * cleaning them up is racy (can race with object removal and a later recreation)
341 cout
<< "skipping head object: oid=" << oid
<< std::endl
;
345 string oid_fp
= obj_fingerprint(oid
);
347 ldout(store
->ctx(), 20) << "oid_fp=" << oid_fp
<< dendl
;
349 int shard
= orphan_shard(oid_fp
);
350 oids
[shard
].push_back(oid
);
352 #define COUNT_BEFORE_FLUSH 1000
354 if (++count
>= COUNT_BEFORE_FLUSH
) {
355 ldout(store
->ctx(), 1) << "iterated through " << total
<< " objects" << dendl
;
356 ret
= log_oids(dpp
, all_objs_index
, oids
);
358 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
365 ret
= log_oids(dpp
, all_objs_index
, oids
);
367 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
374 int RGWOrphanSearch::build_buckets_instance_index(const DoutPrefixProvider
*dpp
)
378 string section
= "bucket.instance";
379 int ret
= store
->meta_list_keys_init(dpp
, section
, string(), &handle
);
381 ldpp_dout(dpp
, -1) << "ERROR: can't get key: " << cpp_strerror(-ret
) << dendl
;
385 map
<int, list
<string
> > instances
;
389 RGWObjectCtx
obj_ctx(store
);
396 ret
= store
->meta_list_keys_next(dpp
, handle
, max
, keys
, &truncated
);
398 ldpp_dout(dpp
, -1) << "ERROR: lists_keys_next(): " << cpp_strerror(-ret
) << dendl
;
402 for (list
<string
>::iterator iter
= keys
.begin(); iter
!= keys
.end(); ++iter
) {
404 ldpp_dout(dpp
, 10) << "bucket_instance=" << *iter
<< " total=" << total
<< dendl
;
405 int shard
= orphan_shard(*iter
);
406 instances
[shard
].push_back(*iter
);
408 if (++count
>= COUNT_BEFORE_FLUSH
) {
409 ret
= log_oids(dpp
, buckets_instance_index
, instances
);
411 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
421 store
->meta_list_keys_complete(handle
);
423 ret
= log_oids(dpp
, buckets_instance_index
, instances
);
425 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
432 int RGWOrphanSearch::handle_stat_result(const DoutPrefixProvider
*dpp
, map
<int, list
<string
> >& oids
, RGWRados::Object::Stat::Result
& result
)
434 set
<string
> obj_oids
;
435 rgw_bucket
& bucket
= result
.obj
.bucket
;
436 if (!result
.manifest
) { /* a very very old object, or part of a multipart upload during upload */
437 const string loc
= bucket
.bucket_id
+ "_" + result
.obj
.get_oid();
438 obj_oids
.insert(obj_fingerprint(loc
));
441 * multipart parts don't have manifest on them, it's in the meta object. Instead of reading the
442 * meta object, just add a "shadow" object to the mix
444 obj_oids
.insert(obj_fingerprint(loc
, "shadow"));
446 RGWObjManifest
& manifest
= *result
.manifest
;
448 if (!detailed_mode
&&
449 manifest
.get_obj_size() <= manifest
.get_head_size()) {
450 ldpp_dout(dpp
, 5) << "skipping object as it fits in a head" << dendl
;
454 RGWObjManifest::obj_iterator miter
;
455 for (miter
= manifest
.obj_begin(dpp
); miter
!= manifest
.obj_end(dpp
); ++miter
) {
456 const rgw_raw_obj
& loc
= miter
.get_location().get_raw_obj(static_cast<rgw::sal::RadosStore
*>(store
));
458 obj_oids
.insert(obj_fingerprint(s
));
462 for (set
<string
>::iterator iter
= obj_oids
.begin(); iter
!= obj_oids
.end(); ++iter
) {
463 ldpp_dout(dpp
, 20) << __func__
<< ": oid for obj=" << result
.obj
<< ": " << *iter
<< dendl
;
465 int shard
= orphan_shard(*iter
);
466 oids
[shard
].push_back(*iter
);
472 int RGWOrphanSearch::pop_and_handle_stat_op(const DoutPrefixProvider
*dpp
, map
<int, list
<string
> >& oids
, std::deque
<RGWRados::Object::Stat
>& ops
)
474 RGWRados::Object::Stat
& front_op
= ops
.front();
476 int ret
= front_op
.wait(dpp
);
478 if (ret
!= -ENOENT
) {
479 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
483 ret
= handle_stat_result(dpp
, oids
, front_op
.result
);
485 ldpp_dout(dpp
, -1) << "ERROR: handle_stat_response() returned error: " << cpp_strerror(-ret
) << dendl
;
492 int RGWOrphanSearch::build_linked_oids_for_bucket(const DoutPrefixProvider
*dpp
, const string
& bucket_instance_id
, map
<int, list
<string
> >& oids
)
494 RGWObjectCtx
obj_ctx(store
);
495 rgw_bucket orphan_bucket
;
497 int ret
= rgw_bucket_parse_bucket_key(store
->ctx(), bucket_instance_id
,
498 &orphan_bucket
, &shard_id
);
500 ldpp_dout(dpp
, 0) << __func__
<< " failed to parse bucket instance: "
501 << bucket_instance_id
<< " skipping" << dendl
;
505 std::unique_ptr
<rgw::sal::Bucket
> cur_bucket
;
506 ret
= store
->get_bucket(dpp
, nullptr, orphan_bucket
, &cur_bucket
, null_yield
);
508 if (ret
== -ENOENT
) {
509 /* probably raced with bucket removal */
512 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: RGWRados::get_bucket_instance_info() returned ret=" << ret
<< dendl
;
516 if (cur_bucket
->get_bucket_id() != orphan_bucket
.bucket_id
) {
517 ldpp_dout(dpp
, 0) << __func__
<< ": Skipping stale bucket instance: "
518 << orphan_bucket
.name
<< ": "
519 << orphan_bucket
.bucket_id
<< dendl
;
523 if (cur_bucket
->get_info().reshard_status
== cls_rgw_reshard_status::IN_PROGRESS
) {
524 ldpp_dout(dpp
, 0) << __func__
<< ": reshard in progress. Skipping "
525 << orphan_bucket
.name
<< ": "
526 << orphan_bucket
.bucket_id
<< dendl
;
531 rgw_bucket_parse_bucket_key(store
->ctx(), bucket_instance_id
, &b
, nullptr);
532 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
533 ret
= store
->get_bucket(dpp
, nullptr, b
, &bucket
, null_yield
);
535 if (ret
== -ENOENT
) {
536 /* probably raced with bucket removal */
539 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: RGWRados::get_bucket_instance_info() returned ret=" << ret
<< dendl
;
543 ldpp_dout(dpp
, 10) << "building linked oids for bucket instance: " << bucket_instance_id
<< dendl
;
544 RGWRados::Bucket
target(store
->getRados(), cur_bucket
->get_info());
545 RGWRados::Bucket::List
list_op(&target
);
548 list_op
.params
.marker
= rgw_obj_key(marker
);
549 list_op
.params
.list_versions
= true;
550 list_op
.params
.enforce_ns
= false;
554 deque
<RGWRados::Object::Stat
> stat_ops
;
557 vector
<rgw_bucket_dir_entry
> result
;
559 ret
= list_op
.list_objects(dpp
, max_list_bucket_entries
,
560 &result
, nullptr, &truncated
, null_yield
);
562 cerr
<< "ERROR: store->list_objects(): " << cpp_strerror(-ret
) << std::endl
;
566 for (vector
<rgw_bucket_dir_entry
>::iterator iter
= result
.begin(); iter
!= result
.end(); ++iter
) {
567 rgw_bucket_dir_entry
& entry
= *iter
;
568 if (entry
.key
.instance
.empty()) {
569 ldpp_dout(dpp
, 20) << "obj entry: " << entry
.key
.name
<< dendl
;
571 ldpp_dout(dpp
, 20) << "obj entry: " << entry
.key
.name
<< " [" << entry
.key
.instance
<< "]" << dendl
;
574 ldpp_dout(dpp
, 20) << __func__
<< ": entry.key.name=" << entry
.key
.name
<< " entry.key.instance=" << entry
.key
.instance
<< dendl
;
576 if (!detailed_mode
&&
577 entry
.meta
.accounted_size
<= (uint64_t)store
->ctx()->_conf
->rgw_max_chunk_size
) {
578 ldpp_dout(dpp
, 5) << __func__
<< "skipping stat as the object " << entry
.key
.name
579 << "fits in a head" << dendl
;
583 rgw_obj
obj(cur_bucket
->get_key(), entry
.key
);
585 RGWRados::Object
op_target(store
->getRados(), cur_bucket
->get_info(), obj_ctx
, obj
);
587 stat_ops
.push_back(RGWRados::Object::Stat(&op_target
));
588 RGWRados::Object::Stat
& op
= stat_ops
.back();
590 ret
= op
.stat_async(dpp
);
592 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
595 if (stat_ops
.size() >= max_concurrent_ios
) {
596 ret
= pop_and_handle_stat_op(dpp
, oids
, stat_ops
);
598 if (ret
!= -ENOENT
) {
599 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
603 if (oids
.size() >= COUNT_BEFORE_FLUSH
) {
604 ret
= log_oids(dpp
, linked_objs_index
, oids
);
606 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
614 while (!stat_ops
.empty()) {
615 ret
= pop_and_handle_stat_op(dpp
, oids
, stat_ops
);
617 if (ret
!= -ENOENT
) {
618 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
626 int RGWOrphanSearch::build_linked_oids_index(const DoutPrefixProvider
*dpp
)
628 map
<int, list
<string
> > oids
;
629 map
<int, string
>::iterator iter
= buckets_instance_index
.find(search_stage
.shard
);
630 for (; iter
!= buckets_instance_index
.end(); ++iter
) {
631 ldpp_dout(dpp
, 0) << "building linked oids index: " << iter
->first
<< "/" << buckets_instance_index
.size() << dendl
;
634 string oid
= iter
->second
;
637 map
<string
, bufferlist
> entries
;
638 int ret
= orphan_store
.read_entries(oid
, search_stage
.marker
, &entries
, &truncated
);
639 if (ret
== -ENOENT
) {
645 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: read_entries() oid=" << oid
<< " returned ret=" << ret
<< dendl
;
649 if (entries
.empty()) {
653 for (map
<string
, bufferlist
>::iterator eiter
= entries
.begin(); eiter
!= entries
.end(); ++eiter
) {
654 ldpp_dout(dpp
, 20) << " indexed entry: " << eiter
->first
<< dendl
;
655 ret
= build_linked_oids_for_bucket(dpp
, eiter
->first
, oids
);
657 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: build_linked_oids_for_bucket() indexed entry=" << eiter
->first
658 << " returned ret=" << ret
<< dendl
;
663 search_stage
.shard
= iter
->first
;
664 search_stage
.marker
= entries
.rbegin()->first
; /* last entry */
667 search_stage
.marker
.clear();
670 int ret
= log_oids(dpp
, linked_objs_index
, oids
);
672 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
678 cerr
<< __func__
<< ": ERROR: failed to write state ret=" << ret
<< std::endl
;
686 librados::IoCtx ioctx
;
689 map
<string
, bufferlist
> entries
;
690 map
<string
, bufferlist
>::iterator iter
;
695 OMAPReader(librados::IoCtx
& _ioctx
, const string
& _oid
) : ioctx(_ioctx
), oid(_oid
), truncated(true) {
696 iter
= entries
.end();
699 int get_next(string
*key
, bufferlist
*pbl
, bool *done
);
702 int OMAPReader::get_next(string
*key
, bufferlist
*pbl
, bool *done
)
704 if (iter
!= entries
.end()) {
720 #define MAX_OMAP_GET_ENTRIES 100
721 int ret
= ioctx
.omap_get_vals(oid
, marker
, MAX_OMAP_GET_ENTRIES
, &entries
);
723 if (ret
== -ENOENT
) {
730 truncated
= (entries
.size() == MAX_OMAP_GET_ENTRIES
);
731 iter
= entries
.begin();
732 return get_next(key
, pbl
, done
);
735 int RGWOrphanSearch::compare_oid_indexes(const DoutPrefixProvider
*dpp
)
737 ceph_assert(linked_objs_index
.size() == all_objs_index
.size());
739 librados::IoCtx
& ioctx
= orphan_store
.get_ioctx();
741 librados::IoCtx data_ioctx
;
743 int ret
= rgw_init_ioctx(dpp
, static_cast<rgw::sal::RadosStore
*>(store
)->getRados()->get_rados_handle(), search_info
.pool
, data_ioctx
);
745 ldpp_dout(dpp
, -1) << __func__
<< ": rgw_init_ioctx() returned ret=" << ret
<< dendl
;
749 uint64_t time_threshold
= search_info
.start_time
.sec() - stale_secs
;
751 map
<int, string
>::iterator liter
= linked_objs_index
.begin();
752 map
<int, string
>::iterator aiter
= all_objs_index
.begin();
754 for (; liter
!= linked_objs_index
.end(); ++liter
, ++aiter
) {
755 OMAPReader
linked_entries(ioctx
, liter
->second
);
756 OMAPReader
all_entries(ioctx
, aiter
->second
);
761 bool linked_done
= false;
766 int r
= all_entries
.get_next(&key
, NULL
, &done
);
774 string key_fp
= obj_fingerprint(key
);
776 while (cur_linked
< key_fp
&& !linked_done
) {
777 r
= linked_entries
.get_next(&cur_linked
, NULL
, &linked_done
);
783 if (cur_linked
== key_fp
) {
784 ldpp_dout(dpp
, 20) << "linked: " << key
<< dendl
;
789 r
= data_ioctx
.stat(key
, NULL
, &mtime
);
792 ldpp_dout(dpp
, -1) << "ERROR: ioctx.stat(" << key
<< ") returned ret=" << r
<< dendl
;
796 if (stale_secs
&& (uint64_t)mtime
>= time_threshold
) {
797 ldpp_dout(dpp
, 20) << "skipping: " << key
<< " (mtime=" << mtime
<< " threshold=" << time_threshold
<< ")" << dendl
;
800 ldpp_dout(dpp
, 20) << "leaked: " << key
<< dendl
;
801 cout
<< "leaked: " << key
<< std::endl
;
808 int RGWOrphanSearch::run(const DoutPrefixProvider
*dpp
)
812 switch (search_stage
.stage
) {
814 case ORPHAN_SEARCH_STAGE_INIT
:
815 ldpp_dout(dpp
, 0) << __func__
<< "(): initializing state" << dendl
;
816 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_LSPOOL
);
819 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
823 case ORPHAN_SEARCH_STAGE_LSPOOL
:
824 ldpp_dout(dpp
, 0) << __func__
<< "(): building index of all objects in pool" << dendl
;
825 r
= build_all_oids_index(dpp
);
827 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
831 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_LSBUCKETS
);
834 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
839 case ORPHAN_SEARCH_STAGE_LSBUCKETS
:
840 ldpp_dout(dpp
, 0) << __func__
<< "(): building index of all bucket indexes" << dendl
;
841 r
= build_buckets_instance_index(dpp
);
843 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
847 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_ITERATE_BI
);
850 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
856 case ORPHAN_SEARCH_STAGE_ITERATE_BI
:
857 ldpp_dout(dpp
, 0) << __func__
<< "(): building index of all linked objects" << dendl
;
858 r
= build_linked_oids_index(dpp
);
860 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
864 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_COMPARE
);
867 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
872 case ORPHAN_SEARCH_STAGE_COMPARE
:
873 r
= compare_oid_indexes(dpp
);
875 ldpp_dout(dpp
, -1) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
889 int RGWOrphanSearch::remove_index(map
<int, string
>& index
)
891 librados::IoCtx
& ioctx
= orphan_store
.get_ioctx();
893 for (map
<int, string
>::iterator iter
= index
.begin(); iter
!= index
.end(); ++iter
) {
894 int r
= ioctx
.remove(iter
->second
);
897 ldout(store
->ctx(), 0) << "ERROR: couldn't remove " << iter
->second
<< ": ret=" << r
<< dendl
;
904 int RGWOrphanSearch::finish()
906 int r
= remove_index(all_objs_index
);
908 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << all_objs_index
<< ") returned ret=" << r
<< dendl
;
910 r
= remove_index(buckets_instance_index
);
912 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << buckets_instance_index
<< ") returned ret=" << r
<< dendl
;
914 r
= remove_index(linked_objs_index
);
916 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << linked_objs_index
<< ") returned ret=" << r
<< dendl
;
919 r
= orphan_store
.remove_job(search_info
.job_name
);
921 ldout(store
->ctx(), 0) << "ERROR: could not remove job name (" << search_info
.job_name
<< ") ret=" << r
<< dendl
;
928 int RGWRadosList::handle_stat_result(const DoutPrefixProvider
*dpp
,
929 RGWRados::Object::Stat::Result
& result
,
930 std::string
& bucket_name
,
931 rgw_obj_key
& obj_key
,
932 std::set
<string
>& obj_oids
)
936 rgw_bucket
& bucket
= result
.obj
.bucket
;
938 ldpp_dout(dpp
, 20) << "RGWRadosList::" << __func__
<<
939 " bucket=" << bucket
<<
940 ", has_manifest=" << result
.manifest
.has_value() <<
943 // iterator to store result of dlo/slo attribute find
944 decltype(result
.attrs
)::iterator attr_it
= result
.attrs
.end();
945 const std::string oid
= bucket
.marker
+ "_" + result
.obj
.get_oid();
946 ldpp_dout(dpp
, 20) << "radoslist processing object=\"" <<
947 oid
<< "\"" << dendl
;
948 if (visited_oids
.find(oid
) != visited_oids
.end()) {
949 // apparently we hit a loop; don't continue with this oid
950 ldpp_dout(dpp
, 15) <<
951 "radoslist stopped loop at already visited object=\"" <<
952 oid
<< "\"" << dendl
;
956 bucket_name
= bucket
.name
;
957 obj_key
= result
.obj
.key
;
959 if (!result
.manifest
) {
960 /* a very very old object, or part of a multipart upload during upload */
961 obj_oids
.insert(oid
);
964 * multipart parts don't have manifest on them, it's in the meta
965 * object; we'll process them in
966 * RGWRadosList::do_incomplete_multipart
968 } else if ((attr_it
= result
.attrs
.find(RGW_ATTR_USER_MANIFEST
)) !=
969 result
.attrs
.end()) {
970 // *** handle DLO object ***
972 obj_oids
.insert(oid
);
973 visited_oids
.insert(oid
); // prevent dlo loops
974 ldpp_dout(dpp
, 15) << "radoslist added to visited list DLO=\"" <<
975 oid
<< "\"" << dendl
;
977 char* prefix_path_c
= attr_it
->second
.c_str();
978 const std::string
& prefix_path
= prefix_path_c
;
980 const size_t sep_pos
= prefix_path
.find('/');
981 if (string::npos
== sep_pos
) {
985 const std::string bucket_name
= prefix_path
.substr(0, sep_pos
);
986 const std::string prefix
= prefix_path
.substr(sep_pos
+ 1);
988 add_bucket_prefix(bucket_name
, prefix
);
989 ldpp_dout(dpp
, 25) << "radoslist DLO oid=\"" << oid
<<
990 "\" added bucket=\"" << bucket_name
<< "\" prefix=\"" <<
991 prefix
<< "\" to process list" << dendl
;
992 } else if ((attr_it
= result
.attrs
.find(RGW_ATTR_USER_MANIFEST
)) !=
993 result
.attrs
.end()) {
994 // *** handle SLO object ***
996 obj_oids
.insert(oid
);
997 visited_oids
.insert(oid
); // prevent slo loops
998 ldpp_dout(dpp
, 15) << "radoslist added to visited list SLO=\"" <<
999 oid
<< "\"" << dendl
;
1001 RGWSLOInfo slo_info
;
1002 bufferlist::const_iterator bliter
= attr_it
->second
.begin();
1004 ::decode(slo_info
, bliter
);
1005 } catch (buffer::error
& err
) {
1006 ldpp_dout(dpp
, 0) <<
1007 "ERROR: failed to decode slo manifest for " << oid
<< dendl
;
1011 for (const auto& iter
: slo_info
.entries
) {
1012 const string
& path_str
= iter
.path
;
1014 const size_t sep_pos
= path_str
.find('/', 1 /* skip initial slash */);
1015 if (string::npos
== sep_pos
) {
1019 std::string bucket_name
;
1020 std::string obj_name
;
1022 bucket_name
= url_decode(path_str
.substr(1, sep_pos
- 1));
1023 obj_name
= url_decode(path_str
.substr(sep_pos
+ 1));
1025 const rgw_obj_key
obj_key(obj_name
);
1026 add_bucket_filter(bucket_name
, obj_key
);
1027 ldpp_dout(dpp
, 25) << "radoslist SLO oid=\"" << oid
<<
1028 "\" added bucket=\"" << bucket_name
<< "\" obj_key=\"" <<
1029 obj_key
<< "\" to process list" << dendl
;
1032 RGWObjManifest
& manifest
= *result
.manifest
;
1034 // in multipart, the head object contains no data and just has the
1035 // manifest AND empty objects have no manifest, but they're
1036 // realized as empty rados objects
1037 if (0 == manifest
.get_max_head_size() ||
1038 manifest
.obj_begin(dpp
) == manifest
.obj_end(dpp
)) {
1039 obj_oids
.insert(oid
);
1040 // first_insert = true;
1043 RGWObjManifest::obj_iterator miter
;
1044 for (miter
= manifest
.obj_begin(dpp
); miter
!= manifest
.obj_end(dpp
); ++miter
) {
1045 const rgw_raw_obj
& loc
=
1046 miter
.get_location().get_raw_obj(static_cast<rgw::sal::RadosStore
*>(store
));
1053 } // RGWRadosList::handle_stat_result
1055 int RGWRadosList::pop_and_handle_stat_op(
1056 const DoutPrefixProvider
*dpp
,
1057 RGWObjectCtx
& obj_ctx
,
1058 std::deque
<RGWRados::Object::Stat
>& ops
)
1060 std::string bucket_name
;
1061 rgw_obj_key obj_key
;
1062 std::set
<std::string
> obj_oids
;
1063 RGWRados::Object::Stat
& front_op
= ops
.front();
1065 int ret
= front_op
.wait(dpp
);
1067 if (ret
!= -ENOENT
) {
1068 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " <<
1069 cpp_strerror(-ret
) << dendl
;
1074 ret
= handle_stat_result(dpp
, front_op
.result
, bucket_name
, obj_key
, obj_oids
);
1076 ldpp_dout(dpp
, -1) << "ERROR: handle_stat_result() returned error: " <<
1077 cpp_strerror(-ret
) << dendl
;
1081 for (const auto& o
: obj_oids
) {
1082 if (include_rgw_obj_name
) {
1084 field_separator
<< bucket_name
<<
1085 field_separator
<< obj_key
<<
1088 std::cout
<< o
<< std::endl
;
1094 // invalidate object context for this object to avoid memory leak
1095 // (see pr https://github.com/ceph/ceph/pull/30174)
1096 obj_ctx
.invalidate(front_op
.result
.obj
);
1103 #if 0 // code that may be the basis for expansion
1104 int RGWRadosList::build_buckets_instance_index()
1108 string section
= "bucket.instance";
1109 int ret
= store
->meta_mgr
->list_keys_init(section
, &handle
);
1111 lderr(store
->ctx()) << "ERROR: can't get key: " << cpp_strerror(-ret
) << dendl
;
1115 map
<int, list
<string
> > instances
;
1119 RGWObjectCtx
obj_ctx(store
);
1126 ret
= store
->meta_mgr
->list_keys_next(handle
, max
, keys
, &truncated
);
1128 lderr(store
->ctx()) << "ERROR: lists_keys_next(): " << cpp_strerror(-ret
) << dendl
;
1132 for (list
<string
>::iterator iter
= keys
.begin(); iter
!= keys
.end(); ++iter
) {
1134 ldout(store
->ctx(), 10) << "bucket_instance=" << *iter
<< " total=" << total
<< dendl
;
1135 int shard
= orphan_shard(*iter
);
1136 instances
[shard
].push_back(*iter
);
1138 if (++count
>= COUNT_BEFORE_FLUSH
) {
1139 ret
= log_oids(buckets_instance_index
, instances
);
1141 lderr(store
->ctx()) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
1148 } while (truncated
);
1150 ret
= log_oids(buckets_instance_index
, instances
);
1152 lderr(store
->ctx()) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
1155 store
->meta_mgr
->list_keys_complete(handle
);
1162 int RGWRadosList::process_bucket(
1163 const DoutPrefixProvider
*dpp
,
1164 const std::string
& bucket_instance_id
,
1165 const std::string
& prefix
,
1166 const std::set
<rgw_obj_key
>& entries_filter
)
1168 ldpp_dout(dpp
, 10) << "RGWRadosList::" << __func__
<<
1169 " bucket_instance_id=" << bucket_instance_id
<<
1170 ", prefix=" << prefix
<<
1171 ", entries_filter.size=" << entries_filter
.size() << dendl
;
1173 RGWBucketInfo bucket_info
;
1174 RGWSysObjectCtx sys_obj_ctx
= store
->svc()->sysobj
->init_obj_ctx();
1175 int ret
= store
->getRados()->get_bucket_instance_info(sys_obj_ctx
,
1183 if (ret
== -ENOENT
) {
1184 // probably raced with bucket removal
1187 ldpp_dout(dpp
, -1) << __func__
<<
1188 ": ERROR: RGWRados::get_bucket_instance_info() returned ret=" <<
1193 RGWRados::Bucket
target(store
->getRados(), bucket_info
);
1194 RGWRados::Bucket::List
list_op(&target
);
1197 list_op
.params
.marker
= rgw_obj_key(marker
);
1198 list_op
.params
.list_versions
= true;
1199 list_op
.params
.enforce_ns
= false;
1200 list_op
.params
.allow_unordered
= false;
1201 list_op
.params
.prefix
= prefix
;
1205 std::deque
<RGWRados::Object::Stat
> stat_ops
;
1206 std::string prev_versioned_key_name
= "";
1208 RGWObjectCtx
obj_ctx(store
);
1211 std::vector
<rgw_bucket_dir_entry
> result
;
1212 constexpr int64_t LIST_OBJS_MAX_ENTRIES
= 100;
1213 ret
= list_op
.list_objects(dpp
, LIST_OBJS_MAX_ENTRIES
, &result
,
1214 NULL
, &truncated
, null_yield
);
1215 if (ret
== -ENOENT
) {
1216 // race with bucket delete?
1219 } else if (ret
< 0) {
1220 std::cerr
<< "ERROR: store->list_objects(): " << cpp_strerror(-ret
) <<
1225 for (std::vector
<rgw_bucket_dir_entry
>::iterator iter
= result
.begin();
1226 iter
!= result
.end();
1228 rgw_bucket_dir_entry
& entry
= *iter
;
1230 if (entry
.key
.instance
.empty()) {
1231 ldpp_dout(dpp
, 20) << "obj entry: " << entry
.key
.name
<< dendl
;
1233 ldpp_dout(dpp
, 20) << "obj entry: " << entry
.key
.name
<<
1234 " [" << entry
.key
.instance
<< "]" << dendl
;
1237 ldpp_dout(dpp
, 20) << __func__
<< ": entry.key.name=" <<
1238 entry
.key
.name
<< " entry.key.instance=" << entry
.key
.instance
<<
1241 // ignore entries that are not in the filter if there is a filter
1242 if (!entries_filter
.empty() &&
1243 entries_filter
.find(entry
.key
) == entries_filter
.cend()) {
1247 // we need to do this in two cases below, so use a lambda
1249 [&](const rgw_obj_key
& key
) -> int {
1252 rgw_obj
obj(bucket_info
.bucket
, key
);
1253 RGWRados::Object
op_target(store
->getRados(), bucket_info
,
1256 stat_ops
.push_back(RGWRados::Object::Stat(&op_target
));
1257 RGWRados::Object::Stat
& op
= stat_ops
.back();
1259 ret
= op
.stat_async(dpp
);
1261 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " <<
1262 cpp_strerror(-ret
) << dendl
;
1266 if (stat_ops
.size() >= max_concurrent_ios
) {
1267 ret
= pop_and_handle_stat_op(dpp
, obj_ctx
, stat_ops
);
1269 if (ret
!= -ENOENT
) {
1270 ldpp_dout(dpp
, -1) <<
1271 "ERROR: pop_and_handle_stat_op() returned error: " <<
1272 cpp_strerror(-ret
) << dendl
;
1275 // clear error, so we'll continue processing directory
1281 }; // do_stat_key lambda
1283 // for versioned objects, make sure the head object is handled
1284 // as well by ignoring the instance identifier
1285 if (!entry
.key
.instance
.empty() &&
1286 entry
.key
.name
!= prev_versioned_key_name
) {
1287 // don't do the same key twice; even though out bucket index
1288 // listing allows unordered, since all versions of an object
1289 // use the same bucket index key, they'll all end up together
1291 prev_versioned_key_name
= entry
.key
.name
;
1293 rgw_obj_key
uninstanced(entry
.key
.name
);
1295 ret
= do_stat_key(uninstanced
);
1301 ret
= do_stat_key(entry
.key
);
1306 } while (truncated
);
1308 while (!stat_ops
.empty()) {
1309 ret
= pop_and_handle_stat_op(dpp
, obj_ctx
, stat_ops
);
1311 if (ret
!= -ENOENT
) {
1312 ldpp_dout(dpp
, -1) << "ERROR: stat_async() returned error: " <<
1313 cpp_strerror(-ret
) << dendl
;
1322 int RGWRadosList::run(const DoutPrefixProvider
*dpp
)
1325 void* handle
= nullptr;
1327 ret
= store
->meta_list_keys_init(dpp
, "bucket", string(), &handle
);
1329 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1330 " ERROR: list_keys_init returned " <<
1331 cpp_strerror(-ret
) << dendl
;
1335 const int max_keys
= 1000;
1336 bool truncated
= true;
1339 std::list
<std::string
> buckets
;
1340 ret
= store
->meta_list_keys_next(dpp
, handle
, max_keys
, buckets
, &truncated
);
1342 for (std::string
& bucket_id
: buckets
) {
1343 ret
= run(dpp
, bucket_id
);
1344 if (ret
== -ENOENT
) {
1346 } else if (ret
< 0) {
1350 } while (truncated
);
1353 } // RGWRadosList::run()
1356 int RGWRadosList::run(const DoutPrefixProvider
*dpp
, const std::string
& start_bucket_name
)
1358 RGWObjectCtx
obj_ctx(store
);
1359 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
1362 add_bucket_entire(start_bucket_name
);
1364 while (! bucket_process_map
.empty()) {
1365 // pop item from map and capture its key data
1366 auto front
= bucket_process_map
.begin();
1367 std::string bucket_name
= front
->first
;
1369 std::swap(process
, front
->second
);
1370 bucket_process_map
.erase(front
);
1372 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
1373 ret
= store
->get_bucket(dpp
, nullptr, tenant_name
, bucket_name
, &bucket
, null_yield
);
1374 if (ret
== -ENOENT
) {
1375 std::cerr
<< "WARNING: bucket " << bucket_name
<<
1376 " does not exist; could it have been deleted very recently?" <<
1379 } else if (ret
< 0) {
1380 std::cerr
<< "ERROR: could not get info for bucket " << bucket_name
<<
1381 " -- " << cpp_strerror(-ret
) << std::endl
;
1385 const std::string bucket_id
= bucket
->get_key().get_key();
1387 static const std::set
<rgw_obj_key
> empty_filter
;
1388 static const std::string empty_prefix
;
1390 auto do_process_bucket
=
1391 [dpp
, &bucket_id
, this]
1392 (const std::string
& prefix
,
1393 const std::set
<rgw_obj_key
>& entries_filter
) -> int {
1394 int ret
= process_bucket(dpp
, bucket_id
, prefix
, entries_filter
);
1395 if (ret
== -ENOENT
) {
1396 // bucket deletion race?
1399 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1400 ": ERROR: process_bucket(); bucket_id=" <<
1401 bucket_id
<< " returned ret=" << ret
<< dendl
;
1407 // either process the whole bucket *or* process the filters and/or
1409 if (process
.entire_container
) {
1410 ret
= do_process_bucket(empty_prefix
, empty_filter
);
1415 if (! process
.filter_keys
.empty()) {
1416 ret
= do_process_bucket(empty_prefix
, process
.filter_keys
);
1421 for (const auto& p
: process
.prefixes
) {
1422 ret
= do_process_bucket(p
, empty_filter
);
1428 } // while (! bucket_process_map.empty())
1430 if (include_rgw_obj_name
) {
1434 // now handle incomplete multipart uploads by going back to the
1437 ret
= store
->get_bucket(dpp
, nullptr, tenant_name
, start_bucket_name
, &bucket
, null_yield
);
1438 if (ret
== -ENOENT
) {
1439 // bucket deletion race?
1441 } else if (ret
< 0) {
1442 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1443 ": ERROR: get_bucket_info returned ret=" << ret
<< dendl
;
1447 ret
= do_incomplete_multipart(dpp
, bucket
.get());
1449 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1450 ": ERROR: do_incomplete_multipart returned ret=" << ret
<< dendl
;
1457 } // RGWRadosList::run(string)
1460 int RGWRadosList::do_incomplete_multipart(const DoutPrefixProvider
*dpp
,
1461 rgw::sal::Bucket
* bucket
)
1463 constexpr int max_uploads
= 1000;
1464 constexpr int max_parts
= 1000;
1466 vector
<std::unique_ptr
<rgw::sal::MultipartUpload
>> uploads
;
1470 // use empty strings for params.{prefix,delim}
1473 ret
= bucket
->list_multiparts(dpp
, string(), marker
, string(), max_uploads
, uploads
, nullptr, &is_truncated
);
1474 if (ret
== -ENOENT
) {
1475 // could bucket have been removed while this is running?
1476 ldpp_dout(dpp
, 5) << "RGWRadosList::" << __func__
<<
1477 ": WARNING: call to list_objects of multipart namespace got ENOENT; "
1478 "assuming bucket removal race" << dendl
;
1480 } else if (ret
< 0) {
1481 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1482 ": ERROR: list_objects op returned ret=" << ret
<< dendl
;
1486 if (!uploads
.empty()) {
1487 // now process the uploads vector
1488 for (const auto& upload
: uploads
) {
1489 int parts_marker
= 0;
1490 bool is_parts_truncated
= false;
1492 do { // while (is_parts_truncated);
1493 ret
= upload
->list_parts(dpp
, store
->ctx(), max_parts
, parts_marker
,
1494 &parts_marker
, &is_parts_truncated
);
1495 if (ret
== -ENOENT
) {
1496 ldpp_dout(dpp
, 5) << "RGWRadosList::" << __func__
<<
1497 ": WARNING: list_multipart_parts returned ret=-ENOENT "
1498 "for " << upload
->get_upload_id() << ", moving on" << dendl
;
1500 } else if (ret
< 0) {
1501 ldpp_dout(dpp
, -1) << "RGWRadosList::" << __func__
<<
1502 ": ERROR: list_multipart_parts returned ret=" << ret
<<
1507 for (auto& p
: upload
->get_parts()) {
1508 rgw::sal::RadosMultipartPart
* part
=
1509 dynamic_cast<rgw::sal::RadosMultipartPart
*>(p
.second
.get());
1510 RGWObjManifest
& manifest
= part
->get_manifest();
1511 for (auto obj_it
= manifest
.obj_begin(dpp
);
1512 obj_it
!= manifest
.obj_end(dpp
);
1514 const rgw_raw_obj
& loc
=
1515 obj_it
.get_location().get_raw_obj(static_cast<rgw::sal::RadosStore
*>(store
));
1516 std::cout
<< loc
.oid
<< std::endl
;
1517 } // for (auto obj_it
1519 } while (is_parts_truncated
);
1520 } // for (const auto& upload
1521 } // if objs not empty
1522 } while (is_truncated
);
1525 } // RGWRadosList::do_incomplete_multipart
1527 void RGWOrphanSearchStage::dump(Formatter
*f
) const
1529 f
->open_object_section("orphan_search_stage");
1532 case ORPHAN_SEARCH_STAGE_INIT
:
1535 case ORPHAN_SEARCH_STAGE_LSPOOL
:
1538 case ORPHAN_SEARCH_STAGE_LSBUCKETS
:
1541 case ORPHAN_SEARCH_STAGE_ITERATE_BI
:
1542 s
= "iterate_bucket_index";
1544 case ORPHAN_SEARCH_STAGE_COMPARE
:
1550 f
->dump_string("search_stage", s
);
1551 f
->dump_int("shard",shard
);
1552 f
->dump_string("marker",marker
);
1556 void RGWOrphanSearchInfo::dump(Formatter
*f
) const
1558 f
->open_object_section("orphan_search_info");
1559 f
->dump_string("job_name", job_name
);
1560 encode_json("pool", pool
, f
);
1561 f
->dump_int("num_shards", num_shards
);
1562 encode_json("start_time", start_time
, f
);
1566 void RGWOrphanSearchState::dump(Formatter
*f
) const
1568 f
->open_object_section("orphan_search_state");
1569 encode_json("info", info
, f
);
1570 encode_json("stage", stage
, f
);