cls_method_handle_t h_rgw_bucket_trim_olh_log;
cls_method_handle_t h_rgw_obj_remove;
cls_method_handle_t h_rgw_bi_get_op;
+cls_method_handle_t h_rgw_bi_list_op;
cls_method_handle_t h_rgw_bi_log_list_op;
cls_method_handle_t h_rgw_dir_suggest_changes;
cls_method_handle_t h_rgw_user_usage_log_add;
++i) {
const string& t = bucket_index_prefixes[i];
- if (s.compare(0, t.size(), t) == 0) {
+ if (s.compare(1, t.size(), t) == 0) {
return i;
}
}
return -EINVAL;
}
+static bool bi_entry_gt(const string& first, const string& second)
+{
+ int fi = bi_entry_type(first);
+ int si = bi_entry_type(second);
+
+ if (fi > si) {
+ return true;
+ } else if (fi < si) {
+ return false;
+ }
+
+ return first > second;
+}
+
static void get_time_key(utime_t& ut, string *key)
{
char buf[32];
return 0;
}
+static int list_plain_entries(cls_method_context_t hctx, const string& name, const string& marker, uint32_t max,
+ list<rgw_cls_bi_entry> *entries)
+{
+ string filter = name;
+ string start_key = marker;
+ int count = 0;
+ map<string, bufferlist> keys;
+ do {
+ if (count >= (int)max) {
+ return count;
+ }
+ keys.clear();
+#define BI_GET_NUM_KEYS 128
+ int ret = cls_cxx_map_get_vals(hctx, start_key, filter, BI_GET_NUM_KEYS, &keys);
+ if (ret < 0) {
+ return ret;
+ }
+
+ map<string, bufferlist>::iterator iter;
+ for (iter = keys.begin(); iter != keys.end(); ++iter) {
+ rgw_cls_bi_entry entry;
+ entry.type = PlainIdx;
+ entry.idx = iter->first;
+ entry.data = iter->second;
+
+ bufferlist::iterator biter = entry.data.begin();
+
+ rgw_bucket_dir_entry e;
+ try {
+ ::decode(e, biter);
+ } catch (buffer::error& err) {
+ CLS_LOG(0, "ERROR: %s(): failed to decode buffer", __func__);
+ return -EIO;
+ }
+
+ if (e.key.name != name) {
+ return count;
+ }
+
+ entries->push_back(entry);
+ count++;
+ start_key = entry.idx;
+ }
+ } while (!keys.empty());
+
+ return count;
+}
+
+static int get_map_vals_starting_at(cls_method_context_t hctx,
+ const string &start_at,
+ const string &filter_prefix,
+ uint64_t max_to_get,
+ std::map<string, bufferlist> *vals)
+{
+ if (max_to_get == 0) {
+ return 0;
+ }
+ bufferlist bl;
+ bool found_first = false;
+
+ if (start_at.substr(0, filter_prefix.size()) == filter_prefix) {
+ int ret = cls_cxx_map_get_val(hctx, start_at, &bl);
+ if (ret < 0 && ret != -ENOENT) {
+ return ret;
+ }
+ found_first = (ret == 0);
+
+ if (found_first) {
+ max_to_get--;
+ }
+ }
+
+ if (max_to_get > 0) {
+ int ret = cls_cxx_map_get_vals(hctx, start_at, filter_prefix, max_to_get, vals);
+ if (ret < 0 && ret != -ENOENT) {
+ return ret;
+ }
+ }
+
+ if (found_first) {
+ (*vals)[start_at] = bl;
+ }
+
+ return 0;
+}
+
+static int list_instance_entries(cls_method_context_t hctx, const string& name, const string& marker, uint32_t max,
+ list<rgw_cls_bi_entry> *entries)
+{
+ cls_rgw_obj_key key(name);
+ string first_instance_idx;
+ encode_obj_versioned_data_key(key, &first_instance_idx);
+ string start_key = first_instance_idx;
+ if (bi_entry_gt(marker, start_key)) {
+ start_key = marker;
+ }
+ int count = 0;
+ map<string, bufferlist> keys;
+ do {
+ if (count >= (int)max) {
+ return count;
+ }
+ keys.clear();
+#define BI_GET_NUM_KEYS 128
+ string filter;
+ int ret = get_map_vals_starting_at(hctx, start_key, filter, BI_GET_NUM_KEYS, &keys);
+ if (ret < 0) {
+ return ret;
+ }
+
+ map<string, bufferlist>::iterator iter;
+ for (iter = keys.begin(); iter != keys.end(); ++iter) {
+ rgw_cls_bi_entry entry;
+ entry.type = InstanceIdx;
+ entry.idx = iter->first;
+ entry.data = iter->second;
+
+ bufferlist::iterator biter = entry.data.begin();
+
+ rgw_bucket_dir_entry e;
+ try {
+ ::decode(e, biter);
+ } catch (buffer::error& err) {
+ CLS_LOG(0, "ERROR: %s(): failed to decode buffer", __func__);
+ return -EIO;
+ }
+
+ if (e.key.name != name) {
+ return count;
+ }
+
+ entries->push_back(entry);
+ count++;
+ start_key = entry.idx;
+ }
+ } while (!keys.empty());
+
+ return count;
+}
+
+static int rgw_bi_list_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ // decode request
+ rgw_cls_bi_list_op op;
+ bufferlist::iterator iter = in->begin();
+ try {
+ ::decode(op, iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(0, "ERROR: %s(): failed to decode request", __func__);
+ return -EINVAL;
+ }
+
+ rgw_cls_bi_list_ret op_ret;
+
+ string filter = op.name;
+#define MAX_BI_LIST_ENTRIES 1000
+ int32_t max = (op.max < MAX_BI_LIST_ENTRIES ? op.max : MAX_BI_LIST_ENTRIES);
+ string start_key = op.marker;
+ int ret = list_plain_entries(hctx, op.name, op.marker, max, &op_ret.entries);
+ if (ret < 0) {
+ CLS_LOG(0, "ERROR: %s(): list_plain_entries retured ret=%d", __func__, ret);
+ return ret;
+ }
+ int count = ret;
+
+ ret = list_instance_entries(hctx, op.name, op.marker, max - count, &op_ret.entries);
+ if (ret < 0) {
+ CLS_LOG(0, "ERROR: %s(): list_instance_entries retured ret=%d", __func__, ret);
+ return ret;
+ }
+
+ cls_rgw_obj_key key(op.name);
+ rgw_cls_bi_entry entry;
+ encode_olh_data_key(key, &entry.idx);
+ ret = cls_cxx_map_get_val(hctx, entry.idx, &entry.data);
+ if (ret < 0 && ret != -ENOENT) {
+ CLS_LOG(0, "ERROR: %s(): cls_cxx_map_get_val retured ret=%d", __func__, ret);
+ return ret;
+ } else if (ret >= 0) {
+ entry.type = OLHIdx;
+ op_ret.entries.push_back(entry);
+ }
+
+ ::encode(op_ret, *out);
+
+ return 0;
+}
+
int bi_log_record_decode(bufferlist& bl, rgw_bi_log_entry& e)
{
bufferlist::iterator iter = bl.begin();
cls_register_cxx_method(h_class, "obj_remove", CLS_METHOD_RD | CLS_METHOD_WR, rgw_obj_remove, &h_rgw_obj_remove);
cls_register_cxx_method(h_class, "bi_get", CLS_METHOD_RD, rgw_bi_get_op, &h_rgw_bi_get_op);
+ cls_register_cxx_method(h_class, "bi_list", CLS_METHOD_RD, rgw_bi_list_op, &h_rgw_bi_list_op);
cls_register_cxx_method(h_class, "bi_log_list", CLS_METHOD_RD, rgw_bi_log_list, &h_rgw_bi_log_list_op);
cls_register_cxx_method(h_class, "bi_log_trim", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bi_log_trim, &h_rgw_bi_log_list_op);
OPT_OBJECT_STAT,
OPT_OBJECT_REWRITE,
OPT_BI_GET,
+ OPT_BI_LIST,
OPT_OLH_GET,
OPT_OLH_READLOG,
OPT_QUOTA_SET,
} else if (strcmp(prev_cmd, "bi") == 0) {
if (strcmp(cmd, "get") == 0)
return OPT_BI_GET;
+ if (strcmp(cmd, "list") == 0)
+ return OPT_BI_LIST;
} else if (strcmp(prev_cmd, "region") == 0) {
if (strcmp(cmd, "get") == 0)
return OPT_REGION_GET;
formatter->flush(cout);
}
+ if (opt_cmd == OPT_BI_LIST) {
+ RGWBucketInfo bucket_info;
+ int ret = init_bucket(bucket_name, bucket_info, bucket);
+ if (ret < 0) {
+ cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
+
+ list<rgw_cls_bi_entry> entries;
+ bool is_truncated;
+ if (max_entries < 0) {
+ max_entries = 1000;
+ }
+
+
+ formatter->open_array_section("entries");
+
+ do {
+ entries.clear();
+ ret = store->bi_list(bucket, object, marker, max_entries, &entries, &is_truncated);
+ if (ret < 0) {
+ cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
+
+ list<rgw_cls_bi_entry>::iterator iter;
+ for (iter = entries.begin(); iter != entries.end(); ++iter) {
+ rgw_cls_bi_entry& entry = *iter;
+ encode_json("entry", entry, formatter);
+ marker = entry.idx;
+ }
+ formatter->flush(cout);
+ } while (is_truncated);
+ formatter->close_section();
+ formatter->flush(cout);
+ }
+
if (opt_cmd == OPT_OBJECT_RM) {
RGWBucketInfo bucket_info;
int ret = init_bucket(bucket_name, bucket_info, bucket);