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(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
);