]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | |
2 | // vim: ts=8 sw=2 smarttab | |
3 | #include <errno.h> | |
4 | ||
5 | #include "cls/rgw/cls_rgw_const.h" | |
6 | #include "cls/rgw/cls_rgw_client.h" | |
7 | ||
8 | #include "common/debug.h" | |
9 | ||
10 | using namespace librados; | |
11 | ||
12 | const string BucketIndexShardsManager::KEY_VALUE_SEPARATOR = "#"; | |
13 | const string BucketIndexShardsManager::SHARDS_SEPARATOR = ","; | |
14 | ||
15 | /** | |
16 | * This class represents the bucket index object operation callback context. | |
17 | */ | |
18 | template <typename T> | |
19 | class ClsBucketIndexOpCtx : public ObjectOperationCompletion { | |
20 | private: | |
21 | T *data; | |
22 | int *ret_code; | |
23 | public: | |
24 | ClsBucketIndexOpCtx(T* _data, int *_ret_code) : data(_data), ret_code(_ret_code) { assert(data); } | |
25 | ~ClsBucketIndexOpCtx() override {} | |
26 | void handle_completion(int r, bufferlist& outbl) override { | |
27 | if (r >= 0) { | |
28 | try { | |
29 | bufferlist::iterator iter = outbl.begin(); | |
30 | ::decode((*data), iter); | |
31 | } catch (buffer::error& err) { | |
32 | r = -EIO; | |
33 | } | |
34 | } | |
35 | if (ret_code) { | |
36 | *ret_code = r; | |
37 | } | |
38 | } | |
39 | }; | |
40 | ||
41 | void BucketIndexAioManager::do_completion(int id) { | |
42 | Mutex::Locker l(lock); | |
43 | ||
44 | map<int, librados::AioCompletion*>::iterator iter = pendings.find(id); | |
45 | assert(iter != pendings.end()); | |
46 | completions[id] = iter->second; | |
47 | pendings.erase(iter); | |
48 | ||
49 | // If the caller needs a list of finished objects, store them | |
50 | // for further processing | |
51 | map<int, string>::iterator miter = pending_objs.find(id); | |
52 | if (miter != pending_objs.end()) { | |
53 | completion_objs[id] = miter->second; | |
54 | pending_objs.erase(miter); | |
55 | } | |
56 | ||
57 | cond.Signal(); | |
58 | } | |
59 | ||
60 | bool BucketIndexAioManager::wait_for_completions(int valid_ret_code, | |
61 | int *num_completions, int *ret_code, map<int, string> *objs) { | |
62 | lock.Lock(); | |
63 | if (pendings.empty() && completions.empty()) { | |
64 | lock.Unlock(); | |
65 | return false; | |
66 | } | |
67 | ||
68 | if (completions.empty()) { | |
69 | // Wait for AIO completion | |
70 | cond.Wait(lock); | |
71 | } | |
72 | ||
73 | // Clear the completed AIOs | |
74 | map<int, librados::AioCompletion*>::iterator iter = completions.begin(); | |
75 | for (; iter != completions.end(); ++iter) { | |
76 | int r = iter->second->get_return_value(); | |
77 | if (objs && r == 0) { /* update list of successfully completed objs */ | |
78 | map<int, string>::iterator liter = completion_objs.find(iter->first); | |
79 | if (liter != completion_objs.end()) { | |
80 | (*objs)[liter->first] = liter->second; | |
81 | } | |
82 | } | |
83 | if (ret_code && (r < 0 && r != valid_ret_code)) | |
84 | (*ret_code) = r; | |
85 | iter->second->release(); | |
86 | } | |
87 | if (num_completions) | |
88 | (*num_completions) = completions.size(); | |
89 | completions.clear(); | |
90 | lock.Unlock(); | |
91 | ||
92 | return true; | |
93 | } | |
94 | ||
95 | void cls_rgw_bucket_init(ObjectWriteOperation& o) | |
96 | { | |
97 | bufferlist in; | |
98 | o.exec(RGW_CLASS, RGW_BUCKET_INIT_INDEX, in); | |
99 | } | |
100 | ||
101 | static bool issue_bucket_index_init_op(librados::IoCtx& io_ctx, | |
102 | const string& oid, BucketIndexAioManager *manager) { | |
103 | bufferlist in; | |
104 | librados::ObjectWriteOperation op; | |
105 | op.create(true); | |
106 | op.exec(RGW_CLASS, RGW_BUCKET_INIT_INDEX, in); | |
107 | return manager->aio_operate(io_ctx, oid, &op); | |
108 | } | |
109 | ||
110 | static bool issue_bucket_set_tag_timeout_op(librados::IoCtx& io_ctx, | |
111 | const string& oid, uint64_t timeout, BucketIndexAioManager *manager) { | |
112 | bufferlist in; | |
113 | struct rgw_cls_tag_timeout_op call; | |
114 | call.tag_timeout = timeout; | |
115 | ::encode(call, in); | |
116 | ObjectWriteOperation op; | |
117 | op.exec(RGW_CLASS, RGW_BUCKET_SET_TAG_TIMEOUT, in); | |
118 | return manager->aio_operate(io_ctx, oid, &op); | |
119 | } | |
120 | ||
121 | int CLSRGWIssueBucketIndexInit::issue_op(int shard_id, const string& oid) | |
122 | { | |
123 | return issue_bucket_index_init_op(io_ctx, oid, &manager); | |
124 | } | |
125 | ||
126 | void CLSRGWIssueBucketIndexInit::cleanup() | |
127 | { | |
128 | // Do best effort removal | |
129 | for (map<int, string>::iterator citer = objs_container.begin(); citer != iter; ++citer) { | |
130 | io_ctx.remove(citer->second); | |
131 | } | |
132 | } | |
133 | ||
134 | int CLSRGWIssueSetTagTimeout::issue_op(int shard_id, const string& oid) | |
135 | { | |
136 | return issue_bucket_set_tag_timeout_op(io_ctx, oid, tag_timeout, &manager); | |
137 | } | |
138 | ||
139 | void cls_rgw_bucket_update_stats(librados::ObjectWriteOperation& o, bool absolute, | |
140 | const map<uint8_t, rgw_bucket_category_stats>& stats) | |
141 | { | |
142 | struct rgw_cls_bucket_update_stats_op call; | |
143 | call.absolute = absolute; | |
144 | call.stats = stats; | |
145 | bufferlist in; | |
146 | ::encode(call, in); | |
147 | o.exec(RGW_CLASS, RGW_BUCKET_UPDATE_STATS, in); | |
148 | } | |
149 | ||
150 | void cls_rgw_bucket_prepare_op(ObjectWriteOperation& o, RGWModifyOp op, string& tag, | |
151 | const cls_rgw_obj_key& key, const string& locator, bool log_op, | |
152 | uint16_t bilog_flags, rgw_zone_set& zones_trace) | |
153 | { | |
154 | struct rgw_cls_obj_prepare_op call; | |
155 | call.op = op; | |
156 | call.tag = tag; | |
157 | call.key = key; | |
158 | call.locator = locator; | |
159 | call.log_op = log_op; | |
160 | call.bilog_flags = bilog_flags; | |
161 | call.zones_trace = zones_trace; | |
162 | bufferlist in; | |
163 | ::encode(call, in); | |
164 | o.exec(RGW_CLASS, RGW_BUCKET_PREPARE_OP, in); | |
165 | } | |
166 | ||
167 | void cls_rgw_bucket_complete_op(ObjectWriteOperation& o, RGWModifyOp op, string& tag, | |
168 | rgw_bucket_entry_ver& ver, | |
169 | const cls_rgw_obj_key& key, | |
170 | rgw_bucket_dir_entry_meta& dir_meta, | |
171 | list<cls_rgw_obj_key> *remove_objs, bool log_op, | |
172 | uint16_t bilog_flags, | |
173 | rgw_zone_set *zones_trace) | |
174 | { | |
175 | ||
176 | bufferlist in; | |
177 | struct rgw_cls_obj_complete_op call; | |
178 | call.op = op; | |
179 | call.tag = tag; | |
180 | call.key = key; | |
181 | call.ver = ver; | |
182 | call.meta = dir_meta; | |
183 | call.log_op = log_op; | |
184 | call.bilog_flags = bilog_flags; | |
185 | if (remove_objs) | |
186 | call.remove_objs = *remove_objs; | |
187 | if (zones_trace) { | |
188 | call.zones_trace = *zones_trace; | |
189 | } | |
190 | ::encode(call, in); | |
191 | o.exec(RGW_CLASS, RGW_BUCKET_COMPLETE_OP, in); | |
192 | } | |
193 | ||
194 | static bool issue_bucket_list_op(librados::IoCtx& io_ctx, | |
195 | const string& oid, const cls_rgw_obj_key& start_obj, const string& filter_prefix, | |
196 | uint32_t num_entries, bool list_versions, BucketIndexAioManager *manager, | |
197 | struct rgw_cls_list_ret *pdata) { | |
198 | bufferlist in; | |
199 | struct rgw_cls_list_op call; | |
200 | call.start_obj = start_obj; | |
201 | call.filter_prefix = filter_prefix; | |
202 | call.num_entries = num_entries; | |
203 | call.list_versions = list_versions; | |
204 | ::encode(call, in); | |
205 | ||
206 | librados::ObjectReadOperation op; | |
207 | op.exec(RGW_CLASS, RGW_BUCKET_LIST, in, new ClsBucketIndexOpCtx<struct rgw_cls_list_ret>(pdata, NULL)); | |
208 | return manager->aio_operate(io_ctx, oid, &op); | |
209 | } | |
210 | ||
211 | int CLSRGWIssueBucketList::issue_op(int shard_id, const string& oid) | |
212 | { | |
213 | return issue_bucket_list_op(io_ctx, oid, start_obj, filter_prefix, num_entries, list_versions, &manager, &result[shard_id]); | |
214 | } | |
215 | ||
216 | void cls_rgw_remove_obj(librados::ObjectWriteOperation& o, list<string>& keep_attr_prefixes) | |
217 | { | |
218 | bufferlist in; | |
219 | struct rgw_cls_obj_remove_op call; | |
220 | call.keep_attr_prefixes = keep_attr_prefixes; | |
221 | ::encode(call, in); | |
222 | o.exec(RGW_CLASS, RGW_OBJ_REMOVE, in); | |
223 | } | |
224 | ||
225 | void cls_rgw_obj_store_pg_ver(librados::ObjectWriteOperation& o, const string& attr) | |
226 | { | |
227 | bufferlist in; | |
228 | struct rgw_cls_obj_store_pg_ver_op call; | |
229 | call.attr = attr; | |
230 | ::encode(call, in); | |
231 | o.exec(RGW_CLASS, RGW_OBJ_STORE_PG_VER, in); | |
232 | } | |
233 | ||
234 | void cls_rgw_obj_check_attrs_prefix(librados::ObjectOperation& o, const string& prefix, bool fail_if_exist) | |
235 | { | |
236 | bufferlist in; | |
237 | struct rgw_cls_obj_check_attrs_prefix call; | |
238 | call.check_prefix = prefix; | |
239 | call.fail_if_exist = fail_if_exist; | |
240 | ::encode(call, in); | |
241 | o.exec(RGW_CLASS, RGW_OBJ_CHECK_ATTRS_PREFIX, in); | |
242 | } | |
243 | ||
244 | void cls_rgw_obj_check_mtime(librados::ObjectOperation& o, const real_time& mtime, bool high_precision_time, RGWCheckMTimeType type) | |
245 | { | |
246 | bufferlist in; | |
247 | struct rgw_cls_obj_check_mtime call; | |
248 | call.mtime = mtime; | |
249 | call.high_precision_time = high_precision_time; | |
250 | call.type = type; | |
251 | ::encode(call, in); | |
252 | o.exec(RGW_CLASS, RGW_OBJ_CHECK_MTIME, in); | |
253 | } | |
254 | ||
255 | int cls_rgw_bi_get(librados::IoCtx& io_ctx, const string oid, | |
256 | BIIndexType index_type, cls_rgw_obj_key& key, | |
257 | rgw_cls_bi_entry *entry) | |
258 | { | |
259 | bufferlist in, out; | |
260 | struct rgw_cls_bi_get_op call; | |
261 | call.key = key; | |
262 | call.type = index_type; | |
263 | ::encode(call, in); | |
264 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_BI_GET, in, out); | |
265 | if (r < 0) | |
266 | return r; | |
267 | ||
268 | struct rgw_cls_bi_get_ret op_ret; | |
269 | bufferlist::iterator iter = out.begin(); | |
270 | try { | |
271 | ::decode(op_ret, iter); | |
272 | } catch (buffer::error& err) { | |
273 | return -EIO; | |
274 | } | |
275 | ||
276 | *entry = op_ret.entry; | |
277 | ||
278 | return 0; | |
279 | } | |
280 | ||
281 | int cls_rgw_bi_put(librados::IoCtx& io_ctx, const string oid, rgw_cls_bi_entry& entry) | |
282 | { | |
283 | bufferlist in, out; | |
284 | struct rgw_cls_bi_put_op call; | |
285 | call.entry = entry; | |
286 | ::encode(call, in); | |
287 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_BI_PUT, in, out); | |
288 | if (r < 0) | |
289 | return r; | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | void cls_rgw_bi_put(ObjectWriteOperation& op, const string oid, rgw_cls_bi_entry& entry) | |
295 | { | |
296 | bufferlist in, out; | |
297 | struct rgw_cls_bi_put_op call; | |
298 | call.entry = entry; | |
299 | ::encode(call, in); | |
300 | op.exec(RGW_CLASS, RGW_BI_PUT, in); | |
301 | } | |
302 | ||
303 | int cls_rgw_bi_list(librados::IoCtx& io_ctx, const string oid, | |
304 | const string& name, const string& marker, uint32_t max, | |
305 | list<rgw_cls_bi_entry> *entries, bool *is_truncated) | |
306 | { | |
307 | bufferlist in, out; | |
308 | struct rgw_cls_bi_list_op call; | |
309 | call.name = name; | |
310 | call.marker = marker; | |
311 | call.max = max; | |
312 | ::encode(call, in); | |
313 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_BI_LIST, in, out); | |
314 | if (r < 0) | |
315 | return r; | |
316 | ||
317 | struct rgw_cls_bi_list_ret op_ret; | |
318 | bufferlist::iterator iter = out.begin(); | |
319 | try { | |
320 | ::decode(op_ret, iter); | |
321 | } catch (buffer::error& err) { | |
322 | return -EIO; | |
323 | } | |
324 | ||
325 | entries->swap(op_ret.entries); | |
326 | *is_truncated = op_ret.is_truncated; | |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
331 | int cls_rgw_bucket_link_olh(librados::IoCtx& io_ctx, librados::ObjectWriteOperation& op, | |
332 | const string& oid, const cls_rgw_obj_key& key, bufferlist& olh_tag, | |
333 | bool delete_marker, const string& op_tag, struct rgw_bucket_dir_entry_meta *meta, | |
334 | uint64_t olh_epoch, ceph::real_time unmod_since, bool high_precision_time, bool log_op, rgw_zone_set& zones_trace) | |
335 | { | |
336 | bufferlist in, out; | |
337 | struct rgw_cls_link_olh_op call; | |
338 | call.key = key; | |
339 | call.olh_tag = string(olh_tag.c_str(), olh_tag.length()); | |
340 | call.op_tag = op_tag; | |
341 | call.delete_marker = delete_marker; | |
342 | if (meta) { | |
343 | call.meta = *meta; | |
344 | } | |
345 | call.olh_epoch = olh_epoch; | |
346 | call.log_op = log_op; | |
347 | call.unmod_since = unmod_since; | |
348 | call.high_precision_time = high_precision_time; | |
349 | call.zones_trace = zones_trace; | |
350 | ::encode(call, in); | |
351 | op.exec(RGW_CLASS, RGW_BUCKET_LINK_OLH, in); | |
352 | int r = io_ctx.operate(oid, &op); | |
353 | if (r < 0) | |
354 | return r; | |
355 | ||
356 | return 0; | |
357 | } | |
358 | ||
359 | int cls_rgw_bucket_unlink_instance(librados::IoCtx& io_ctx, librados::ObjectWriteOperation& op, | |
360 | const string& oid, | |
361 | const cls_rgw_obj_key& key, const string& op_tag, | |
362 | const string& olh_tag, uint64_t olh_epoch, bool log_op, rgw_zone_set& zones_trace) | |
363 | { | |
364 | bufferlist in, out; | |
365 | struct rgw_cls_unlink_instance_op call; | |
366 | call.key = key; | |
367 | call.op_tag = op_tag; | |
368 | call.olh_epoch = olh_epoch; | |
369 | call.olh_tag = olh_tag; | |
370 | call.log_op = log_op; | |
371 | call.zones_trace = zones_trace; | |
372 | ::encode(call, in); | |
373 | op.exec(RGW_CLASS, RGW_BUCKET_UNLINK_INSTANCE, in); | |
374 | int r = io_ctx.operate(oid, &op); | |
375 | if (r < 0) | |
376 | return r; | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
381 | int cls_rgw_get_olh_log(IoCtx& io_ctx, string& oid, librados::ObjectReadOperation& op, const cls_rgw_obj_key& olh, uint64_t ver_marker, | |
382 | const string& olh_tag, | |
383 | map<uint64_t, vector<struct rgw_bucket_olh_log_entry> > *log, bool *is_truncated) | |
384 | { | |
385 | bufferlist in, out; | |
386 | struct rgw_cls_read_olh_log_op call; | |
387 | call.olh = olh; | |
388 | call.ver_marker = ver_marker; | |
389 | call.olh_tag = olh_tag; | |
390 | ::encode(call, in); | |
391 | int op_ret; | |
392 | op.exec(RGW_CLASS, RGW_BUCKET_READ_OLH_LOG, in, &out, &op_ret); | |
393 | int r = io_ctx.operate(oid, &op, NULL); | |
394 | if (r < 0) { | |
395 | return r; | |
396 | } | |
397 | if (op_ret < 0) { | |
398 | return op_ret; | |
399 | } | |
400 | ||
401 | struct rgw_cls_read_olh_log_ret ret; | |
402 | try { | |
403 | bufferlist::iterator iter = out.begin(); | |
404 | ::decode(ret, iter); | |
405 | } catch (buffer::error& err) { | |
406 | return -EIO; | |
407 | } | |
408 | ||
409 | if (log) { | |
410 | *log = ret.log; | |
411 | } | |
412 | if (is_truncated) { | |
413 | *is_truncated = ret.is_truncated; | |
414 | } | |
415 | ||
416 | return r; | |
417 | } | |
418 | ||
419 | void cls_rgw_trim_olh_log(librados::ObjectWriteOperation& op, const cls_rgw_obj_key& olh, uint64_t ver, const string& olh_tag) | |
420 | { | |
421 | bufferlist in; | |
422 | struct rgw_cls_trim_olh_log_op call; | |
423 | call.olh = olh; | |
424 | call.ver = ver; | |
425 | call.olh_tag = olh_tag; | |
426 | ::encode(call, in); | |
427 | op.exec(RGW_CLASS, RGW_BUCKET_TRIM_OLH_LOG, in); | |
428 | } | |
429 | ||
430 | int cls_rgw_clear_olh(IoCtx& io_ctx, librados::ObjectWriteOperation& op, string& oid, const cls_rgw_obj_key& olh, const string& olh_tag) | |
431 | { | |
432 | bufferlist in, out; | |
433 | struct rgw_cls_bucket_clear_olh_op call; | |
434 | call.key = olh; | |
435 | call.olh_tag = olh_tag; | |
436 | ::encode(call, in); | |
437 | int op_ret; | |
438 | op.exec(RGW_CLASS, RGW_BUCKET_CLEAR_OLH, in, &out, &op_ret); | |
439 | int r = io_ctx.operate(oid, &op); | |
440 | if (r < 0) { | |
441 | return r; | |
442 | } | |
443 | return op_ret; | |
444 | } | |
445 | ||
446 | static bool issue_bi_log_list_op(librados::IoCtx& io_ctx, const string& oid, int shard_id, | |
447 | BucketIndexShardsManager& marker_mgr, uint32_t max, BucketIndexAioManager *manager, | |
448 | struct cls_rgw_bi_log_list_ret *pdata) { | |
449 | bufferlist in; | |
450 | cls_rgw_bi_log_list_op call; | |
451 | call.marker = marker_mgr.get(shard_id, ""); | |
452 | call.max = max; | |
453 | ::encode(call, in); | |
454 | ||
455 | librados::ObjectReadOperation op; | |
456 | op.exec(RGW_CLASS, RGW_BI_LOG_LIST, in, new ClsBucketIndexOpCtx<struct cls_rgw_bi_log_list_ret>(pdata, NULL)); | |
457 | return manager->aio_operate(io_ctx, oid, &op); | |
458 | } | |
459 | ||
460 | int CLSRGWIssueBILogList::issue_op(int shard_id, const string& oid) | |
461 | { | |
462 | return issue_bi_log_list_op(io_ctx, oid, shard_id, marker_mgr, max, &manager, &result[shard_id]); | |
463 | } | |
464 | ||
465 | static bool issue_bi_log_trim(librados::IoCtx& io_ctx, const string& oid, int shard_id, | |
466 | BucketIndexShardsManager& start_marker_mgr, | |
467 | BucketIndexShardsManager& end_marker_mgr, BucketIndexAioManager *manager) { | |
468 | bufferlist in; | |
469 | cls_rgw_bi_log_trim_op call; | |
470 | call.start_marker = start_marker_mgr.get(shard_id, ""); | |
471 | call.end_marker = end_marker_mgr.get(shard_id, ""); | |
472 | ::encode(call, in); | |
473 | ObjectWriteOperation op; | |
474 | op.exec(RGW_CLASS, RGW_BI_LOG_TRIM, in); | |
475 | return manager->aio_operate(io_ctx, oid, &op); | |
476 | } | |
477 | ||
478 | int CLSRGWIssueBILogTrim::issue_op(int shard_id, const string& oid) | |
479 | { | |
480 | return issue_bi_log_trim(io_ctx, oid, shard_id, start_marker_mgr, end_marker_mgr, &manager); | |
481 | } | |
482 | ||
483 | static bool issue_bucket_check_index_op(IoCtx& io_ctx, const string& oid, BucketIndexAioManager *manager, | |
484 | struct rgw_cls_check_index_ret *pdata) { | |
485 | bufferlist in; | |
486 | librados::ObjectReadOperation op; | |
487 | op.exec(RGW_CLASS, RGW_BUCKET_CHECK_INDEX, in, new ClsBucketIndexOpCtx<struct rgw_cls_check_index_ret>( | |
488 | pdata, NULL)); | |
489 | return manager->aio_operate(io_ctx, oid, &op); | |
490 | } | |
491 | ||
492 | int CLSRGWIssueBucketCheck::issue_op(int shard_id, const string& oid) | |
493 | { | |
494 | return issue_bucket_check_index_op(io_ctx, oid, &manager, &result[shard_id]); | |
495 | } | |
496 | ||
497 | static bool issue_bucket_rebuild_index_op(IoCtx& io_ctx, const string& oid, | |
498 | BucketIndexAioManager *manager) { | |
499 | bufferlist in; | |
500 | librados::ObjectWriteOperation op; | |
501 | op.exec(RGW_CLASS, RGW_BUCKET_REBUILD_INDEX, in); | |
502 | return manager->aio_operate(io_ctx, oid, &op); | |
503 | } | |
504 | ||
505 | int CLSRGWIssueBucketRebuild::issue_op(int shard_id, const string& oid) | |
506 | { | |
507 | return issue_bucket_rebuild_index_op(io_ctx, oid, &manager); | |
508 | } | |
509 | ||
510 | void cls_rgw_encode_suggestion(char op, rgw_bucket_dir_entry& dirent, bufferlist& updates) | |
511 | { | |
512 | updates.append(op); | |
513 | ::encode(dirent, updates); | |
514 | } | |
515 | ||
516 | void cls_rgw_suggest_changes(ObjectWriteOperation& o, bufferlist& updates) | |
517 | { | |
518 | o.exec(RGW_CLASS, RGW_DIR_SUGGEST_CHANGES, updates); | |
519 | } | |
520 | ||
521 | int CLSRGWIssueGetDirHeader::issue_op(int shard_id, const string& oid) | |
522 | { | |
523 | cls_rgw_obj_key nokey; | |
524 | return issue_bucket_list_op(io_ctx, oid, nokey, "", 0, false, &manager, &result[shard_id]); | |
525 | } | |
526 | ||
527 | static bool issue_resync_bi_log(librados::IoCtx& io_ctx, const string& oid, BucketIndexAioManager *manager) | |
528 | { | |
529 | bufferlist in; | |
530 | librados::ObjectWriteOperation op; | |
531 | op.exec("rgw", "bi_log_resync", in); | |
532 | return manager->aio_operate(io_ctx, oid, &op); | |
533 | } | |
534 | ||
535 | int CLSRGWIssueResyncBucketBILog::issue_op(int shard_id, const string& oid) | |
536 | { | |
537 | return issue_resync_bi_log(io_ctx, oid, &manager); | |
538 | } | |
539 | ||
540 | static bool issue_bi_log_stop(librados::IoCtx& io_ctx, const string& oid, BucketIndexAioManager *manager) | |
541 | { | |
542 | bufferlist in; | |
543 | librados::ObjectWriteOperation op; | |
544 | op.exec("rgw", "bi_log_stop", in); | |
545 | return manager->aio_operate(io_ctx, oid, &op); | |
546 | } | |
547 | ||
548 | int CLSRGWIssueBucketBILogStop::issue_op(int shard_id, const string& oid) | |
549 | { | |
550 | return issue_bi_log_stop(io_ctx, oid, &manager); | |
551 | } | |
552 | ||
553 | class GetDirHeaderCompletion : public ObjectOperationCompletion { | |
554 | RGWGetDirHeader_CB *ret_ctx; | |
555 | public: | |
556 | explicit GetDirHeaderCompletion(RGWGetDirHeader_CB *_ctx) : ret_ctx(_ctx) {} | |
557 | ~GetDirHeaderCompletion() override { | |
558 | ret_ctx->put(); | |
559 | } | |
560 | void handle_completion(int r, bufferlist& outbl) override { | |
561 | struct rgw_cls_list_ret ret; | |
562 | try { | |
563 | bufferlist::iterator iter = outbl.begin(); | |
564 | ::decode(ret, iter); | |
565 | } catch (buffer::error& err) { | |
566 | r = -EIO; | |
567 | } | |
568 | ||
569 | ret_ctx->handle_response(r, ret.dir.header); | |
570 | } | |
571 | }; | |
572 | ||
573 | int cls_rgw_get_dir_header_async(IoCtx& io_ctx, string& oid, RGWGetDirHeader_CB *ctx) | |
574 | { | |
575 | bufferlist in, out; | |
576 | struct rgw_cls_list_op call; | |
577 | call.num_entries = 0; | |
578 | ::encode(call, in); | |
579 | ObjectReadOperation op; | |
580 | GetDirHeaderCompletion *cb = new GetDirHeaderCompletion(ctx); | |
581 | op.exec(RGW_CLASS, RGW_BUCKET_LIST, in, cb); | |
582 | AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); | |
583 | int r = io_ctx.aio_operate(oid, c, &op, NULL); | |
584 | c->release(); | |
585 | if (r < 0) | |
586 | return r; | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
591 | int cls_rgw_usage_log_read(IoCtx& io_ctx, string& oid, string& user, | |
592 | uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, | |
593 | string& read_iter, map<rgw_user_bucket, rgw_usage_log_entry>& usage, | |
594 | bool *is_truncated) | |
595 | { | |
596 | if (is_truncated) | |
597 | *is_truncated = false; | |
598 | ||
599 | bufferlist in, out; | |
600 | rgw_cls_usage_log_read_op call; | |
601 | call.start_epoch = start_epoch; | |
602 | call.end_epoch = end_epoch; | |
603 | call.owner = user; | |
604 | call.max_entries = max_entries; | |
605 | call.iter = read_iter; | |
606 | ::encode(call, in); | |
607 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_USER_USAGE_LOG_READ, in, out); | |
608 | if (r < 0) | |
609 | return r; | |
610 | ||
611 | try { | |
612 | rgw_cls_usage_log_read_ret result; | |
613 | bufferlist::iterator iter = out.begin(); | |
614 | ::decode(result, iter); | |
615 | read_iter = result.next_iter; | |
616 | if (is_truncated) | |
617 | *is_truncated = result.truncated; | |
618 | ||
619 | usage = result.usage; | |
620 | } catch (buffer::error& e) { | |
621 | return -EINVAL; | |
622 | } | |
623 | ||
624 | return 0; | |
625 | } | |
626 | ||
627 | void cls_rgw_usage_log_trim(ObjectWriteOperation& op, string& user, | |
628 | uint64_t start_epoch, uint64_t end_epoch) | |
629 | { | |
630 | bufferlist in; | |
631 | rgw_cls_usage_log_trim_op call; | |
632 | call.start_epoch = start_epoch; | |
633 | call.end_epoch = end_epoch; | |
634 | call.user = user; | |
635 | ::encode(call, in); | |
636 | op.exec(RGW_CLASS, RGW_USER_USAGE_LOG_TRIM, in); | |
637 | } | |
638 | ||
639 | void cls_rgw_usage_log_add(ObjectWriteOperation& op, rgw_usage_log_info& info) | |
640 | { | |
641 | bufferlist in; | |
642 | rgw_cls_usage_log_add_op call; | |
643 | call.info = info; | |
644 | ::encode(call, in); | |
645 | op.exec(RGW_CLASS, RGW_USER_USAGE_LOG_ADD, in); | |
646 | } | |
647 | ||
648 | /* garbage collection */ | |
649 | ||
650 | void cls_rgw_gc_set_entry(ObjectWriteOperation& op, uint32_t expiration_secs, cls_rgw_gc_obj_info& info) | |
651 | { | |
652 | bufferlist in; | |
653 | cls_rgw_gc_set_entry_op call; | |
654 | call.expiration_secs = expiration_secs; | |
655 | call.info = info; | |
656 | ::encode(call, in); | |
657 | op.exec(RGW_CLASS, RGW_GC_SET_ENTRY, in); | |
658 | } | |
659 | ||
660 | void cls_rgw_gc_defer_entry(ObjectWriteOperation& op, uint32_t expiration_secs, const string& tag) | |
661 | { | |
662 | bufferlist in; | |
663 | cls_rgw_gc_defer_entry_op call; | |
664 | call.expiration_secs = expiration_secs; | |
665 | call.tag = tag; | |
666 | ::encode(call, in); | |
667 | op.exec(RGW_CLASS, RGW_GC_DEFER_ENTRY, in); | |
668 | } | |
669 | ||
670 | int cls_rgw_gc_list(IoCtx& io_ctx, string& oid, string& marker, uint32_t max, bool expired_only, | |
671 | list<cls_rgw_gc_obj_info>& entries, bool *truncated, string& next_marker) | |
672 | { | |
673 | bufferlist in, out; | |
674 | cls_rgw_gc_list_op call; | |
675 | call.marker = marker; | |
676 | call.max = max; | |
677 | call.expired_only = expired_only; | |
678 | ::encode(call, in); | |
679 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_GC_LIST, in, out); | |
680 | if (r < 0) | |
681 | return r; | |
682 | ||
683 | cls_rgw_gc_list_ret ret; | |
684 | try { | |
685 | bufferlist::iterator iter = out.begin(); | |
686 | ::decode(ret, iter); | |
687 | } catch (buffer::error& err) { | |
688 | return -EIO; | |
689 | } | |
690 | ||
691 | entries.swap(ret.entries); | |
692 | ||
693 | if (truncated) | |
694 | *truncated = ret.truncated; | |
695 | next_marker = std::move(ret.next_marker); | |
696 | return r; | |
697 | } | |
698 | ||
699 | void cls_rgw_gc_remove(librados::ObjectWriteOperation& op, const list<string>& tags) | |
700 | { | |
701 | bufferlist in; | |
702 | cls_rgw_gc_remove_op call; | |
703 | call.tags = tags; | |
704 | ::encode(call, in); | |
705 | op.exec(RGW_CLASS, RGW_GC_REMOVE, in); | |
706 | } | |
707 | ||
708 | int cls_rgw_lc_get_head(IoCtx& io_ctx, string& oid, cls_rgw_lc_obj_head& head) | |
709 | { | |
710 | bufferlist in, out; | |
711 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_GET_HEAD, in, out); | |
712 | if (r < 0) | |
713 | return r; | |
714 | ||
715 | cls_rgw_lc_get_head_ret ret; | |
716 | try { | |
717 | bufferlist::iterator iter = out.begin(); | |
718 | ::decode(ret, iter); | |
719 | } catch (buffer::error& err) { | |
720 | return -EIO; | |
721 | } | |
722 | head = ret.head; | |
723 | ||
724 | return r; | |
725 | } | |
726 | ||
727 | int cls_rgw_lc_put_head(IoCtx& io_ctx, string& oid, cls_rgw_lc_obj_head& head) | |
728 | { | |
729 | bufferlist in, out; | |
730 | cls_rgw_lc_put_head_op call; | |
731 | call.head = head; | |
732 | ::encode(call, in); | |
733 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_PUT_HEAD, in, out); | |
734 | return r; | |
735 | } | |
736 | ||
737 | int cls_rgw_lc_get_next_entry(IoCtx& io_ctx, string& oid, string& marker, pair<string, int>& entry) | |
738 | { | |
739 | bufferlist in, out; | |
740 | cls_rgw_lc_get_next_entry_op call; | |
741 | call.marker = marker; | |
742 | ::encode(call, in); | |
743 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_GET_NEXT_ENTRY, in, out); | |
744 | if (r < 0) | |
745 | return r; | |
746 | ||
747 | cls_rgw_lc_get_next_entry_ret ret; | |
748 | try { | |
749 | bufferlist::iterator iter = out.begin(); | |
750 | ::decode(ret, iter); | |
751 | } catch (buffer::error& err) { | |
752 | return -EIO; | |
753 | } | |
754 | entry = ret.entry; | |
755 | ||
756 | return r; | |
757 | } | |
758 | ||
759 | int cls_rgw_lc_rm_entry(IoCtx& io_ctx, string& oid, pair<string, int>& entry) | |
760 | { | |
761 | bufferlist in, out; | |
762 | cls_rgw_lc_rm_entry_op call; | |
763 | call.entry = entry; | |
764 | ::encode(call, in); | |
765 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_RM_ENTRY, in, out); | |
766 | return r; | |
767 | } | |
768 | ||
769 | int cls_rgw_lc_set_entry(IoCtx& io_ctx, string& oid, pair<string, int>& entry) | |
770 | { | |
771 | bufferlist in, out; | |
772 | cls_rgw_lc_set_entry_op call; | |
773 | call.entry = entry; | |
774 | ::encode(call, in); | |
775 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_SET_ENTRY, in, out); | |
776 | return r; | |
777 | } | |
778 | ||
779 | int cls_rgw_lc_list(IoCtx& io_ctx, string& oid, | |
780 | const string& marker, | |
781 | uint32_t max_entries, | |
782 | map<string, int>& entries) | |
783 | { | |
784 | bufferlist in, out; | |
785 | cls_rgw_lc_list_entries_op op; | |
786 | ||
787 | entries.clear(); | |
788 | ||
789 | op.marker = marker; | |
790 | op.max_entries = max_entries; | |
791 | ||
792 | ::encode(op, in); | |
793 | ||
794 | int r = io_ctx.exec(oid, RGW_CLASS, RGW_LC_LIST_ENTRIES, in, out); | |
795 | if (r < 0) | |
796 | return r; | |
797 | ||
798 | cls_rgw_lc_list_entries_ret ret; | |
799 | try { | |
800 | bufferlist::iterator iter = out.begin(); | |
801 | ::decode(ret, iter); | |
802 | } catch (buffer::error& err) { | |
803 | return -EIO; | |
804 | } | |
805 | entries.insert(ret.entries.begin(),ret.entries.end()); | |
806 | ||
807 | return r; | |
808 | } | |
809 | ||
810 | void cls_rgw_reshard_add(librados::ObjectWriteOperation& op, const cls_rgw_reshard_entry& entry) | |
811 | { | |
812 | bufferlist in; | |
813 | struct cls_rgw_reshard_add_op call; | |
814 | call.entry = entry; | |
815 | ::encode(call, in); | |
816 | op.exec("rgw", "reshard_add", in); | |
817 | } | |
818 | ||
819 | int cls_rgw_reshard_list(librados::IoCtx& io_ctx, const string& oid, string& marker, uint32_t max, | |
820 | list<cls_rgw_reshard_entry>& entries, bool* is_truncated) | |
821 | { | |
822 | bufferlist in, out; | |
823 | struct cls_rgw_reshard_list_op call; | |
824 | call.marker = marker; | |
825 | call.max = max; | |
826 | ::encode(call, in); | |
827 | int r = io_ctx.exec(oid, "rgw", "reshard_list", in, out); | |
828 | if (r < 0) | |
829 | return r; | |
830 | ||
831 | struct cls_rgw_reshard_list_ret op_ret; | |
832 | bufferlist::iterator iter = out.begin(); | |
833 | try { | |
834 | ::decode(op_ret, iter); | |
835 | } catch (buffer::error& err) { | |
836 | return -EIO; | |
837 | } | |
838 | ||
839 | entries.swap(op_ret.entries); | |
840 | *is_truncated = op_ret.is_truncated; | |
841 | ||
842 | return 0; | |
843 | } | |
844 | ||
845 | int cls_rgw_reshard_get(librados::IoCtx& io_ctx, const string& oid, cls_rgw_reshard_entry& entry) | |
846 | { | |
847 | bufferlist in, out; | |
848 | struct cls_rgw_reshard_get_op call; | |
849 | call.entry = entry; | |
850 | ::encode(call, in); | |
851 | int r = io_ctx.exec(oid, "rgw", "reshard_get", in, out); | |
852 | if (r < 0) | |
853 | return r; | |
854 | ||
855 | struct cls_rgw_reshard_get_ret op_ret; | |
856 | bufferlist::iterator iter = out.begin(); | |
857 | try { | |
858 | ::decode(op_ret, iter); | |
859 | } catch (buffer::error& err) { | |
860 | return -EIO; | |
861 | } | |
862 | ||
863 | entry = op_ret.entry; | |
864 | ||
865 | return 0; | |
866 | } | |
867 | ||
868 | void cls_rgw_reshard_remove(librados::ObjectWriteOperation& op, const cls_rgw_reshard_entry& entry) | |
869 | { | |
870 | bufferlist in; | |
871 | struct cls_rgw_reshard_remove_op call; | |
872 | call.tenant = entry.tenant; | |
873 | call.bucket_name = entry.bucket_name; | |
874 | call.bucket_id = entry.bucket_id; | |
875 | ::encode(call, in); | |
876 | op.exec("rgw", "reshard_remove", in); | |
877 | } | |
878 | ||
879 | int cls_rgw_set_bucket_resharding(librados::IoCtx& io_ctx, const string& oid, | |
880 | const cls_rgw_bucket_instance_entry& entry) | |
881 | { | |
882 | bufferlist in, out; | |
883 | struct cls_rgw_set_bucket_resharding_op call; | |
884 | call.entry = entry; | |
885 | ::encode(call, in); | |
886 | return io_ctx.exec(oid, "rgw", "set_bucket_resharding", in, out); | |
887 | } | |
888 | ||
889 | int cls_rgw_clear_bucket_resharding(librados::IoCtx& io_ctx, const string& oid) | |
890 | { | |
891 | bufferlist in, out; | |
892 | struct cls_rgw_clear_bucket_resharding_op call; | |
893 | ::encode(call, in); | |
894 | return io_ctx.exec(oid, "rgw", "clear_bucket_resharding", in, out); | |
895 | } | |
896 | ||
897 | int cls_rgw_get_bucket_resharding(librados::IoCtx& io_ctx, const string& oid, | |
898 | cls_rgw_bucket_instance_entry *entry) | |
899 | { | |
900 | bufferlist in, out; | |
901 | struct cls_rgw_get_bucket_resharding_op call; | |
902 | ::encode(call, in); | |
903 | int r= io_ctx.exec(oid, "rgw", "get_bucket_resharding", in, out); | |
904 | if (r < 0) | |
905 | return r; | |
906 | ||
907 | struct cls_rgw_get_bucket_resharding_ret op_ret; | |
908 | bufferlist::iterator iter = out.begin(); | |
909 | try { | |
910 | ::decode(op_ret, iter); | |
911 | } catch (buffer::error& err) { | |
912 | return -EIO; | |
913 | } | |
914 | ||
915 | *entry = op_ret.new_instance; | |
916 | ||
917 | return 0; | |
918 | } | |
919 | ||
920 | void cls_rgw_guard_bucket_resharding(librados::ObjectOperation& op, int ret_err) | |
921 | { | |
922 | bufferlist in, out; | |
923 | struct cls_rgw_guard_bucket_resharding_op call; | |
924 | call.ret_err = ret_err; | |
925 | ::encode(call, in); | |
926 | op.exec("rgw", "guard_bucket_resharding", in); | |
927 | } | |
928 | ||
929 | static bool issue_set_bucket_resharding(librados::IoCtx& io_ctx, const string& oid, | |
930 | const cls_rgw_bucket_instance_entry& entry, | |
931 | BucketIndexAioManager *manager) { | |
932 | bufferlist in; | |
933 | struct cls_rgw_set_bucket_resharding_op call; | |
934 | call.entry = entry; | |
935 | ::encode(call, in); | |
936 | librados::ObjectWriteOperation op; | |
937 | op.exec("rgw", "set_bucket_resharding", in); | |
938 | return manager->aio_operate(io_ctx, oid, &op); | |
939 | } | |
940 | ||
941 | int CLSRGWIssueSetBucketResharding::issue_op(int shard_id, const string& oid) | |
942 | { | |
943 | return issue_set_bucket_resharding(io_ctx, oid, entry, &manager); | |
944 | } | |
945 |