diff options
Diffstat (limited to 'src/rgw/rgw_quota.cc')
-rw-r--r-- | src/rgw/rgw_quota.cc | 107 |
1 files changed, 102 insertions, 5 deletions
diff --git a/src/rgw/rgw_quota.cc b/src/rgw/rgw_quota.cc index 70ab0762ce6..1f406a2c82c 100644 --- a/src/rgw/rgw_quota.cc +++ b/src/rgw/rgw_quota.cc @@ -26,6 +26,9 @@ public: int get_bucket_stats(rgw_bucket& bucket, RGWBucketStats& stats); void adjust_bucket_stats(rgw_bucket& bucket, int objs_delta, uint64_t added_bytes, uint64_t removed_bytes); + + int async_refresh(rgw_bucket& bucket, RGWQuotaBucketStats& qs); + void async_refresh_response(rgw_bucket& bucket, RGWBucketStats& stats); }; int RGWBucketStatsCache::fetch_bucket_totals(rgw_bucket& bucket, RGWBucketStats& stats) @@ -42,6 +45,8 @@ int RGWBucketStatsCache::fetch_bucket_totals(rgw_bucket& bucket, RGWBucketStats& return r; } + stats = RGWBucketStats(); + map<RGWObjCategory, RGWBucketStats>::iterator iter; for (iter = bucket_stats.begin(); iter != bucket_stats.end(); ++iter) { RGWBucketStats& s = iter->second; @@ -53,23 +58,115 @@ int RGWBucketStatsCache::fetch_bucket_totals(rgw_bucket& bucket, RGWBucketStats& return 0; } +class AsyncRefreshHandler : public RGWGetBucketStats_CB { + RGWRados *store; + RGWBucketStatsCache *cache; +public: + AsyncRefreshHandler(RGWRados *_store, RGWBucketStatsCache *_cache, rgw_bucket& _bucket) : RGWGetBucketStats_CB(_bucket), cache(_cache) {} + + int init_fetch(); + + void handle_response(int r); +}; + + +int AsyncRefreshHandler::init_fetch() +{ + map<RGWObjCategory, RGWBucketStats> bucket_stats; + int r = store->get_bucket_stats_async(bucket, this); + if (r < 0) { + ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket.name << dendl; + + /* get_bucket_stats_async() dropped our reference already */ + return r; + } + + return 0; +} + +void AsyncRefreshHandler::handle_response(int r) +{ + if (r < 0) + return; /* nothing to do here */ + + RGWBucketStats bs; + + map<RGWObjCategory, RGWBucketStats>::iterator iter; + for (iter = stats->begin(); iter != stats->end(); ++iter) { + RGWBucketStats& s = iter->second; + bs.num_kb += s.num_kb; + bs.num_kb_rounded += s.num_kb_rounded; + bs.num_objects += s.num_objects; + } + + cache->async_refresh_response(bucket, bs); +} + +int RGWBucketStatsCache::async_refresh(rgw_bucket& bucket, RGWQuotaBucketStats& qs) +{ + if (qs.async_update_flag.inc() != 1) { /* are we the first one here? */ + qs.async_update_flag.dec(); + return 0; + } + + AsyncRefreshHandler *handler = new AsyncRefreshHandler(store, this, bucket); + + async_refcount.get(); + + int ret = handler->init_fetch(); + if (ret < 0) { + async_refcount.put(); + handler->put(); + return ret; + } + + return 0; +} + +void RGWBucketStatsCache::async_refresh_response(rgw_bucket& bucket, RGWBucketStats& stats) +{ + RGWQuotaBucketStats qs; + + stats_map.find(bucket, qs); + + set_stats(bucket, qs, stats); + async_refcount.put(); +} + +void RGWBucketStatsCache::set_stats(rgw_bucket& bucket, RGWQuotaBucketStats& qs, RGWBucketStats& stats) +{ + qs.stats = stats; + qs.expiration = ceph_clock_now(store->ctx()); + qs.async_refresh_time = qs.expiration; + qs.expiration += store->ctx()->_conf->rgw_bucket_quota_ttl; + qs.async_refresh_time += store->ctx()->_conf->rgw_bucket_quota_ttl / 2; + + stats_map.add(bucket, qs); +} + int RGWBucketStatsCache::get_bucket_stats(rgw_bucket& bucket, RGWBucketStats& stats) { RGWQuotaBucketStats qs; + utime_t now = ceph_clock_now(store->ctx()); if (stats_map.find(bucket, qs)) { + if (now >= qs.async_refresh_time) { + int r = async_refresh(bucket); + if (r < 0) { + ldout(s->ctx(), 0) << "ERROR: quota async refresh returned ret=" << ret << dendl; + + /* continue processing, might be a transient error, async refresh is just optimization */ + } + } if (qs.expiration > ceph_clock_now(store->ctx())) { stats = qs.stats; return 0; } } - int ret = fetch_bucket_totals(bucket, qs.stats); + int ret = fetch_bucket_totals(bucket, stats); if (ret < 0 && ret != -ENOENT) return ret; - qs.expiration = ceph_clock_now(store->ctx()); - qs.expiration += store->ctx()->_conf->rgw_bucket_quota_ttl; - - stats_map.add(bucket, qs); + set_stats(bucket, qs, stats); return 0; } |