]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_gc.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rgw / rgw_gc.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "rgw_gc.h"
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"
10
11 #include <list>
12
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rgw
15
16 using namespace std;
17 using namespace librados;
18
19 static string gc_oid_prefix = "gc";
20 static string gc_index_lock_name = "gc_process";
21
22
23 #define HASH_PRIME 7877
24
25 void RGWGC::initialize(CephContext *_cct, RGWRados *_store) {
26 cct = _cct;
27 store = _store;
28
29 max_objs = cct->_conf->rgw_gc_max_objs;
30 if (max_objs > HASH_PRIME)
31 max_objs = HASH_PRIME;
32
33 obj_names = new string[max_objs];
34
35 for (int i = 0; i < max_objs; i++) {
36 obj_names[i] = gc_oid_prefix;
37 char buf[32];
38 snprintf(buf, 32, ".%d", i);
39 obj_names[i].append(buf);
40 }
41 }
42
43 void RGWGC::finalize()
44 {
45 delete[] obj_names;
46 }
47
48 int RGWGC::tag_index(const string& tag)
49 {
50 return ceph_str_hash_linux(tag.c_str(), tag.size()) % HASH_PRIME % max_objs;
51 }
52
53 void RGWGC::add_chain(ObjectWriteOperation& op, cls_rgw_obj_chain& chain, const string& tag)
54 {
55 cls_rgw_gc_obj_info info;
56 info.chain = chain;
57 info.tag = tag;
58
59 cls_rgw_gc_set_entry(op, cct->_conf->rgw_gc_obj_min_wait, info);
60 }
61
62 int RGWGC::send_chain(cls_rgw_obj_chain& chain, const string& tag, bool sync)
63 {
64 ObjectWriteOperation op;
65 add_chain(op, chain, tag);
66
67 int i = tag_index(tag);
68
69 if (sync)
70 return store->gc_operate(obj_names[i], &op);
71
72 return store->gc_aio_operate(obj_names[i], &op);
73 }
74
75 int RGWGC::defer_chain(const string& tag, bool sync)
76 {
77 ObjectWriteOperation op;
78 cls_rgw_gc_defer_entry(op, cct->_conf->rgw_gc_obj_min_wait, tag);
79
80 int i = tag_index(tag);
81
82 if (sync)
83 return store->gc_operate(obj_names[i], &op);
84
85 return store->gc_aio_operate(obj_names[i], &op);
86 }
87
88 int RGWGC::remove(int index, const std::list<string>& tags)
89 {
90 ObjectWriteOperation op;
91 cls_rgw_gc_remove(op, tags);
92 return store->gc_operate(obj_names[index], &op);
93 }
94
95 int RGWGC::list(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated)
96 {
97 result.clear();
98
99 for (; *index < max_objs && result.size() < max; (*index)++, marker.clear()) {
100 std::list<cls_rgw_gc_obj_info> entries;
101 int ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[*index], marker, max - result.size(), expired_only, entries, truncated);
102 if (ret == -ENOENT)
103 continue;
104 if (ret < 0)
105 return ret;
106
107 std::list<cls_rgw_gc_obj_info>::iterator iter;
108 for (iter = entries.begin(); iter != entries.end(); ++iter) {
109 result.push_back(*iter);
110 }
111
112 if (*index == max_objs - 1) {
113 /* we cut short here, truncated will hold the correct value */
114 return 0;
115 }
116
117 if (result.size() == max) {
118 /* close approximation, it might be that the next of the objects don't hold
119 * anything, in this case truncated should have been false, but we can find
120 * that out on the next iteration
121 */
122 *truncated = true;
123 return 0;
124 }
125
126 }
127 *truncated = false;
128
129 return 0;
130 }
131
132 int RGWGC::process(int index, int max_secs)
133 {
134 rados::cls::lock::Lock l(gc_index_lock_name);
135 utime_t end = ceph_clock_now();
136 std::list<string> remove_tags;
137
138 /* max_secs should be greater than zero. We don't want a zero max_secs
139 * to be translated as no timeout, since we'd then need to break the
140 * lock and that would require a manual intervention. In this case
141 * we can just wait it out. */
142 if (max_secs <= 0)
143 return -EAGAIN;
144
145 end += max_secs;
146 utime_t time(max_secs, 0);
147 l.set_duration(time);
148
149 int ret = l.lock_exclusive(&store->gc_pool_ctx, obj_names[index]);
150 if (ret == -EBUSY) { /* already locked by another gc processor */
151 dout(0) << "RGWGC::process() failed to acquire lock on " << obj_names[index] << dendl;
152 return 0;
153 }
154 if (ret < 0)
155 return ret;
156
157 string marker;
158 bool truncated;
159 IoCtx *ctx = new IoCtx;
160 do {
161 int max = 100;
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);
164 if (ret == -ENOENT) {
165 ret = 0;
166 goto done;
167 }
168 if (ret < 0)
169 goto done;
170
171 string last_pool;
172 std::list<cls_rgw_gc_obj_info>::iterator iter;
173 for (iter = entries.begin(); iter != entries.end(); ++iter) {
174 bool remove_tag;
175 cls_rgw_gc_obj_info& info = *iter;
176 std::list<cls_rgw_obj>::iterator liter;
177 cls_rgw_obj_chain& chain = info.chain;
178
179 utime_t now = ceph_clock_now();
180 if (now >= end)
181 goto done;
182
183 remove_tag = true;
184 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
185 cls_rgw_obj& obj = *liter;
186
187 if (obj.pool != last_pool) {
188 delete ctx;
189 ctx = new IoCtx;
190 ret = rgw_init_ioctx(store->get_rados_handle(), obj.pool, *ctx);
191 if (ret < 0) {
192 dout(0) << "ERROR: failed to create ioctx pool=" << obj.pool << dendl;
193 continue;
194 }
195 last_pool = obj.pool;
196 }
197
198 ctx->locator_set_key(obj.loc);
199
200 const string& oid = obj.key.name; /* just stored raw oid there */
201
202 dout(0) << "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);
206 if (ret == -ENOENT)
207 ret = 0;
208 if (ret < 0) {
209 remove_tag = false;
210 dout(0) << "failed to remove " << obj.pool << ":" << oid << "@" << obj.loc << dendl;
211 }
212
213 if (going_down()) // leave early, even if tag isn't removed, it's ok
214 goto done;
215 }
216 if (remove_tag) {
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);
221 remove_tags.clear();
222 }
223 }
224 }
225 } while (truncated);
226
227 done:
228 if (!remove_tags.empty())
229 RGWGC::remove(index, remove_tags);
230 l.unlock(&store->gc_pool_ctx, obj_names[index]);
231 delete ctx;
232 return 0;
233 }
234
235 int RGWGC::process()
236 {
237 int max_secs = cct->_conf->rgw_gc_processor_max_time;
238
239 unsigned start;
240 int ret = get_random_bytes((char *)&start, sizeof(start));
241 if (ret < 0)
242 return ret;
243
244 for (int i = 0; i < max_objs; i++) {
245 int index = (i + start) % max_objs;
246 ret = process(index, max_secs);
247 if (ret < 0)
248 return ret;
249 }
250
251 return 0;
252 }
253
254 bool RGWGC::going_down()
255 {
256 return down_flag;
257 }
258
259 void RGWGC::start_processor()
260 {
261 worker = new GCWorker(cct, this);
262 worker->create("rgw_gc");
263 }
264
265 void RGWGC::stop_processor()
266 {
267 down_flag = true;
268 if (worker) {
269 worker->stop();
270 worker->join();
271 }
272 delete worker;
273 worker = NULL;
274 }
275
276 void *RGWGC::GCWorker::entry() {
277 do {
278 utime_t start = ceph_clock_now();
279 dout(2) << "garbage collection: start" << dendl;
280 int r = gc->process();
281 if (r < 0) {
282 dout(0) << "ERROR: garbage collection process() returned error r=" << r << dendl;
283 }
284 dout(2) << "garbage collection: stop" << dendl;
285
286 if (gc->going_down())
287 break;
288
289 utime_t end = ceph_clock_now();
290 end -= start;
291 int secs = cct->_conf->rgw_gc_processor_period;
292
293 if (secs <= end.sec())
294 continue; // next round
295
296 secs -= end.sec();
297
298 lock.Lock();
299 cond.WaitInterval(lock, utime_t(secs, 0));
300 lock.Unlock();
301 } while (!gc->going_down());
302
303 return NULL;
304 }
305
306 void RGWGC::GCWorker::stop()
307 {
308 Mutex::Locker l(lock);
309 cond.Signal();
310 }
311