Skip to content
Permalink
Browse files

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 <ivancich@redhat.com>
(cherry picked from commit 73d7d36)

Conflicts:
	src/rgw/rgw_gc.cc dout() vs ldpp_dout()
  • Loading branch information...
ivancich authored and cbodley committed Feb 15, 2019
1 parent e6d1c63 commit a598ccce2e6863a00500504532ce15a022649520
Showing with 164 additions and 68 deletions.
  1. +47 −19 src/cls/rgw/cls_rgw.cc
  2. +2 −2 src/common/options.cc
  3. +115 −47 src/rgw/rgw_gc.cc
@@ -3221,23 +3221,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;
}

@@ -3294,16 +3307,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<string, bufferlist> keys;
string filter_prefix, end_key;
uint32_t i = 0;
string key;

if (truncated)
@@ -3327,18 +3346,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<string, bufferlist>::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;

@@ -3350,8 +3371,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)
@@ -3360,10 +3384,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;
@@ -5682,7 +5682,7 @@ std::vector<Option> get_rgw_options() {

Option("rgw_gc_obj_min_wait", Option::TYPE_INT, Option::LEVEL_ADVANCED)
.set_default(2_hr)
.set_description("Garabge collection object expiration time")
.set_description("Garbage collection object expiration time")
.set_long_description(
"The length of time (in seconds) that the RGW collector will wait before purging "
"a deleted object's data. RGW will not remove object immediately, as object could "
@@ -5697,7 +5697,7 @@ std::vector<Option> get_rgw_options() {
"Garbage collection thread in RGW process holds a lease on its data shards. These "
"objects contain the information about the objects that need to be removed. RGW "
"takes a lease in order to prevent multiple RGW processes from handling the same "
"objects concurrently. This time signifies that maximum amount of time that RGW "
"objects concurrently. This time signifies that maximum amount of time (in seconds) that RGW "
"is allowed to hold that lease. In the case where RGW goes down uncleanly, this "
"is the amount of time where processing of that data shard will be blocked.")
.add_see_also({"rgw_gc_max_objs", "rgw_gc_obj_min_wait", "rgw_gc_processor_period", "rgw_gc_max_concurrent_io"}),

0 comments on commit a598ccc

Please sign in to comment.
You can’t perform that action at this time.