1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
10 #include <boost/utility/string_ref.hpp>
11 #include <boost/format.hpp>
13 #include "common/errno.h"
14 #include "common/ceph_json.h"
15 #include "common/backport14.h"
16 #include "rgw_rados.h"
18 #include "rgw_acl_s3.h"
20 #include "include/types.h"
21 #include "rgw_bucket.h"
23 #include "rgw_string.h"
24 #include "rgw_multi.h"
26 #include "include/rados/librados.hpp"
27 // until everything is moved from rgw_common
28 #include "rgw_common.h"
30 #include "cls/user/cls_user_types.h"
32 #define dout_context g_ceph_context
33 #define dout_subsys ceph_subsys_rgw
35 #define BUCKET_TAG_TIMEOUT 30
39 static RGWMetadataHandler
*bucket_meta_handler
= NULL
;
40 static RGWMetadataHandler
*bucket_instance_meta_handler
= NULL
;
42 // define as static when RGWBucket implementation compete
43 void rgw_get_buckets_obj(const rgw_user
& user_id
, string
& buckets_obj_id
)
45 buckets_obj_id
= user_id
.to_str();
46 buckets_obj_id
+= RGW_BUCKETS_OBJ_SUFFIX
;
50 * Note that this is not a reversal of parse_bucket(). That one deals
51 * with the syntax we need in metadata and such. This one deals with
52 * the representation in RADOS pools. We chose '/' because it's not
53 * acceptable in bucket names and thus qualified buckets cannot conflict
54 * with the legacy or S3 buckets.
56 std::string
rgw_make_bucket_entry_name(const std::string
& tenant_name
,
57 const std::string
& bucket_name
) {
58 std::string bucket_entry
;
60 if (bucket_name
.empty()) {
62 } else if (tenant_name
.empty()) {
63 bucket_entry
= bucket_name
;
65 bucket_entry
= tenant_name
+ "/" + bucket_name
;
72 * Tenants are separated from buckets in URLs by a colon in S3.
73 * This function is not to be used on Swift URLs, not even for COPY arguments.
75 void rgw_parse_url_bucket(const string
&bucket
, const string
& auth_tenant
,
76 string
&tenant_name
, string
&bucket_name
) {
78 int pos
= bucket
.find(':');
81 * N.B.: We allow ":bucket" syntax with explicit empty tenant in order
82 * to refer to the legacy tenant, in case users in new named tenants
83 * want to access old global buckets.
85 tenant_name
= bucket
.substr(0, pos
);
86 bucket_name
= bucket
.substr(pos
+ 1);
88 tenant_name
= auth_tenant
;
94 * Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
95 * Returns: 0 on success, -ERR# on failure.
97 int rgw_read_user_buckets(RGWRados
* store
,
98 const rgw_user
& user_id
,
99 RGWUserBuckets
& buckets
,
100 const string
& marker
,
101 const string
& end_marker
,
105 uint64_t default_amount
)
109 std::string buckets_obj_id
;
110 rgw_get_buckets_obj(user_id
, buckets_obj_id
);
111 rgw_raw_obj
obj(store
->get_zone_params().user_uid_pool
, buckets_obj_id
);
113 bool truncated
= false;
119 max
= default_amount
;
123 std::list
<cls_user_bucket_entry
> entries
;
124 ret
= store
->cls_user_list_buckets(obj
, m
, end_marker
, max
- total
, entries
, &m
, &truncated
);
125 if (ret
== -ENOENT
) {
133 for (auto& entry
: entries
) {
134 buckets
.add(RGWBucketEnt(user_id
, std::move(entry
)));
138 } while (truncated
&& total
< max
);
140 if (is_truncated
!= nullptr) {
141 *is_truncated
= truncated
;
145 map
<string
, RGWBucketEnt
>& m
= buckets
.get_buckets();
146 ret
= store
->update_containers_stats(m
);
147 if (ret
< 0 && ret
!= -ENOENT
) {
148 ldout(store
->ctx(), 0) << "ERROR: could not get stats for buckets" << dendl
;
155 int rgw_bucket_sync_user_stats(RGWRados
*store
, const rgw_user
& user_id
, const RGWBucketInfo
& bucket_info
)
157 string buckets_obj_id
;
158 rgw_get_buckets_obj(user_id
, buckets_obj_id
);
159 rgw_raw_obj
obj(store
->get_zone_params().user_uid_pool
, buckets_obj_id
);
161 return store
->cls_user_sync_bucket_stats(obj
, bucket_info
);
164 int rgw_bucket_sync_user_stats(RGWRados
*store
, const string
& tenant_name
, const string
& bucket_name
)
166 RGWBucketInfo bucket_info
;
167 RGWObjectCtx
obj_ctx(store
);
168 int ret
= store
->get_bucket_info(obj_ctx
, tenant_name
, bucket_name
, bucket_info
, NULL
);
170 ldout(store
->ctx(), 0) << "ERROR: could not fetch bucket info: ret=" << ret
<< dendl
;
174 ret
= rgw_bucket_sync_user_stats(store
, bucket_info
.owner
, bucket_info
);
176 ldout(store
->ctx(), 0) << "ERROR: could not sync user stats for bucket " << bucket_name
<< ": ret=" << ret
<< dendl
;
183 int rgw_link_bucket(RGWRados
* const store
,
184 const rgw_user
& user_id
,
186 ceph::real_time creation_time
,
187 bool update_entrypoint
)
190 string
& tenant_name
= bucket
.tenant
;
191 string
& bucket_name
= bucket
.name
;
193 cls_user_bucket_entry new_bucket
;
195 RGWBucketEntryPoint ep
;
196 RGWObjVersionTracker ot
;
198 bucket
.convert(&new_bucket
.bucket
);
200 if (real_clock::is_zero(creation_time
))
201 new_bucket
.creation_time
= real_clock::now();
203 new_bucket
.creation_time
= creation_time
;
205 map
<string
, bufferlist
> attrs
;
206 RGWObjectCtx
obj_ctx(store
);
208 if (update_entrypoint
) {
209 ret
= store
->get_bucket_entrypoint_info(obj_ctx
, tenant_name
, bucket_name
, ep
, &ot
, NULL
, &attrs
);
210 if (ret
< 0 && ret
!= -ENOENT
) {
211 ldout(store
->ctx(), 0) << "ERROR: store->get_bucket_entrypoint_info() returned: "
212 << cpp_strerror(-ret
) << dendl
;
216 string buckets_obj_id
;
217 rgw_get_buckets_obj(user_id
, buckets_obj_id
);
219 rgw_raw_obj
obj(store
->get_zone_params().user_uid_pool
, buckets_obj_id
);
220 ret
= store
->cls_user_add_bucket(obj
, new_bucket
);
222 ldout(store
->ctx(), 0) << "ERROR: error adding bucket to directory: "
223 << cpp_strerror(-ret
) << dendl
;
227 if (!update_entrypoint
)
233 ret
= store
->put_bucket_entrypoint_info(tenant_name
, bucket_name
, ep
, false, ot
, real_time(), &attrs
);
239 int r
= rgw_unlink_bucket(store
, user_id
, bucket
.tenant
, bucket
.name
);
241 ldout(store
->ctx(), 0) << "ERROR: failed unlinking bucket on error cleanup: "
242 << cpp_strerror(-r
) << dendl
;
247 int rgw_unlink_bucket(RGWRados
*store
, const rgw_user
& user_id
, const string
& tenant_name
, const string
& bucket_name
, bool update_entrypoint
)
251 string buckets_obj_id
;
252 rgw_get_buckets_obj(user_id
, buckets_obj_id
);
254 cls_user_bucket bucket
;
255 bucket
.name
= bucket_name
;
256 rgw_raw_obj
obj(store
->get_zone_params().user_uid_pool
, buckets_obj_id
);
257 ret
= store
->cls_user_remove_bucket(obj
, bucket
);
259 ldout(store
->ctx(), 0) << "ERROR: error removing bucket from directory: "
260 << cpp_strerror(-ret
)<< dendl
;
263 if (!update_entrypoint
)
266 RGWBucketEntryPoint ep
;
267 RGWObjVersionTracker ot
;
268 map
<string
, bufferlist
> attrs
;
269 RGWObjectCtx
obj_ctx(store
);
270 ret
= store
->get_bucket_entrypoint_info(obj_ctx
, tenant_name
, bucket_name
, ep
, &ot
, NULL
, &attrs
);
279 if (ep
.owner
!= user_id
) {
280 ldout(store
->ctx(), 0) << "bucket entry point user mismatch, can't unlink bucket: " << ep
.owner
<< " != " << user_id
<< dendl
;
285 return store
->put_bucket_entrypoint_info(tenant_name
, bucket_name
, ep
, false, ot
, real_time(), &attrs
);
288 int rgw_bucket_store_info(RGWRados
*store
, const string
& bucket_name
, bufferlist
& bl
, bool exclusive
,
289 map
<string
, bufferlist
> *pattrs
, RGWObjVersionTracker
*objv_tracker
,
291 return store
->meta_mgr
->put_entry(bucket_meta_handler
, bucket_name
, bl
, exclusive
, objv_tracker
, mtime
, pattrs
);
294 int rgw_bucket_instance_store_info(RGWRados
*store
, string
& entry
, bufferlist
& bl
, bool exclusive
,
295 map
<string
, bufferlist
> *pattrs
, RGWObjVersionTracker
*objv_tracker
,
297 return store
->meta_mgr
->put_entry(bucket_instance_meta_handler
, entry
, bl
, exclusive
, objv_tracker
, mtime
, pattrs
);
300 int rgw_bucket_instance_remove_entry(RGWRados
*store
, string
& entry
, RGWObjVersionTracker
*objv_tracker
) {
301 return store
->meta_mgr
->remove_entry(bucket_instance_meta_handler
, entry
, objv_tracker
);
304 // 'tenant/' is used in bucket instance keys for sync to avoid parsing ambiguity
305 // with the existing instance[:shard] format. once we parse the shard, the / is
306 // replaced with a : to match the [tenant:]instance format
307 void rgw_bucket_instance_key_to_oid(string
& key
)
309 // replace tenant/ with tenant:
310 auto c
= key
.find('/');
311 if (c
!= string::npos
) {
316 // convert bucket instance oids back to the tenant/ format for metadata keys.
317 // it's safe to parse 'tenant:' only for oids, because they won't contain the
318 // optional :shard at the end
319 void rgw_bucket_instance_oid_to_key(string
& oid
)
321 // find first : (could be tenant:bucket or bucket:instance)
322 auto c
= oid
.find(':');
323 if (c
!= string::npos
) {
324 // if we find another :, the first one was for tenant
325 if (oid
.find(':', c
+ 1) != string::npos
) {
331 int rgw_bucket_parse_bucket_instance(const string
& bucket_instance
, string
*target_bucket_instance
, int *shard_id
)
333 ssize_t pos
= bucket_instance
.rfind(':');
338 string first
= bucket_instance
.substr(0, pos
);
339 string second
= bucket_instance
.substr(pos
+ 1);
341 if (first
.find(':') == string::npos
) {
343 *target_bucket_instance
= bucket_instance
;
347 *target_bucket_instance
= first
;
349 *shard_id
= strict_strtol(second
.c_str(), 10, &err
);
357 // parse key in format: [tenant/]name:instance[:shard_id]
358 int rgw_bucket_parse_bucket_key(CephContext
*cct
, const string
& key
,
359 rgw_bucket
*bucket
, int *shard_id
)
361 boost::string_ref name
{key
};
362 boost::string_ref instance
;
365 auto pos
= name
.find('/');
366 if (pos
!= boost::string_ref::npos
) {
367 auto tenant
= name
.substr(0, pos
);
368 bucket
->tenant
.assign(tenant
.begin(), tenant
.end());
369 name
= name
.substr(pos
+ 1);
372 // split name:instance
373 pos
= name
.find(':');
374 if (pos
!= boost::string_ref::npos
) {
375 instance
= name
.substr(pos
+ 1);
376 name
= name
.substr(0, pos
);
378 bucket
->name
.assign(name
.begin(), name
.end());
380 // split instance:shard
381 pos
= instance
.find(':');
382 if (pos
== boost::string_ref::npos
) {
383 bucket
->bucket_id
.assign(instance
.begin(), instance
.end());
389 auto shard
= instance
.substr(pos
+ 1);
391 auto id
= strict_strtol(shard
.data(), 10, &err
);
393 ldout(cct
, 0) << "ERROR: failed to parse bucket shard '"
394 << instance
.data() << "': " << err
<< dendl
;
399 instance
= instance
.substr(0, pos
);
400 bucket
->bucket_id
.assign(instance
.begin(), instance
.end());
404 int rgw_bucket_set_attrs(RGWRados
*store
, RGWBucketInfo
& bucket_info
,
405 map
<string
, bufferlist
>& attrs
,
406 RGWObjVersionTracker
*objv_tracker
)
408 rgw_bucket
& bucket
= bucket_info
.bucket
;
410 if (!bucket_info
.has_instance_obj
) {
411 /* an old bucket object, need to convert it */
412 RGWObjectCtx
obj_ctx(store
);
413 int ret
= store
->convert_old_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
);
415 ldout(store
->ctx(), 0) << "ERROR: failed converting old bucket info: " << ret
<< dendl
;
420 /* we want the bucket instance name without the oid prefix cruft */
421 string key
= bucket
.get_key();
424 ::encode(bucket_info
, bl
);
426 return rgw_bucket_instance_store_info(store
, key
, bl
, false, &attrs
, objv_tracker
, real_time());
429 static void dump_mulipart_index_results(list
<rgw_obj_index_key
>& objs_to_unlink
,
432 for (const auto& o
: objs_to_unlink
) {
433 f
->dump_string("object", o
.name
);
437 void check_bad_user_bucket_mapping(RGWRados
*store
, const rgw_user
& user_id
,
440 RGWUserBuckets user_buckets
;
441 bool is_truncated
= false;
444 CephContext
*cct
= store
->ctx();
446 size_t max_entries
= cct
->_conf
->rgw_list_buckets_max_chunk
;
449 int ret
= rgw_read_user_buckets(store
, user_id
, user_buckets
, marker
,
450 string(), max_entries
, false,
453 ldout(store
->ctx(), 0) << "failed to read user buckets: "
454 << cpp_strerror(-ret
) << dendl
;
458 map
<string
, RGWBucketEnt
>& buckets
= user_buckets
.get_buckets();
459 for (map
<string
, RGWBucketEnt
>::iterator i
= buckets
.begin();
464 RGWBucketEnt
& bucket_ent
= i
->second
;
465 rgw_bucket
& bucket
= bucket_ent
.bucket
;
467 RGWBucketInfo bucket_info
;
469 RGWObjectCtx
obj_ctx(store
);
470 int r
= store
->get_bucket_info(obj_ctx
, user_id
.tenant
, bucket
.name
, bucket_info
, &mtime
);
472 ldout(store
->ctx(), 0) << "could not get bucket info for bucket=" << bucket
<< dendl
;
476 rgw_bucket
& actual_bucket
= bucket_info
.bucket
;
478 if (actual_bucket
.name
.compare(bucket
.name
) != 0 ||
479 actual_bucket
.tenant
.compare(bucket
.tenant
) != 0 ||
480 actual_bucket
.marker
.compare(bucket
.marker
) != 0 ||
481 actual_bucket
.bucket_id
.compare(bucket
.bucket_id
) != 0) {
482 cout
<< "bucket info mismatch: expected " << actual_bucket
<< " got " << bucket
<< std::endl
;
484 cout
<< "fixing" << std::endl
;
485 r
= rgw_link_bucket(store
, user_id
, actual_bucket
,
486 bucket_info
.creation_time
);
488 cerr
<< "failed to fix bucket: " << cpp_strerror(-r
) << std::endl
;
493 } while (is_truncated
);
496 static bool bucket_object_check_filter(const string
& oid
)
500 return rgw_obj_key::oid_to_key_in_ns(oid
, &key
, ns
);
503 int rgw_remove_object(RGWRados
*store
, RGWBucketInfo
& bucket_info
, rgw_bucket
& bucket
, rgw_obj_key
& key
)
505 RGWObjectCtx
rctx(store
);
507 if (key
.instance
.empty()) {
508 key
.instance
= "null";
511 rgw_obj
obj(bucket
, key
);
513 return store
->delete_obj(rctx
, bucket_info
, obj
, bucket_info
.versioning_status());
516 int rgw_remove_bucket(RGWRados
*store
, rgw_bucket
& bucket
, bool delete_children
)
519 map
<RGWObjCategory
, RGWStorageStats
> stats
;
520 std::vector
<rgw_bucket_dir_entry
> objs
;
521 map
<string
, bool> common_prefixes
;
523 RGWObjectCtx
obj_ctx(store
);
525 string bucket_ver
, master_ver
;
527 ret
= store
->get_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
, info
, NULL
);
531 ret
= store
->get_bucket_stats(info
, RGW_NO_SHARD
, &bucket_ver
, &master_ver
, stats
, NULL
);
535 RGWRados::Bucket
target(store
, info
);
536 RGWRados::Bucket::List
list_op(&target
);
537 CephContext
*cct
= store
->ctx();
540 list_op
.params
.list_versions
= true;
545 ret
= list_op
.list_objects(max
, &objs
, &common_prefixes
, NULL
);
549 if (!objs
.empty() && !delete_children
) {
550 lderr(store
->ctx()) << "ERROR: could not remove non-empty bucket " << bucket
.name
<< dendl
;
554 for (const auto& obj
: objs
) {
555 rgw_obj_key
key(obj
.key
);
556 ret
= rgw_remove_object(store
, info
, bucket
, key
);
561 } while (!objs
.empty());
563 string prefix
, delimiter
;
565 ret
= abort_bucket_multiparts(store
, cct
, info
, prefix
, delimiter
);
570 ret
= rgw_bucket_sync_user_stats(store
, info
.owner
, info
);
572 dout(1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret
<< dendl
;
575 RGWObjVersionTracker objv_tracker
;
577 ret
= store
->delete_bucket(info
, objv_tracker
);
579 lderr(store
->ctx()) << "ERROR: could not remove bucket " << bucket
.name
<< dendl
;
583 ret
= rgw_unlink_bucket(store
, info
.owner
, bucket
.tenant
, bucket
.name
, false);
585 lderr(store
->ctx()) << "ERROR: unable to remove user bucket information" << dendl
;
591 static int aio_wait(librados::AioCompletion
*handle
)
593 librados::AioCompletion
*c
= (librados::AioCompletion
*)handle
;
595 int ret
= c
->get_return_value();
600 static int drain_handles(list
<librados::AioCompletion
*>& pending
)
603 while (!pending
.empty()) {
604 librados::AioCompletion
*handle
= pending
.front();
606 int r
= aio_wait(handle
);
614 int rgw_remove_bucket_bypass_gc(RGWRados
*store
, rgw_bucket
& bucket
,
615 int concurrent_max
, bool keep_index_consistent
)
618 map
<RGWObjCategory
, RGWStorageStats
> stats
;
619 std::vector
<rgw_bucket_dir_entry
> objs
;
620 map
<string
, bool> common_prefixes
;
622 RGWObjectCtx
obj_ctx(store
);
623 CephContext
*cct
= store
->ctx();
625 string bucket_ver
, master_ver
;
627 ret
= store
->get_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
, info
, NULL
);
631 ret
= store
->get_bucket_stats(info
, RGW_NO_SHARD
, &bucket_ver
, &master_ver
, stats
, NULL
);
635 string prefix
, delimiter
;
637 ret
= abort_bucket_multiparts(store
, cct
, info
, prefix
, delimiter
);
642 RGWRados::Bucket
target(store
, info
);
643 RGWRados::Bucket::List
list_op(&target
);
645 list_op
.params
.list_versions
= true;
647 std::list
<librados::AioCompletion
*> handles
;
650 int max_aio
= concurrent_max
;
651 ret
= list_op
.list_objects(max
, &objs
, &common_prefixes
, NULL
);
655 while (!objs
.empty()) {
656 std::vector
<rgw_bucket_dir_entry
>::iterator it
= objs
.begin();
657 for (; it
!= objs
.end(); ++it
) {
658 RGWObjState
*astate
= NULL
;
659 rgw_obj
obj(bucket
, (*it
).key
);
661 ret
= store
->get_obj_state(&obj_ctx
, info
, obj
, &astate
, false);
662 if (ret
== -ENOENT
) {
663 dout(1) << "WARNING: cannot find obj state for obj " << obj
.get_oid() << dendl
;
667 lderr(store
->ctx()) << "ERROR: get obj state returned with error " << ret
<< dendl
;
671 if (astate
->has_manifest
) {
672 RGWObjManifest
& manifest
= astate
->manifest
;
673 RGWObjManifest::obj_iterator miter
= manifest
.obj_begin();
674 rgw_obj head_obj
= manifest
.get_obj();
675 rgw_raw_obj raw_head_obj
;
676 store
->obj_to_raw(info
.placement_rule
, head_obj
, &raw_head_obj
);
679 for (; miter
!= manifest
.obj_end() && max_aio
--; ++miter
) {
681 ret
= drain_handles(handles
);
683 lderr(store
->ctx()) << "ERROR: could not drain handles as aio completion returned with " << ret
<< dendl
;
686 max_aio
= concurrent_max
;
689 rgw_raw_obj last_obj
= miter
.get_location().get_raw_obj(store
);
690 if (last_obj
== raw_head_obj
) {
691 // have the head obj deleted at the end
695 ret
= store
->delete_raw_obj_aio(last_obj
, handles
);
697 lderr(store
->ctx()) << "ERROR: delete obj aio failed with " << ret
<< dendl
;
700 } // for all shadow objs
702 ret
= store
->delete_obj_aio(head_obj
, info
, astate
, handles
, keep_index_consistent
);
704 lderr(store
->ctx()) << "ERROR: delete obj aio failed with " << ret
<< dendl
;
710 ret
= drain_handles(handles
);
712 lderr(store
->ctx()) << "ERROR: could not drain handles as aio completion returned with " << ret
<< dendl
;
715 max_aio
= concurrent_max
;
717 } // for all RGW objects
720 ret
= list_op
.list_objects(max
, &objs
, &common_prefixes
, NULL
);
725 ret
= drain_handles(handles
);
727 lderr(store
->ctx()) << "ERROR: could not drain handles as aio completion returned with " << ret
<< dendl
;
731 ret
= rgw_bucket_sync_user_stats(store
, info
.owner
, info
);
733 dout(1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret
<< dendl
;
736 RGWObjVersionTracker objv_tracker
;
738 ret
= store
->delete_bucket(info
, objv_tracker
);
740 lderr(store
->ctx()) << "ERROR: could not remove bucket " << bucket
.name
<< dendl
;
744 ret
= rgw_unlink_bucket(store
, info
.owner
, bucket
.tenant
, bucket
.name
, false);
746 lderr(store
->ctx()) << "ERROR: unable to remove user bucket information" << dendl
;
752 int rgw_bucket_delete_bucket_obj(RGWRados
*store
,
753 const string
& tenant_name
,
754 const string
& bucket_name
,
755 RGWObjVersionTracker
& objv_tracker
)
759 rgw_make_bucket_entry_name(tenant_name
, bucket_name
, key
);
760 return store
->meta_mgr
->remove_entry(bucket_meta_handler
, key
, &objv_tracker
);
763 static void set_err_msg(std::string
*sink
, std::string msg
)
765 if (sink
&& !msg
.empty())
769 int RGWBucket::init(RGWRados
*storage
, RGWBucketAdminOpState
& op_state
)
776 rgw_user user_id
= op_state
.get_user_id();
777 tenant
= user_id
.tenant
;
778 bucket_name
= op_state
.get_bucket_name();
779 RGWUserBuckets user_buckets
;
780 RGWObjectCtx
obj_ctx(store
);
782 if (bucket_name
.empty() && user_id
.empty())
785 if (!bucket_name
.empty()) {
786 int r
= store
->get_bucket_info(obj_ctx
, tenant
, bucket_name
, bucket_info
, NULL
);
788 ldout(store
->ctx(), 0) << "could not get bucket info for bucket=" << bucket_name
<< dendl
;
792 op_state
.set_bucket(bucket_info
.bucket
);
795 if (!user_id
.empty()) {
796 int r
= rgw_get_user_info_by_uid(store
, user_id
, user_info
);
800 op_state
.display_name
= user_info
.display_name
;
807 int RGWBucket::link(RGWBucketAdminOpState
& op_state
, std::string
*err_msg
)
809 if (!op_state
.is_user_op()) {
810 set_err_msg(err_msg
, "empty user id");
814 string bucket_id
= op_state
.get_bucket_id();
815 if (bucket_id
.empty()) {
816 set_err_msg(err_msg
, "empty bucket instance id");
820 std::string display_name
= op_state
.get_user_display_name();
821 rgw_bucket bucket
= op_state
.get_bucket();
823 const rgw_pool
& root_pool
= store
->get_zone_params().domain_root
;
824 rgw_raw_obj
obj(root_pool
, bucket
.name
);
825 RGWObjVersionTracker objv_tracker
;
827 map
<string
, bufferlist
> attrs
;
828 RGWBucketInfo bucket_info
;
830 string key
= bucket
.name
+ ":" + bucket_id
;
831 RGWObjectCtx
obj_ctx(store
);
832 int r
= store
->get_bucket_instance_info(obj_ctx
, key
, bucket_info
, NULL
, &attrs
);
837 rgw_user user_id
= op_state
.get_user_id();
839 map
<string
, bufferlist
>::iterator aiter
= attrs
.find(RGW_ATTR_ACL
);
840 if (aiter
!= attrs
.end()) {
841 bufferlist aclbl
= aiter
->second
;
842 RGWAccessControlPolicy policy
;
845 bufferlist::iterator iter
= aclbl
.begin();
846 ::decode(policy
, iter
);
847 owner
= policy
.get_owner();
848 } catch (buffer::error
& err
) {
849 set_err_msg(err_msg
, "couldn't decode policy");
853 r
= rgw_unlink_bucket(store
, owner
.get_id(), bucket
.tenant
, bucket
.name
, false);
855 set_err_msg(err_msg
, "could not unlink policy from user " + owner
.get_id().to_str());
859 // now update the user for the bucket...
860 if (display_name
.empty()) {
861 ldout(store
->ctx(), 0) << "WARNING: user " << user_info
.user_id
<< " has no display name set" << dendl
;
863 policy
.create_default(user_info
.user_id
, display_name
);
865 owner
= policy
.get_owner();
866 r
= store
->set_bucket_owner(bucket_info
.bucket
, owner
);
868 set_err_msg(err_msg
, "failed to set bucket owner: " + cpp_strerror(-r
));
872 // ...and encode the acl
874 policy
.encode(aclbl
);
876 r
= store
->system_obj_set_attr(NULL
, obj
, RGW_ATTR_ACL
, aclbl
, &objv_tracker
);
881 RGWAccessControlPolicy policy_instance
;
882 policy_instance
.create_default(user_info
.user_id
, display_name
);
884 policy_instance
.encode(aclbl
);
886 string oid_bucket_instance
= RGW_BUCKET_INSTANCE_MD_PREFIX
+ key
;
887 rgw_raw_obj
obj_bucket_instance(root_pool
, oid_bucket_instance
);
888 r
= store
->system_obj_set_attr(NULL
, obj_bucket_instance
, RGW_ATTR_ACL
, aclbl
, &objv_tracker
);
893 r
= rgw_link_bucket(store
, user_info
.user_id
, bucket_info
.bucket
,
903 int RGWBucket::unlink(RGWBucketAdminOpState
& op_state
, std::string
*err_msg
)
905 rgw_bucket bucket
= op_state
.get_bucket();
907 if (!op_state
.is_user_op()) {
908 set_err_msg(err_msg
, "could not fetch user or user bucket info");
912 int r
= rgw_unlink_bucket(store
, user_info
.user_id
, bucket
.tenant
, bucket
.name
);
914 set_err_msg(err_msg
, "error unlinking bucket" + cpp_strerror(-r
));
920 int RGWBucket::set_quota(RGWBucketAdminOpState
& op_state
, std::string
*err_msg
)
922 rgw_bucket bucket
= op_state
.get_bucket();
923 RGWBucketInfo bucket_info
;
924 map
<string
, bufferlist
> attrs
;
925 RGWObjectCtx
obj_ctx(store
);
926 int r
= store
->get_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
, bucket_info
, NULL
, &attrs
);
928 set_err_msg(err_msg
, "could not get bucket info for bucket=" + bucket
.name
+ ": " + cpp_strerror(-r
));
932 bucket_info
.quota
= op_state
.quota
;
933 r
= store
->put_bucket_instance_info(bucket_info
, false, real_time(), &attrs
);
935 set_err_msg(err_msg
, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r
));
941 int RGWBucket::remove(RGWBucketAdminOpState
& op_state
, bool bypass_gc
,
942 bool keep_index_consistent
, std::string
*err_msg
)
944 bool delete_children
= op_state
.will_delete_children();
945 rgw_bucket bucket
= op_state
.get_bucket();
949 if (delete_children
) {
950 ret
= rgw_remove_bucket_bypass_gc(store
, bucket
, op_state
.get_max_aio(), keep_index_consistent
);
952 set_err_msg(err_msg
, "purge objects should be set for gc to be bypassed");
956 ret
= rgw_remove_bucket(store
, bucket
, delete_children
);
960 set_err_msg(err_msg
, "unable to remove bucket" + cpp_strerror(-ret
));
967 int RGWBucket::remove_object(RGWBucketAdminOpState
& op_state
, std::string
*err_msg
)
969 rgw_bucket bucket
= op_state
.get_bucket();
970 std::string object_name
= op_state
.get_object_name();
972 rgw_obj_key
key(object_name
);
974 int ret
= rgw_remove_object(store
, bucket_info
, bucket
, key
);
976 set_err_msg(err_msg
, "unable to remove object" + cpp_strerror(-ret
));
983 static void dump_bucket_index(map
<string
, rgw_bucket_dir_entry
> result
, Formatter
*f
)
985 map
<string
, rgw_bucket_dir_entry
>::iterator iter
;
986 for (iter
= result
.begin(); iter
!= result
.end(); ++iter
) {
987 f
->dump_string("object", iter
->first
);
991 static void dump_bucket_usage(map
<RGWObjCategory
, RGWStorageStats
>& stats
, Formatter
*formatter
)
993 map
<RGWObjCategory
, RGWStorageStats
>::iterator iter
;
995 formatter
->open_object_section("usage");
996 for (iter
= stats
.begin(); iter
!= stats
.end(); ++iter
) {
997 RGWStorageStats
& s
= iter
->second
;
998 const char *cat_name
= rgw_obj_category_name(iter
->first
);
999 formatter
->open_object_section(cat_name
);
1001 formatter
->close_section();
1003 formatter
->close_section();
1006 static void dump_index_check(map
<RGWObjCategory
, RGWStorageStats
> existing_stats
,
1007 map
<RGWObjCategory
, RGWStorageStats
> calculated_stats
,
1008 Formatter
*formatter
)
1010 formatter
->open_object_section("check_result");
1011 formatter
->open_object_section("existing_header");
1012 dump_bucket_usage(existing_stats
, formatter
);
1013 formatter
->close_section();
1014 formatter
->open_object_section("calculated_header");
1015 dump_bucket_usage(calculated_stats
, formatter
);
1016 formatter
->close_section();
1017 formatter
->close_section();
1020 int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState
& op_state
,
1021 RGWFormatterFlusher
& flusher
,std::string
*err_msg
)
1023 bool fix_index
= op_state
.will_fix_index();
1024 rgw_bucket bucket
= op_state
.get_bucket();
1028 map
<string
, bool> common_prefixes
;
1031 map
<string
, bool> meta_objs
;
1032 map
<rgw_obj_index_key
, string
> all_objs
;
1034 RGWBucketInfo bucket_info
;
1035 RGWObjectCtx
obj_ctx(store
);
1036 int r
= store
->get_bucket_instance_info(obj_ctx
, bucket
, bucket_info
, nullptr, nullptr);
1038 ldout(store
->ctx(), 0) << "ERROR: " << __func__
<< "(): get_bucket_instance_info(bucket=" << bucket
<< ") returned r=" << r
<< dendl
;
1042 RGWRados::Bucket
target(store
, bucket_info
);
1043 RGWRados::Bucket::List
list_op(&target
);
1045 list_op
.params
.list_versions
= true;
1046 list_op
.params
.ns
= RGW_OBJ_NS_MULTIPART
;
1049 vector
<rgw_bucket_dir_entry
> result
;
1050 int r
= list_op
.list_objects(max
, &result
, &common_prefixes
, &is_truncated
);
1052 set_err_msg(err_msg
, "failed to list objects in bucket=" + bucket
.name
+
1053 " err=" + cpp_strerror(-r
));
1058 vector
<rgw_bucket_dir_entry
>::iterator iter
;
1059 for (iter
= result
.begin(); iter
!= result
.end(); ++iter
) {
1060 rgw_obj_index_key key
= iter
->key
;
1061 rgw_obj
obj(bucket
, key
);
1062 string oid
= obj
.get_oid();
1064 int pos
= oid
.find_last_of('.');
1066 /* obj has no suffix */
1067 all_objs
[key
] = oid
;
1069 /* obj has suffix */
1070 string name
= oid
.substr(0, pos
);
1071 string suffix
= oid
.substr(pos
+ 1);
1073 if (suffix
.compare("meta") == 0) {
1074 meta_objs
[name
] = true;
1076 all_objs
[key
] = name
;
1081 } while (is_truncated
);
1083 list
<rgw_obj_index_key
> objs_to_unlink
;
1084 Formatter
*f
= flusher
.get_formatter();
1086 f
->open_array_section("invalid_multipart_entries");
1088 for (auto aiter
= all_objs
.begin(); aiter
!= all_objs
.end(); ++aiter
) {
1089 string
& name
= aiter
->second
;
1091 if (meta_objs
.find(name
) == meta_objs
.end()) {
1092 objs_to_unlink
.push_back(aiter
->first
);
1095 if (objs_to_unlink
.size() > max
) {
1097 int r
= store
->remove_objs_from_index(bucket_info
, objs_to_unlink
);
1099 set_err_msg(err_msg
, "ERROR: remove_obj_from_index() returned error: " +
1105 dump_mulipart_index_results(objs_to_unlink
, flusher
.get_formatter());
1107 objs_to_unlink
.clear();
1112 int r
= store
->remove_objs_from_index(bucket_info
, objs_to_unlink
);
1114 set_err_msg(err_msg
, "ERROR: remove_obj_from_index() returned error: " +
1121 dump_mulipart_index_results(objs_to_unlink
, f
);
1128 int RGWBucket::check_object_index(RGWBucketAdminOpState
& op_state
,
1129 RGWFormatterFlusher
& flusher
,
1130 std::string
*err_msg
)
1133 bool fix_index
= op_state
.will_fix_index();
1135 rgw_bucket bucket
= op_state
.get_bucket();
1138 set_err_msg(err_msg
, "check-objects flag requires fix index enabled");
1142 store
->cls_obj_set_bucket_tag_timeout(bucket_info
, BUCKET_TAG_TIMEOUT
);
1145 rgw_obj_index_key marker
;
1146 bool is_truncated
= true;
1148 Formatter
*formatter
= flusher
.get_formatter();
1149 formatter
->open_object_section("objects");
1150 while (is_truncated
) {
1151 map
<string
, rgw_bucket_dir_entry
> result
;
1153 int r
= store
->cls_bucket_list_ordered(bucket_info
, RGW_NO_SHARD
,
1154 marker
, prefix
, 1000, true,
1155 result
, &is_truncated
, &marker
,
1156 bucket_object_check_filter
);
1159 } else if (r
< 0 && r
!= -ENOENT
) {
1160 set_err_msg(err_msg
, "ERROR: failed operation r=" + cpp_strerror(-r
));
1163 dump_bucket_index(result
, formatter
);
1167 formatter
->close_section();
1169 store
->cls_obj_set_bucket_tag_timeout(bucket_info
, 0);
1175 int RGWBucket::check_index(RGWBucketAdminOpState
& op_state
,
1176 map
<RGWObjCategory
, RGWStorageStats
>& existing_stats
,
1177 map
<RGWObjCategory
, RGWStorageStats
>& calculated_stats
,
1178 std::string
*err_msg
)
1180 rgw_bucket bucket
= op_state
.get_bucket();
1181 bool fix_index
= op_state
.will_fix_index();
1183 int r
= store
->bucket_check_index(bucket_info
, &existing_stats
, &calculated_stats
);
1185 set_err_msg(err_msg
, "failed to check index error=" + cpp_strerror(-r
));
1190 r
= store
->bucket_rebuild_index(bucket_info
);
1192 set_err_msg(err_msg
, "failed to rebuild index err=" + cpp_strerror(-r
));
1201 int RGWBucket::policy_bl_to_stream(bufferlist
& bl
, ostream
& o
)
1203 RGWAccessControlPolicy_S3
policy(g_ceph_context
);
1204 bufferlist::iterator iter
= bl
.begin();
1206 policy
.decode(iter
);
1207 } catch (buffer::error
& err
) {
1208 dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl
;
1215 static int policy_decode(RGWRados
*store
, bufferlist
& bl
, RGWAccessControlPolicy
& policy
)
1217 bufferlist::iterator iter
= bl
.begin();
1219 policy
.decode(iter
);
1220 } catch (buffer::error
& err
) {
1221 ldout(store
->ctx(), 0) << "ERROR: caught buffer::error, could not decode policy" << dendl
;
1227 int RGWBucket::get_policy(RGWBucketAdminOpState
& op_state
, RGWAccessControlPolicy
& policy
)
1229 std::string object_name
= op_state
.get_object_name();
1230 rgw_bucket bucket
= op_state
.get_bucket();
1231 RGWObjectCtx
obj_ctx(store
);
1233 RGWBucketInfo bucket_info
;
1234 map
<string
, bufferlist
> attrs
;
1235 int ret
= store
->get_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
, bucket_info
, NULL
, &attrs
);
1240 if (!object_name
.empty()) {
1242 rgw_obj
obj(bucket
, object_name
);
1244 RGWRados::Object
op_target(store
, bucket_info
, obj_ctx
, obj
);
1245 RGWRados::Object::Read
rop(&op_target
);
1247 int ret
= rop
.get_attr(RGW_ATTR_ACL
, bl
);
1251 return policy_decode(store
, bl
, policy
);
1254 map
<string
, bufferlist
>::iterator aiter
= attrs
.find(RGW_ATTR_ACL
);
1255 if (aiter
== attrs
.end()) {
1259 return policy_decode(store
, aiter
->second
, policy
);
1263 int RGWBucketAdminOp::get_policy(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1264 RGWAccessControlPolicy
& policy
)
1268 int ret
= bucket
.init(store
, op_state
);
1272 ret
= bucket
.get_policy(op_state
, policy
);
1279 /* Wrappers to facilitate RESTful interface */
1282 int RGWBucketAdminOp::get_policy(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1283 RGWFormatterFlusher
& flusher
)
1285 RGWAccessControlPolicy
policy(store
->ctx());
1287 int ret
= get_policy(store
, op_state
, policy
);
1291 Formatter
*formatter
= flusher
.get_formatter();
1295 formatter
->open_object_section("policy");
1296 policy
.dump(formatter
);
1297 formatter
->close_section();
1304 int RGWBucketAdminOp::dump_s3_policy(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1307 RGWAccessControlPolicy_S3
policy(store
->ctx());
1309 int ret
= get_policy(store
, op_state
, policy
);
1318 int RGWBucketAdminOp::unlink(RGWRados
*store
, RGWBucketAdminOpState
& op_state
)
1322 int ret
= bucket
.init(store
, op_state
);
1326 return bucket
.unlink(op_state
);
1329 int RGWBucketAdminOp::link(RGWRados
*store
, RGWBucketAdminOpState
& op_state
, string
*err
)
1333 int ret
= bucket
.init(store
, op_state
);
1337 return bucket
.link(op_state
, err
);
1341 int RGWBucketAdminOp::check_index(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1342 RGWFormatterFlusher
& flusher
)
1345 map
<RGWObjCategory
, RGWStorageStats
> existing_stats
;
1346 map
<RGWObjCategory
, RGWStorageStats
> calculated_stats
;
1351 ret
= bucket
.init(store
, op_state
);
1355 Formatter
*formatter
= flusher
.get_formatter();
1358 ret
= bucket
.check_bad_index_multipart(op_state
, flusher
);
1362 ret
= bucket
.check_object_index(op_state
, flusher
);
1366 ret
= bucket
.check_index(op_state
, existing_stats
, calculated_stats
);
1370 dump_index_check(existing_stats
, calculated_stats
, formatter
);
1376 int RGWBucketAdminOp::remove_bucket(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1377 bool bypass_gc
, bool keep_index_consistent
)
1381 int ret
= bucket
.init(store
, op_state
);
1385 std::string err_msg
;
1386 ret
= bucket
.remove(op_state
, bypass_gc
, keep_index_consistent
, &err_msg
);
1387 if (!err_msg
.empty()) {
1388 lderr(store
->ctx()) << "ERROR: " << err_msg
<< dendl
;
1393 int RGWBucketAdminOp::remove_object(RGWRados
*store
, RGWBucketAdminOpState
& op_state
)
1397 int ret
= bucket
.init(store
, op_state
);
1401 return bucket
.remove_object(op_state
);
1404 static int bucket_stats(RGWRados
*store
, const std::string
& tenant_name
, std::string
& bucket_name
, Formatter
*formatter
)
1406 RGWBucketInfo bucket_info
;
1407 map
<RGWObjCategory
, RGWStorageStats
> stats
;
1410 RGWObjectCtx
obj_ctx(store
);
1411 int r
= store
->get_bucket_info(obj_ctx
, tenant_name
, bucket_name
, bucket_info
, &mtime
);
1415 rgw_bucket
& bucket
= bucket_info
.bucket
;
1417 string bucket_ver
, master_ver
;
1419 int ret
= store
->get_bucket_stats(bucket_info
, RGW_NO_SHARD
, &bucket_ver
, &master_ver
, stats
, &max_marker
);
1421 cerr
<< "error getting bucket stats ret=" << ret
<< std::endl
;
1427 formatter
->open_object_section("stats");
1428 formatter
->dump_string("bucket", bucket
.name
);
1429 formatter
->dump_string("zonegroup", bucket_info
.zonegroup
);
1430 formatter
->dump_string("placement_rule", bucket_info
.placement_rule
);
1431 ::encode_json("explicit_placement", bucket
.explicit_placement
, formatter
);
1432 formatter
->dump_string("id", bucket
.bucket_id
);
1433 formatter
->dump_string("marker", bucket
.marker
);
1434 formatter
->dump_stream("index_type") << bucket_info
.index_type
;
1435 ::encode_json("owner", bucket_info
.owner
, formatter
);
1436 formatter
->dump_string("ver", bucket_ver
);
1437 formatter
->dump_string("master_ver", master_ver
);
1438 formatter
->dump_stream("mtime") << ut
;
1439 formatter
->dump_string("max_marker", max_marker
);
1440 dump_bucket_usage(stats
, formatter
);
1441 encode_json("bucket_quota", bucket_info
.quota
, formatter
);
1442 formatter
->close_section();
1447 int RGWBucketAdminOp::limit_check(RGWRados
*store
,
1448 RGWBucketAdminOpState
& op_state
,
1449 const std::list
<std::string
>& user_ids
,
1450 RGWFormatterFlusher
& flusher
,
1454 const size_t max_entries
=
1455 store
->ctx()->_conf
->rgw_list_buckets_max_chunk
;
1457 const size_t safe_max_objs_per_shard
=
1458 store
->ctx()->_conf
->rgw_safe_max_objects_per_shard
;
1460 uint16_t shard_warn_pct
=
1461 store
->ctx()->_conf
->rgw_shard_warning_threshold
;
1462 if (shard_warn_pct
> 100)
1463 shard_warn_pct
= 90;
1465 Formatter
*formatter
= flusher
.get_formatter();
1468 formatter
->open_array_section("users");
1470 for (const auto& user_id
: user_ids
) {
1471 formatter
->open_object_section("user");
1472 formatter
->dump_string("user_id", user_id
);
1474 formatter
->open_array_section("buckets");
1476 RGWUserBuckets buckets
;
1480 ret
= rgw_read_user_buckets(store
, user_id
, buckets
,
1481 marker
, string(), max_entries
, false,
1486 map
<string
, RGWBucketEnt
>& m_buckets
= buckets
.get_buckets();
1488 for (const auto& iter
: m_buckets
) {
1489 auto& bucket
= iter
.second
.bucket
;
1490 uint32_t num_shards
= 1;
1491 uint64_t num_objects
= 0;
1493 /* need info for num_shards */
1495 RGWObjectCtx
obj_ctx(store
);
1497 marker
= bucket
.name
; /* Casey's location for marker update,
1498 * as we may now not reach the end of
1501 ret
= store
->get_bucket_info(obj_ctx
, bucket
.tenant
, bucket
.name
,
1506 /* need stats for num_entries */
1507 string bucket_ver
, master_ver
;
1508 std::map
<RGWObjCategory
, RGWStorageStats
> stats
;
1509 ret
= store
->get_bucket_stats(info
, RGW_NO_SHARD
, &bucket_ver
,
1510 &master_ver
, stats
, nullptr);
1515 for (const auto& s
: stats
) {
1516 num_objects
+= s
.second
.num_objects
;
1519 num_shards
= info
.num_shards
;
1520 uint64_t objs_per_shard
=
1521 (num_shards
) ? num_objects
/num_shards
: num_objects
;
1525 if (objs_per_shard
> safe_max_objs_per_shard
) {
1527 100 - (safe_max_objs_per_shard
/objs_per_shard
* 100);
1528 ss
<< boost::format("OVER %4f%%") % over
;
1532 objs_per_shard
/ safe_max_objs_per_shard
* 100;
1533 if (fill_pct
>= shard_warn_pct
) {
1534 ss
<< boost::format("WARN %4f%%") % fill_pct
;
1541 if (warn
|| (! warnings_only
)) {
1542 formatter
->open_object_section("bucket");
1543 formatter
->dump_string("bucket", bucket
.name
);
1544 formatter
->dump_string("tenant", bucket
.tenant
);
1545 formatter
->dump_int("num_objects", num_objects
);
1546 formatter
->dump_int("num_shards", num_shards
);
1547 formatter
->dump_int("objects_per_shard", objs_per_shard
);
1548 formatter
->dump_string("fill_status", ss
.str());
1549 formatter
->close_section();
1554 done
= (m_buckets
.size() < max_entries
);
1555 } while (!done
); /* foreach: bucket */
1557 formatter
->close_section();
1558 formatter
->close_section();
1559 formatter
->flush(cout
);
1561 } /* foreach: user_id */
1563 formatter
->close_section();
1564 formatter
->flush(cout
);
1567 } /* RGWBucketAdminOp::limit_check */
1569 int RGWBucketAdminOp::info(RGWRados
*store
, RGWBucketAdminOpState
& op_state
,
1570 RGWFormatterFlusher
& flusher
)
1575 string bucket_name
= op_state
.get_bucket_name();
1577 if (!bucket_name
.empty()) {
1578 ret
= bucket
.init(store
, op_state
);
1583 Formatter
*formatter
= flusher
.get_formatter();
1586 CephContext
*cct
= store
->ctx();
1588 const size_t max_entries
= cct
->_conf
->rgw_list_buckets_max_chunk
;
1590 bool show_stats
= op_state
.will_fetch_stats();
1591 rgw_user user_id
= op_state
.get_user_id();
1592 if (op_state
.is_user_op()) {
1593 formatter
->open_array_section("buckets");
1595 RGWUserBuckets buckets
;
1597 bool is_truncated
= false;
1600 ret
= rgw_read_user_buckets(store
, op_state
.get_user_id(), buckets
,
1601 marker
, string(), max_entries
, false,
1606 map
<string
, RGWBucketEnt
>& m
= buckets
.get_buckets();
1607 map
<string
, RGWBucketEnt
>::iterator iter
;
1609 for (iter
= m
.begin(); iter
!= m
.end(); ++iter
) {
1610 std::string obj_name
= iter
->first
;
1612 bucket_stats(store
, user_id
.tenant
, obj_name
, formatter
);
1614 formatter
->dump_string("bucket", obj_name
);
1620 } while (is_truncated
);
1622 formatter
->close_section();
1623 } else if (!bucket_name
.empty()) {
1624 bucket_stats(store
, user_id
.tenant
, bucket_name
, formatter
);
1626 RGWAccessHandle handle
;
1628 formatter
->open_array_section("buckets");
1629 if (store
->list_buckets_init(&handle
) >= 0) {
1630 rgw_bucket_dir_entry obj
;
1631 while (store
->list_buckets_next(obj
, &handle
) >= 0) {
1633 bucket_stats(store
, user_id
.tenant
, obj
.key
.name
, formatter
);
1635 formatter
->dump_string("bucket", obj
.key
.name
);
1639 formatter
->close_section();
1647 int RGWBucketAdminOp::set_quota(RGWRados
*store
, RGWBucketAdminOpState
& op_state
)
1651 int ret
= bucket
.init(store
, op_state
);
1654 return bucket
.set_quota(op_state
);
1657 void rgw_data_change::dump(Formatter
*f
) const
1660 switch (entity_type
) {
1661 case ENTITY_TYPE_BUCKET
:
1667 encode_json("entity_type", type
, f
);
1668 encode_json("key", key
, f
);
1669 utime_t
ut(timestamp
);
1670 encode_json("timestamp", ut
, f
);
1673 void rgw_data_change::decode_json(JSONObj
*obj
) {
1675 JSONDecoder::decode_json("entity_type", s
, obj
);
1676 if (s
== "bucket") {
1677 entity_type
= ENTITY_TYPE_BUCKET
;
1679 entity_type
= ENTITY_TYPE_UNKNOWN
;
1681 JSONDecoder::decode_json("key", key
, obj
);
1683 JSONDecoder::decode_json("timestamp", ut
, obj
);
1684 timestamp
= ut
.to_real_time();
1687 void rgw_data_change_log_entry::dump(Formatter
*f
) const
1689 encode_json("log_id", log_id
, f
);
1690 utime_t
ut(log_timestamp
);
1691 encode_json("log_timestamp", ut
, f
);
1692 encode_json("entry", entry
, f
);
1695 void rgw_data_change_log_entry::decode_json(JSONObj
*obj
) {
1696 JSONDecoder::decode_json("log_id", log_id
, obj
);
1698 JSONDecoder::decode_json("log_timestamp", ut
, obj
);
1699 log_timestamp
= ut
.to_real_time();
1700 JSONDecoder::decode_json("entry", entry
, obj
);
1703 int RGWDataChangesLog::choose_oid(const rgw_bucket_shard
& bs
) {
1704 const string
& name
= bs
.bucket
.name
;
1705 int shard_shift
= (bs
.shard_id
> 0 ? bs
.shard_id
: 0);
1706 uint32_t r
= (ceph_str_hash_linux(name
.c_str(), name
.size()) + shard_shift
) % num_shards
;
1711 int RGWDataChangesLog::renew_entries()
1713 if (!store
->need_to_log_data())
1716 /* we can't keep the bucket name as part of the cls_log_entry, and we need
1717 * it later, so we keep two lists under the map */
1718 map
<int, pair
<list
<rgw_bucket_shard
>, list
<cls_log_entry
> > > m
;
1721 map
<rgw_bucket_shard
, bool> entries
;
1722 entries
.swap(cur_cycle
);
1725 map
<rgw_bucket_shard
, bool>::iterator iter
;
1727 real_time ut
= real_clock::now();
1728 for (iter
= entries
.begin(); iter
!= entries
.end(); ++iter
) {
1729 const rgw_bucket_shard
& bs
= iter
->first
;
1731 int index
= choose_oid(bs
);
1733 cls_log_entry entry
;
1735 rgw_data_change change
;
1737 change
.entity_type
= ENTITY_TYPE_BUCKET
;
1738 change
.key
= bs
.get_key();
1739 change
.timestamp
= ut
;
1740 ::encode(change
, bl
);
1742 store
->time_log_prepare_entry(entry
, ut
, section
, change
.key
, bl
);
1744 m
[index
].first
.push_back(bs
);
1745 m
[index
].second
.emplace_back(std::move(entry
));
1748 map
<int, pair
<list
<rgw_bucket_shard
>, list
<cls_log_entry
> > >::iterator miter
;
1749 for (miter
= m
.begin(); miter
!= m
.end(); ++miter
) {
1750 list
<cls_log_entry
>& entries
= miter
->second
.second
;
1752 real_time now
= real_clock::now();
1754 int ret
= store
->time_log_add(oids
[miter
->first
], entries
, NULL
);
1756 /* we don't really need to have a special handling for failed cases here,
1757 * as this is just an optimization. */
1758 lderr(cct
) << "ERROR: store->time_log_add() returned " << ret
<< dendl
;
1762 real_time expiration
= now
;
1763 expiration
+= make_timespan(cct
->_conf
->rgw_data_log_window
);
1765 list
<rgw_bucket_shard
>& buckets
= miter
->second
.first
;
1766 list
<rgw_bucket_shard
>::iterator liter
;
1767 for (liter
= buckets
.begin(); liter
!= buckets
.end(); ++liter
) {
1768 update_renewed(*liter
, expiration
);
1775 void RGWDataChangesLog::_get_change(const rgw_bucket_shard
& bs
, ChangeStatusPtr
& status
)
1777 assert(lock
.is_locked());
1778 if (!changes
.find(bs
, status
)) {
1779 status
= ChangeStatusPtr(new ChangeStatus
);
1780 changes
.add(bs
, status
);
1784 void RGWDataChangesLog::register_renew(rgw_bucket_shard
& bs
)
1786 Mutex::Locker
l(lock
);
1787 cur_cycle
[bs
] = true;
1790 void RGWDataChangesLog::update_renewed(rgw_bucket_shard
& bs
, real_time
& expiration
)
1792 Mutex::Locker
l(lock
);
1793 ChangeStatusPtr status
;
1794 _get_change(bs
, status
);
1796 ldout(cct
, 20) << "RGWDataChangesLog::update_renewd() bucket_name=" << bs
.bucket
.name
<< " shard_id=" << bs
.shard_id
<< " expiration=" << expiration
<< dendl
;
1797 status
->cur_expiration
= expiration
;
1800 int RGWDataChangesLog::get_log_shard_id(rgw_bucket
& bucket
, int shard_id
) {
1801 rgw_bucket_shard
bs(bucket
, shard_id
);
1803 return choose_oid(bs
);
1806 int RGWDataChangesLog::add_entry(rgw_bucket
& bucket
, int shard_id
) {
1807 if (!store
->need_to_log_data())
1811 observer
->on_bucket_changed(bucket
.get_key());
1814 rgw_bucket_shard
bs(bucket
, shard_id
);
1816 int index
= choose_oid(bs
);
1817 mark_modified(index
, bs
);
1821 ChangeStatusPtr status
;
1822 _get_change(bs
, status
);
1826 real_time now
= real_clock::now();
1828 status
->lock
->Lock();
1830 ldout(cct
, 20) << "RGWDataChangesLog::add_entry() bucket.name=" << bucket
.name
<< " shard_id=" << shard_id
<< " now=" << now
<< " cur_expiration=" << status
->cur_expiration
<< dendl
;
1832 if (now
< status
->cur_expiration
) {
1833 /* no need to send, recently completed */
1834 status
->lock
->Unlock();
1840 RefCountedCond
*cond
;
1842 if (status
->pending
) {
1843 cond
= status
->cond
;
1847 status
->cond
->get();
1848 status
->lock
->Unlock();
1850 int ret
= cond
->wait();
1858 status
->cond
= new RefCountedCond
;
1859 status
->pending
= true;
1861 string
& oid
= oids
[index
];
1862 real_time expiration
;
1867 status
->cur_sent
= now
;
1870 expiration
+= ceph::make_timespan(cct
->_conf
->rgw_data_log_window
);
1872 status
->lock
->Unlock();
1875 rgw_data_change change
;
1876 change
.entity_type
= ENTITY_TYPE_BUCKET
;
1877 change
.key
= bs
.get_key();
1878 change
.timestamp
= now
;
1879 ::encode(change
, bl
);
1882 ldout(cct
, 20) << "RGWDataChangesLog::add_entry() sending update with now=" << now
<< " cur_expiration=" << expiration
<< dendl
;
1884 ret
= store
->time_log_add(oid
, now
, section
, change
.key
, bl
);
1886 now
= real_clock::now();
1888 status
->lock
->Lock();
1890 } while (!ret
&& real_clock::now() > expiration
);
1892 cond
= status
->cond
;
1894 status
->pending
= false;
1895 status
->cur_expiration
= status
->cur_sent
; /* time of when operation started, not completed */
1896 status
->cur_expiration
+= make_timespan(cct
->_conf
->rgw_data_log_window
);
1897 status
->cond
= NULL
;
1898 status
->lock
->Unlock();
1906 int RGWDataChangesLog::list_entries(int shard
, const real_time
& start_time
, const real_time
& end_time
, int max_entries
,
1907 list
<rgw_data_change_log_entry
>& entries
,
1908 const string
& marker
,
1911 if (shard
>= num_shards
)
1914 list
<cls_log_entry
> log_entries
;
1916 int ret
= store
->time_log_list(oids
[shard
], start_time
, end_time
,
1917 max_entries
, log_entries
, marker
,
1918 out_marker
, truncated
);
1922 list
<cls_log_entry
>::iterator iter
;
1923 for (iter
= log_entries
.begin(); iter
!= log_entries
.end(); ++iter
) {
1924 rgw_data_change_log_entry log_entry
;
1925 log_entry
.log_id
= iter
->id
;
1926 real_time rt
= iter
->timestamp
.to_real_time();
1927 log_entry
.log_timestamp
= rt
;
1928 bufferlist::iterator liter
= iter
->data
.begin();
1930 ::decode(log_entry
.entry
, liter
);
1931 } catch (buffer::error
& err
) {
1932 lderr(cct
) << "ERROR: failed to decode data changes log entry" << dendl
;
1935 entries
.push_back(log_entry
);
1941 int RGWDataChangesLog::list_entries(const real_time
& start_time
, const real_time
& end_time
, int max_entries
,
1942 list
<rgw_data_change_log_entry
>& entries
, LogMarker
& marker
, bool *ptruncated
) {
1946 for (; marker
.shard
< num_shards
&& (int)entries
.size() < max_entries
;
1947 marker
.shard
++, marker
.marker
.clear()) {
1948 int ret
= list_entries(marker
.shard
, start_time
, end_time
, max_entries
- entries
.size(), entries
,
1949 marker
.marker
, NULL
, &truncated
);
1950 if (ret
== -ENOENT
) {
1962 *ptruncated
= (marker
.shard
< num_shards
);
1967 int RGWDataChangesLog::get_info(int shard_id
, RGWDataChangesLogInfo
*info
)
1969 if (shard_id
>= num_shards
)
1972 string oid
= oids
[shard_id
];
1974 cls_log_header header
;
1976 int ret
= store
->time_log_info(oid
, &header
);
1977 if ((ret
< 0) && (ret
!= -ENOENT
))
1980 info
->marker
= header
.max_marker
;
1981 info
->last_update
= header
.max_time
.to_real_time();
1986 int RGWDataChangesLog::trim_entries(int shard_id
, const real_time
& start_time
, const real_time
& end_time
,
1987 const string
& start_marker
, const string
& end_marker
)
1991 if (shard_id
> num_shards
)
1994 ret
= store
->time_log_trim(oids
[shard_id
], start_time
, end_time
, start_marker
, end_marker
);
1996 if (ret
== -ENOENT
|| ret
== -ENODATA
)
2002 int RGWDataChangesLog::trim_entries(const real_time
& start_time
, const real_time
& end_time
,
2003 const string
& start_marker
, const string
& end_marker
)
2005 for (int shard
= 0; shard
< num_shards
; shard
++) {
2006 int ret
= store
->time_log_trim(oids
[shard
], start_time
, end_time
, start_marker
, end_marker
);
2007 if (ret
== -ENOENT
|| ret
== -ENODATA
) {
2017 bool RGWDataChangesLog::going_down()
2022 RGWDataChangesLog::~RGWDataChangesLog() {
2024 renew_thread
->stop();
2025 renew_thread
->join();
2026 delete renew_thread
;
2030 void *RGWDataChangesLog::ChangesRenewThread::entry() {
2032 dout(2) << "RGWDataChangesLog::ChangesRenewThread: start" << dendl
;
2033 int r
= log
->renew_entries();
2035 dout(0) << "ERROR: RGWDataChangesLog::renew_entries returned error r=" << r
<< dendl
;
2038 if (log
->going_down())
2041 int interval
= cct
->_conf
->rgw_data_log_window
* 3 / 4;
2043 cond
.WaitInterval(lock
, utime_t(interval
, 0));
2045 } while (!log
->going_down());
2050 void RGWDataChangesLog::ChangesRenewThread::stop()
2052 Mutex::Locker
l(lock
);
2056 void RGWDataChangesLog::mark_modified(int shard_id
, const rgw_bucket_shard
& bs
)
2058 auto key
= bs
.get_key();
2059 modified_lock
.get_read();
2060 map
<int, set
<string
> >::iterator iter
= modified_shards
.find(shard_id
);
2061 if (iter
!= modified_shards
.end()) {
2062 set
<string
>& keys
= iter
->second
;
2063 if (keys
.find(key
) != keys
.end()) {
2064 modified_lock
.unlock();
2068 modified_lock
.unlock();
2070 RWLock::WLocker
wl(modified_lock
);
2071 modified_shards
[shard_id
].insert(key
);
2074 void RGWDataChangesLog::read_clear_modified(map
<int, set
<string
> > &modified
)
2076 RWLock::WLocker
wl(modified_lock
);
2077 modified
.swap(modified_shards
);
2078 modified_shards
.clear();
2081 void RGWBucketCompleteInfo::dump(Formatter
*f
) const {
2082 encode_json("bucket_info", info
, f
);
2083 encode_json("attrs", attrs
, f
);
2086 void RGWBucketCompleteInfo::decode_json(JSONObj
*obj
) {
2087 JSONDecoder::decode_json("bucket_info", info
, obj
);
2088 JSONDecoder::decode_json("attrs", attrs
, obj
);
2091 class RGWBucketMetadataHandler
: public RGWMetadataHandler
{
2094 string
get_type() override
{ return "bucket"; }
2096 int get(RGWRados
*store
, string
& entry
, RGWMetadataObject
**obj
) override
{
2097 RGWObjVersionTracker ot
;
2098 RGWBucketEntryPoint be
;
2101 map
<string
, bufferlist
> attrs
;
2102 RGWObjectCtx
obj_ctx(store
);
2104 string tenant_name
, bucket_name
;
2105 parse_bucket(entry
, &tenant_name
, &bucket_name
);
2106 int ret
= store
->get_bucket_entrypoint_info(obj_ctx
, tenant_name
, bucket_name
, be
, &ot
, &mtime
, &attrs
);
2110 RGWBucketEntryMetadataObject
*mdo
= new RGWBucketEntryMetadataObject(be
, ot
.read_version
, mtime
);
2117 int put(RGWRados
*store
, string
& entry
, RGWObjVersionTracker
& objv_tracker
,
2118 real_time mtime
, JSONObj
*obj
, sync_type_t sync_type
) override
{
2119 RGWBucketEntryPoint be
, old_be
;
2121 decode_json_obj(be
, obj
);
2122 } catch (JSONDecoder::err
& e
) {
2126 real_time orig_mtime
;
2127 map
<string
, bufferlist
> attrs
;
2129 RGWObjVersionTracker old_ot
;
2130 RGWObjectCtx
obj_ctx(store
);
2132 string tenant_name
, bucket_name
;
2133 parse_bucket(entry
, &tenant_name
, &bucket_name
);
2134 int ret
= store
->get_bucket_entrypoint_info(obj_ctx
, tenant_name
, bucket_name
, old_be
, &old_ot
, &orig_mtime
, &attrs
);
2135 if (ret
< 0 && ret
!= -ENOENT
)
2138 // are we actually going to perform this put, or is it too old?
2139 if (ret
!= -ENOENT
&&
2140 !check_versions(old_ot
.read_version
, orig_mtime
,
2141 objv_tracker
.write_version
, mtime
, sync_type
)) {
2142 return STATUS_NO_APPLY
;
2145 objv_tracker
.read_version
= old_ot
.read_version
; /* maintain the obj version we just read */
2147 ret
= store
->put_bucket_entrypoint_info(tenant_name
, bucket_name
, be
, false, objv_tracker
, mtime
, &attrs
);
2153 ret
= rgw_link_bucket(store
, be
.owner
, be
.bucket
, be
.creation_time
, false);
2155 ret
= rgw_unlink_bucket(store
, be
.owner
, be
.bucket
.tenant
,
2156 be
.bucket
.name
, false);
2162 struct list_keys_info
{
2164 RGWListRawObjsCtx ctx
;
2167 int remove(RGWRados
*store
, string
& entry
, RGWObjVersionTracker
& objv_tracker
) override
{
2168 RGWBucketEntryPoint be
;
2169 RGWObjectCtx
obj_ctx(store
);
2171 string tenant_name
, bucket_name
;
2172 parse_bucket(entry
, &tenant_name
, &bucket_name
);
2173 int ret
= store
->get_bucket_entrypoint_info(obj_ctx
, tenant_name
, bucket_name
, be
, &objv_tracker
, NULL
, NULL
);
2178 * We're unlinking the bucket but we don't want to update the entrypoint here - we're removing
2179 * it immediately and don't want to invalidate our cached objv_version or the bucket obj removal
2180 * will incorrectly fail.
2182 ret
= rgw_unlink_bucket(store
, be
.owner
, tenant_name
, bucket_name
, false);
2184 lderr(store
->ctx()) << "could not unlink bucket=" << entry
<< " owner=" << be
.owner
<< dendl
;
2187 ret
= rgw_bucket_delete_bucket_obj(store
, tenant_name
, bucket_name
, objv_tracker
);
2189 lderr(store
->ctx()) << "could not delete bucket=" << entry
<< dendl
;
2195 void get_pool_and_oid(RGWRados
*store
, const string
& key
, rgw_pool
& pool
, string
& oid
) override
{
2197 pool
= store
->get_zone_params().domain_root
;
2200 int list_keys_init(RGWRados
*store
, const string
& marker
, void **phandle
) override
{
2201 auto info
= ceph::make_unique
<list_keys_info
>();
2203 info
->store
= store
;
2205 int ret
= store
->list_raw_objects_init(store
->get_zone_params().domain_root
, marker
,
2210 *phandle
= (void *)info
.release();
2215 int list_keys_next(void *handle
, int max
, list
<string
>& keys
, bool *truncated
) override
{
2216 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2222 RGWRados
*store
= info
->store
;
2224 list
<string
> unfiltered_keys
;
2226 int ret
= store
->list_raw_objects_next(no_filter
, max
, info
->ctx
,
2227 unfiltered_keys
, truncated
);
2228 if (ret
< 0 && ret
!= -ENOENT
)
2230 if (ret
== -ENOENT
) {
2236 // now filter out the system entries
2237 list
<string
>::iterator iter
;
2238 for (iter
= unfiltered_keys
.begin(); iter
!= unfiltered_keys
.end(); ++iter
) {
2249 void list_keys_complete(void *handle
) override
{
2250 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2254 string
get_marker(void *handle
) {
2255 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2256 return info
->store
->list_raw_objs_get_cursor(info
->ctx
);
2260 class RGWBucketInstanceMetadataHandler
: public RGWMetadataHandler
{
2263 string
get_type() override
{ return "bucket.instance"; }
2265 int get(RGWRados
*store
, string
& oid
, RGWMetadataObject
**obj
) override
{
2266 RGWBucketCompleteInfo bci
;
2269 RGWObjectCtx
obj_ctx(store
);
2271 int ret
= store
->get_bucket_instance_info(obj_ctx
, oid
, bci
.info
, &mtime
, &bci
.attrs
);
2275 RGWBucketInstanceMetadataObject
*mdo
= new RGWBucketInstanceMetadataObject(bci
, bci
.info
.objv_tracker
.read_version
, mtime
);
2282 int put(RGWRados
*store
, string
& entry
, RGWObjVersionTracker
& objv_tracker
,
2283 real_time mtime
, JSONObj
*obj
, sync_type_t sync_type
) override
{
2284 RGWBucketCompleteInfo bci
, old_bci
;
2286 decode_json_obj(bci
, obj
);
2287 } catch (JSONDecoder::err
& e
) {
2291 real_time orig_mtime
;
2292 RGWObjectCtx
obj_ctx(store
);
2294 int ret
= store
->get_bucket_instance_info(obj_ctx
, entry
, old_bci
.info
,
2295 &orig_mtime
, &old_bci
.attrs
);
2296 bool exists
= (ret
!= -ENOENT
);
2297 if (ret
< 0 && exists
)
2300 if (!exists
|| old_bci
.info
.bucket
.bucket_id
!= bci
.info
.bucket
.bucket_id
) {
2301 /* a new bucket, we need to select a new bucket placement for it */
2303 rgw_bucket_instance_oid_to_key(key
);
2306 string bucket_instance
;
2307 parse_bucket(key
, &tenant_name
, &bucket_name
, &bucket_instance
);
2309 RGWZonePlacementInfo rule_info
;
2310 bci
.info
.bucket
.name
= bucket_name
;
2311 bci
.info
.bucket
.bucket_id
= bucket_instance
;
2312 bci
.info
.bucket
.tenant
= tenant_name
;
2313 ret
= store
->select_bucket_location_by_rule(bci
.info
.placement_rule
, &rule_info
);
2315 ldout(store
->ctx(), 0) << "ERROR: select_bucket_placement() returned " << ret
<< dendl
;
2318 bci
.info
.index_type
= rule_info
.index_type
;
2320 /* existing bucket, keep its placement */
2321 bci
.info
.bucket
.explicit_placement
= old_bci
.info
.bucket
.explicit_placement
;
2322 bci
.info
.placement_rule
= old_bci
.info
.placement_rule
;
2325 if (exists
&& old_bci
.info
.datasync_flag_enabled() != bci
.info
.datasync_flag_enabled()) {
2326 int shards_num
= bci
.info
.num_shards
? bci
.info
.num_shards
: 1;
2327 int shard_id
= bci
.info
.num_shards
? 0 : -1;
2329 if (!bci
.info
.datasync_flag_enabled()) {
2330 ret
= store
->stop_bi_log_entries(bci
.info
, -1);
2332 lderr(store
->ctx()) << "ERROR: failed writing bilog" << dendl
;
2336 ret
= store
->resync_bi_log_entries(bci
.info
, -1);
2338 lderr(store
->ctx()) << "ERROR: failed writing bilog" << dendl
;
2343 for (int i
= 0; i
< shards_num
; ++i
, ++shard_id
) {
2344 ret
= store
->data_log
->add_entry(bci
.info
.bucket
, shard_id
);
2346 lderr(store
->ctx()) << "ERROR: failed writing data log" << dendl
;
2352 // are we actually going to perform this put, or is it too old?
2354 !check_versions(old_bci
.info
.objv_tracker
.read_version
, orig_mtime
,
2355 objv_tracker
.write_version
, mtime
, sync_type
)) {
2356 objv_tracker
.read_version
= old_bci
.info
.objv_tracker
.read_version
;
2357 return STATUS_NO_APPLY
;
2360 /* record the read version (if any), store the new version */
2361 bci
.info
.objv_tracker
.read_version
= old_bci
.info
.objv_tracker
.read_version
;
2362 bci
.info
.objv_tracker
.write_version
= objv_tracker
.write_version
;
2364 ret
= store
->put_bucket_instance_info(bci
.info
, false, mtime
, &bci
.attrs
);
2368 objv_tracker
= bci
.info
.objv_tracker
;
2370 ret
= store
->init_bucket_index(bci
.info
, bci
.info
.num_shards
);
2374 return STATUS_APPLIED
;
2377 struct list_keys_info
{
2379 RGWListRawObjsCtx ctx
;
2382 int remove(RGWRados
*store
, string
& entry
, RGWObjVersionTracker
& objv_tracker
) override
{
2384 RGWObjectCtx
obj_ctx(store
);
2386 int ret
= store
->get_bucket_instance_info(obj_ctx
, entry
, info
, NULL
, NULL
);
2387 if (ret
< 0 && ret
!= -ENOENT
)
2390 return rgw_bucket_instance_remove_entry(store
, entry
, &info
.objv_tracker
);
2393 void get_pool_and_oid(RGWRados
*store
, const string
& key
, rgw_pool
& pool
, string
& oid
) override
{
2394 oid
= RGW_BUCKET_INSTANCE_MD_PREFIX
+ key
;
2395 rgw_bucket_instance_key_to_oid(oid
);
2396 pool
= store
->get_zone_params().domain_root
;
2399 int list_keys_init(RGWRados
*store
, const string
& marker
, void **phandle
) override
{
2400 auto info
= ceph::make_unique
<list_keys_info
>();
2402 info
->store
= store
;
2404 int ret
= store
->list_raw_objects_init(store
->get_zone_params().domain_root
, marker
,
2409 *phandle
= (void *)info
.release();
2414 int list_keys_next(void *handle
, int max
, list
<string
>& keys
, bool *truncated
) override
{
2415 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2421 RGWRados
*store
= info
->store
;
2423 list
<string
> unfiltered_keys
;
2425 int ret
= store
->list_raw_objects_next(no_filter
, max
, info
->ctx
,
2426 unfiltered_keys
, truncated
);
2427 if (ret
< 0 && ret
!= -ENOENT
)
2429 if (ret
== -ENOENT
) {
2435 constexpr int prefix_size
= sizeof(RGW_BUCKET_INSTANCE_MD_PREFIX
) - 1;
2436 // now filter in the relevant entries
2437 list
<string
>::iterator iter
;
2438 for (iter
= unfiltered_keys
.begin(); iter
!= unfiltered_keys
.end(); ++iter
) {
2441 if (k
.compare(0, prefix_size
, RGW_BUCKET_INSTANCE_MD_PREFIX
) == 0) {
2442 auto oid
= k
.substr(prefix_size
);
2443 rgw_bucket_instance_oid_to_key(oid
);
2444 keys
.emplace_back(std::move(oid
));
2451 void list_keys_complete(void *handle
) override
{
2452 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2456 string
get_marker(void *handle
) {
2457 list_keys_info
*info
= static_cast<list_keys_info
*>(handle
);
2458 return info
->store
->list_raw_objs_get_cursor(info
->ctx
);
2462 * hash entry for mdlog placement. Use the same hash key we'd have for the bucket entry
2463 * point, so that the log entries end up at the same log shard, so that we process them
2466 void get_hash_key(const string
& section
, const string
& key
, string
& hash_key
) override
{
2468 int pos
= key
.find(':');
2472 k
= key
.substr(0, pos
);
2473 hash_key
= "bucket:" + k
;
2477 void rgw_bucket_init(RGWMetadataManager
*mm
)
2479 bucket_meta_handler
= new RGWBucketMetadataHandler
;
2480 mm
->register_handler(bucket_meta_handler
);
2481 bucket_instance_meta_handler
= new RGWBucketInstanceMetadataHandler
;
2482 mm
->register_handler(bucket_instance_meta_handler
);