This allows operators to do targeted GC work against specific shards, instead of working on all of them.
Signed-off-by: Nathan Hoad <nhoad@bloomberg.net>
AI-Assisted: Used AI to generate the initial implementation.
.. option:: --shard-id=<shard-id>
- Optional for mdlog list, bi list, data sync status. Required for ``mdlog trim``.
+ Optional for mdlog list, bi list, data sync status, gc list, gc process. Required for ``mdlog trim``.
.. option:: --max-entries=<entries>
return cls_rgw_gc_list_decode(bl, entries, truncated, next_marker);
}
-int RGWGC::list(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue)
+int RGWGC::list(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue, std::optional<int> shard_id)
{
result.clear();
string next_marker;
bool check_queue = false;
- for (; *index < max_objs && result.size() < max; (*index)++, marker.clear(), check_queue = false) {
+ int max_index = shard_id.has_value() ? (shard_id.value() + 1) : max_objs;
+ if (shard_id.has_value()) {
+ *index = shard_id.value();
+ }
+
+ for (; *index < max_index && result.size() < max; (*index)++, marker.clear(), check_queue = false) {
std::list<cls_rgw_gc_obj_info> entries, queue_entries;
int ret = 0;
marker = next_marker;
- if (*index == max_objs - 1) {
+ if (*index == max_index - 1) {
if (queue_entries.size() > 0 && *truncated) {
processing_queue = true;
} else {
return 0;
}
-int RGWGC::process(bool expired_only, optional_yield y)
+int RGWGC::process(bool expired_only, optional_yield y, std::optional<int> shard_id)
{
int max_secs = cct->_conf->rgw_gc_processor_max_time;
- const int start = ceph::util::generate_random_number(0, max_objs - 1);
-
RGWGCIOManager io_manager(this, store->ctx(), this);
- for (int i = 0; i < max_objs; i++) {
- int index = (i + start) % max_objs;
- int ret = process(index, max_secs, expired_only, io_manager, y);
+ if (shard_id.has_value()) {
+ // Process only the specified shard
+ int ret = process(shard_id.value(), max_secs, expired_only, io_manager, y);
if (ret < 0)
return ret;
+ } else {
+ // Process all shards with random start
+ const int start = ceph::util::generate_random_number(0, max_objs - 1);
+ for (int i = 0; i < max_objs; i++) {
+ int index = (i + start) % max_objs;
+ int ret = process(index, max_secs, expired_only, io_manager, y);
+ if (ret < 0)
+ return ret;
+ }
}
if (!going_down()) {
io_manager.drain();
void initialize(CephContext *_cct, RGWRados *_store, optional_yield y);
void finalize();
- int list(int *index, std::string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue);
- void list_init(int *index) { *index = 0; }
+ int list(int *index, std::string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue, std::optional<int> shard_id = std::nullopt);
int process(int index, int process_max_secs, bool expired_only,
RGWGCIOManager& io_manager, optional_yield y);
- int process(bool expired_only, optional_yield y);
+ int process(bool expired_only, optional_yield y, std::optional<int> shard_id = std::nullopt);
bool going_down();
void start_processor();
return rgw_rados_operate(dpp, gc_pool_ctx, oid, std::move(op), pbl, y);
}
-int RGWRados::list_gc_objs(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue)
+int RGWRados::list_gc_objs(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated, bool& processing_queue, std::optional<int> shard_id)
{
- return gc->list(index, marker, max, expired_only, result, truncated, processing_queue);
+ return gc->list(index, marker, max, expired_only, result, truncated, processing_queue, shard_id);
}
-int RGWRados::process_gc(bool expired_only, optional_yield y)
+int RGWRados::process_gc(bool expired_only, optional_yield y, std::optional<int> shard_id)
{
- return gc->process(expired_only, y);
+ return gc->process(expired_only, y, shard_id);
}
int RGWRados::process_lc(const std::unique_ptr<rgw::sal::Bucket>& optional_bucket)
librados::ObjectWriteOperation *op);
int gc_operate(const DoutPrefixProvider *dpp, std::string& oid, librados::ObjectReadOperation&& op, bufferlist *pbl, optional_yield y);
- 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);
+ 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, std::optional<int> shard_id = std::nullopt);
+ int process_gc(bool expired_only, optional_yield y, std::optional<int> shard_id = std::nullopt);
bool process_expired_objects(const DoutPrefixProvider *dpp, optional_yield y);
int process_lc(const std::unique_ptr<rgw::sal::Bucket>& optional_bucket);
cout << " mdlog list\n";
cout << " data sync status\n";
cout << " sync error trim\n";
+ cout << " gc list\n";
+ cout << " gc process\n";
cout << " required for:\n";
cout << " mdlog trim\n";
cout << " --gen=<gen-id> optional for:\n";
}
if (opt_cmd == OPT::GC_LIST) {
+ if (specified_shard_id) {
+ int max_gc_shards = min(static_cast<int>(g_ceph_context->_conf->rgw_gc_max_objs), rgw_shards_max());
+ if (shard_id < 0 || shard_id >= max_gc_shards) {
+ cerr << "ERROR: shard-id must be in the range [0, " << max_gc_shards - 1 << "]" << std::endl;
+ return EINVAL;
+ }
+ }
+
int index = 0;
bool truncated;
bool processing_queue = false;
formatter->open_array_section("entries");
+ std::optional<int> gc_shard_id = specified_shard_id ? std::optional<int>(shard_id) : std::nullopt;
+
do {
list<cls_rgw_gc_obj_info> result;
- int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue);
+ int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue, gc_shard_id);
if (ret < 0) {
cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
return 1;
}
if (opt_cmd == OPT::GC_PROCESS) {
+ if (specified_shard_id) {
+ int max_gc_shards = min(static_cast<int>(g_ceph_context->_conf->rgw_gc_max_objs), rgw_shards_max());
+ if (shard_id < 0 || shard_id >= max_gc_shards) {
+ cerr << "ERROR: shard-id must be in the range [0, " << max_gc_shards - 1 << "]" << std::endl;
+ return EINVAL;
+ }
+ }
+
rgw::sal::RadosStore* rados_store = dynamic_cast<rgw::sal::RadosStore*>(driver);
if (!rados_store) {
cerr <<
}
RGWRados* store = rados_store->getRados();
- int ret = store->process_gc(!include_all, null_yield);
+ std::optional<int> gc_shard_id = specified_shard_id ? std::optional<int>(shard_id) : std::nullopt;
+ int ret = store->process_gc(!include_all, null_yield, gc_shard_id);
if (ret < 0) {
cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
return 1;
mdlog list
data sync status
sync error trim
+ gc list
+ gc process
required for:
mdlog trim
--gen=<gen-id> optional for: