]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/services/svc_bucket_sobj.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / services / svc_bucket_sobj.cc
CommitLineData
9f95a23c
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab ft=cpp
3
4
5#include "svc_bucket_sobj.h"
6#include "svc_zone.h"
7#include "svc_sys_obj.h"
8#include "svc_sys_obj_cache.h"
9#include "svc_bi.h"
10#include "svc_meta.h"
11#include "svc_meta_be_sobj.h"
12#include "svc_sync_modules.h"
13
14#include "rgw/rgw_bucket.h"
15#include "rgw/rgw_tools.h"
16#include "rgw/rgw_zone.h"
17
18#define dout_subsys ceph_subsys_rgw
19
20#define RGW_BUCKET_INSTANCE_MD_PREFIX ".bucket.meta."
21
20effc67
TL
22using namespace std;
23
9f95a23c
TL
24class RGWSI_Bucket_SObj_Module : public RGWSI_MBSObj_Handler_Module {
25 RGWSI_Bucket_SObj::Svc& svc;
26
27 const string prefix;
28public:
29 RGWSI_Bucket_SObj_Module(RGWSI_Bucket_SObj::Svc& _svc) : RGWSI_MBSObj_Handler_Module("bucket"),
30 svc(_svc) {}
31
32 void get_pool_and_oid(const string& key, rgw_pool *pool, string *oid) override {
33 if (pool) {
34 *pool = svc.zone->get_zone_params().domain_root;
35 }
36 if (oid) {
37 *oid = key;
38 }
39 }
40
41 const string& get_oid_prefix() override {
42 return prefix;
43 }
44
45 bool is_valid_oid(const string& oid) override {
46 return (!oid.empty() && oid[0] != '.');
47 }
48
49 string key_to_oid(const string& key) override {
50 return key;
51 }
52
53 string oid_to_key(const string& oid) override {
54 /* should have been called after is_valid_oid(),
55 * so no need to check for validity */
56 return oid;
57 }
58};
59
60class RGWSI_BucketInstance_SObj_Module : public RGWSI_MBSObj_Handler_Module {
61 RGWSI_Bucket_SObj::Svc& svc;
62
63 const string prefix;
64public:
65 RGWSI_BucketInstance_SObj_Module(RGWSI_Bucket_SObj::Svc& _svc) : RGWSI_MBSObj_Handler_Module("bucket.instance"),
66 svc(_svc), prefix(RGW_BUCKET_INSTANCE_MD_PREFIX) {}
67
68 void get_pool_and_oid(const string& key, rgw_pool *pool, string *oid) override {
69 if (pool) {
70 *pool = svc.zone->get_zone_params().domain_root;
71 }
72 if (oid) {
73 *oid = key_to_oid(key);
74 }
75 }
76
77 const string& get_oid_prefix() override {
78 return prefix;
79 }
80
81 bool is_valid_oid(const string& oid) override {
82 return (oid.compare(0, prefix.size(), RGW_BUCKET_INSTANCE_MD_PREFIX) == 0);
83 }
84
85// 'tenant/' is used in bucket instance keys for sync to avoid parsing ambiguity
86// with the existing instance[:shard] format. once we parse the shard, the / is
87// replaced with a : to match the [tenant:]instance format
88 string key_to_oid(const string& key) override {
89 string oid = prefix + key;
90
91 // replace tenant/ with tenant:
92 auto c = oid.find('/', prefix.size());
93 if (c != string::npos) {
94 oid[c] = ':';
95 }
96
97 return oid;
98 }
99
100 // convert bucket instance oids back to the tenant/ format for metadata keys.
101 // it's safe to parse 'tenant:' only for oids, because they won't contain the
102 // optional :shard at the end
103 string oid_to_key(const string& oid) override {
104 /* this should have been called after oid was checked for validity */
105
106 if (oid.size() < prefix.size()) { /* just sanity check */
107 return string();
108 }
109
110 string key = oid.substr(prefix.size());
111
112 // find first : (could be tenant:bucket or bucket:instance)
113 auto c = key.find(':');
114 if (c != string::npos) {
115 // if we find another :, the first one was for tenant
116 if (key.find(':', c + 1) != string::npos) {
117 key[c] = '/';
118 }
119 }
120
121 return key;
122 }
123
124 /*
125 * hash entry for mdlog placement. Use the same hash key we'd have for the bucket entry
126 * point, so that the log entries end up at the same log shard, so that we process them
127 * in order
128 */
129 string get_hash_key(const string& key) override {
130 string k = "bucket:";
131 int pos = key.find(':');
132 if (pos < 0)
133 k.append(key);
134 else
135 k.append(key.substr(0, pos));
136
137 return k;
138 }
139};
140
141RGWSI_Bucket_SObj::RGWSI_Bucket_SObj(CephContext *cct): RGWSI_Bucket(cct) {
142}
143
144RGWSI_Bucket_SObj::~RGWSI_Bucket_SObj() {
145}
146
147void RGWSI_Bucket_SObj::init(RGWSI_Zone *_zone_svc, RGWSI_SysObj *_sysobj_svc,
148 RGWSI_SysObj_Cache *_cache_svc, RGWSI_BucketIndex *_bi,
149 RGWSI_Meta *_meta_svc, RGWSI_MetaBackend *_meta_be_svc,
150 RGWSI_SyncModules *_sync_modules_svc,
151 RGWSI_Bucket_Sync *_bucket_sync_svc)
152{
153 svc.bucket = this;
154 svc.zone = _zone_svc;
155 svc.sysobj = _sysobj_svc;
156 svc.cache = _cache_svc;
157 svc.bi = _bi;
158 svc.meta = _meta_svc;
159 svc.meta_be = _meta_be_svc;
160 svc.sync_modules = _sync_modules_svc;
161 svc.bucket_sync = _bucket_sync_svc;
162}
163
b3b6e05e 164int RGWSI_Bucket_SObj::do_start(optional_yield, const DoutPrefixProvider *dpp)
9f95a23c
TL
165{
166 binfo_cache.reset(new RGWChainedCacheImpl<bucket_info_cache_entry>);
167 binfo_cache->init(svc.cache);
168
169 /* create first backend handler for bucket entrypoints */
170
171 RGWSI_MetaBackend_Handler *ep_handler;
172
173 int r = svc.meta->create_be_handler(RGWSI_MetaBackend::Type::MDBE_SOBJ, &ep_handler);
174 if (r < 0) {
b3b6e05e 175 ldpp_dout(dpp, 0) << "ERROR: failed to create be handler: r=" << r << dendl;
9f95a23c
TL
176 return r;
177 }
178
179 ep_be_handler = ep_handler;
180
181 RGWSI_MetaBackend_Handler_SObj *ep_bh = static_cast<RGWSI_MetaBackend_Handler_SObj *>(ep_handler);
182
183 auto ep_module = new RGWSI_Bucket_SObj_Module(svc);
184 ep_be_module.reset(ep_module);
185 ep_bh->set_module(ep_module);
186
187 /* create a second backend handler for bucket instance */
188
189 RGWSI_MetaBackend_Handler *bi_handler;
190
191 r = svc.meta->create_be_handler(RGWSI_MetaBackend::Type::MDBE_SOBJ, &bi_handler);
192 if (r < 0) {
b3b6e05e 193 ldpp_dout(dpp, 0) << "ERROR: failed to create be handler: r=" << r << dendl;
9f95a23c
TL
194 return r;
195 }
196
197 bi_be_handler = bi_handler;
198
199 RGWSI_MetaBackend_Handler_SObj *bi_bh = static_cast<RGWSI_MetaBackend_Handler_SObj *>(bi_handler);
200
201 auto bi_module = new RGWSI_BucketInstance_SObj_Module(svc);
202 bi_be_module.reset(bi_module);
203 bi_bh->set_module(bi_module);
204
205 return 0;
206}
207
208int RGWSI_Bucket_SObj::read_bucket_entrypoint_info(RGWSI_Bucket_EP_Ctx& ctx,
209 const string& key,
210 RGWBucketEntryPoint *entry_point,
211 RGWObjVersionTracker *objv_tracker,
212 real_time *pmtime,
213 map<string, bufferlist> *pattrs,
214 optional_yield y,
b3b6e05e 215 const DoutPrefixProvider *dpp,
9f95a23c
TL
216 rgw_cache_entry_info *cache_info,
217 boost::optional<obj_version> refresh_version)
218{
219 bufferlist bl;
220
221 auto params = RGWSI_MBSObj_GetParams(&bl, pattrs, pmtime).set_cache_info(cache_info)
222 .set_refresh_version(refresh_version);
223
b3b6e05e 224 int ret = svc.meta_be->get_entry(ctx.get(), key, params, objv_tracker, y, dpp);
9f95a23c
TL
225 if (ret < 0) {
226 return ret;
227 }
228
229 auto iter = bl.cbegin();
230 try {
231 decode(*entry_point, iter);
232 } catch (buffer::error& err) {
b3b6e05e 233 ldpp_dout(dpp, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl;
9f95a23c
TL
234 return -EIO;
235 }
236 return 0;
237}
238
239int RGWSI_Bucket_SObj::store_bucket_entrypoint_info(RGWSI_Bucket_EP_Ctx& ctx,
240 const string& key,
241 RGWBucketEntryPoint& info,
242 bool exclusive,
243 real_time mtime,
244 map<string, bufferlist> *pattrs,
245 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
246 optional_yield y,
247 const DoutPrefixProvider *dpp)
9f95a23c
TL
248{
249 bufferlist bl;
250 encode(info, bl);
251
252 RGWSI_MBSObj_PutParams params(bl, pattrs, mtime, exclusive);
253
b3b6e05e 254 int ret = svc.meta_be->put(ctx.get(), key, params, objv_tracker, y, dpp);
9f95a23c
TL
255 if (ret < 0) {
256 return ret;
257 }
258
259 return ret;
260}
261
262int RGWSI_Bucket_SObj::remove_bucket_entrypoint_info(RGWSI_Bucket_EP_Ctx& ctx,
263 const string& key,
264 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
265 optional_yield y,
266 const DoutPrefixProvider *dpp)
9f95a23c
TL
267{
268 RGWSI_MBSObj_RemoveParams params;
b3b6e05e 269 return svc.meta_be->remove(ctx.get(), key, params, objv_tracker, y, dpp);
9f95a23c
TL
270}
271
272int RGWSI_Bucket_SObj::read_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
273 const string& key,
274 RGWBucketInfo *info,
275 real_time *pmtime, map<string, bufferlist> *pattrs,
276 optional_yield y,
b3b6e05e 277 const DoutPrefixProvider *dpp,
9f95a23c
TL
278 rgw_cache_entry_info *cache_info,
279 boost::optional<obj_version> refresh_version)
280{
281 string cache_key("bi/");
282 cache_key.append(key);
283
284 if (auto e = binfo_cache->find(cache_key)) {
285 if (refresh_version &&
286 e->info.objv_tracker.read_version.compare(&(*refresh_version))) {
b3b6e05e 287 ldpp_dout(dpp, -1) << "WARNING: The bucket info cache is inconsistent. This is "
9f95a23c
TL
288 << "a failure that should be debugged. I am a nice machine, "
289 << "so I will try to recover." << dendl;
290 binfo_cache->invalidate(key);
291 } else {
292 *info = e->info;
293 if (pattrs)
294 *pattrs = e->attrs;
295 if (pmtime)
296 *pmtime = e->mtime;
297 return 0;
298 }
299 }
300
301 bucket_info_cache_entry e;
302 rgw_cache_entry_info ci;
303
304 int ret = do_read_bucket_instance_info(ctx, key,
305 &e.info, &e.mtime, &e.attrs,
b3b6e05e 306 &ci, refresh_version, y, dpp);
9f95a23c
TL
307 *info = e.info;
308
309 if (ret < 0) {
310 if (ret != -ENOENT) {
b3b6e05e 311 ldpp_dout(dpp, -1) << "ERROR: do_read_bucket_instance_info failed: " << ret << dendl;
9f95a23c 312 } else {
b3b6e05e 313 ldpp_dout(dpp, 20) << "do_read_bucket_instance_info, bucket instance not found (key=" << key << ")" << dendl;
9f95a23c
TL
314 }
315 return ret;
316 }
317
318 if (pmtime) {
319 *pmtime = e.mtime;
320 }
321 if (pattrs) {
322 *pattrs = e.attrs;
323 }
324 if (cache_info) {
325 *cache_info = ci;
326 }
327
328 /* chain to only bucket instance and *not* bucket entrypoint */
b3b6e05e
TL
329 if (!binfo_cache->put(dpp, svc.cache, cache_key, &e, {&ci})) {
330 ldpp_dout(dpp, 20) << "couldn't put binfo cache entry, might have raced with data changes" << dendl;
9f95a23c
TL
331 }
332
333 if (refresh_version &&
334 refresh_version->compare(&info->objv_tracker.read_version)) {
b3b6e05e 335 ldpp_dout(dpp, -1) << "WARNING: The OSD has the same version I have. Something may "
9f95a23c
TL
336 << "have gone squirrelly. An administrator may have forced a "
337 << "change; otherwise there is a problem somewhere." << dendl;
338 }
339
340 return 0;
341}
342
343int RGWSI_Bucket_SObj::do_read_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
344 const string& key,
345 RGWBucketInfo *info,
346 real_time *pmtime, map<string, bufferlist> *pattrs,
347 rgw_cache_entry_info *cache_info,
348 boost::optional<obj_version> refresh_version,
b3b6e05e
TL
349 optional_yield y,
350 const DoutPrefixProvider *dpp)
9f95a23c
TL
351{
352 bufferlist bl;
353 RGWObjVersionTracker ot;
354
355 auto params = RGWSI_MBSObj_GetParams(&bl, pattrs, pmtime).set_cache_info(cache_info)
356 .set_refresh_version(refresh_version);
357
b3b6e05e 358 int ret = svc.meta_be->get_entry(ctx.get(), key, params, &ot, y, dpp);
9f95a23c
TL
359 if (ret < 0) {
360 return ret;
361 }
362
363 auto iter = bl.cbegin();
364 try {
365 decode(*info, iter);
366 } catch (buffer::error& err) {
b3b6e05e 367 ldpp_dout(dpp, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl;
9f95a23c
TL
368 return -EIO;
369 }
370 info->objv_tracker = ot;
371 return 0;
372}
373
374int RGWSI_Bucket_SObj::read_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
375 const rgw_bucket& bucket,
376 RGWBucketInfo *info,
377 real_time *pmtime,
378 map<string, bufferlist> *pattrs,
379 boost::optional<obj_version> refresh_version,
b3b6e05e
TL
380 optional_yield y,
381 const DoutPrefixProvider *dpp)
9f95a23c
TL
382{
383 rgw_cache_entry_info cache_info;
384
385 if (!bucket.bucket_id.empty()) {
386 return read_bucket_instance_info(ctx.bi, get_bi_meta_key(bucket),
387 info,
388 pmtime, pattrs,
389 y,
b3b6e05e 390 dpp,
9f95a23c
TL
391 &cache_info, refresh_version);
392 }
393
394 string bucket_entry = get_entrypoint_meta_key(bucket);
395 string cache_key("b/");
396 cache_key.append(bucket_entry);
397
398 if (auto e = binfo_cache->find(cache_key)) {
399 bool found_version = (bucket.bucket_id.empty() ||
400 bucket.bucket_id == e->info.bucket.bucket_id);
401
402 if (!found_version ||
403 (refresh_version &&
404 e->info.objv_tracker.read_version.compare(&(*refresh_version)))) {
20effc67 405 ldpp_dout(dpp, -1) << "WARNING: The bucket info cache is inconsistent. This is "
9f95a23c
TL
406 << "a failure that should be debugged. I am a nice machine, "
407 << "so I will try to recover." << dendl;
408 binfo_cache->invalidate(cache_key);
409 } else {
410 *info = e->info;
411 if (pattrs)
412 *pattrs = e->attrs;
413 if (pmtime)
414 *pmtime = e->mtime;
415 return 0;
416 }
417 }
418
419 RGWBucketEntryPoint entry_point;
420 real_time ep_mtime;
421 RGWObjVersionTracker ot;
422 rgw_cache_entry_info entry_cache_info;
423 int ret = read_bucket_entrypoint_info(ctx.ep, bucket_entry,
424 &entry_point, &ot, &ep_mtime, pattrs,
425 y,
b3b6e05e 426 dpp,
9f95a23c
TL
427 &entry_cache_info, refresh_version);
428 if (ret < 0) {
429 /* only init these fields */
430 info->bucket = bucket;
431 return ret;
432 }
433
434 if (entry_point.has_bucket_info) {
435 *info = entry_point.old_bucket_info;
436 info->bucket.tenant = bucket.tenant;
b3b6e05e 437 ldpp_dout(dpp, 20) << "rgw_get_bucket_info: old bucket info, bucket=" << info->bucket << " owner " << info->owner << dendl;
9f95a23c
TL
438 return 0;
439 }
440
441 /* data is in the bucket instance object, we need to get attributes from there, clear everything
442 * that we got
443 */
444 if (pattrs) {
445 pattrs->clear();
446 }
447
b3b6e05e 448 ldpp_dout(dpp, 20) << "rgw_get_bucket_info: bucket instance: " << entry_point.bucket << dendl;
9f95a23c
TL
449
450
451 /* read bucket instance info */
452
453 bucket_info_cache_entry e;
454
455 ret = read_bucket_instance_info(ctx.bi, get_bi_meta_key(entry_point.bucket),
456 &e.info, &e.mtime, &e.attrs,
457 y,
b3b6e05e 458 dpp,
9f95a23c
TL
459 &cache_info, refresh_version);
460 *info = e.info;
461 if (ret < 0) {
b3b6e05e 462 ldpp_dout(dpp, -1) << "ERROR: read_bucket_instance_from_oid failed: " << ret << dendl;
9f95a23c
TL
463 info->bucket = bucket;
464 // XXX and why return anything in case of an error anyway?
465 return ret;
466 }
467
468 if (pmtime)
469 *pmtime = e.mtime;
470 if (pattrs)
471 *pattrs = e.attrs;
472
473 /* chain to both bucket entry point and bucket instance */
b3b6e05e
TL
474 if (!binfo_cache->put(dpp, svc.cache, cache_key, &e, {&entry_cache_info, &cache_info})) {
475 ldpp_dout(dpp, 20) << "couldn't put binfo cache entry, might have raced with data changes" << dendl;
9f95a23c
TL
476 }
477
478 if (refresh_version &&
479 refresh_version->compare(&info->objv_tracker.read_version)) {
b3b6e05e 480 ldpp_dout(dpp, -1) << "WARNING: The OSD has the same version I have. Something may "
9f95a23c
TL
481 << "have gone squirrelly. An administrator may have forced a "
482 << "change; otherwise there is a problem somewhere." << dendl;
483 }
484
485 return 0;
486}
487
488
489int RGWSI_Bucket_SObj::store_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
490 const string& key,
491 RGWBucketInfo& info,
492 std::optional<RGWBucketInfo *> orig_info,
493 bool exclusive,
494 real_time mtime,
495 map<string, bufferlist> *pattrs,
b3b6e05e
TL
496 optional_yield y,
497 const DoutPrefixProvider *dpp)
9f95a23c
TL
498{
499 bufferlist bl;
500 encode(info, bl);
501
502 /*
503 * we might need some special handling if overwriting
504 */
505 RGWBucketInfo shared_bucket_info;
506 if (!orig_info && !exclusive) { /* if exclusive, we're going to fail when try
507 to overwrite, so the whole check here is moot */
508 /*
509 * we're here because orig_info wasn't passed in
510 * we don't have info about what was there before, so need to fetch first
511 */
512 int r = read_bucket_instance_info(ctx,
513 key,
514 &shared_bucket_info,
515 nullptr, nullptr,
516 y,
b3b6e05e 517 dpp,
9f95a23c
TL
518 nullptr, boost::none);
519 if (r < 0) {
520 if (r != -ENOENT) {
b3b6e05e 521 ldpp_dout(dpp, 0) << "ERROR: " << __func__ << "(): read_bucket_instance_info() of key=" << key << " returned r=" << r << dendl;
9f95a23c
TL
522 return r;
523 }
524 } else {
525 orig_info = &shared_bucket_info;
526 }
527 }
528
529 if (orig_info && *orig_info && !exclusive) {
b3b6e05e 530 int r = svc.bi->handle_overwrite(dpp, info, *(orig_info.value()));
9f95a23c 531 if (r < 0) {
b3b6e05e 532 ldpp_dout(dpp, 0) << "ERROR: " << __func__ << "(): svc.bi->handle_overwrite() of key=" << key << " returned r=" << r << dendl;
9f95a23c
TL
533 return r;
534 }
535 }
536
537 RGWSI_MBSObj_PutParams params(bl, pattrs, mtime, exclusive);
538
b3b6e05e 539 int ret = svc.meta_be->put(ctx.get(), key, params, &info.objv_tracker, y, dpp);
9f95a23c
TL
540
541 if (ret >= 0) {
b3b6e05e 542 int r = svc.bucket_sync->handle_bi_update(dpp, info,
9f95a23c
TL
543 orig_info.value_or(nullptr),
544 y);
545 if (r < 0) {
546 return r;
547 }
548 } else if (ret == -EEXIST) {
549 /* well, if it's exclusive we shouldn't overwrite it, because we might race with another
550 * bucket operation on this specific bucket (e.g., being synced from the master), but
20effc67 551 * since bucket instance meta object is unique for this specific bucket instance, we don't
9f95a23c
TL
552 * need to return an error.
553 * A scenario where we'd get -EEXIST here, is in a multi-zone config, we're not on the
554 * master, creating a bucket, sending bucket creation to the master, we create the bucket
555 * locally, while in the sync thread we sync the new bucket.
556 */
557 ret = 0;
558 }
559
560 if (ret < 0) {
561 return ret;
562 }
563
564 return ret;
565}
566
567int RGWSI_Bucket_SObj::remove_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
568 const string& key,
569 const RGWBucketInfo& info,
570 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
571 optional_yield y,
572 const DoutPrefixProvider *dpp)
9f95a23c
TL
573{
574 RGWSI_MBSObj_RemoveParams params;
b3b6e05e 575 int ret = svc.meta_be->remove_entry(dpp, ctx.get(), key, params, objv_tracker, y);
9f95a23c
TL
576
577 if (ret < 0 &&
578 ret != -ENOENT) {
579 return ret;
580 }
581
b3b6e05e 582 int r = svc.bucket_sync->handle_bi_removal(dpp, info, y);
9f95a23c 583 if (r < 0) {
b3b6e05e 584 ldpp_dout(dpp, 0) << "ERROR: failed to update bucket instance sync index: r=" << r << dendl;
9f95a23c
TL
585 /* returning success as index is just keeping hints, so will keep extra hints,
586 * but bucket removal succeeded
587 */
588 }
589
590 return 0;
591}
592
593int RGWSI_Bucket_SObj::read_bucket_stats(const RGWBucketInfo& bucket_info,
594 RGWBucketEnt *ent,
b3b6e05e
TL
595 optional_yield y,
596 const DoutPrefixProvider *dpp)
9f95a23c
TL
597{
598 ent->count = 0;
599 ent->size = 0;
600 ent->size_rounded = 0;
601
602 vector<rgw_bucket_dir_header> headers;
603
b3b6e05e 604 int r = svc.bi->read_stats(dpp, bucket_info, ent, y);
9f95a23c 605 if (r < 0) {
b3b6e05e 606 ldpp_dout(dpp, 0) << "ERROR: " << __func__ << "(): read_stats returned r=" << r << dendl;
9f95a23c
TL
607 return r;
608 }
609
610 return 0;
611}
612
613int RGWSI_Bucket_SObj::read_bucket_stats(RGWSI_Bucket_X_Ctx& ctx,
614 const rgw_bucket& bucket,
615 RGWBucketEnt *ent,
b3b6e05e
TL
616 optional_yield y,
617 const DoutPrefixProvider *dpp)
9f95a23c
TL
618{
619 RGWBucketInfo bucket_info;
b3b6e05e 620 int ret = read_bucket_info(ctx, bucket, &bucket_info, nullptr, nullptr, boost::none, y, dpp);
9f95a23c
TL
621 if (ret < 0) {
622 return ret;
623 }
624
b3b6e05e 625 return read_bucket_stats(bucket_info, ent, y, dpp);
9f95a23c
TL
626}
627
628int RGWSI_Bucket_SObj::read_buckets_stats(RGWSI_Bucket_X_Ctx& ctx,
629 map<string, RGWBucketEnt>& m,
b3b6e05e
TL
630 optional_yield y,
631 const DoutPrefixProvider *dpp)
9f95a23c
TL
632{
633 map<string, RGWBucketEnt>::iterator iter;
634 for (iter = m.begin(); iter != m.end(); ++iter) {
635 RGWBucketEnt& ent = iter->second;
b3b6e05e 636 int r = read_bucket_stats(ctx, ent.bucket, &ent, y, dpp);
9f95a23c 637 if (r < 0) {
b3b6e05e 638 ldpp_dout(dpp, 0) << "ERROR: " << __func__ << "(): read_bucket_stats returned r=" << r << dendl;
9f95a23c
TL
639 return r;
640 }
641 }
642
643 return m.size();
20effc67 644}