1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "include/rados/librados.hpp"
6 #include "cls/rgw/cls_rgw_client.h"
7 #include "cls/refcount/cls_refcount_client.h"
8 #include "cls/lock/cls_lock_client.h"
9 #include "auth/Crypto.h"
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rgw
17 using namespace librados;
19 static string gc_oid_prefix = "gc";
20 static string gc_index_lock_name = "gc_process";
23 void RGWGC::initialize(CephContext *_cct, RGWRados *_store) {
27 max_objs = min(static_cast<int>(cct->_conf->rgw_gc_max_objs), rgw_shards_max());
29 obj_names = new string[max_objs];
31 for (int i = 0; i < max_objs; i++) {
32 obj_names[i] = gc_oid_prefix;
34 snprintf(buf, 32, ".%d", i);
35 obj_names[i].append(buf);
39 void RGWGC::finalize()
44 int RGWGC::tag_index(const string& tag)
46 return rgw_shards_hash(tag, max_objs);
49 void RGWGC::add_chain(ObjectWriteOperation& op, cls_rgw_obj_chain& chain, const string& tag)
51 cls_rgw_gc_obj_info info;
55 cls_rgw_gc_set_entry(op, cct->_conf->rgw_gc_obj_min_wait, info);
58 int RGWGC::send_chain(cls_rgw_obj_chain& chain, const string& tag, bool sync)
60 ObjectWriteOperation op;
61 add_chain(op, chain, tag);
63 int i = tag_index(tag);
66 return store->gc_operate(obj_names[i], &op);
68 return store->gc_aio_operate(obj_names[i], &op);
71 int RGWGC::defer_chain(const string& tag, bool sync)
73 ObjectWriteOperation op;
74 cls_rgw_gc_defer_entry(op, cct->_conf->rgw_gc_obj_min_wait, tag);
76 int i = tag_index(tag);
79 return store->gc_operate(obj_names[i], &op);
81 return store->gc_aio_operate(obj_names[i], &op);
84 int RGWGC::remove(int index, const std::list<string>& tags)
86 ObjectWriteOperation op;
87 cls_rgw_gc_remove(op, tags);
88 return store->gc_operate(obj_names[index], &op);
91 int RGWGC::list(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated)
96 for (; *index < max_objs && result.size() < max; (*index)++, marker.clear()) {
97 std::list<cls_rgw_gc_obj_info> entries;
98 int ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[*index], marker, max - result.size(), expired_only, entries, truncated, next_marker);
104 std::list<cls_rgw_gc_obj_info>::iterator iter;
105 for (iter = entries.begin(); iter != entries.end(); ++iter) {
106 result.push_back(*iter);
109 marker = next_marker;
111 if (*index == max_objs - 1) {
112 /* we cut short here, truncated will hold the correct value */
116 if (result.size() == max) {
117 /* close approximation, it might be that the next of the objects don't hold
118 * anything, in this case truncated should have been false, but we can find
119 * that out on the next iteration
131 int RGWGC::process(int index, int max_secs)
133 rados::cls::lock::Lock l(gc_index_lock_name);
134 utime_t end = ceph_clock_now();
135 std::list<string> remove_tags;
137 /* max_secs should be greater than zero. We don't want a zero max_secs
138 * to be translated as no timeout, since we'd then need to break the
139 * lock and that would require a manual intervention. In this case
140 * we can just wait it out. */
145 utime_t time(max_secs, 0);
146 l.set_duration(time);
148 int ret = l.lock_exclusive(&store->gc_pool_ctx, obj_names[index]);
149 if (ret == -EBUSY) { /* already locked by another gc processor */
150 dout(10) << "RGWGC::process() failed to acquire lock on " << obj_names[index] << dendl;
159 IoCtx *ctx = new IoCtx;
162 std::list<cls_rgw_gc_obj_info> entries;
163 ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[index], marker, max, true, entries, &truncated, next_marker);
164 if (ret == -ENOENT) {
172 std::list<cls_rgw_gc_obj_info>::iterator iter;
173 for (iter = entries.begin(); iter != entries.end(); ++iter) {
175 cls_rgw_gc_obj_info& info = *iter;
176 std::list<cls_rgw_obj>::iterator liter;
177 cls_rgw_obj_chain& chain = info.chain;
179 utime_t now = ceph_clock_now();
184 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
185 cls_rgw_obj& obj = *liter;
187 if (obj.pool != last_pool) {
190 ret = rgw_init_ioctx(store->get_rados_handle(), obj.pool, *ctx);
192 dout(0) << "ERROR: failed to create ioctx pool=" << obj.pool << dendl;
195 last_pool = obj.pool;
198 ctx->locator_set_key(obj.loc);
200 const string& oid = obj.key.name; /* just stored raw oid there */
202 dout(5) << "gc::process: removing " << obj.pool << ":" << obj.key.name << dendl;
203 ObjectWriteOperation op;
204 cls_refcount_put(op, info.tag, true);
205 ret = ctx->operate(oid, &op);
210 dout(0) << "failed to remove " << obj.pool << ":" << oid << "@" << obj.loc << dendl;
213 if (going_down()) // leave early, even if tag isn't removed, it's ok
217 remove_tags.push_back(info.tag);
218 #define MAX_REMOVE_CHUNK 16
219 if (remove_tags.size() > MAX_REMOVE_CHUNK) {
220 RGWGC::remove(index, remove_tags);
225 if (!remove_tags.empty()) {
226 RGWGC::remove(index, remove_tags);
232 if (!remove_tags.empty())
233 RGWGC::remove(index, remove_tags);
234 l.unlock(&store->gc_pool_ctx, obj_names[index]);
241 int max_secs = cct->_conf->rgw_gc_processor_max_time;
244 int ret = get_random_bytes((char *)&start, sizeof(start));
248 for (int i = 0; i < max_objs; i++) {
249 int index = (i + start) % max_objs;
250 ret = process(index, max_secs);
258 bool RGWGC::going_down()
263 void RGWGC::start_processor()
265 worker = new GCWorker(cct, this);
266 worker->create("rgw_gc");
269 void RGWGC::stop_processor()
280 void *RGWGC::GCWorker::entry() {
282 utime_t start = ceph_clock_now();
283 dout(2) << "garbage collection: start" << dendl;
284 int r = gc->process();
286 dout(0) << "ERROR: garbage collection process() returned error r=" << r << dendl;
288 dout(2) << "garbage collection: stop" << dendl;
290 if (gc->going_down())
293 utime_t end = ceph_clock_now();
295 int secs = cct->_conf->rgw_gc_processor_period;
297 if (secs <= end.sec())
298 continue; // next round
303 cond.WaitInterval(lock, utime_t(secs, 0));
305 } while (!gc->going_down());
310 void RGWGC::GCWorker::stop()
312 Mutex::Locker l(lock);