1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 * Ceph - scalable distributed file system
7 * Copyright (C) 2015 Red Hat
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
18 #include "common/config.h"
19 #include "common/Formatter.h"
20 #include "common/errno.h"
22 #include "rgw_sal_rados.h"
24 #define dout_subsys ceph_subsys_rgw
26 #define RGW_ORPHAN_INDEX_OID "orphan.index"
27 #define RGW_ORPHAN_INDEX_PREFIX "orphan.scan"
30 enum RGWOrphanSearchStageId
{
31 ORPHAN_SEARCH_STAGE_UNKNOWN
= 0,
32 ORPHAN_SEARCH_STAGE_INIT
= 1,
33 ORPHAN_SEARCH_STAGE_LSPOOL
= 2,
34 ORPHAN_SEARCH_STAGE_LSBUCKETS
= 3,
35 ORPHAN_SEARCH_STAGE_ITERATE_BI
= 4,
36 ORPHAN_SEARCH_STAGE_COMPARE
= 5,
40 struct RGWOrphanSearchStage
{
41 RGWOrphanSearchStageId stage
;
45 RGWOrphanSearchStage() : stage(ORPHAN_SEARCH_STAGE_UNKNOWN
), shard(0) {}
46 explicit RGWOrphanSearchStage(RGWOrphanSearchStageId _stage
) : stage(_stage
), shard(0) {}
47 RGWOrphanSearchStage(RGWOrphanSearchStageId _stage
, int _shard
, const std::string
& _marker
) : stage(_stage
), shard(_shard
), marker(_marker
) {}
49 void encode(bufferlist
& bl
) const {
50 ENCODE_START(1, 1, bl
);
51 encode((int)stage
, bl
);
57 void decode(bufferlist::const_iterator
& bl
) {
61 stage
= (RGWOrphanSearchStageId
)s
;
67 void dump(Formatter
*f
) const;
69 WRITE_CLASS_ENCODER(RGWOrphanSearchStage
)
71 struct RGWOrphanSearchInfo
{
77 void encode(bufferlist
& bl
) const {
78 ENCODE_START(2, 1, bl
);
80 encode(pool
.to_str(), bl
);
81 encode(num_shards
, bl
);
82 encode(start_time
, bl
);
86 void decode(bufferlist::const_iterator
& bl
) {
92 decode(num_shards
, bl
);
93 decode(start_time
, bl
);
97 void dump(Formatter
*f
) const;
99 WRITE_CLASS_ENCODER(RGWOrphanSearchInfo
)
101 struct RGWOrphanSearchState
{
102 RGWOrphanSearchInfo info
;
103 RGWOrphanSearchStage stage
;
105 RGWOrphanSearchState() : stage(ORPHAN_SEARCH_STAGE_UNKNOWN
) {}
107 void encode(bufferlist
& bl
) const {
108 ENCODE_START(1, 1, bl
);
114 void decode(bufferlist::const_iterator
& bl
) {
121 void dump(Formatter
*f
) const;
123 WRITE_CLASS_ENCODER(RGWOrphanSearchState
)
125 class RGWOrphanStore
{
126 rgw::sal::RadosStore
* store
;
127 librados::IoCtx ioctx
;
132 explicit RGWOrphanStore(rgw::sal::RadosStore
* _store
) : store(_store
), oid(RGW_ORPHAN_INDEX_OID
) {}
134 librados::IoCtx
& get_ioctx() { return ioctx
; }
136 int init(const DoutPrefixProvider
*dpp
);
138 int read_job(const std::string
& job_name
, RGWOrphanSearchState
& state
);
139 int write_job(const std::string
& job_name
, const RGWOrphanSearchState
& state
);
140 int remove_job(const std::string
& job_name
);
141 int list_jobs(std::map
<std::string
,RGWOrphanSearchState
> &job_list
);
144 int store_entries(const DoutPrefixProvider
*dpp
, const std::string
& oid
, const std::map
<std::string
, bufferlist
>& entries
);
145 int read_entries(const std::string
& oid
, const std::string
& marker
, std::map
<std::string
, bufferlist
> *entries
, bool *truncated
);
149 class RGWOrphanSearch
{
150 rgw::sal::RadosStore
* store
;
152 RGWOrphanStore orphan_store
;
154 RGWOrphanSearchInfo search_info
;
155 RGWOrphanSearchStage search_stage
;
157 std::map
<int, std::string
> all_objs_index
;
158 std::map
<int, std::string
> buckets_instance_index
;
159 std::map
<int, std::string
> linked_objs_index
;
161 std::string index_objs_prefix
;
163 uint16_t max_concurrent_ios
;
165 int64_t max_list_bucket_entries
;
169 struct log_iter_info
{
171 std::list
<std::string
>::iterator cur
;
172 std::list
<std::string
>::iterator end
;
175 int log_oids(const DoutPrefixProvider
*dpp
, std::map
<int, std::string
>& log_shards
, std::map
<int, std::list
<std::string
> >& oids
);
177 #define RGW_ORPHANSEARCH_HASH_PRIME 7877
178 int orphan_shard(const std::string
& str
) {
179 return ceph_str_hash_linux(str
.c_str(), str
.size()) % RGW_ORPHANSEARCH_HASH_PRIME
% search_info
.num_shards
;
182 int handle_stat_result(const DoutPrefixProvider
*dpp
, std::map
<int, std::list
<std::string
> >& oids
, RGWRados::Object::Stat::Result
& result
);
183 int pop_and_handle_stat_op(const DoutPrefixProvider
*dpp
, std::map
<int, std::list
<std::string
> >& oids
, std::deque
<RGWRados::Object::Stat
>& ops
);
185 int remove_index(std::map
<int, std::string
>& index
);
187 RGWOrphanSearch(rgw::sal::RadosStore
* _store
, int _max_ios
, uint64_t _stale_secs
) : store(_store
), orphan_store(store
), max_concurrent_ios(_max_ios
), stale_secs(_stale_secs
) {}
190 RGWOrphanSearchState state
;
191 state
.info
= search_info
;
192 state
.stage
= search_stage
;
193 return orphan_store
.write_job(search_info
.job_name
, state
);
196 int init(const DoutPrefixProvider
*dpp
, const std::string
& job_name
, RGWOrphanSearchInfo
*info
, bool _detailed_mode
=false);
198 int create(const std::string
& job_name
, int num_shards
);
200 int build_all_oids_index(const DoutPrefixProvider
*dpp
);
201 int build_buckets_instance_index(const DoutPrefixProvider
*dpp
);
202 int build_linked_oids_for_bucket(const DoutPrefixProvider
*dpp
, const std::string
& bucket_instance_id
, std::map
<int, std::list
<std::string
> >& oids
);
203 int build_linked_oids_index(const DoutPrefixProvider
*dpp
);
204 int compare_oid_indexes(const DoutPrefixProvider
*dpp
);
206 int run(const DoutPrefixProvider
*dpp
);
214 * process_t describes how to process a irectory, we will either
215 * process the whole thing (entire_container == true) or a portion
216 * of it (entire_container == false). When we only process a
217 * portion, we will list the specific keys and/or specific lexical
221 bool entire_container
;
222 std::set
<rgw_obj_key
> filter_keys
;
223 std::set
<std::string
> prefixes
;
226 entire_container(false)
230 std::map
<std::string
,process_t
> bucket_process_map
;
231 std::set
<std::string
> visited_oids
;
233 void add_bucket_entire(const std::string
& bucket_name
) {
234 auto p
= bucket_process_map
.emplace(std::make_pair(bucket_name
,
236 p
.first
->second
.entire_container
= true;
239 void add_bucket_prefix(const std::string
& bucket_name
,
240 const std::string
& prefix
) {
241 auto p
= bucket_process_map
.emplace(std::make_pair(bucket_name
,
243 p
.first
->second
.prefixes
.insert(prefix
);
246 void add_bucket_filter(const std::string
& bucket_name
,
247 const rgw_obj_key
& obj_key
) {
248 auto p
= bucket_process_map
.emplace(std::make_pair(bucket_name
,
250 p
.first
->second
.filter_keys
.insert(obj_key
);
253 rgw::sal::RadosStore
* store
;
255 uint16_t max_concurrent_ios
;
257 std::string tenant_name
;
259 bool include_rgw_obj_name
;
260 std::string field_separator
;
262 int handle_stat_result(const DoutPrefixProvider
*dpp
,
263 RGWRados::Object::Stat::Result
& result
,
264 std::string
& bucket_name
,
265 rgw_obj_key
& obj_key
,
266 std::set
<std::string
>& obj_oids
);
267 int pop_and_handle_stat_op(const DoutPrefixProvider
*dpp
,
268 RGWObjectCtx
& obj_ctx
,
269 std::deque
<RGWRados::Object::Stat
>& ops
);
273 RGWRadosList(rgw::sal::RadosStore
* _store
,
275 uint64_t _stale_secs
,
276 const std::string
& _tenant_name
) :
278 max_concurrent_ios(_max_ios
),
279 stale_secs(_stale_secs
),
280 tenant_name(_tenant_name
),
281 include_rgw_obj_name(false)
284 int process_bucket(const DoutPrefixProvider
*dpp
,
285 const std::string
& bucket_instance_id
,
286 const std::string
& prefix
,
287 const std::set
<rgw_obj_key
>& entries_filter
);
289 int do_incomplete_multipart(const DoutPrefixProvider
*dpp
,
290 rgw::sal::Bucket
* bucket
);
292 int build_linked_oids_index();
294 int run(const DoutPrefixProvider
*dpp
, const std::string
& bucket_id
);
295 int run(const DoutPrefixProvider
*dpp
);
297 // if there's a non-empty field separator, that means we'll display
298 // bucket and object names
299 void set_field_separator(const std::string
& fs
) {
300 field_separator
= fs
;
301 include_rgw_obj_name
= !field_separator
.empty();
303 }; // class RGWRadosList