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 <boost/algorithm/string.hpp>
7 #include "svc_user_rados.h"
9 #include "svc_sys_obj.h"
10 #include "svc_sys_obj_cache.h"
12 #include "svc_meta_be_sobj.h"
13 #include "svc_sync_modules.h"
15 #include "rgw/rgw_user.h"
16 #include "rgw/rgw_bucket.h"
17 #include "rgw/rgw_tools.h"
18 #include "rgw/rgw_zone.h"
19 #include "rgw/rgw_rados.h"
21 #include "cls/user/cls_user_client.h"
23 #define dout_subsys ceph_subsys_rgw
25 #define RGW_BUCKETS_OBJ_SUFFIX ".buckets"
27 class RGWSI_User_Module
: public RGWSI_MBSObj_Handler_Module
{
28 RGWSI_User_RADOS::Svc
& svc
;
32 RGWSI_User_Module(RGWSI_User_RADOS::Svc
& _svc
) : RGWSI_MBSObj_Handler_Module("user"),
35 void get_pool_and_oid(const string
& key
, rgw_pool
*pool
, string
*oid
) override
{
37 *pool
= svc
.zone
->get_zone_params().user_uid_pool
;
44 const string
& get_oid_prefix() override
{
48 bool is_valid_oid(const string
& oid
) override
{
49 // filter out the user.buckets objects
50 return !boost::algorithm::ends_with(oid
, RGW_BUCKETS_OBJ_SUFFIX
);
53 string
key_to_oid(const string
& key
) override
{
57 string
oid_to_key(const string
& oid
) override
{
62 RGWSI_User_RADOS::RGWSI_User_RADOS(CephContext
*cct
): RGWSI_User(cct
) {
65 RGWSI_User_RADOS::~RGWSI_User_RADOS() {
68 void RGWSI_User_RADOS::init(RGWSI_RADOS
*_rados_svc
,
69 RGWSI_Zone
*_zone_svc
, RGWSI_SysObj
*_sysobj_svc
,
70 RGWSI_SysObj_Cache
*_cache_svc
, RGWSI_Meta
*_meta_svc
,
71 RGWSI_MetaBackend
*_meta_be_svc
,
72 RGWSI_SyncModules
*_sync_modules_svc
)
75 svc
.rados
= _rados_svc
;
77 svc
.sysobj
= _sysobj_svc
;
78 svc
.cache
= _cache_svc
;
80 svc
.meta_be
= _meta_be_svc
;
81 svc
.sync_modules
= _sync_modules_svc
;
84 int RGWSI_User_RADOS::do_start()
86 uinfo_cache
.reset(new RGWChainedCacheImpl
<user_info_cache_entry
>);
87 uinfo_cache
->init(svc
.cache
);
89 int r
= svc
.meta
->create_be_handler(RGWSI_MetaBackend::Type::MDBE_SOBJ
, &be_handler
);
91 ldout(ctx(), 0) << "ERROR: failed to create be handler: r=" << r
<< dendl
;
95 RGWSI_MetaBackend_Handler_SObj
*bh
= static_cast<RGWSI_MetaBackend_Handler_SObj
*>(be_handler
);
97 auto module
= new RGWSI_User_Module(svc
);
98 be_module
.reset(module
);
99 bh
->set_module(module
);
103 rgw_raw_obj
RGWSI_User_RADOS::get_buckets_obj(const rgw_user
& user
) const
105 string oid
= user
.to_str() + RGW_BUCKETS_OBJ_SUFFIX
;
106 return rgw_raw_obj(svc
.zone
->get_zone_params().user_uid_pool
, oid
);
109 int RGWSI_User_RADOS::read_user_info(RGWSI_MetaBackend::Context
*ctx
,
110 const rgw_user
& user
,
112 RGWObjVersionTracker
* const objv_tracker
,
113 real_time
* const pmtime
,
114 rgw_cache_entry_info
* const cache_info
,
115 map
<string
, bufferlist
> * const pattrs
,
121 RGWSI_MBSObj_GetParams
params(&bl
, pattrs
, pmtime
);
122 params
.set_cache_info(cache_info
);
124 int ret
= svc
.meta_be
->get_entry(ctx
, get_meta_key(user
), params
, objv_tracker
, y
);
129 auto iter
= bl
.cbegin();
131 decode(user_id
, iter
);
132 if (user_id
.user_id
!= user
) {
133 lderr(svc
.meta_be
->ctx()) << "ERROR: rgw_get_user_info_by_uid(): user id mismatch: " << user_id
.user_id
<< " != " << user
<< dendl
;
139 } catch (buffer::error
& err
) {
140 ldout(svc
.meta_be
->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl
;
149 RGWSI_User_RADOS::Svc
& svc
;
150 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
;
152 const RGWUserInfo
& info
;
153 RGWUserInfo
*old_info
;
154 RGWObjVersionTracker
*objv_tracker
;
155 const real_time
& mtime
;
157 map
<string
, bufferlist
> *pattrs
;
158 RGWObjVersionTracker ot
;
162 void set_err_msg(string msg
) {
163 if (!err_msg
.empty()) {
164 err_msg
= std::move(msg
);
169 PutOperation(RGWSI_User_RADOS::Svc
& svc
,
170 RGWSI_MetaBackend::Context
*_ctx
,
171 const RGWUserInfo
& info
,
172 RGWUserInfo
*old_info
,
173 RGWObjVersionTracker
*objv_tracker
,
174 const real_time
& mtime
,
176 map
<string
, bufferlist
> *pattrs
,
178 svc(svc
), info(info
), old_info(old_info
),
179 objv_tracker(objv_tracker
), mtime(mtime
),
180 exclusive(exclusive
), pattrs(pattrs
), y(y
) {
181 ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
182 ui
.user_id
= info
.user_id
;
190 if (ot
.write_version
.tag
.empty()) {
191 if (ot
.read_version
.tag
.empty()) {
192 ot
.generate_new_write_ver(svc
.meta_be
->ctx());
194 ot
.write_version
= ot
.read_version
;
195 ot
.write_version
.ver
++;
199 for (auto iter
= info
.swift_keys
.begin(); iter
!= info
.swift_keys
.end(); ++iter
) {
200 if (old_info
&& old_info
->swift_keys
.count(iter
->first
) != 0)
202 auto& k
= iter
->second
;
203 /* check if swift mapping exists */
205 int r
= svc
.user
->get_user_info_by_swift(ctx
, k
.id
, &inf
, nullptr, nullptr, y
);
206 if (r
>= 0 && inf
.user_id
!= info
.user_id
&&
207 (!old_info
|| inf
.user_id
!= old_info
->user_id
)) {
208 ldout(svc
.meta_be
->ctx(), 0) << "WARNING: can't store user info, swift id (" << k
.id
209 << ") already mapped to another user (" << info
.user_id
<< ")" << dendl
;
214 /* check if access keys already exist */
215 for (auto iter
= info
.access_keys
.begin(); iter
!= info
.access_keys
.end(); ++iter
) {
216 if (old_info
&& old_info
->access_keys
.count(iter
->first
) != 0)
218 auto& k
= iter
->second
;
220 int r
= svc
.user
->get_user_info_by_access_key(ctx
, k
.id
, &inf
, nullptr, nullptr, y
);
221 if (r
>= 0 && inf
.user_id
!= info
.user_id
&&
222 (!old_info
|| inf
.user_id
!= old_info
->user_id
)) {
223 ldout(svc
.meta_be
->ctx(), 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl
;
234 encode(info
, data_bl
);
236 RGWSI_MBSObj_PutParams
params(data_bl
, pattrs
, mtime
, exclusive
);
238 int ret
= svc
.meta_be
->put(ctx
, RGWSI_User::get_meta_key(info
.user_id
), params
, &ot
, y
);
251 auto& obj_ctx
= *ctx
->obj_ctx
;
253 if (!info
.user_email
.empty()) {
255 old_info
->user_email
.compare(info
.user_email
) != 0) { /* only if new index changed */
256 ret
= rgw_put_system_obj(obj_ctx
, svc
.zone
->get_zone_params().user_email_pool
, info
.user_email
,
257 link_bl
, exclusive
, NULL
, real_time(), y
);
263 const bool renamed
= old_info
&& old_info
->user_id
!= info
.user_id
;
264 for (auto iter
= info
.access_keys
.begin(); iter
!= info
.access_keys
.end(); ++iter
) {
265 auto& k
= iter
->second
;
266 if (old_info
&& old_info
->access_keys
.count(iter
->first
) != 0 && !renamed
)
269 ret
= rgw_put_system_obj(obj_ctx
, svc
.zone
->get_zone_params().user_keys_pool
, k
.id
,
270 link_bl
, exclusive
, NULL
, real_time(), y
);
275 for (auto siter
= info
.swift_keys
.begin(); siter
!= info
.swift_keys
.end(); ++siter
) {
276 auto& k
= siter
->second
;
277 if (old_info
&& old_info
->swift_keys
.count(siter
->first
) != 0 && !renamed
)
280 ret
= rgw_put_system_obj(obj_ctx
, svc
.zone
->get_zone_params().user_swift_pool
, k
.id
,
281 link_bl
, exclusive
, NULL
, real_time(), y
);
287 ret
= remove_old_indexes(*old_info
, info
, y
);
296 int remove_old_indexes(const RGWUserInfo
& old_info
, const RGWUserInfo
& new_info
, optional_yield y
) {
299 if (!old_info
.user_id
.empty() &&
300 old_info
.user_id
!= new_info
.user_id
) {
301 if (old_info
.user_id
.tenant
!= new_info
.user_id
.tenant
) {
302 ldout(svc
.user
->ctx(), 0) << "ERROR: tenant mismatch: " << old_info
.user_id
.tenant
<< " != " << new_info
.user_id
.tenant
<< dendl
;
305 ret
= svc
.user
->remove_uid_index(ctx
, old_info
, nullptr, y
);
306 if (ret
< 0 && ret
!= -ENOENT
) {
307 set_err_msg("ERROR: could not remove index for uid " + old_info
.user_id
.to_str());
312 if (!old_info
.user_email
.empty() &&
313 old_info
.user_email
!= new_info
.user_email
) {
314 ret
= svc
.user
->remove_email_index(ctx
, old_info
.user_email
, y
);
315 if (ret
< 0 && ret
!= -ENOENT
) {
316 set_err_msg("ERROR: could not remove index for email " + old_info
.user_email
);
321 for ([[maybe_unused
]] const auto& [name
, access_key
] : old_info
.access_keys
) {
322 if (!new_info
.access_keys
.count(access_key
.id
)) {
323 ret
= svc
.user
->remove_key_index(ctx
, access_key
, y
);
324 if (ret
< 0 && ret
!= -ENOENT
) {
325 set_err_msg("ERROR: could not remove index for key " + access_key
.id
);
331 for (auto old_iter
= old_info
.swift_keys
.begin(); old_iter
!= old_info
.swift_keys
.end(); ++old_iter
) {
332 const auto& swift_key
= old_iter
->second
;
333 auto new_iter
= new_info
.swift_keys
.find(swift_key
.id
);
334 if (new_iter
== new_info
.swift_keys
.end()) {
335 ret
= svc
.user
->remove_swift_name_index(ctx
, swift_key
.id
, y
);
336 if (ret
< 0 && ret
!= -ENOENT
) {
337 set_err_msg("ERROR: could not remove index for swift_name " + swift_key
.id
);
346 const string
& get_err_msg() {
351 int RGWSI_User_RADOS::store_user_info(RGWSI_MetaBackend::Context
*ctx
,
352 const RGWUserInfo
& info
,
353 RGWUserInfo
*old_info
,
354 RGWObjVersionTracker
*objv_tracker
,
355 const real_time
& mtime
,
357 map
<string
, bufferlist
> *attrs
,
360 PutOperation
op(svc
, ctx
,
367 int r
= op
.prepare();
385 int RGWSI_User_RADOS::remove_key_index(RGWSI_MetaBackend::Context
*_ctx
,
386 const RGWAccessKey
& access_key
,
389 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
390 rgw_raw_obj
obj(svc
.zone
->get_zone_params().user_keys_pool
, access_key
.id
);
391 auto sysobj
= ctx
->obj_ctx
->get_obj(obj
);
392 return sysobj
.wop().remove(y
);
395 int RGWSI_User_RADOS::remove_email_index(RGWSI_MetaBackend::Context
*_ctx
,
402 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
403 rgw_raw_obj
obj(svc
.zone
->get_zone_params().user_email_pool
, email
);
404 auto sysobj
= ctx
->obj_ctx
->get_obj(obj
);
405 return sysobj
.wop().remove(y
);
408 int RGWSI_User_RADOS::remove_swift_name_index(RGWSI_MetaBackend::Context
*_ctx
, const string
& swift_name
,
411 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
412 rgw_raw_obj
obj(svc
.zone
->get_zone_params().user_swift_pool
, swift_name
);
413 auto sysobj
= ctx
->obj_ctx
->get_obj(obj
);
414 return sysobj
.wop().remove(y
);
418 * delete a user's presence from the RGW system.
419 * First remove their bucket ACLs, then delete them
420 * from the user and user email pools. This leaves the pools
421 * themselves alone, as well as any ACLs embedded in object xattrs.
423 int RGWSI_User_RADOS::remove_user_info(RGWSI_MetaBackend::Context
*_ctx
,
424 const RGWUserInfo
& info
,
425 RGWObjVersionTracker
*objv_tracker
,
430 auto cct
= svc
.meta_be
->ctx();
432 auto kiter
= info
.access_keys
.begin();
433 for (; kiter
!= info
.access_keys
.end(); ++kiter
) {
434 ldout(cct
, 10) << "removing key index: " << kiter
->first
<< dendl
;
435 ret
= remove_key_index(_ctx
, kiter
->second
, y
);
436 if (ret
< 0 && ret
!= -ENOENT
) {
437 ldout(cct
, 0) << "ERROR: could not remove " << kiter
->first
<< " (access key object), should be fixed (err=" << ret
<< ")" << dendl
;
442 auto siter
= info
.swift_keys
.begin();
443 for (; siter
!= info
.swift_keys
.end(); ++siter
) {
444 auto& k
= siter
->second
;
445 ldout(cct
, 10) << "removing swift subuser index: " << k
.id
<< dendl
;
446 /* check if swift mapping exists */
447 ret
= remove_swift_name_index(_ctx
, k
.id
, y
);
448 if (ret
< 0 && ret
!= -ENOENT
) {
449 ldout(cct
, 0) << "ERROR: could not remove " << k
.id
<< " (swift name object), should be fixed (err=" << ret
<< ")" << dendl
;
454 ldout(cct
, 10) << "removing email index: " << info
.user_email
<< dendl
;
455 ret
= remove_email_index(_ctx
, info
.user_email
, y
);
456 if (ret
< 0 && ret
!= -ENOENT
) {
457 ldout(cct
, 0) << "ERROR: could not remove email index object for "
458 << info
.user_email
<< ", should be fixed (err=" << ret
<< ")" << dendl
;
462 rgw_raw_obj uid_bucks
= get_buckets_obj(info
.user_id
);
463 ldout(cct
, 10) << "removing user buckets index" << dendl
;
464 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
465 auto sysobj
= ctx
->obj_ctx
->get_obj(uid_bucks
);
466 ret
= sysobj
.wop().remove(y
);
467 if (ret
< 0 && ret
!= -ENOENT
) {
468 ldout(cct
, 0) << "ERROR: could not remove " << info
.user_id
<< ":" << uid_bucks
<< ", should be fixed (err=" << ret
<< ")" << dendl
;
472 ret
= remove_uid_index(ctx
, info
, objv_tracker
, y
);
473 if (ret
< 0 && ret
!= -ENOENT
) {
480 int RGWSI_User_RADOS::remove_uid_index(RGWSI_MetaBackend::Context
*ctx
, const RGWUserInfo
& user_info
, RGWObjVersionTracker
*objv_tracker
,
483 ldout(cct
, 10) << "removing user index: " << user_info
.user_id
<< dendl
;
485 RGWSI_MBSObj_RemoveParams params
;
486 int ret
= svc
.meta_be
->remove(ctx
, get_meta_key(user_info
.user_id
), params
, objv_tracker
, y
);
487 if (ret
< 0 && ret
!= -ENOENT
&& ret
!= -ECANCELED
) {
489 user_info
.user_id
.to_str(key
);
490 rgw_raw_obj
uid_obj(svc
.zone
->get_zone_params().user_uid_pool
, key
);
491 ldout(cct
, 0) << "ERROR: could not remove " << user_info
.user_id
<< ":" << uid_obj
<< ", should be fixed (err=" << ret
<< ")" << dendl
;
498 int RGWSI_User_RADOS::get_user_info_from_index(RGWSI_MetaBackend::Context
*_ctx
,
500 const rgw_pool
& pool
,
502 RGWObjVersionTracker
* const objv_tracker
,
503 real_time
* const pmtime
, optional_yield y
)
505 RGWSI_MetaBackend_SObj::Context_SObj
*ctx
= static_cast<RGWSI_MetaBackend_SObj::Context_SObj
*>(_ctx
);
507 string cache_key
= pool
.to_str() + "/" + key
;
509 if (auto e
= uinfo_cache
->find(cache_key
)) {
512 *objv_tracker
= e
->objv_tracker
;
518 user_info_cache_entry e
;
522 int ret
= rgw_get_system_obj(*ctx
->obj_ctx
, pool
, key
, bl
, nullptr, &e
.mtime
, y
);
526 rgw_cache_entry_info cache_info
;
528 auto iter
= bl
.cbegin();
532 int ret
= read_user_info(ctx
, uid
.user_id
,
533 &e
.info
, &e
.objv_tracker
, nullptr, &cache_info
, nullptr,
538 } catch (buffer::error
& err
) {
539 ldout(svc
.meta_be
->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl
;
543 uinfo_cache
->put(svc
.cache
, cache_key
, &e
, { &cache_info
});
547 *objv_tracker
= e
.objv_tracker
;
555 * Given an email, finds the user info associated with it.
556 * returns: 0 on success, -ERR# on failure (including nonexistence)
558 int RGWSI_User_RADOS::get_user_info_by_email(RGWSI_MetaBackend::Context
*ctx
,
559 const string
& email
, RGWUserInfo
*info
,
560 RGWObjVersionTracker
*objv_tracker
,
561 real_time
*pmtime
, optional_yield y
)
563 return get_user_info_from_index(ctx
, email
, svc
.zone
->get_zone_params().user_email_pool
,
564 info
, objv_tracker
, pmtime
, y
);
568 * Given an swift username, finds the user_info associated with it.
569 * returns: 0 on success, -ERR# on failure (including nonexistence)
571 int RGWSI_User_RADOS::get_user_info_by_swift(RGWSI_MetaBackend::Context
*ctx
,
572 const string
& swift_name
,
573 RGWUserInfo
*info
, /* out */
574 RGWObjVersionTracker
* const objv_tracker
,
575 real_time
* const pmtime
, optional_yield y
)
577 return get_user_info_from_index(ctx
,
579 svc
.zone
->get_zone_params().user_swift_pool
,
580 info
, objv_tracker
, pmtime
, y
);
584 * Given an access key, finds the user info associated with it.
585 * returns: 0 on success, -ERR# on failure (including nonexistence)
587 int RGWSI_User_RADOS::get_user_info_by_access_key(RGWSI_MetaBackend::Context
*ctx
,
588 const std::string
& access_key
,
590 RGWObjVersionTracker
* objv_tracker
,
591 real_time
*pmtime
, optional_yield y
)
593 return get_user_info_from_index(ctx
,
595 svc
.zone
->get_zone_params().user_keys_pool
,
596 info
, objv_tracker
, pmtime
, y
);
599 int RGWSI_User_RADOS::cls_user_update_buckets(rgw_raw_obj
& obj
, list
<cls_user_bucket_entry
>& entries
, bool add
)
601 auto rados_obj
= svc
.rados
->obj(obj
);
602 int r
= rados_obj
.open();
607 librados::ObjectWriteOperation op
;
608 cls_user_set_buckets(op
, entries
, add
);
609 r
= rados_obj
.operate(&op
, null_yield
);
617 int RGWSI_User_RADOS::cls_user_add_bucket(rgw_raw_obj
& obj
, const cls_user_bucket_entry
& entry
)
619 list
<cls_user_bucket_entry
> l
;
622 return cls_user_update_buckets(obj
, l
, true);
625 int RGWSI_User_RADOS::cls_user_remove_bucket(rgw_raw_obj
& obj
, const cls_user_bucket
& bucket
)
627 auto rados_obj
= svc
.rados
->obj(obj
);
628 int r
= rados_obj
.open();
633 librados::ObjectWriteOperation op
;
634 ::cls_user_remove_bucket(op
, bucket
);
635 r
= rados_obj
.operate(&op
, null_yield
);
642 int RGWSI_User_RADOS::add_bucket(RGWSI_MetaBackend::Context
*ctx
,
643 const rgw_user
& user
,
644 const rgw_bucket
& bucket
,
645 ceph::real_time creation_time
)
649 cls_user_bucket_entry new_bucket
;
651 bucket
.convert(&new_bucket
.bucket
);
653 if (real_clock::is_zero(creation_time
))
654 new_bucket
.creation_time
= real_clock::now();
656 new_bucket
.creation_time
= creation_time
;
658 rgw_raw_obj obj
= get_buckets_obj(user
);
659 ret
= cls_user_add_bucket(obj
, new_bucket
);
661 ldout(cct
, 0) << "ERROR: error adding bucket to user: ret=" << ret
<< dendl
;
669 int RGWSI_User_RADOS::remove_bucket(RGWSI_MetaBackend::Context
*ctx
,
670 const rgw_user
& user
,
671 const rgw_bucket
& _bucket
)
673 cls_user_bucket bucket
;
674 bucket
.name
= _bucket
.name
;
675 rgw_raw_obj obj
= get_buckets_obj(user
);
676 int ret
= cls_user_remove_bucket(obj
, bucket
);
678 ldout(cct
, 0) << "ERROR: error removing bucket from user: ret=" << ret
<< dendl
;
684 int RGWSI_User_RADOS::cls_user_flush_bucket_stats(rgw_raw_obj
& user_obj
,
685 const RGWBucketEnt
& ent
)
687 cls_user_bucket_entry entry
;
690 list
<cls_user_bucket_entry
> entries
;
691 entries
.push_back(entry
);
693 int r
= cls_user_update_buckets(user_obj
, entries
, false);
695 ldout(cct
, 20) << "cls_user_update_buckets() returned " << r
<< dendl
;
702 int RGWSI_User_RADOS::cls_user_list_buckets(rgw_raw_obj
& obj
,
703 const string
& in_marker
,
704 const string
& end_marker
,
705 const int max_entries
,
706 list
<cls_user_bucket_entry
>& entries
,
707 string
* const out_marker
,
708 bool * const truncated
)
710 auto rados_obj
= svc
.rados
->obj(obj
);
711 int r
= rados_obj
.open();
716 librados::ObjectReadOperation op
;
719 cls_user_bucket_list(op
, in_marker
, end_marker
, max_entries
, entries
, out_marker
, truncated
, &rc
);
721 r
= rados_obj
.operate(&op
, &ibl
, null_yield
);
730 int RGWSI_User_RADOS::list_buckets(RGWSI_MetaBackend::Context
*ctx
,
731 const rgw_user
& user
,
732 const string
& marker
,
733 const string
& end_marker
,
735 RGWUserBuckets
*buckets
,
742 rgw_raw_obj obj
= get_buckets_obj(user
);
744 bool truncated
= false;
750 std::list
<cls_user_bucket_entry
> entries
;
751 ret
= cls_user_list_buckets(obj
, m
, end_marker
, max
- total
, entries
, &m
, &truncated
);
752 if (ret
== -ENOENT
) {
760 for (auto& entry
: entries
) {
761 buckets
->add(RGWBucketEnt(user
, std::move(entry
)));
765 } while (truncated
&& total
< max
);
768 *is_truncated
= truncated
;
774 int RGWSI_User_RADOS::flush_bucket_stats(RGWSI_MetaBackend::Context
*ctx
,
775 const rgw_user
& user
,
776 const RGWBucketEnt
& ent
)
778 rgw_raw_obj obj
= get_buckets_obj(user
);
780 return cls_user_flush_bucket_stats(obj
, ent
);
783 int RGWSI_User_RADOS::reset_bucket_stats(RGWSI_MetaBackend::Context
*ctx
,
784 const rgw_user
& user
)
786 return cls_user_reset_stats(user
);
789 int RGWSI_User_RADOS::cls_user_reset_stats(const rgw_user
& user
)
791 rgw_raw_obj obj
= get_buckets_obj(user
);
792 auto rados_obj
= svc
.rados
->obj(obj
);
793 int r
= rados_obj
.open();
797 librados::ObjectWriteOperation op
;
798 ::cls_user_reset_stats(op
);
799 return rados_obj
.operate(&op
, null_yield
);
802 int RGWSI_User_RADOS::complete_flush_stats(RGWSI_MetaBackend::Context
*ctx
,
803 const rgw_user
& user
)
805 rgw_raw_obj obj
= get_buckets_obj(user
);
806 auto rados_obj
= svc
.rados
->obj(obj
);
807 int r
= rados_obj
.open();
811 librados::ObjectWriteOperation op
;
812 ::cls_user_complete_stats_sync(op
);
813 return rados_obj
.operate(&op
, null_yield
);
816 int RGWSI_User_RADOS::cls_user_get_header(const rgw_user
& user
, cls_user_header
*header
)
818 rgw_raw_obj obj
= get_buckets_obj(user
);
819 auto rados_obj
= svc
.rados
->obj(obj
);
820 int r
= rados_obj
.open();
826 librados::ObjectReadOperation op
;
827 ::cls_user_get_header(op
, header
, &rc
);
828 return rados_obj
.operate(&op
, &ibl
, null_yield
);
831 int RGWSI_User_RADOS::cls_user_get_header_async(const string
& user_str
, RGWGetUserHeader_CB
*cb
)
833 rgw_raw_obj obj
= get_buckets_obj(rgw_user(user_str
));
834 auto rados_obj
= svc
.rados
->obj(obj
);
835 int r
= rados_obj
.open();
840 auto& ref
= rados_obj
.get_ref();
842 r
= ::cls_user_get_header_async(ref
.pool
.ioctx(), ref
.obj
.oid
, cb
);
850 int RGWSI_User_RADOS::read_stats(RGWSI_MetaBackend::Context
*ctx
,
851 const rgw_user
& user
, RGWStorageStats
*stats
,
852 ceph::real_time
*last_stats_sync
,
853 ceph::real_time
*last_stats_update
)
855 string user_str
= user
.to_str();
857 cls_user_header header
;
858 int r
= cls_user_get_header(rgw_user(user_str
), &header
);
862 const cls_user_stats
& hs
= header
.stats
;
864 stats
->size
= hs
.total_bytes
;
865 stats
->size_rounded
= hs
.total_bytes_rounded
;
866 stats
->num_objects
= hs
.total_entries
;
868 if (last_stats_sync
) {
869 *last_stats_sync
= header
.last_stats_sync
;
872 if (last_stats_update
) {
873 *last_stats_update
= header
.last_stats_update
;
879 class RGWGetUserStatsContext
: public RGWGetUserHeader_CB
{
880 RGWGetUserStats_CB
*cb
;
883 explicit RGWGetUserStatsContext(RGWGetUserStats_CB
* const cb
)
886 void handle_response(int r
, cls_user_header
& header
) override
{
887 const cls_user_stats
& hs
= header
.stats
;
889 RGWStorageStats stats
;
891 stats
.size
= hs
.total_bytes
;
892 stats
.size_rounded
= hs
.total_bytes_rounded
;
893 stats
.num_objects
= hs
.total_entries
;
895 cb
->set_response(stats
);
898 cb
->handle_response(r
);
904 int RGWSI_User_RADOS::read_stats_async(RGWSI_MetaBackend::Context
*ctx
,
905 const rgw_user
& user
, RGWGetUserStats_CB
*_cb
)
907 string user_str
= user
.to_str();
909 RGWGetUserStatsContext
*cb
= new RGWGetUserStatsContext(_cb
);
910 int r
= cls_user_get_header_async(user_str
, cb
);