1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
4 #include "svc_bi_rados.h"
5 #include "svc_bilog_rados.h"
8 #include "rgw/rgw_bucket.h"
9 #include "rgw/rgw_zone.h"
10 #include "rgw/rgw_datalog.h"
12 #include "cls/rgw/cls_rgw_client.h"
14 #define dout_subsys ceph_subsys_rgw
16 static string dir_oid_prefix
= ".dir.";
18 RGWSI_BucketIndex_RADOS::RGWSI_BucketIndex_RADOS(CephContext
*cct
) : RGWSI_BucketIndex(cct
)
22 void RGWSI_BucketIndex_RADOS::init(RGWSI_Zone
*zone_svc
,
23 RGWSI_RADOS
*rados_svc
,
24 RGWSI_BILog_RADOS
*bilog_svc
,
25 RGWDataChangesLog
*datalog_rados_svc
)
28 svc
.rados
= rados_svc
;
29 svc
.bilog
= bilog_svc
;
30 svc
.datalog_rados
= datalog_rados_svc
;
33 int RGWSI_BucketIndex_RADOS::open_pool(const rgw_pool
& pool
,
34 RGWSI_RADOS::Pool
*index_pool
,
37 *index_pool
= svc
.rados
->pool(pool
);
38 return index_pool
->open(RGWSI_RADOS::OpenParams()
39 .set_mostly_omap(mostly_omap
));
42 int RGWSI_BucketIndex_RADOS::open_bucket_index_pool(const RGWBucketInfo
& bucket_info
,
43 RGWSI_RADOS::Pool
*index_pool
)
45 const rgw_pool
& explicit_pool
= bucket_info
.bucket
.explicit_placement
.index_pool
;
47 if (!explicit_pool
.empty()) {
48 return open_pool(explicit_pool
, index_pool
, false);
51 auto& zonegroup
= svc
.zone
->get_zonegroup();
52 auto& zone_params
= svc
.zone
->get_zone_params();
54 const rgw_placement_rule
*rule
= &bucket_info
.placement_rule
;
56 rule
= &zonegroup
.default_placement
;
58 auto iter
= zone_params
.placement_pools
.find(rule
->name
);
59 if (iter
== zone_params
.placement_pools
.end()) {
60 ldout(cct
, 0) << "could not find placement rule " << *rule
<< " within zonegroup " << dendl
;
64 int r
= open_pool(iter
->second
.index_pool
, index_pool
, true);
71 int RGWSI_BucketIndex_RADOS::open_bucket_index_base(const RGWBucketInfo
& bucket_info
,
72 RGWSI_RADOS::Pool
*index_pool
,
73 string
*bucket_oid_base
)
75 const rgw_bucket
& bucket
= bucket_info
.bucket
;
76 int r
= open_bucket_index_pool(bucket_info
, index_pool
);
80 if (bucket
.bucket_id
.empty()) {
81 ldout(cct
, 0) << "ERROR: empty bucket_id for bucket operation" << dendl
;
85 *bucket_oid_base
= dir_oid_prefix
;
86 bucket_oid_base
->append(bucket
.bucket_id
);
92 int RGWSI_BucketIndex_RADOS::open_bucket_index(const RGWBucketInfo
& bucket_info
,
93 RGWSI_RADOS::Pool
*index_pool
,
96 const rgw_bucket
& bucket
= bucket_info
.bucket
;
97 int r
= open_bucket_index_pool(bucket_info
, index_pool
);
99 ldout(cct
, 20) << __func__
<< ": open_bucket_index_pool() returned "
104 if (bucket
.bucket_id
.empty()) {
105 ldout(cct
, 0) << "ERROR: empty bucket id for bucket operation" << dendl
;
109 *bucket_oid
= dir_oid_prefix
;
110 bucket_oid
->append(bucket
.bucket_id
);
115 static void get_bucket_index_objects(const string
& bucket_oid_base
,
117 map
<int, string
> *_bucket_objects
,
120 auto& bucket_objects
= *_bucket_objects
;
122 bucket_objects
[0] = bucket_oid_base
;
124 char buf
[bucket_oid_base
.size() + 32];
126 for (uint32_t i
= 0; i
< num_shards
; ++i
) {
127 snprintf(buf
, sizeof(buf
), "%s.%d", bucket_oid_base
.c_str(), i
);
128 bucket_objects
[i
] = buf
;
131 if ((uint32_t)shard_id
> num_shards
) {
134 snprintf(buf
, sizeof(buf
), "%s.%d", bucket_oid_base
.c_str(), shard_id
);
135 bucket_objects
[shard_id
] = buf
;
140 static void get_bucket_instance_ids(const RGWBucketInfo
& bucket_info
,
142 map
<int, string
> *result
)
144 const rgw_bucket
& bucket
= bucket_info
.bucket
;
145 string plain_id
= bucket
.name
+ ":" + bucket
.bucket_id
;
147 if (!bucket_info
.layout
.current_index
.layout
.normal
.num_shards
) {
148 (*result
)[0] = plain_id
;
152 for (uint32_t i
= 0; i
< bucket_info
.layout
.current_index
.layout
.normal
.num_shards
; ++i
) {
153 snprintf(buf
, sizeof(buf
), ":%d", i
);
154 (*result
)[i
] = plain_id
+ buf
;
157 if ((uint32_t)shard_id
> bucket_info
.layout
.current_index
.layout
.normal
.num_shards
) {
160 snprintf(buf
, sizeof(buf
), ":%d", shard_id
);
161 (*result
)[shard_id
] = plain_id
+ buf
;
166 int RGWSI_BucketIndex_RADOS::open_bucket_index(const RGWBucketInfo
& bucket_info
,
167 std::optional
<int> _shard_id
,
168 RGWSI_RADOS::Pool
*index_pool
,
169 map
<int, string
> *bucket_objs
,
170 map
<int, string
> *bucket_instance_ids
)
172 int shard_id
= _shard_id
.value_or(-1);
173 string bucket_oid_base
;
174 int ret
= open_bucket_index_base(bucket_info
, index_pool
, &bucket_oid_base
);
176 ldout(cct
, 20) << __func__
<< ": open_bucket_index_pool() returned "
181 get_bucket_index_objects(bucket_oid_base
, bucket_info
.layout
.current_index
.layout
.normal
.num_shards
, bucket_objs
, shard_id
);
182 if (bucket_instance_ids
) {
183 get_bucket_instance_ids(bucket_info
, shard_id
, bucket_instance_ids
);
188 void RGWSI_BucketIndex_RADOS::get_bucket_index_object(const string
& bucket_oid_base
,
195 // By default with no sharding, we use the bucket oid as itself
196 (*bucket_obj
) = bucket_oid_base
;
198 char buf
[bucket_oid_base
.size() + 64];
200 snprintf(buf
, sizeof(buf
), "%s.%" PRIu64
".%d", bucket_oid_base
.c_str(), gen_id
, shard_id
);
203 // for backward compatibility, gen_id(0) will not be added in the object name
204 snprintf(buf
, sizeof(buf
), "%s.%d", bucket_oid_base
.c_str(), shard_id
);
210 int RGWSI_BucketIndex_RADOS::get_bucket_index_object(const string
& bucket_oid_base
, const string
& obj_key
,
211 uint32_t num_shards
, rgw::BucketHashType hash_type
,
212 string
*bucket_obj
, int *shard_id
)
216 case rgw::BucketHashType::Mod
:
218 // By default with no sharding, we use the bucket oid as itself
219 (*bucket_obj
) = bucket_oid_base
;
224 uint32_t sid
= bucket_shard_index(obj_key
, num_shards
);
225 char buf
[bucket_oid_base
.size() + 32];
226 snprintf(buf
, sizeof(buf
), "%s.%d", bucket_oid_base
.c_str(), sid
);
229 *shard_id
= (int)sid
;
239 int RGWSI_BucketIndex_RADOS::open_bucket_index_shard(const RGWBucketInfo
& bucket_info
,
240 const string
& obj_key
,
241 RGWSI_RADOS::Obj
*bucket_obj
,
244 string bucket_oid_base
;
246 RGWSI_RADOS::Pool pool
;
248 int ret
= open_bucket_index_base(bucket_info
, &pool
, &bucket_oid_base
);
250 ldout(cct
, 20) << __func__
<< ": open_bucket_index_pool() returned "
257 ret
= get_bucket_index_object(bucket_oid_base
, obj_key
, bucket_info
.layout
.current_index
.layout
.normal
.num_shards
,
258 bucket_info
.layout
.current_index
.layout
.normal
.hash_type
, &oid
, shard_id
);
260 ldout(cct
, 10) << "get_bucket_index_object() returned ret=" << ret
<< dendl
;
264 *bucket_obj
= svc
.rados
->obj(pool
, oid
);
269 int RGWSI_BucketIndex_RADOS::open_bucket_index_shard(const RGWBucketInfo
& bucket_info
,
271 const rgw::bucket_index_layout_generation
& idx_layout
,
272 RGWSI_RADOS::Obj
*bucket_obj
)
274 RGWSI_RADOS::Pool index_pool
;
275 string bucket_oid_base
;
276 int ret
= open_bucket_index_base(bucket_info
, &index_pool
, &bucket_oid_base
);
278 ldout(cct
, 20) << __func__
<< ": open_bucket_index_pool() returned "
285 get_bucket_index_object(bucket_oid_base
, idx_layout
.layout
.normal
.num_shards
,
286 shard_id
, idx_layout
.gen
, &oid
);
288 *bucket_obj
= svc
.rados
->obj(index_pool
, oid
);
293 int RGWSI_BucketIndex_RADOS::cls_bucket_head(const RGWBucketInfo
& bucket_info
,
295 vector
<rgw_bucket_dir_header
> *headers
,
296 map
<int, string
> *bucket_instance_ids
,
299 RGWSI_RADOS::Pool index_pool
;
300 map
<int, string
> oids
;
301 int r
= open_bucket_index(bucket_info
, shard_id
, &index_pool
, &oids
, bucket_instance_ids
);
305 map
<int, struct rgw_cls_list_ret
> list_results
;
306 for (auto& iter
: oids
) {
307 list_results
.emplace(iter
.first
, rgw_cls_list_ret());
310 r
= CLSRGWIssueGetDirHeader(index_pool
.ioctx(), oids
, list_results
, cct
->_conf
->rgw_bucket_index_max_aio
)();
314 map
<int, struct rgw_cls_list_ret
>::iterator iter
= list_results
.begin();
315 for(; iter
!= list_results
.end(); ++iter
) {
316 headers
->push_back(std::move(iter
->second
.dir
.header
));
322 int RGWSI_BucketIndex_RADOS::init_index(RGWBucketInfo
& bucket_info
)
324 RGWSI_RADOS::Pool index_pool
;
326 string dir_oid
= dir_oid_prefix
;
327 int r
= open_bucket_index_pool(bucket_info
, &index_pool
);
332 dir_oid
.append(bucket_info
.bucket
.bucket_id
);
334 map
<int, string
> bucket_objs
;
335 get_bucket_index_objects(dir_oid
, bucket_info
.layout
.current_index
.layout
.normal
.num_shards
, &bucket_objs
);
337 return CLSRGWIssueBucketIndexInit(index_pool
.ioctx(),
339 cct
->_conf
->rgw_bucket_index_max_aio
)();
342 int RGWSI_BucketIndex_RADOS::clean_index(RGWBucketInfo
& bucket_info
)
344 RGWSI_RADOS::Pool index_pool
;
346 std::string dir_oid
= dir_oid_prefix
;
347 int r
= open_bucket_index_pool(bucket_info
, &index_pool
);
352 dir_oid
.append(bucket_info
.bucket
.bucket_id
);
354 std::map
<int, std::string
> bucket_objs
;
355 get_bucket_index_objects(dir_oid
, bucket_info
.layout
.current_index
.layout
.normal
.num_shards
, &bucket_objs
);
357 return CLSRGWIssueBucketIndexClean(index_pool
.ioctx(),
359 cct
->_conf
->rgw_bucket_index_max_aio
)();
362 int RGWSI_BucketIndex_RADOS::read_stats(const RGWBucketInfo
& bucket_info
,
363 RGWBucketEnt
*result
,
366 vector
<rgw_bucket_dir_header
> headers
;
368 result
->bucket
= bucket_info
.bucket
;
369 int r
= cls_bucket_head(bucket_info
, RGW_NO_SHARD
, &headers
, nullptr, y
);
374 auto hiter
= headers
.begin();
375 for (; hiter
!= headers
.end(); ++hiter
) {
376 RGWObjCategory category
= RGWObjCategory::Main
;
377 auto iter
= (hiter
->stats
).find(category
);
378 if (iter
!= hiter
->stats
.end()) {
379 struct rgw_bucket_category_stats
& stats
= iter
->second
;
380 result
->count
+= stats
.num_entries
;
381 result
->size
+= stats
.total_size
;
382 result
->size_rounded
+= stats
.total_size_rounded
;
386 result
->placement_rule
= std::move(bucket_info
.placement_rule
);
391 int RGWSI_BucketIndex_RADOS::get_reshard_status(const RGWBucketInfo
& bucket_info
, list
<cls_rgw_bucket_instance_entry
> *status
)
393 map
<int, string
> bucket_objs
;
395 RGWSI_RADOS::Pool index_pool
;
397 int r
= open_bucket_index(bucket_info
,
406 for (auto i
: bucket_objs
) {
407 cls_rgw_bucket_instance_entry entry
;
409 int ret
= cls_rgw_get_bucket_resharding(index_pool
.ioctx(), i
.second
, &entry
);
410 if (ret
< 0 && ret
!= -ENOENT
) {
411 lderr(cct
) << "ERROR: " << __func__
<< ": cls_rgw_get_bucket_resharding() returned ret=" << ret
<< dendl
;
415 status
->push_back(entry
);
421 int RGWSI_BucketIndex_RADOS::handle_overwrite(const RGWBucketInfo
& info
,
422 const RGWBucketInfo
& orig_info
)
424 bool new_sync_enabled
= info
.datasync_flag_enabled();
425 bool old_sync_enabled
= orig_info
.datasync_flag_enabled();
427 if (old_sync_enabled
!= new_sync_enabled
) {
428 int shards_num
= info
.layout
.current_index
.layout
.normal
.num_shards
? info
.layout
.current_index
.layout
.normal
.num_shards
: 1;
429 int shard_id
= info
.layout
.current_index
.layout
.normal
.num_shards
? 0 : -1;
432 if (!new_sync_enabled
) {
433 ret
= svc
.bilog
->log_stop(info
, -1);
435 ret
= svc
.bilog
->log_start(info
, -1);
438 lderr(cct
) << "ERROR: failed writing bilog (bucket=" << info
.bucket
<< "); ret=" << ret
<< dendl
;
442 for (int i
= 0; i
< shards_num
; ++i
, ++shard_id
) {
443 ret
= svc
.datalog_rados
->add_entry(info
, shard_id
);
445 lderr(cct
) << "ERROR: failed writing data log (info.bucket=" << info
.bucket
<< ", shard_id=" << shard_id
<< ")" << dendl
;