cls_method_handle_t h_rgw_bucket_unlink_instance_op;
cls_method_handle_t h_rgw_bucket_read_olh_log;
cls_method_handle_t h_rgw_bucket_trim_olh_log;
+cls_method_handle_t h_rgw_bucket_clear_olh;
cls_method_handle_t h_rgw_obj_remove;
cls_method_handle_t h_rgw_bi_get_op;
cls_method_handle_t h_rgw_bi_put_op;
olh_data_entry.exists = exists;
}
+ bool pending_removal() { return olh_data_entry.pending_removal; }
+
+ void set_pending_removal(bool pending_removal) {
+ olh_data_entry.pending_removal = pending_removal;
+ }
+
const string& get_tag() { return olh_data_entry.tag; }
void set_tag(const string& tag) {
olh_data_entry.tag = tag;
if (olh_found) {
const string& olh_tag = olh.get_tag();
if (op.olh_tag != olh_tag) {
- CLS_LOG(5, "NOTICE: op.olh_tag (%s) != olh.tag (%s)", op.olh_tag.c_str(), olh_tag.c_str());
- return -ECANCELED;
+ if (!olh.pending_removal()) {
+ CLS_LOG(5, "NOTICE: op.olh_tag (%s) != olh.tag (%s)", op.olh_tag.c_str(), olh_tag.c_str());
+ return -ECANCELED;
+ }
+ /* if pending removal, this is a new olh instance */
+ olh.set_tag(op.olh_tag);
}
if (olh.exists()) {
rgw_bucket_olh_entry& olh_entry = olh.get_entry();
}
}
}
+ olh.set_pending_removal(false);
} else {
bool instance_only = (op.key.instance.empty() && op.delete_marker);
cls_rgw_obj_key key(op.key.name);
olh.update(next_key, false);
olh.update_log(CLS_RGW_OLH_OP_UNLINK_OLH, op.op_tag, next_key, false);
olh.set_exists(false);
+ olh.set_pending_removal(true);
}
}
return 0;
}
+static int rgw_bucket_clear_olh(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ // decode request
+ rgw_cls_bucket_clear_olh_op op;
+ bufferlist::iterator iter = in->begin();
+ try {
+ ::decode(op, iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(0, "ERROR: rgw_bucket_clear_olh(): failed to decode request\n");
+ return -EINVAL;
+ }
+
+ if (!op.key.instance.empty()) {
+ CLS_LOG(1, "bad key passed in (non empty instance)");
+ return -EINVAL;
+ }
+
+ /* read olh entry */
+ struct rgw_bucket_olh_entry olh_data_entry;
+ string olh_data_key;
+ encode_olh_data_key(op.key, &olh_data_key);
+ int ret = read_index_entry(hctx, olh_data_key, &olh_data_entry);
+ if (ret < 0 && ret != -ENOENT) {
+ CLS_LOG(0, "ERROR: read_index_entry() olh_key=%s ret=%d", olh_data_key.c_str(), ret);
+ return ret;
+ }
+
+ if (olh_data_entry.tag != op.olh_tag) {
+ CLS_LOG(1, "NOTICE: %s(): olh_tag_mismatch olh_data_entry.tag=%s op.olh_tag=%s", __func__, olh_data_entry.tag.c_str(), op.olh_tag.c_str());
+ return -ECANCELED;
+ }
+
+ ret = cls_cxx_map_remove_key(hctx, olh_data_key);
+ if (ret < 0) {
+ CLS_LOG(1, "NOTICE: %s(): can't remove key %s ret=%d", __func__, olh_data_key.c_str(), ret);
+ return ret;
+ }
+
+ rgw_bucket_dir_entry plain_entry;
+
+ /* read plain entry, make sure it's a versioned place holder */
+ ret = read_index_entry(hctx, op.key.name, &plain_entry);
+ if (ret == -ENOENT) {
+ /* we're done, no entry existing */
+ return 0;
+ }
+ if (ret < 0) {
+ CLS_LOG(0, "ERROR: read_index_entry key=%s ret=%d", op.key.name.c_str(), ret);
+ return ret;
+ }
+
+ if ((plain_entry.flags & RGW_BUCKET_DIRENT_FLAG_VER_MARKER) == 0) {
+ /* it's not a version marker, don't remove it */
+ return 0;
+ }
+
+ ret = cls_cxx_map_remove_key(hctx, op.key.name);
+ if (ret < 0) {
+ CLS_LOG(1, "NOTICE: %s(): can't remove key %s ret=%d", __func__, op.key.name.c_str(), ret);
+ return ret;
+ }
+
+ return 0;
+}
+
int rgw_dir_suggest_changes(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
CLS_LOG(1, "rgw_dir_suggest_changes()");
cls_register_cxx_method(h_class, "bucket_unlink_instance", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_unlink_instance, &h_rgw_bucket_unlink_instance_op);
cls_register_cxx_method(h_class, "bucket_read_olh_log", CLS_METHOD_RD, rgw_bucket_read_olh_log, &h_rgw_bucket_read_olh_log);
cls_register_cxx_method(h_class, "bucket_trim_olh_log", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_trim_olh_log, &h_rgw_bucket_trim_olh_log);
+ cls_register_cxx_method(h_class, "bucket_clear_olh", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_clear_olh, &h_rgw_bucket_clear_olh);
cls_register_cxx_method(h_class, "obj_remove", CLS_METHOD_RD | CLS_METHOD_WR, rgw_obj_remove, &h_rgw_obj_remove);
op.exec("rgw", "bucket_trim_olh_log", in);
}
+int cls_rgw_clear_olh(IoCtx& io_ctx, string& oid, const cls_rgw_obj_key& olh, const string& olh_tag)
+{
+ bufferlist in, out;
+ struct rgw_cls_bucket_clear_olh_op call;
+ call.key = olh;
+ call.olh_tag = olh_tag;
+ ::encode(call, in);
+ librados::ObjectWriteOperation op;
+ int op_ret;
+ op.exec("rgw", "bucket_clear_olh", in, &out, &op_ret);
+ int r = io_ctx.operate(oid, &op);
+ if (r < 0) {
+ return r;
+ }
+ return op_ret;
+}
+
int cls_rgw_bucket_check_index_op(IoCtx& io_ctx, string& oid,
rgw_bucket_dir_header *existing_header,
rgw_bucket_dir_header *calculated_header)
const string& olh_tag,
map<uint64_t, vector<struct rgw_bucket_olh_log_entry> > *log, bool *is_truncated);
void cls_rgw_trim_olh_log(librados::ObjectWriteOperation& op, string& oid, const cls_rgw_obj_key& olh, uint64_t ver, const string& olh_tag);
+int cls_rgw_clear_olh(librados::IoCtx& io_ctx, string& oid, const cls_rgw_obj_key& olh, const string& olh_tag);
int cls_rgw_bucket_check_index_op(librados::IoCtx& io_ctx, string& oid,
rgw_bucket_dir_header *existing_header,
::encode_json("olh_tag", olh_tag, f);
}
+void rgw_cls_bucket_clear_olh_op::generate_test_instances(list<rgw_cls_bucket_clear_olh_op *>& o)
+{
+
+ rgw_cls_bucket_clear_olh_op *op = new rgw_cls_bucket_clear_olh_op;
+ op->key.name = "key.name";
+ op->olh_tag = "olh_tag";
+
+ o.push_back(op);
+ o.push_back(new rgw_cls_bucket_clear_olh_op);
+}
+
+void rgw_cls_bucket_clear_olh_op::dump(Formatter *f) const
+{
+ ::encode_json("key", key, f);
+ ::encode_json("olh_tag", olh_tag, f);
+}
+
void rgw_cls_list_op::generate_test_instances(list<rgw_cls_list_op*>& o)
{
rgw_cls_list_op *op = new rgw_cls_list_op;
};
WRITE_CLASS_ENCODER(rgw_cls_trim_olh_log_op)
+struct rgw_cls_bucket_clear_olh_op {
+ cls_rgw_obj_key key;
+ string olh_tag;
+
+ rgw_cls_bucket_clear_olh_op() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ ::encode(key, bl);
+ ::encode(olh_tag, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::iterator& bl) {
+ DECODE_START(1, bl);
+ ::decode(key, bl);
+ ::decode(olh_tag, bl);
+ DECODE_FINISH(bl);
+ }
+
+ static void generate_test_instances(list<rgw_cls_bucket_clear_olh_op *>& o);
+ void dump(Formatter *f) const;
+};
+WRITE_CLASS_ENCODER(rgw_cls_bucket_clear_olh_op)
+
struct rgw_cls_list_op
{
cls_rgw_obj_key start_obj;
encode_json("pending_log", pending_log, f);
encode_json("tag", tag, f);
encode_json("exists", exists, f);
+ encode_json("pending_removal", pending_removal, f);
}
void rgw_bucket_olh_log_entry::generate_test_instances(list<rgw_bucket_olh_log_entry*>& o)
map<uint64_t, vector<struct rgw_bucket_olh_log_entry> > pending_log;
string tag;
bool exists;
+ bool pending_removal;
- rgw_bucket_olh_entry() : delete_marker(false), epoch(0), exists(false) {}
+ rgw_bucket_olh_entry() : delete_marker(false), epoch(0), exists(false), pending_removal(false) {}
void encode(bufferlist &bl) const {
ENCODE_START(1, 1, bl);
::encode(pending_log, bl);
::encode(tag, bl);
::encode(exists, bl);
+ ::encode(pending_removal, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator &bl) {
::decode(pending_log, bl);
::decode(tag, bl);
::decode(exists, bl);
+ ::decode(pending_removal, bl);
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
return 0;
}
+int RGWRados::bucket_index_clear_olh(RGWObjState& state, rgw_obj& obj_instance)
+{
+ rgw_rados_ref ref;
+ rgw_bucket bucket;
+ int r = get_obj_ref(obj_instance, &ref, &bucket);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::IoCtx index_ctx;
+ string oid;
+
+ int ret = open_bucket_index(bucket, index_ctx, oid);
+ if (ret < 0) {
+ return ret;
+ }
+
+ string olh_tag(state.olh_tag.c_str(), state.olh_tag.length());
+
+ cls_rgw_obj_key key(obj_instance.get_index_key_name(), string());
+
+ ret = cls_rgw_clear_olh(index_ctx, oid, key, olh_tag);
+ if (ret < 0) {
+ ldout(cct, 5) << "cls_rgw_clear_olh() returned ret=" << ret << dendl;
+ return ret;
+ }
+
+ return 0;
+}
+
int RGWRados::apply_olh_log(RGWObjectCtx& obj_ctx, RGWObjState& state, RGWBucketInfo& bucket_info, rgw_obj& obj,
bufferlist& olh_tag, map<uint64_t, vector<rgw_bucket_olh_log_entry> >& log,
uint64_t *plast_ver)
cls_rgw_obj_key key;
bool delete_marker = false;
list<cls_rgw_obj_key> remove_instances;
+ bool need_to_remove = false;
for (iter = log.begin(); iter != log.end(); ++iter) {
vector<rgw_bucket_olh_log_entry>::iterator viter = iter->second.begin();
break;
case CLS_RGW_OLH_OP_LINK_OLH:
need_to_link = true;
+ need_to_remove = false;
key = entry.key;
delete_marker = entry.delete_marker;
break;
case CLS_RGW_OLH_OP_UNLINK_OLH:
- /* treat this as linking into a delete marker */
- need_to_link = true;
- key = entry.key;
- delete_marker = true;
+ need_to_remove = true;
+ need_to_link = false;
break;
default:
ldout(cct, 0) << "ERROR: apply_olh_log: invalid op: " << (int)entry.op << dendl;
return r;
}
- if (need_to_link) {
+ if (need_to_remove) {
+ op.remove();
+ } else if (need_to_link) {
rgw_obj target(bucket, key.name);
target.set_instance(key.instance);
RGWOLHInfo info;
/* update olh object */
r = ref.ioctx.operate(ref.oid, &op);
+ if (need_to_remove && (r == -ENOENT || r == -ECANCELED)) {
+ r = 0;
+ }
if (r < 0) {
ldout(cct, 0) << "ERROR: could not apply olh update, r=" << r << dendl;
return r;
r = bucket_index_trim_olh_log(state, obj, last_ver);
if (r < 0) {
ldout(cct, 0) << "ERROR: could not trim olh log, r=" << r << dendl;
+ return r;
}
- return r;
+
+ if (need_to_remove) {
+ r = bucket_index_clear_olh(state, obj);
+ if (r < 0) {
+ ldout(cct, 0) << "ERROR: could not clear bucket index olh entries r=" << r << dendl;
+ return r;
+ }
+ }
+
+ return 0;
}
/*
int bucket_index_read_olh_log(RGWObjState& state, rgw_obj& obj_instance, uint64_t ver_marker,
map<uint64_t, vector<rgw_bucket_olh_log_entry> > *log, bool *is_truncated);
int bucket_index_trim_olh_log(RGWObjState& obj_state, rgw_obj& obj_instance, uint64_t ver);
+ int bucket_index_clear_olh(RGWObjState& state, rgw_obj& obj_instance);
int apply_olh_log(RGWObjectCtx& ctx, RGWObjState& obj_state, RGWBucketInfo& bucket_info, rgw_obj& obj,
bufferlist& obj_tag, map<uint64_t, vector<rgw_bucket_olh_log_entry> >& log,
uint64_t *plast_ver);