From: Nathan Hoad Date: Thu, 23 Apr 2026 18:03:24 +0000 (-0400) Subject: rgw: Remove GC deferred entries options and code. X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b40ee54935550c77dd28f0a77b9f80881cb64286;p=ceph.git rgw: Remove GC deferred entries options and code. This code has been disabled since v16.2.8. Signed-off-by: Nathan Hoad --- diff --git a/src/cls/rgw_gc/cls_rgw_gc.cc b/src/cls/rgw_gc/cls_rgw_gc.cc index ecaba00cacfd..60d6d2dedbb2 100644 --- a/src/cls/rgw_gc/cls_rgw_gc.cc +++ b/src/cls/rgw_gc/cls_rgw_gc.cc @@ -47,8 +47,7 @@ static int cls_rgw_gc_queue_init(cls_method_context_t hctx, bufferlist *in, buff 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); @@ -497,22 +496,6 @@ static int cls_rgw_gc_queue_update_entry(cls_method_context_t hctx, bufferlist * 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 = ""; if (! op.info.chain.objs.empty()) { first_chain = op.info.chain.objs.cbegin()->key.name; @@ -521,7 +504,6 @@ static int cls_rgw_gc_queue_update_entry(cls_method_context_t hctx, bufferlist * "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(); diff --git a/src/common/options/rgw.yaml.in b/src/common/options/rgw.yaml.in index 57000c5154b5..b52d85d758a4 100644 --- a/src/common/options/rgw.yaml.in +++ b/src/common/options/rgw.yaml.in @@ -1962,34 +1962,17 @@ options: - 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 diff --git a/src/rgw/driver/rados/rgw_gc.cc b/src/rgw/driver/rados/rgw_gc.cc index 8a9e464f1dd5..de52f29936d6 100644 --- a/src/rgw/driver/rados/rgw_gc.cc +++ b/src/rgw/driver/rados/rgw_gc.cc @@ -50,8 +50,8 @@ void RGWGC::initialize(CephContext *_cct, RGWRados *_store, optional_yield y) { //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); } } @@ -139,90 +139,6 @@ int RGWGC::send_chain(const cls_rgw_obj_chain& chain, const string& tag, optiona 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 state{static_cast(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(); - 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& tags, AioCompletion **pc, optional_yield y) { ObjectWriteOperation op; diff --git a/src/rgw/driver/rados/rgw_gc.h b/src/rgw/driver/rados/rgw_gc.h index b7a118204271..57fc084b63bd 100644 --- a/src/rgw/driver/rados/rgw_gc.h +++ b/src/rgw/driver/rados/rgw_gc.h @@ -52,12 +52,6 @@ public: std::vector transitioned_objects_cache; std::tuple> 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& tags, librados::AioCompletion **pc, optional_yield y); int remove(int index, int num_entries, optional_yield y); diff --git a/src/rgw/driver/rados/rgw_rados.cc b/src/rgw/driver/rados/rgw_rados.cc index c495903d9041..2a8127a8817e 100644 --- a/src/rgw/driver/rados/rgw_rados.cc +++ b/src/rgw/driver/rados/rgw_rados.cc @@ -6449,43 +6449,6 @@ int RGWRados::bucket_resync_encrypted_multipart(const DoutPrefixProvider* dpp, 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 prefixes; diff --git a/src/rgw/driver/rados/rgw_rados.h b/src/rgw/driver/rados/rgw_rados.h index d8fe665fcf3e..d1b619336067 100644 --- a/src/rgw/driver/rados/rgw_rados.h +++ b/src/rgw/driver/rados/rgw_rados.h @@ -1630,7 +1630,6 @@ public: int list_gc_objs(int *index, std::string& marker, uint32_t max, bool expired_only, std::list& 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& optional_bucket); diff --git a/src/test/cls_rgw_gc/test_cls_rgw_gc.cc b/src/test/cls_rgw_gc/test_cls_rgw_gc.cc index 6014542a324c..44cc464ffd08 100644 --- a/src/test/cls_rgw_gc/test_cls_rgw_gc.cc +++ b/src/test/cls_rgw_gc/test_cls_rgw_gc.cc @@ -207,161 +207,6 @@ TEST(cls_rgw_gc, gc_queue_ops2) 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 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 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