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 #define HASH_PRIME 7877
25 void RGWGC::initialize(CephContext
*_cct
, RGWRados
*_store
) {
29 max_objs
= cct
->_conf
->rgw_gc_max_objs
;
30 if (max_objs
> HASH_PRIME
)
31 max_objs
= HASH_PRIME
;
33 obj_names
= new string
[max_objs
];
35 for (int i
= 0; i
< max_objs
; i
++) {
36 obj_names
[i
] = gc_oid_prefix
;
38 snprintf(buf
, 32, ".%d", i
);
39 obj_names
[i
].append(buf
);
43 void RGWGC::finalize()
48 int RGWGC::tag_index(const string
& tag
)
50 return ceph_str_hash_linux(tag
.c_str(), tag
.size()) % HASH_PRIME
% max_objs
;
53 void RGWGC::add_chain(ObjectWriteOperation
& op
, cls_rgw_obj_chain
& chain
, const string
& tag
)
55 cls_rgw_gc_obj_info info
;
59 cls_rgw_gc_set_entry(op
, cct
->_conf
->rgw_gc_obj_min_wait
, info
);
62 int RGWGC::send_chain(cls_rgw_obj_chain
& chain
, const string
& tag
, bool sync
)
64 ObjectWriteOperation op
;
65 add_chain(op
, chain
, tag
);
67 int i
= tag_index(tag
);
70 return store
->gc_operate(obj_names
[i
], &op
);
72 return store
->gc_aio_operate(obj_names
[i
], &op
);
75 int RGWGC::defer_chain(const string
& tag
, bool sync
)
77 ObjectWriteOperation op
;
78 cls_rgw_gc_defer_entry(op
, cct
->_conf
->rgw_gc_obj_min_wait
, tag
);
80 int i
= tag_index(tag
);
83 return store
->gc_operate(obj_names
[i
], &op
);
85 return store
->gc_aio_operate(obj_names
[i
], &op
);
88 int RGWGC::remove(int index
, const std::list
<string
>& tags
)
90 ObjectWriteOperation op
;
91 cls_rgw_gc_remove(op
, tags
);
92 return store
->gc_operate(obj_names
[index
], &op
);
95 int RGWGC::list(int *index
, string
& marker
, uint32_t max
, bool expired_only
, std::list
<cls_rgw_gc_obj_info
>& result
, bool *truncated
)
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
);
107 std::list
<cls_rgw_gc_obj_info
>::iterator iter
;
108 for (iter
= entries
.begin(); iter
!= entries
.end(); ++iter
) {
109 result
.push_back(*iter
);
112 if (*index
== max_objs
- 1) {
113 /* we cut short here, truncated will hold the correct value */
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
132 int RGWGC::process(int index
, int max_secs
)
134 rados::cls::lock::Lock
l(gc_index_lock_name
);
135 utime_t end
= ceph_clock_now();
136 std::list
<string
> remove_tags
;
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. */
146 utime_t
time(max_secs
, 0);
147 l
.set_duration(time
);
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
;
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
);
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(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
);
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
);
228 if (!remove_tags
.empty())
229 RGWGC::remove(index
, remove_tags
);
230 l
.unlock(&store
->gc_pool_ctx
, obj_names
[index
]);
237 int max_secs
= cct
->_conf
->rgw_gc_processor_max_time
;
240 int ret
= get_random_bytes((char *)&start
, sizeof(start
));
244 for (int i
= 0; i
< max_objs
; i
++) {
245 int index
= (i
+ start
) % max_objs
;
246 ret
= process(index
, max_secs
);
254 bool RGWGC::going_down()
259 void RGWGC::start_processor()
261 worker
= new GCWorker(cct
, this);
262 worker
->create("rgw_gc");
265 void RGWGC::stop_processor()
276 void *RGWGC::GCWorker::entry() {
278 utime_t start
= ceph_clock_now();
279 dout(2) << "garbage collection: start" << dendl
;
280 int r
= gc
->process();
282 dout(0) << "ERROR: garbage collection process() returned error r=" << r
<< dendl
;
284 dout(2) << "garbage collection: stop" << dendl
;
286 if (gc
->going_down())
289 utime_t end
= ceph_clock_now();
291 int secs
= cct
->_conf
->rgw_gc_processor_period
;
293 if (secs
<= end
.sec())
294 continue; // next round
299 cond
.WaitInterval(lock
, utime_t(secs
, 0));
301 } while (!gc
->going_down());
306 void RGWGC::GCWorker::stop()
308 Mutex::Locker
l(lock
);