From: Yehuda Sadeh Date: Tue, 10 Dec 2013 00:09:41 +0000 (-0800) Subject: cls/user: accounting functionality X-Git-Tag: v0.78~270^2~33 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=438aea7f7f20609b9995bfb9b0f95e4c0d41d7b4;p=ceph.git cls/user: accounting functionality Keep user total accounting in omap header, handle add/dec functionality. Signed-off-by: Yehuda Sadeh --- diff --git a/src/cls/user/cls_user.cc b/src/cls/user/cls_user.cc index 4f9446cb3341..77eb58d82bef 100644 --- a/src/cls/user/cls_user.cc +++ b/src/cls/user/cls_user.cc @@ -75,6 +75,43 @@ static int get_existing_bucket_entry(cls_method_context_t hctx, const string& bu return 0; } +static int read_header(cls_method_context_t hctx, cls_user_header *header) +{ + bufferlist bl; + + int ret = cls_cxx_map_read_header(hctx, &bl); + if (ret < 0) + return ret; + + if (bl.length() == 0) { + *header = cls_user_header(); + return 0; + } + + try { + ::decode(*header, bl); + } catch (buffer::error& err) { + CLS_LOG(0, "ERROR: failed to decode user header"); + return -EIO; + } + + return 0; +} + +static void add_header_stats(cls_user_header *header, cls_user_bucket_entry& entry) +{ + header->total_entries += entry.count; + header->total_bytes += entry.size; + header->total_bytes_rounded += entry.size_rounded; +} + +static void dec_header_stats(cls_user_header *header, cls_user_bucket_entry& entry) +{ + header->total_bytes -= entry.size; + header->total_bytes_rounded -= entry.size_rounded; + header->total_entries -= entry.count; +} + static int cls_user_set_buckets_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); @@ -87,6 +124,13 @@ static int cls_user_set_buckets_info(cls_method_context_t hctx, bufferlist *in, return -EINVAL; } + cls_user_header header; + int ret = read_header(hctx, &header); + if (ret < 0) { + CLS_LOG(0, "ERROR: failed to read user info header ret=%d", ret); + return ret; + } + for (list::iterator iter = op.entries.begin(); iter != op.entries.end(); ++iter) { cls_user_bucket_entry& entry = *iter; @@ -95,11 +139,26 @@ static int cls_user_set_buckets_info(cls_method_context_t hctx, bufferlist *in, get_key_by_bucket_name(entry.bucket.name, &key); - CLS_LOG(0, "storing entry by client/op at %s", key.c_str()); + cls_user_bucket_entry old_entry; + ret = get_existing_bucket_entry(hctx, key, old_entry); + + if (ret == -ENOENT) + continue; /* racing bucket removal */ + + if (ret < 0) { + CLS_LOG(0, "ERROR: get_existing_bucket_entry() key=%s returned %d", key.c_str(), ret); + return ret; + } else if (ret >= 0) { + dec_header_stats(&header, old_entry); + } + + CLS_LOG(20, "storing entry by client/op at %s", key.c_str()); - int ret = write_entry(hctx, key, entry); + ret = write_entry(hctx, key, entry); if (ret < 0) return ret; + + add_header_stats(&header, entry); } return 0; @@ -117,13 +176,32 @@ static int cls_user_remove_bucket(cls_method_context_t hctx, bufferlist *in, buf return -EINVAL; } + cls_user_header header; + int ret = read_header(hctx, &header); + if (ret < 0) { + CLS_LOG(0, "ERROR: failed to read user info header ret=%d", ret); + return ret; + } + string key; get_key_by_bucket_name(op.bucket.name, &key); + cls_user_bucket_entry entry; + ret = get_existing_bucket_entry(hctx, key, entry); + if (ret == -ENOENT) { + return 0; /* idempotent removal */ + } + if (ret < 0) { + CLS_LOG(0, "ERROR: get existing bucket entry, key=%s ret=%d", key.c_str(), ret); + return ret; + } + + dec_header_stats(&header, entry); + CLS_LOG(20, "removing entry at %s", key.c_str()); - int ret = remove_entry(hctx, key); + ret = remove_entry(hctx, key); if (ret < 0) return ret; diff --git a/src/cls/user/cls_user_types.h b/src/cls/user/cls_user_types.h index f4f0c14d78fa..1eddc10aadfa 100644 --- a/src/cls/user/cls_user_types.h +++ b/src/cls/user/cls_user_types.h @@ -105,6 +105,30 @@ struct cls_user_bucket_entry { }; WRITE_CLASS_ENCODER(cls_user_bucket_entry) +/* + * this needs to be compatible with with rgw_bucket, as it replaces it + */ +struct cls_user_header { + uint64_t total_entries; + uint64_t total_bytes; + uint64_t total_bytes_rounded; + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + ::encode(total_entries, bl); + ::encode(total_bytes, bl); + ::encode(total_bytes_rounded, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::iterator& bl) { + DECODE_START(1, bl); + ::decode(total_entries, bl); + ::decode(total_bytes, bl); + ::decode(total_bytes_rounded, bl); + DECODE_FINISH(bl); + } +}; +WRITE_CLASS_ENCODER(cls_user_header) #endif