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"
11 #include "rgw_rados.h"
12 #include "rgw_orphan.h"
14 #include "rgw_bucket.h"
16 #include "services/svc_zone.h"
17 #include "services/svc_sys_obj.h"
19 #define dout_subsys ceph_subsys_rgw
21 #define DEFAULT_NUM_SHARDS 64
23 static string
obj_fingerprint(const string
& oid
, const char *force_ns
= NULL
)
25 ssize_t pos
= oid
.find('_');
27 cerr
<< "ERROR: object does not have a bucket marker: " << oid
<< std::endl
;
30 string obj_marker
= oid
.substr(0, pos
);
34 rgw_obj_key::parse_raw_oid(oid
.substr(pos
+ 1), &key
);
44 rgw_obj
new_obj(b
, key
);
45 s
= obj_marker
+ "_" + new_obj
.get_oid();
49 size_t i
= s
.size() - 1;
50 for (; i
>= s
.size() - 10; --i
) {
52 if (!isdigit(c
) && c
!= '.' && c
!= '_') {
57 return s
.substr(0, i
+ 1);
60 int RGWOrphanStore::read_job(const string
& job_name
, RGWOrphanSearchState
& state
)
63 map
<string
, bufferlist
> vals
;
64 keys
.insert(job_name
);
65 int r
= ioctx
.omap_get_vals_by_keys(oid
, keys
, &vals
);
70 map
<string
, bufferlist
>::iterator iter
= vals
.find(job_name
);
71 if (iter
== vals
.end()) {
76 bufferlist
& bl
= iter
->second
;
78 } catch (buffer::error
& err
) {
79 lderr(store
->ctx()) << "ERROR: could not decode buffer" << dendl
;
86 int RGWOrphanStore::write_job(const string
& job_name
, const RGWOrphanSearchState
& state
)
88 map
<string
, bufferlist
> vals
;
92 int r
= ioctx
.omap_set(oid
, vals
);
100 int RGWOrphanStore::remove_job(const string
& job_name
)
103 keys
.insert(job_name
);
105 int r
= ioctx
.omap_rm_keys(oid
, keys
);
113 int RGWOrphanStore::list_jobs(map
<string
,RGWOrphanSearchState
>& job_list
)
115 map
<string
,bufferlist
> vals
;
120 // loop through all the omap vals from index object, storing them to job_list,
121 // read in batches of 1024, we update the marker every iteration and exit the
122 // loop when we find that total size read out is less than batch size
124 r
= ioctx
.omap_get_vals(oid
, marker
, MAX_READ
, &vals
);
130 for (const auto &it
: vals
) {
132 RGWOrphanSearchState state
;
134 bufferlist bl
= it
.second
;
136 } catch (buffer::error
& err
) {
137 lderr(store
->ctx()) << "ERROR: could not decode buffer" << dendl
;
140 job_list
[it
.first
] = state
;
142 } while (r
== MAX_READ
);
147 int RGWOrphanStore::init()
149 const rgw_pool
& log_pool
= store
->svc()->zone
->get_zone_params().log_pool
;
150 int r
= rgw_init_ioctx(store
->getRados()->get_rados_handle(), log_pool
, ioctx
);
152 cerr
<< "ERROR: failed to open log pool (" << log_pool
<< " ret=" << r
<< std::endl
;
159 int RGWOrphanStore::store_entries(const string
& oid
, const map
<string
, bufferlist
>& entries
)
161 librados::ObjectWriteOperation op
;
162 op
.omap_set(entries
);
163 cout
<< "storing " << entries
.size() << " entries at " << oid
<< std::endl
;
164 ldout(store
->ctx(), 20) << "storing " << entries
.size() << " entries at " << oid
<< ": " << dendl
;
165 for (map
<string
, bufferlist
>::const_iterator iter
= entries
.begin(); iter
!= entries
.end(); ++iter
) {
166 ldout(store
->ctx(), 20) << " > " << iter
->first
<< dendl
;
168 int ret
= rgw_rados_operate(ioctx
, oid
, &op
, null_yield
);
170 lderr(store
->ctx()) << "ERROR: " << __func__
<< "(" << oid
<< ") returned ret=" << ret
<< dendl
;
176 int RGWOrphanStore::read_entries(const string
& oid
, const string
& marker
, map
<string
, bufferlist
> *entries
, bool *truncated
)
178 #define MAX_OMAP_GET 100
179 int ret
= ioctx
.omap_get_vals(oid
, marker
, MAX_OMAP_GET
, entries
);
180 if (ret
< 0 && ret
!= -ENOENT
) {
181 cerr
<< "ERROR: " << __func__
<< "(" << oid
<< ") returned ret=" << cpp_strerror(-ret
) << std::endl
;
184 *truncated
= (entries
->size() == MAX_OMAP_GET
);
189 int RGWOrphanSearch::init(const string
& job_name
, RGWOrphanSearchInfo
*info
, bool _detailed_mode
)
191 int r
= orphan_store
.init();
196 constexpr int64_t MAX_LIST_OBJS_ENTRIES
=100;
198 max_list_bucket_entries
= std::max(store
->ctx()->_conf
->rgw_list_bucket_min_readahead
,
199 MAX_LIST_OBJS_ENTRIES
);
201 detailed_mode
= _detailed_mode
;
202 RGWOrphanSearchState state
;
203 r
= orphan_store
.read_job(job_name
, state
);
204 if (r
< 0 && r
!= -ENOENT
) {
205 lderr(store
->ctx()) << "ERROR: failed to read state ret=" << r
<< dendl
;
210 search_info
= state
.info
;
211 search_stage
= state
.stage
;
212 } else if (info
) { /* r == -ENOENT, initiate a new job if info was provided */
214 search_info
.job_name
= job_name
;
215 search_info
.num_shards
= (info
->num_shards
? info
->num_shards
: DEFAULT_NUM_SHARDS
);
216 search_info
.start_time
= ceph_clock_now();
217 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_INIT
);
221 lderr(store
->ctx()) << "ERROR: failed to write state ret=" << r
<< dendl
;
225 lderr(store
->ctx()) << "ERROR: job not found" << dendl
;
229 index_objs_prefix
= RGW_ORPHAN_INDEX_PREFIX
+ string(".");
230 index_objs_prefix
+= job_name
;
232 for (int i
= 0; i
< search_info
.num_shards
; i
++) {
235 snprintf(buf
, sizeof(buf
), "%s.rados.%d", index_objs_prefix
.c_str(), i
);
236 all_objs_index
[i
] = buf
;
238 snprintf(buf
, sizeof(buf
), "%s.buckets.%d", index_objs_prefix
.c_str(), i
);
239 buckets_instance_index
[i
] = buf
;
241 snprintf(buf
, sizeof(buf
), "%s.linked.%d", index_objs_prefix
.c_str(), i
);
242 linked_objs_index
[i
] = buf
;
247 int RGWOrphanSearch::log_oids(map
<int, string
>& log_shards
, map
<int, list
<string
> >& oids
)
249 map
<int, list
<string
> >::iterator miter
= oids
.begin();
251 list
<log_iter_info
> liters
; /* a list of iterator pairs for begin and end */
253 for (; miter
!= oids
.end(); ++miter
) {
255 info
.oid
= log_shards
[miter
->first
];
256 info
.cur
= miter
->second
.begin();
257 info
.end
= miter
->second
.end();
258 liters
.push_back(info
);
261 list
<log_iter_info
>::iterator list_iter
;
262 while (!liters
.empty()) {
263 list_iter
= liters
.begin();
265 while (list_iter
!= liters
.end()) {
266 log_iter_info
& cur_info
= *list_iter
;
268 list
<string
>::iterator
& cur
= cur_info
.cur
;
269 list
<string
>::iterator
& end
= cur_info
.end
;
271 map
<string
, bufferlist
> entries
;
272 #define MAX_OMAP_SET_ENTRIES 100
273 for (int j
= 0; cur
!= end
&& j
!= MAX_OMAP_SET_ENTRIES
; ++cur
, ++j
) {
274 ldout(store
->ctx(), 20) << "adding obj: " << *cur
<< dendl
;
275 entries
[*cur
] = bufferlist();
278 int ret
= orphan_store
.store_entries(cur_info
.oid
, entries
);
282 list
<log_iter_info
>::iterator tmp
= list_iter
;
292 int RGWOrphanSearch::build_all_oids_index()
294 librados::IoCtx ioctx
;
296 int ret
= rgw_init_ioctx(store
->getRados()->get_rados_handle(), search_info
.pool
, ioctx
);
298 lderr(store
->ctx()) << __func__
<< ": rgw_init_ioctx() returned ret=" << ret
<< dendl
;
302 ioctx
.set_namespace(librados::all_nspaces
);
303 librados::NObjectIterator i
= ioctx
.nobjects_begin();
304 librados::NObjectIterator i_end
= ioctx
.nobjects_end();
306 map
<int, list
<string
> > oids
;
311 cout
<< "logging all objects in the pool" << std::endl
;
313 for (; i
!= i_end
; ++i
) {
314 string nspace
= i
->get_nspace();
315 string oid
= i
->get_oid();
316 string locator
= i
->get_locator();
318 ssize_t pos
= oid
.find('_');
320 cout
<< "unidentified oid: " << oid
<< ", skipping" << std::endl
;
321 /* what is this object, oids should be in the format of <bucket marker>_<obj>,
326 string stripped_oid
= oid
.substr(pos
+ 1);
328 if (!rgw_obj_key::parse_raw_oid(stripped_oid
, &key
)) {
329 cout
<< "cannot parse oid: " << oid
<< ", skipping" << std::endl
;
333 if (key
.ns
.empty()) {
334 /* skipping head objects, we don't want to remove these as they are mutable and
335 * cleaning them up is racy (can race with object removal and a later recreation)
337 cout
<< "skipping head object: oid=" << oid
<< std::endl
;
341 string oid_fp
= obj_fingerprint(oid
);
343 ldout(store
->ctx(), 20) << "oid_fp=" << oid_fp
<< dendl
;
345 int shard
= orphan_shard(oid_fp
);
346 oids
[shard
].push_back(oid
);
348 #define COUNT_BEFORE_FLUSH 1000
350 if (++count
>= COUNT_BEFORE_FLUSH
) {
351 ldout(store
->ctx(), 1) << "iterated through " << total
<< " objects" << dendl
;
352 ret
= log_oids(all_objs_index
, oids
);
354 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
361 ret
= log_oids(all_objs_index
, oids
);
363 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
370 int RGWOrphanSearch::build_buckets_instance_index()
374 string section
= "bucket.instance";
375 int ret
= store
->ctl()->meta
.mgr
->list_keys_init(section
, &handle
);
377 lderr(store
->ctx()) << "ERROR: can't get key: " << cpp_strerror(-ret
) << dendl
;
381 map
<int, list
<string
> > instances
;
385 RGWObjectCtx
obj_ctx(store
);
392 ret
= store
->ctl()->meta
.mgr
->list_keys_next(handle
, max
, keys
, &truncated
);
394 lderr(store
->ctx()) << "ERROR: lists_keys_next(): " << cpp_strerror(-ret
) << dendl
;
398 for (list
<string
>::iterator iter
= keys
.begin(); iter
!= keys
.end(); ++iter
) {
400 ldout(store
->ctx(), 10) << "bucket_instance=" << *iter
<< " total=" << total
<< dendl
;
401 int shard
= orphan_shard(*iter
);
402 instances
[shard
].push_back(*iter
);
404 if (++count
>= COUNT_BEFORE_FLUSH
) {
405 ret
= log_oids(buckets_instance_index
, instances
);
407 lderr(store
->ctx()) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
417 ret
= log_oids(buckets_instance_index
, instances
);
419 lderr(store
->ctx()) << __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< dendl
;
422 store
->ctl()->meta
.mgr
->list_keys_complete(handle
);
427 int RGWOrphanSearch::handle_stat_result(map
<int, list
<string
> >& oids
, RGWRados::Object::Stat::Result
& result
)
429 set
<string
> obj_oids
;
430 rgw_bucket
& bucket
= result
.obj
.bucket
;
431 if (!result
.manifest
) { /* a very very old object, or part of a multipart upload during upload */
432 const string loc
= bucket
.bucket_id
+ "_" + result
.obj
.get_oid();
433 obj_oids
.insert(obj_fingerprint(loc
));
436 * multipart parts don't have manifest on them, it's in the meta object. Instead of reading the
437 * meta object, just add a "shadow" object to the mix
439 obj_oids
.insert(obj_fingerprint(loc
, "shadow"));
441 RGWObjManifest
& manifest
= *result
.manifest
;
443 if (!detailed_mode
&&
444 manifest
.get_obj_size() <= manifest
.get_head_size()) {
445 ldout(store
->ctx(), 5) << "skipping object as it fits in a head" << dendl
;
449 RGWObjManifest::obj_iterator miter
;
450 for (miter
= manifest
.obj_begin(); miter
!= manifest
.obj_end(); ++miter
) {
451 const rgw_raw_obj
& loc
= miter
.get_location().get_raw_obj(store
->getRados());
453 obj_oids
.insert(obj_fingerprint(s
));
457 for (set
<string
>::iterator iter
= obj_oids
.begin(); iter
!= obj_oids
.end(); ++iter
) {
458 ldout(store
->ctx(), 20) << __func__
<< ": oid for obj=" << result
.obj
<< ": " << *iter
<< dendl
;
460 int shard
= orphan_shard(*iter
);
461 oids
[shard
].push_back(*iter
);
467 int RGWOrphanSearch::pop_and_handle_stat_op(map
<int, list
<string
> >& oids
, std::deque
<RGWRados::Object::Stat
>& ops
)
469 RGWRados::Object::Stat
& front_op
= ops
.front();
471 int ret
= front_op
.wait();
473 if (ret
!= -ENOENT
) {
474 lderr(store
->ctx()) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
478 ret
= handle_stat_result(oids
, front_op
.result
);
480 lderr(store
->ctx()) << "ERROR: handle_stat_response() returned error: " << cpp_strerror(-ret
) << dendl
;
487 int RGWOrphanSearch::build_linked_oids_for_bucket(const string
& bucket_instance_id
, map
<int, list
<string
> >& oids
)
489 RGWObjectCtx
obj_ctx(store
);
490 auto sysobj_ctx
= store
->svc()->sysobj
->init_obj_ctx();
492 rgw_bucket orphan_bucket
;
494 int ret
= rgw_bucket_parse_bucket_key(store
->ctx(), bucket_instance_id
,
495 &orphan_bucket
, &shard_id
);
497 ldout(store
->ctx(),0) << __func__
<< " failed to parse bucket instance: "
498 << bucket_instance_id
<< " skipping" << dendl
;
502 RGWBucketInfo cur_bucket_info
;
503 ret
= store
->getRados()->get_bucket_info(store
->svc(), orphan_bucket
.tenant
,
504 orphan_bucket
.name
, cur_bucket_info
, nullptr, null_yield
);
506 if (ret
== -ENOENT
) {
507 /* probably raced with bucket removal */
510 lderr(store
->ctx()) << __func__
<< ": ERROR: RGWRados::get_bucket_instance_info() returned ret=" << ret
<< dendl
;
514 if (cur_bucket_info
.bucket
.bucket_id
!= orphan_bucket
.bucket_id
) {
515 ldout(store
->ctx(), 0) << __func__
<< ": Skipping stale bucket instance: "
516 << orphan_bucket
.name
<< ": "
517 << orphan_bucket
.bucket_id
<< dendl
;
521 if (cur_bucket_info
.reshard_status
== cls_rgw_reshard_status::IN_PROGRESS
) {
522 ldout(store
->ctx(), 0) << __func__
<< ": reshard in progress. Skipping "
523 << orphan_bucket
.name
<< ": "
524 << orphan_bucket
.bucket_id
<< dendl
;
528 RGWBucketInfo bucket_info
;
529 ret
= store
->getRados()->get_bucket_instance_info(sysobj_ctx
, bucket_instance_id
, bucket_info
, nullptr, nullptr, null_yield
);
531 if (ret
== -ENOENT
) {
532 /* probably raced with bucket removal */
535 lderr(store
->ctx()) << __func__
<< ": ERROR: RGWRados::get_bucket_instance_info() returned ret=" << ret
<< dendl
;
539 ldout(store
->ctx(), 10) << "building linked oids for bucket instance: " << bucket_instance_id
<< dendl
;
540 RGWRados::Bucket
target(store
->getRados(), bucket_info
);
541 RGWRados::Bucket::List
list_op(&target
);
544 list_op
.params
.marker
= rgw_obj_key(marker
);
545 list_op
.params
.list_versions
= true;
546 list_op
.params
.enforce_ns
= false;
550 deque
<RGWRados::Object::Stat
> stat_ops
;
553 vector
<rgw_bucket_dir_entry
> result
;
555 ret
= list_op
.list_objects(max_list_bucket_entries
,
556 &result
, nullptr, &truncated
, null_yield
);
558 cerr
<< "ERROR: store->list_objects(): " << cpp_strerror(-ret
) << std::endl
;
562 for (vector
<rgw_bucket_dir_entry
>::iterator iter
= result
.begin(); iter
!= result
.end(); ++iter
) {
563 rgw_bucket_dir_entry
& entry
= *iter
;
564 if (entry
.key
.instance
.empty()) {
565 ldout(store
->ctx(), 20) << "obj entry: " << entry
.key
.name
<< dendl
;
567 ldout(store
->ctx(), 20) << "obj entry: " << entry
.key
.name
<< " [" << entry
.key
.instance
<< "]" << dendl
;
570 ldout(store
->ctx(), 20) << __func__
<< ": entry.key.name=" << entry
.key
.name
<< " entry.key.instance=" << entry
.key
.instance
<< dendl
;
572 if (!detailed_mode
&&
573 entry
.meta
.accounted_size
<= (uint64_t)store
->ctx()->_conf
->rgw_max_chunk_size
) {
574 ldout(store
->ctx(),5) << __func__
<< "skipping stat as the object " << entry
.key
.name
575 << "fits in a head" << dendl
;
579 rgw_obj
obj(bucket_info
.bucket
, entry
.key
);
581 RGWRados::Object
op_target(store
->getRados(), bucket_info
, obj_ctx
, obj
);
583 stat_ops
.push_back(RGWRados::Object::Stat(&op_target
));
584 RGWRados::Object::Stat
& op
= stat_ops
.back();
587 ret
= op
.stat_async();
589 lderr(store
->ctx()) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
592 if (stat_ops
.size() >= max_concurrent_ios
) {
593 ret
= pop_and_handle_stat_op(oids
, stat_ops
);
595 if (ret
!= -ENOENT
) {
596 lderr(store
->ctx()) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
600 if (oids
.size() >= COUNT_BEFORE_FLUSH
) {
601 ret
= log_oids(linked_objs_index
, oids
);
603 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
611 while (!stat_ops
.empty()) {
612 ret
= pop_and_handle_stat_op(oids
, stat_ops
);
614 if (ret
!= -ENOENT
) {
615 lderr(store
->ctx()) << "ERROR: stat_async() returned error: " << cpp_strerror(-ret
) << dendl
;
623 int RGWOrphanSearch::build_linked_oids_index()
625 map
<int, list
<string
> > oids
;
626 map
<int, string
>::iterator iter
= buckets_instance_index
.find(search_stage
.shard
);
627 for (; iter
!= buckets_instance_index
.end(); ++iter
) {
628 ldout(store
->ctx(), 0) << "building linked oids index: " << iter
->first
<< "/" << buckets_instance_index
.size() << dendl
;
631 string oid
= iter
->second
;
634 map
<string
, bufferlist
> entries
;
635 int ret
= orphan_store
.read_entries(oid
, search_stage
.marker
, &entries
, &truncated
);
636 if (ret
== -ENOENT
) {
642 lderr(store
->ctx()) << __func__
<< ": ERROR: read_entries() oid=" << oid
<< " returned ret=" << ret
<< dendl
;
646 if (entries
.empty()) {
650 for (map
<string
, bufferlist
>::iterator eiter
= entries
.begin(); eiter
!= entries
.end(); ++eiter
) {
651 ldout(store
->ctx(), 20) << " indexed entry: " << eiter
->first
<< dendl
;
652 ret
= build_linked_oids_for_bucket(eiter
->first
, oids
);
654 lderr(store
->ctx()) << __func__
<< ": ERROR: build_linked_oids_for_bucket() indexed entry=" << eiter
->first
655 << " returned ret=" << ret
<< dendl
;
660 search_stage
.shard
= iter
->first
;
661 search_stage
.marker
= entries
.rbegin()->first
; /* last entry */
664 search_stage
.marker
.clear();
667 int ret
= log_oids(linked_objs_index
, oids
);
669 cerr
<< __func__
<< ": ERROR: log_oids() returned ret=" << ret
<< std::endl
;
675 cerr
<< __func__
<< ": ERROR: failed to write state ret=" << ret
<< std::endl
;
683 librados::IoCtx ioctx
;
686 map
<string
, bufferlist
> entries
;
687 map
<string
, bufferlist
>::iterator iter
;
692 OMAPReader(librados::IoCtx
& _ioctx
, const string
& _oid
) : ioctx(_ioctx
), oid(_oid
), truncated(true) {
693 iter
= entries
.end();
696 int get_next(string
*key
, bufferlist
*pbl
, bool *done
);
699 int OMAPReader::get_next(string
*key
, bufferlist
*pbl
, bool *done
)
701 if (iter
!= entries
.end()) {
717 #define MAX_OMAP_GET_ENTRIES 100
718 int ret
= ioctx
.omap_get_vals(oid
, marker
, MAX_OMAP_GET_ENTRIES
, &entries
);
720 if (ret
== -ENOENT
) {
727 truncated
= (entries
.size() == MAX_OMAP_GET_ENTRIES
);
728 iter
= entries
.begin();
729 return get_next(key
, pbl
, done
);
732 int RGWOrphanSearch::compare_oid_indexes()
734 ceph_assert(linked_objs_index
.size() == all_objs_index
.size());
736 librados::IoCtx
& ioctx
= orphan_store
.get_ioctx();
738 librados::IoCtx data_ioctx
;
740 int ret
= rgw_init_ioctx(store
->getRados()->get_rados_handle(), search_info
.pool
, data_ioctx
);
742 lderr(store
->ctx()) << __func__
<< ": rgw_init_ioctx() returned ret=" << ret
<< dendl
;
746 uint64_t time_threshold
= search_info
.start_time
.sec() - stale_secs
;
748 map
<int, string
>::iterator liter
= linked_objs_index
.begin();
749 map
<int, string
>::iterator aiter
= all_objs_index
.begin();
751 for (; liter
!= linked_objs_index
.end(); ++liter
, ++aiter
) {
752 OMAPReader
linked_entries(ioctx
, liter
->second
);
753 OMAPReader
all_entries(ioctx
, aiter
->second
);
758 bool linked_done
= false;
763 int r
= all_entries
.get_next(&key
, NULL
, &done
);
771 string key_fp
= obj_fingerprint(key
);
773 while (cur_linked
< key_fp
&& !linked_done
) {
774 r
= linked_entries
.get_next(&cur_linked
, NULL
, &linked_done
);
780 if (cur_linked
== key_fp
) {
781 ldout(store
->ctx(), 20) << "linked: " << key
<< dendl
;
786 r
= data_ioctx
.stat(key
, NULL
, &mtime
);
789 lderr(store
->ctx()) << "ERROR: ioctx.stat(" << key
<< ") returned ret=" << r
<< dendl
;
793 if (stale_secs
&& (uint64_t)mtime
>= time_threshold
) {
794 ldout(store
->ctx(), 20) << "skipping: " << key
<< " (mtime=" << mtime
<< " threshold=" << time_threshold
<< ")" << dendl
;
797 ldout(store
->ctx(), 20) << "leaked: " << key
<< dendl
;
798 cout
<< "leaked: " << key
<< std::endl
;
805 int RGWOrphanSearch::run()
809 switch (search_stage
.stage
) {
811 case ORPHAN_SEARCH_STAGE_INIT
:
812 ldout(store
->ctx(), 0) << __func__
<< "(): initializing state" << dendl
;
813 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_LSPOOL
);
816 lderr(store
->ctx()) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
820 case ORPHAN_SEARCH_STAGE_LSPOOL
:
821 ldout(store
->ctx(), 0) << __func__
<< "(): building index of all objects in pool" << dendl
;
822 r
= build_all_oids_index();
824 lderr(store
->ctx()) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
828 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_LSBUCKETS
);
831 lderr(store
->ctx()) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
836 case ORPHAN_SEARCH_STAGE_LSBUCKETS
:
837 ldout(store
->ctx(), 0) << __func__
<< "(): building index of all bucket indexes" << dendl
;
838 r
= build_buckets_instance_index();
840 lderr(store
->ctx()) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
844 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_ITERATE_BI
);
847 lderr(store
->ctx()) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
853 case ORPHAN_SEARCH_STAGE_ITERATE_BI
:
854 ldout(store
->ctx(), 0) << __func__
<< "(): building index of all linked objects" << dendl
;
855 r
= build_linked_oids_index();
857 lderr(store
->ctx()) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
861 search_stage
= RGWOrphanSearchStage(ORPHAN_SEARCH_STAGE_COMPARE
);
864 lderr(store
->ctx()) << __func__
<< ": ERROR: failed to save state, ret=" << r
<< dendl
;
869 case ORPHAN_SEARCH_STAGE_COMPARE
:
870 r
= compare_oid_indexes();
872 lderr(store
->ctx()) << __func__
<< ": ERROR: build_all_objs_index returned ret=" << r
<< dendl
;
886 int RGWOrphanSearch::remove_index(map
<int, string
>& index
)
888 librados::IoCtx
& ioctx
= orphan_store
.get_ioctx();
890 for (map
<int, string
>::iterator iter
= index
.begin(); iter
!= index
.end(); ++iter
) {
891 int r
= ioctx
.remove(iter
->second
);
894 ldout(store
->ctx(), 0) << "ERROR: couldn't remove " << iter
->second
<< ": ret=" << r
<< dendl
;
901 int RGWOrphanSearch::finish()
903 int r
= remove_index(all_objs_index
);
905 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << all_objs_index
<< ") returned ret=" << r
<< dendl
;
907 r
= remove_index(buckets_instance_index
);
909 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << buckets_instance_index
<< ") returned ret=" << r
<< dendl
;
911 r
= remove_index(linked_objs_index
);
913 ldout(store
->ctx(), 0) << "ERROR: remove_index(" << linked_objs_index
<< ") returned ret=" << r
<< dendl
;
916 r
= orphan_store
.remove_job(search_info
.job_name
);
918 ldout(store
->ctx(), 0) << "ERROR: could not remove job name (" << search_info
.job_name
<< ") ret=" << r
<< dendl
;