This code has been disabled since v16.2.8.
Signed-off-by: Nathan Hoad <nhoad@bloomberg.net>
CLS_LOG(10, "INFO: cls_rgw_gc_queue_init: queue size is %lu\n", op.size);
init_op.queue_size = op.size;
- const auto& conf = cls_get_config(hctx);
- init_op.max_urgent_data_size = conf->rgw_gc_max_deferred_entries_size;
+ init_op.max_urgent_data_size = 0;
encode(urgent_data, init_op.bl_urgent_data);
return queue_init(hctx, init_op);
return -ENOSPC;
}
- // Due to Tracker 47866 we are no longer executing this code, as it
- // appears to possibly create a GC entry for an object that has not
- // been deleted. Instead we will log at level 0 to perhaps confirm
- // that when and how often this bug would otherwise be hit.
-#if 0
- cls_queue_enqueue_op enqueue_op;
- bufferlist bl_data;
- encode(op.info, bl_data);
- enqueue_op.bl_data_vec.emplace_back(bl_data);
- CLS_LOG(10, "INFO: cls_gc_update_entry: Data size is: %u \n", bl_data.length());
-
- ret = queue_enqueue(hctx, enqueue_op, head);
- if (ret < 0) {
- return ret;
- }
-#else
std::string first_chain = "<empty-chain>";
if (! op.info.chain.objs.empty()) {
first_chain = op.info.chain.objs.cbegin()->key.name;
"INFO: refrained from enqueueing GC entry during GC defer"
" tag=%s, first_chain=%s\n",
op.info.tag.c_str(), first_chain.c_str());
-#endif
if (has_urgent_data) {
head.bl_urgent_data.clear();
- rgw_gc_processor_max_time
- rgw_gc_max_concurrent_io
with_legacy: true
-- name: rgw_gc_max_deferred_entries_size
- type: uint
- level: advanced
- desc: maximum allowed size of deferred entries in queue head for gc
- default: 3_K
- services:
- - rgw
- with_legacy: true
- name: rgw_gc_max_queue_size
type: uint
level: advanced
desc: Maximum allowed queue size for gc
long_desc: The maximum allowed size of each gc queue, and its value should not be
- greater than (osd_max_object_size - rgw_gc_max_deferred_entries_size - 1K).
- default: 131068_K
+ greater than osd_max_object_size - 1K.
+ default: 134068_K
services:
- rgw
see_also:
- osd_max_object_size
- - rgw_gc_max_deferred_entries_size
- with_legacy: true
-- name: rgw_gc_max_deferred
- type: uint
- level: advanced
- desc: Number of maximum deferred data entries to be stored in queue for gc
- default: 50
- services:
- - rgw
with_legacy: true
- name: rgw_s3_success_create_obj_status
type: int
//version = 1 -> marked ready for transition
librados::ObjectWriteOperation op;
op.create(false);
- const uint64_t queue_size = cct->_conf->rgw_gc_max_queue_size, num_deferred_entries = cct->_conf->rgw_gc_max_deferred;
- gc_log_init2(op, queue_size, num_deferred_entries);
+ const uint64_t queue_size = cct->_conf->rgw_gc_max_queue_size;
+ gc_log_init2(op, queue_size, 0);
store->gc_operate(this, obj_names[i], std::move(op), y);
}
}
return store->gc_operate(this, obj_names[i], std::move(set_entry_op), y);
}
-struct defer_chain_state {
- librados::AioCompletion* completion = nullptr;
- // TODO: hold a reference on the state in RGWGC to avoid use-after-free if
- // RGWGC destructs before this completion fires
- RGWGC* gc = nullptr;
- cls_rgw_gc_obj_info info;
-
- ~defer_chain_state() {
- if (completion) {
- completion->release();
- }
- }
-};
-
-static void async_defer_callback(librados::completion_t, void* arg)
-{
- std::unique_ptr<defer_chain_state> state{static_cast<defer_chain_state*>(arg)};
- if (state->completion->get_return_value() == -ECANCELED) {
- state->gc->on_defer_canceled(state->info);
- }
-}
-
-void RGWGC::on_defer_canceled(const cls_rgw_gc_obj_info& info)
-{
- const std::string& tag = info.tag;
- const int i = tag_index(tag);
-
- // ECANCELED from cls_version_check() tells us that we've transitioned
- transitioned_objects_cache[i] = true;
-
- ObjectWriteOperation op;
- cls_rgw_gc_queue_defer_entry(op, cct->_conf->rgw_gc_obj_min_wait, info);
- cls_rgw_gc_remove(op, {tag});
-
- aio_completion_ptr c{librados::Rados::aio_create_completion(nullptr, nullptr)};
-
- store->gc_aio_operate(obj_names[i], c.get(), &op);
-}
-
-int RGWGC::async_defer_chain(const string& tag, const cls_rgw_obj_chain& chain)
-{
- const int i = tag_index(tag);
- cls_rgw_gc_obj_info info;
- info.chain = chain;
- info.tag = tag;
-
- // if we've transitioned this shard object, we can rely on the cls_rgw_gc queue
- if (transitioned_objects_cache[i]) {
- ObjectWriteOperation op;
- cls_rgw_gc_queue_defer_entry(op, cct->_conf->rgw_gc_obj_min_wait, info);
-
- // this tag may still be present in omap, so remove it once the cls_rgw_gc
- // enqueue succeeds
- cls_rgw_gc_remove(op, {tag});
-
- aio_completion_ptr c{librados::Rados::aio_create_completion(nullptr, nullptr)};
-
- int ret = store->gc_aio_operate(obj_names[i], c.get(), &op);
- return ret;
- }
-
- // if we haven't seen the transition yet, write the defer to omap with cls_rgw
- ObjectWriteOperation op;
-
- // assert that we haven't initialized cls_rgw_gc queue. this prevents us
- // from writing new entries to omap after the transition
- gc_log_defer1(op, cct->_conf->rgw_gc_obj_min_wait, info);
-
- // prepare a callback to detect the transition via ECANCELED from cls_version_check()
- auto state = std::make_unique<defer_chain_state>();
- state->gc = this;
- state->info.chain = chain;
- state->info.tag = tag;
- state->completion = librados::Rados::aio_create_completion(
- state.get(), async_defer_callback);
-
- int ret = store->gc_aio_operate(obj_names[i], state->completion, &op);
- if (ret == 0) {
- // coverity[leaked_storage:SUPPRESS]
- state.release(); // release ownership until async_defer_callback()
- }
- return ret;
-}
-
int RGWGC::remove(int index, const std::vector<string>& tags, AioCompletion **pc, optional_yield y)
{
ObjectWriteOperation op;
std::vector<bool> transitioned_objects_cache;
std::tuple<int, std::optional<cls_rgw_obj_chain>> send_split_chain(const cls_rgw_obj_chain& chain, const std::string& tag, optional_yield y);
- // asynchronously defer garbage collection on an object that's still being read
- int async_defer_chain(const std::string& tag, const cls_rgw_obj_chain& info);
-
- // callback for when async_defer_chain() fails with ECANCELED
- void on_defer_canceled(const cls_rgw_gc_obj_info& info);
-
int remove(int index, const std::vector<std::string>& tags, librados::AioCompletion **pc, optional_yield y);
int remove(int index, int num_entries, optional_yield y);
return 0;
}
-int RGWRados::defer_gc(const DoutPrefixProvider *dpp, RGWObjectCtx* octx, RGWBucketInfo& bucket_info, const rgw_obj& obj, optional_yield y)
-{
- std::string oid, key;
- get_obj_bucket_and_oid_loc(obj, oid, key);
- if (!octx)
- return 0;
-
- RGWObjState *state = NULL;
- RGWObjManifest *manifest = nullptr;
-
- int r = get_obj_state(dpp, octx, bucket_info, obj, &state, &manifest, false, y);
- if (r < 0)
- return r;
-
- if (!state->is_atomic) {
- ldpp_dout(dpp, 20) << "state for obj=" << obj << " is not atomic, not deferring gc operation" << dendl;
- return -EINVAL;
- }
-
- string tag;
-
- if (state->tail_tag.length() > 0) {
- tag = state->tail_tag.c_str();
- } else if (state->obj_tag.length() > 0) {
- tag = state->obj_tag.c_str();
- } else {
- ldpp_dout(dpp, 20) << "state->obj_tag is empty, not deferring gc operation" << dendl;
- return -EINVAL;
- }
-
- ldpp_dout(dpp, 0) << "defer chain tag=" << tag << dendl;
-
- cls_rgw_obj_chain chain;
- update_gc_chain(dpp, state->obj, *manifest, &chain);
- return gc->async_defer_chain(tag, chain);
-}
-
void RGWRados::remove_rgw_head_obj(ObjectWriteOperation& op)
{
list<string> prefixes;
int list_gc_objs(int *index, std::string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue);
int process_gc(bool expired_only, optional_yield y);
bool process_expired_objects(const DoutPrefixProvider *dpp, optional_yield y);
- int defer_gc(const DoutPrefixProvider *dpp, RGWObjectCtx* ctx, RGWBucketInfo& bucket_info, const rgw_obj& obj, optional_yield y);
int process_lc(const std::unique_ptr<rgw::sal::Bucket>& optional_bucket);
ASSERT_EQ("chain-1", it.tag);
}
-#if 0 // TODO: fix or remove defer_gc()
-TEST(cls_rgw_gc, gc_queue_ops3)
-{
- //Testing remove queue entries
- string queue_name = "my-third-queue";
- uint64_t queue_size = 501, num_urgent_data_entries = 10;
- librados::ObjectWriteOperation op;
- op.create(true);
- cls_rgw_gc_queue_init(op, queue_size, num_urgent_data_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &op));
-
- uint64_t size = 0;
- int ret = cls_rgw_gc_queue_get_capacity(ioctx, queue_name, size);
- ASSERT_EQ(0, ret);
- ASSERT_EQ(size, queue_size);
-
- //Test remove queue, when queue is empty
- librados::ObjectWriteOperation remove_op;
- string marker1;
- uint64_t num_entries = 2;
- cls_rgw_gc_queue_remove_entries(remove_op, num_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &remove_op));
-
- cls_rgw_gc_obj_info defer_info;
-
- //Test enqueue
- for (int i = 0; i < 2; i++) {
- string tag = "chain-" + to_string(i);
- librados::ObjectWriteOperation op;
- cls_rgw_gc_obj_info info;
-
- cls_rgw_obj obj1, obj2;
- create_obj(obj1, i, 1);
- create_obj(obj2, i, 2);
- info.chain.objs.push_back(obj1);
- info.chain.objs.push_back(obj2);
-
- info.tag = tag;
- cls_rgw_gc_queue_enqueue(op, 5, info);
- ASSERT_EQ(0, ioctx.operate(queue_name, &op));
- if (i == 0)
- defer_info = info;
- }
-
- //Test defer entry for 1st element
- librados::ObjectWriteOperation defer_op;
- cls_rgw_gc_queue_defer_entry(defer_op, 10, defer_info);
- ASSERT_EQ(0, ioctx.operate(queue_name, &defer_op));
-
- //Test list queue
- list<cls_rgw_gc_obj_info> list_info1, list_info2;
- string marker, next_marker;
- uint64_t max = 2;
- bool expired_only = false, truncated;
- cls_rgw_gc_queue_list_entries(ioctx, queue_name, marker, max, expired_only, list_info1, &truncated, next_marker);
- ASSERT_EQ(2, list_info1.size());
-
- int i = 0;
- for (auto it : list_info1) {
- std::cerr << "[ ] list info tag = " << it.tag << std::endl;
- if (i == 0) {
- ASSERT_EQ("chain-1", it.tag);
- }
- if (i == 1) {
- ASSERT_EQ("chain-0", it.tag);
- }
- i++;
- }
-
- //Test remove entries
- num_entries = 2;
- cls_rgw_gc_queue_remove_entries(remove_op, num_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &remove_op));
-
- //Test list queue again
- cls_rgw_gc_queue_list_entries(ioctx, queue_name, marker, max, expired_only, list_info2, &truncated, next_marker);
- ASSERT_EQ(0, list_info2.size());
-
-}
-
-TEST(cls_rgw_gc, gc_queue_ops4)
-{
- //Testing remove queue entries
- string queue_name = "my-fourth-queue";
- uint64_t queue_size = 501, num_urgent_data_entries = 10;
- librados::ObjectWriteOperation op;
- op.create(true);
- cls_rgw_gc_queue_init(op, queue_size, num_urgent_data_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &op));
-
- uint64_t size = 0;
- int ret = cls_rgw_gc_queue_get_capacity(ioctx, queue_name, size);
- ASSERT_EQ(0, ret);
- ASSERT_EQ(size, queue_size);
-
- //Test remove queue, when queue is empty
- librados::ObjectWriteOperation remove_op;
- string marker1;
- uint64_t num_entries = 2;
-
- cls_rgw_gc_queue_remove_entries(remove_op, num_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &remove_op));
-
- cls_rgw_gc_obj_info defer_info;
-
- //Test enqueue
- for (int i = 0; i < 2; i++) {
- string tag = "chain-" + to_string(i);
- librados::ObjectWriteOperation op;
- cls_rgw_gc_obj_info info;
-
- cls_rgw_obj obj1, obj2;
- create_obj(obj1, i, 1);
- create_obj(obj2, i, 2);
- info.chain.objs.push_back(obj1);
- info.chain.objs.push_back(obj2);
-
- info.tag = tag;
- cls_rgw_gc_queue_enqueue(op, 5, info);
- ASSERT_EQ(0, ioctx.operate(queue_name, &op));
- defer_info = info;
- }
-
- //Test defer entry for last element
- librados::ObjectWriteOperation defer_op;
- cls_rgw_gc_queue_defer_entry(defer_op, 10, defer_info);
- ASSERT_EQ(0, ioctx.operate(queue_name, &defer_op));
-
- //Test list queue
- list<cls_rgw_gc_obj_info> list_info1, list_info2;
- string marker, next_marker;
- uint64_t max = 2;
- bool expired_only = false, truncated;
- cls_rgw_gc_queue_list_entries(ioctx, queue_name, marker, max, expired_only, list_info1, &truncated, next_marker);
- ASSERT_EQ(2, list_info1.size());
-
- int i = 0;
- for (auto it : list_info1) {
- string tag = "chain-" + to_string(i);
- ASSERT_EQ(tag, it.tag);
- i++;
- }
-
- //Test remove entries
- num_entries = 2;
- cls_rgw_gc_queue_remove_entries(remove_op, num_entries);
- ASSERT_EQ(0, ioctx.operate(queue_name, &remove_op));
-
- //Test list queue again
- cls_rgw_gc_queue_list_entries(ioctx, queue_name, marker, max, expired_only, list_info2, &truncated, next_marker);
- ASSERT_EQ(0, list_info2.size());
-
-}
-#endif // defer_gc() disabled
-
TEST(cls_rgw_gc, gc_queue_ops5)
{
//Testing remove queue entries