summaryrefslogtreecommitdiff
path: root/src/rgw/rgw_quota.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/rgw_quota.cc')
-rw-r--r--src/rgw/rgw_quota.cc107
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;
}