From 26f22d220a2c37e5030aca24ee0e438a9b47c765 Mon Sep 17 00:00:00 2001 From: "J. Eric Ivancich" Date: Thu, 14 Feb 2019 20:30:46 -0500 Subject: [PATCH] rgw: resolve bugs and clean up garbage collection code Does a number of things to clean up rgw gc code: * adds additional logging to make future debugging easier. * resolves bug where the truncated flag was not always set correctly in gc_iterate_entries * resolves bug where marker in RGWGC::process was not advanced * resolves bug in which gc entries with a zero-length chain were not trimmed * resolves bug where same gc entry tag was added to list for deletion multiple times Fixes: http://tracker.ceph.com/issues/38454 Signed-off-by: J. Eric Ivancich (cherry picked from commit 73d7d36) Conflicts: src/rgw/rgw_gc.cc dout() vs ldpp_dout() Note: This was a clean cherry-pick from Mimic, which already resolved dout() vs ldpp_dout() conficts. Signed-off-by: Dan Hill (cherry picked from commit a598ccce2e) --- src/cls/rgw/cls_rgw.cc | 66 ++++++++++++----- src/common/options.cc | 4 +- src/rgw/rgw_gc.cc | 162 +++++++++++++++++++++++++++++------------ 3 files changed, 164 insertions(+), 68 deletions(-) diff --git a/src/cls/rgw/cls_rgw.cc b/src/cls/rgw/cls_rgw.cc index f56c7f55a5961..9f0b1e3243ab2 100644 --- a/src/cls/rgw/cls_rgw.cc +++ b/src/cls/rgw/cls_rgw.cc @@ -3212,23 +3212,36 @@ static int gc_update_entry(cls_method_context_t hctx, uint32_t expiration_secs, return ret; } } + + // calculate time and time key info.time = ceph::real_clock::now(); info.time += make_timespan(expiration_secs); + string time_key; + get_time_key(info.time, &time_key); + + if (info.chain.objs.empty()) { + CLS_LOG(0, + "WARNING: %s setting GC log entry with zero-length chain, " + "tag='%s', timekey='%s'", + __func__, info.tag.c_str(), time_key.c_str()); + } + ret = gc_omap_set(hctx, GC_OBJ_NAME_INDEX, info.tag, &info); if (ret < 0) return ret; - string key; - get_time_key(info.time, &key); - ret = gc_omap_set(hctx, GC_OBJ_TIME_INDEX, key, &info); + ret = gc_omap_set(hctx, GC_OBJ_TIME_INDEX, time_key, &info); if (ret < 0) goto done_err; return 0; done_err: - CLS_LOG(0, "ERROR: gc_set_entry error info.tag=%s, ret=%d\n", info.tag.c_str(), ret); + + CLS_LOG(0, "ERROR: gc_set_entry error info.tag=%s, ret=%d\n", + info.tag.c_str(), ret); gc_omap_remove(hctx, GC_OBJ_NAME_INDEX, info.tag); + return ret; } @@ -3285,16 +3298,22 @@ static int rgw_cls_gc_defer_entry(cls_method_context_t hctx, bufferlist *in, buf return gc_defer_entry(hctx, op.tag, op.expiration_secs); } -static int gc_iterate_entries(cls_method_context_t hctx, const string& marker, bool expired_only, - string& key_iter, uint32_t max_entries, bool *truncated, - int (*cb)(cls_method_context_t, const string&, cls_rgw_gc_obj_info&, void *), +static int gc_iterate_entries(cls_method_context_t hctx, + const string& marker, + bool expired_only, + string& out_marker, + uint32_t max_entries, + bool *truncated, + int (*cb)(cls_method_context_t, + const string&, + cls_rgw_gc_obj_info&, + void *), void *param) { - CLS_LOG(10, "gc_iterate_range"); + CLS_LOG(10, "gc_iterate_entries"); map keys; string filter_prefix, end_key; - uint32_t i = 0; string key; if (truncated) @@ -3318,18 +3337,20 @@ static int gc_iterate_entries(cls_method_context_t hctx, const string& marker, b string filter; - int ret = cls_cxx_map_get_vals(hctx, start_key, filter, max_entries, &keys, truncated); + int ret = cls_cxx_map_get_vals(hctx, start_key, filter, max_entries, + &keys, truncated); if (ret < 0) return ret; - map::iterator iter = keys.begin(); - if (iter == keys.end()) + if (iter == keys.end()) { + // if keys empty must not come back as truncated + ceph_assert(!truncated || !(*truncated)); return 0; + } - uint32_t num_keys = keys.size(); - - for (; iter != keys.end(); ++iter, ++i) { + const string* last_key = nullptr; // last key processed, for end-marker + for (; iter != keys.end(); ++iter) { const string& key = iter->first; cls_rgw_gc_obj_info e; @@ -3341,8 +3362,11 @@ static int gc_iterate_entries(cls_method_context_t hctx, const string& marker, b return 0; } - if (!key_in_index(key, GC_OBJ_TIME_INDEX)) + if (!key_in_index(key, GC_OBJ_TIME_INDEX)) { + if (truncated) + *truncated = false; return 0; + } ret = gc_record_decode(iter->second, e); if (ret < 0) @@ -3351,10 +3375,14 @@ static int gc_iterate_entries(cls_method_context_t hctx, const string& marker, b ret = cb(hctx, key, e, param); if (ret < 0) return ret; + last_key = &(iter->first); // update when callback successful + } - if (i == num_keys - 1) { - key_iter = key; - } + // set the out marker if either caller does not capture truncated or + // if they do capture and we are truncated + if (!truncated || *truncated) { + assert(last_key); + out_marker = *last_key; } return 0; diff --git a/src/common/options.cc b/src/common/options.cc index 527d08f93e167..1911f40ef1dac 100644 --- a/src/common/options.cc +++ b/src/common/options.cc @@ -5205,7 +5205,7 @@ std::vector