]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_rados.cc
update sources to v12.2.4
[ceph.git] / ceph / src / rgw / rgw_rados.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 "include/compat.h"
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <boost/algorithm/string.hpp>
9
10 #include <boost/format.hpp>
11 #include <boost/optional.hpp>
12 #include <boost/utility/in_place_factory.hpp>
13
14 #include "common/ceph_json.h"
15 #include "common/utf8.h"
16
17 #include "common/errno.h"
18 #include "common/Formatter.h"
19 #include "common/Throttle.h"
20 #include "common/Finisher.h"
21
22 #include "rgw_rados.h"
23 #include "rgw_cache.h"
24 #include "rgw_acl.h"
25 #include "rgw_acl_s3.h" /* for dumping s3policy in debug log */
26 #include "rgw_metadata.h"
27 #include "rgw_bucket.h"
28 #include "rgw_rest_conn.h"
29 #include "rgw_cr_rados.h"
30 #include "rgw_cr_rest.h"
31
32 #include "cls/rgw/cls_rgw_ops.h"
33 #include "cls/rgw/cls_rgw_types.h"
34 #include "cls/rgw/cls_rgw_client.h"
35 #include "cls/rgw/cls_rgw_const.h"
36 #include "cls/refcount/cls_refcount_client.h"
37 #include "cls/version/cls_version_client.h"
38 #include "cls/log/cls_log_client.h"
39 #include "cls/statelog/cls_statelog_client.h"
40 #include "cls/timeindex/cls_timeindex_client.h"
41 #include "cls/lock/cls_lock_client.h"
42 #include "cls/user/cls_user_client.h"
43 #include "osd/osd_types.h"
44
45 #include "rgw_tools.h"
46 #include "rgw_coroutine.h"
47 #include "rgw_compression.h"
48
49 #undef fork // fails to compile RGWPeriod::fork() below
50
51 #include "common/Clock.h"
52
53 #include "include/rados/librados.hpp"
54 using namespace librados;
55
56 #include <string>
57 #include <iostream>
58 #include <vector>
59 #include <atomic>
60 #include <list>
61 #include <map>
62 #include "auth/Crypto.h" // get_random_bytes()
63
64 #include "rgw_log.h"
65
66 #include "rgw_gc.h"
67 #include "rgw_lc.h"
68
69 #include "rgw_object_expirer_core.h"
70 #include "rgw_sync.h"
71 #include "rgw_data_sync.h"
72 #include "rgw_realm_watcher.h"
73 #include "rgw_reshard.h"
74
75 #include "compressor/Compressor.h"
76
77 #define dout_context g_ceph_context
78 #define dout_subsys ceph_subsys_rgw
79
80 using namespace std;
81
82 static string notify_oid_prefix = "notify";
83 static string *notify_oids = NULL;
84 static string shadow_ns = "shadow";
85 static string dir_oid_prefix = ".dir.";
86 static string default_storage_pool_suffix = "rgw.buckets.data";
87 static string default_bucket_index_pool_suffix = "rgw.buckets.index";
88 static string default_storage_extra_pool_suffix = "rgw.buckets.non-ec";
89 static string avail_pools = ".pools.avail";
90
91 static string zone_info_oid_prefix = "zone_info.";
92 static string zone_names_oid_prefix = "zone_names.";
93 static string region_info_oid_prefix = "region_info.";
94 static string zone_group_info_oid_prefix = "zonegroup_info.";
95 static string realm_names_oid_prefix = "realms_names.";
96 static string realm_info_oid_prefix = "realms.";
97 static string default_region_info_oid = "default.region";
98 static string default_zone_group_info_oid = "default.zonegroup";
99 static string period_info_oid_prefix = "periods.";
100 static string period_latest_epoch_info_oid = ".latest_epoch";
101 static string region_map_oid = "region_map";
102 static string zonegroup_map_oid = "zonegroup_map";
103 static string log_lock_name = "rgw_log_lock";
104 static string default_realm_info_oid = "default.realm";
105 const string default_zonegroup_name = "default";
106 const string default_zone_name = "default";
107 static string zonegroup_names_oid_prefix = "zonegroups_names.";
108 static RGWObjCategory main_category = RGW_OBJ_CATEGORY_MAIN;
109 #define RGW_USAGE_OBJ_PREFIX "usage."
110 #define FIRST_EPOCH 1
111 static string RGW_DEFAULT_ZONE_ROOT_POOL = "rgw.root";
112 static string RGW_DEFAULT_ZONEGROUP_ROOT_POOL = "rgw.root";
113 static string RGW_DEFAULT_REALM_ROOT_POOL = "rgw.root";
114 static string RGW_DEFAULT_PERIOD_ROOT_POOL = "rgw.root";
115
116 #define RGW_STATELOG_OBJ_PREFIX "statelog."
117
118 #define dout_subsys ceph_subsys_rgw
119
120
121 static bool rgw_get_obj_data_pool(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params,
122 const string& placement_id, const rgw_obj& obj, rgw_pool *pool)
123 {
124 if (!zone_params.get_head_data_pool(placement_id, obj, pool)) {
125 RGWZonePlacementInfo placement;
126 if (!zone_params.get_placement(zonegroup.default_placement, &placement)) {
127 return false;
128 }
129
130 if (!obj.in_extra_data) {
131 *pool = placement.data_pool;
132 } else {
133 *pool = placement.get_data_extra_pool();
134 }
135 }
136
137 return true;
138 }
139
140 static bool rgw_obj_to_raw(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params,
141 const string& placement_id, const rgw_obj& obj, rgw_raw_obj *raw_obj)
142 {
143 get_obj_bucket_and_oid_loc(obj, raw_obj->oid, raw_obj->loc);
144
145 return rgw_get_obj_data_pool(zonegroup, zone_params, placement_id, obj, &raw_obj->pool);
146 }
147
148 rgw_raw_obj rgw_obj_select::get_raw_obj(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params) const
149 {
150 if (!is_raw) {
151 rgw_raw_obj r;
152 rgw_obj_to_raw(zonegroup, zone_params, placement_rule, obj, &r);
153 return r;
154 }
155 return raw_obj;
156 }
157
158 rgw_raw_obj rgw_obj_select::get_raw_obj(RGWRados *store) const
159 {
160 if (!is_raw) {
161 rgw_raw_obj r;
162 store->obj_to_raw(placement_rule, obj, &r);
163 return r;
164 }
165 return raw_obj;
166 }
167
168 int rgw_init_ioctx(librados::Rados *rados, const rgw_pool& pool, IoCtx& ioctx, bool create)
169 {
170 int r = rados->ioctx_create(pool.name.c_str(), ioctx);
171 if (r == -ENOENT && create) {
172 r = rados->pool_create(pool.name.c_str());
173 if (r < 0 && r != -EEXIST) {
174 return r;
175 }
176
177 r = rados->ioctx_create(pool.name.c_str(), ioctx);
178 if (r < 0) {
179 return r;
180 }
181
182 r = ioctx.application_enable(pg_pool_t::APPLICATION_NAME_RGW, false);
183 if (r < 0 && r != -EOPNOTSUPP) {
184 return r;
185 }
186 } else if (r < 0) {
187 return r;
188 }
189 if (!pool.ns.empty()) {
190 ioctx.set_namespace(pool.ns);
191 }
192 return 0;
193 }
194
195 template<>
196 void RGWObjectCtxImpl<rgw_obj, RGWObjState>::invalidate(rgw_obj& obj) {
197 RWLock::WLocker wl(lock);
198 auto iter = objs_state.find(obj);
199 if (iter == objs_state.end()) {
200 return;
201 }
202 bool is_atomic = iter->second.is_atomic;
203 bool prefetch_data = iter->second.prefetch_data;
204
205 objs_state.erase(iter);
206
207 if (is_atomic || prefetch_data) {
208 auto& s = objs_state[obj];
209 s.is_atomic = is_atomic;
210 s.prefetch_data = prefetch_data;
211 }
212 }
213
214 template<>
215 void RGWObjectCtxImpl<rgw_raw_obj, RGWRawObjState>::invalidate(rgw_raw_obj& obj) {
216 RWLock::WLocker wl(lock);
217 auto iter = objs_state.find(obj);
218 if (iter == objs_state.end()) {
219 return;
220 }
221
222 objs_state.erase(iter);
223 }
224
225 void RGWDefaultZoneGroupInfo::dump(Formatter *f) const {
226 encode_json("default_zonegroup", default_zonegroup, f);
227 }
228
229 void RGWDefaultZoneGroupInfo::decode_json(JSONObj *obj) {
230
231 JSONDecoder::decode_json("default_zonegroup", default_zonegroup, obj);
232 /* backward compatability with region */
233 if (default_zonegroup.empty()) {
234 JSONDecoder::decode_json("default_region", default_zonegroup, obj);
235 }
236 }
237
238 rgw_pool RGWZoneGroup::get_pool(CephContext *cct_)
239 {
240 if (cct_->_conf->rgw_zonegroup_root_pool.empty()) {
241 return rgw_pool(RGW_DEFAULT_ZONEGROUP_ROOT_POOL);
242 }
243
244 return rgw_pool(cct_->_conf->rgw_zonegroup_root_pool);
245 }
246
247 int RGWZoneGroup::create_default(bool old_format)
248 {
249 name = default_zonegroup_name;
250 is_master = true;
251
252 RGWZoneGroupPlacementTarget placement_target;
253 placement_target.name = "default-placement";
254 placement_targets[placement_target.name] = placement_target;
255 default_placement = "default-placement";
256
257 RGWZoneParams zone_params(default_zone_name);
258
259 int r = zone_params.init(cct, store, false);
260 if (r < 0) {
261 ldout(cct, 0) << "create_default: error initializing zone params: " << cpp_strerror(-r) << dendl;
262 return r;
263 }
264
265 r = zone_params.create_default();
266 if (r < 0 && r != -EEXIST) {
267 ldout(cct, 0) << "create_default: error in create_default zone params: " << cpp_strerror(-r) << dendl;
268 return r;
269 } else if (r == -EEXIST) {
270 ldout(cct, 10) << "zone_params::create_default() returned -EEXIST, we raced with another default zone_params creation" << dendl;
271 zone_params.clear_id();
272 r = zone_params.init(cct, store);
273 if (r < 0) {
274 ldout(cct, 0) << "create_default: error in init existing zone params: " << cpp_strerror(-r) << dendl;
275 return r;
276 }
277 ldout(cct, 20) << "zone_params::create_default() " << zone_params.get_name() << " id " << zone_params.get_id()
278 << dendl;
279 }
280
281 RGWZone& default_zone = zones[zone_params.get_id()];
282 default_zone.name = zone_params.get_name();
283 default_zone.id = zone_params.get_id();
284 master_zone = default_zone.id;
285
286 r = create();
287 if (r < 0 && r != -EEXIST) {
288 ldout(cct, 0) << "error storing zone group info: " << cpp_strerror(-r) << dendl;
289 return r;
290 }
291
292 if (r == -EEXIST) {
293 ldout(cct, 10) << "create_default() returned -EEXIST, we raced with another zonegroup creation" << dendl;
294 id.clear();
295 r = init(cct, store);
296 if (r < 0) {
297 return r;
298 }
299 }
300
301 if (old_format) {
302 name = id;
303 }
304
305 post_process_params();
306
307 return 0;
308 }
309
310 const string RGWZoneGroup::get_default_oid(bool old_region_format)
311 {
312 if (old_region_format) {
313 if (cct->_conf->rgw_default_region_info_oid.empty()) {
314 return default_region_info_oid;
315 }
316 return cct->_conf->rgw_default_region_info_oid;
317 }
318
319 string default_oid = cct->_conf->rgw_default_zonegroup_info_oid;
320
321 if (cct->_conf->rgw_default_zonegroup_info_oid.empty()) {
322 default_oid = default_zone_group_info_oid;
323 }
324
325 default_oid += "." + realm_id;
326
327 return default_oid;
328 }
329
330 const string& RGWZoneGroup::get_info_oid_prefix(bool old_region_format)
331 {
332 if (old_region_format) {
333 return region_info_oid_prefix;
334 }
335 return zone_group_info_oid_prefix;
336 }
337
338 const string& RGWZoneGroup::get_names_oid_prefix()
339 {
340 return zonegroup_names_oid_prefix;
341 }
342
343 const string& RGWZoneGroup::get_predefined_name(CephContext *cct) {
344 return cct->_conf->rgw_zonegroup;
345 }
346
347 int RGWZoneGroup::equals(const string& other_zonegroup) const
348 {
349 if (is_master && other_zonegroup.empty())
350 return true;
351
352 return (id == other_zonegroup);
353 }
354
355 int RGWZoneGroup::add_zone(const RGWZoneParams& zone_params, bool *is_master, bool *read_only,
356 const list<string>& endpoints, const string *ptier_type,
357 bool *psync_from_all, list<string>& sync_from, list<string>& sync_from_rm)
358 {
359 auto& zone_id = zone_params.get_id();
360 auto& zone_name = zone_params.get_name();
361
362 // check for duplicate zone name on insert
363 if (!zones.count(zone_id)) {
364 for (const auto& zone : zones) {
365 if (zone.second.name == zone_name) {
366 ldout(cct, 0) << "ERROR: found existing zone name " << zone_name
367 << " (" << zone.first << ") in zonegroup " << get_name() << dendl;
368 return -EEXIST;
369 }
370 }
371 }
372
373 if (is_master) {
374 if (*is_master) {
375 if (!master_zone.empty() && master_zone != zone_params.get_id()) {
376 ldout(cct, 0) << "NOTICE: overriding master zone: " << master_zone << dendl;
377 }
378 master_zone = zone_params.get_id();
379 } else if (master_zone == zone_params.get_id()) {
380 master_zone.clear();
381 }
382 }
383
384 RGWZone& zone = zones[zone_params.get_id()];
385 zone.name = zone_params.get_name();
386 zone.id = zone_params.get_id();
387 if (!endpoints.empty()) {
388 zone.endpoints = endpoints;
389 }
390 if (read_only) {
391 zone.read_only = *read_only;
392 }
393 if (ptier_type) {
394 zone.tier_type = *ptier_type;
395 }
396
397 if (psync_from_all) {
398 zone.sync_from_all = *psync_from_all;
399 }
400
401 for (auto add : sync_from) {
402 zone.sync_from.insert(add);
403 }
404
405 for (auto rm : sync_from_rm) {
406 zone.sync_from.erase(rm);
407 }
408
409 post_process_params();
410
411 return update();
412 }
413
414
415 int RGWZoneGroup::rename_zone(const RGWZoneParams& zone_params)
416 {
417 RGWZone& zone = zones[zone_params.get_id()];
418 zone.name = zone_params.get_name();
419
420 return update();
421 }
422
423 void RGWZoneGroup::post_process_params()
424 {
425 bool log_data = zones.size() > 1;
426
427 if (master_zone.empty()) {
428 map<string, RGWZone>::iterator iter = zones.begin();
429 if (iter != zones.end()) {
430 master_zone = iter->first;
431 }
432 }
433
434 for (map<string, RGWZone>::iterator iter = zones.begin(); iter != zones.end(); ++iter) {
435 RGWZone& zone = iter->second;
436 zone.log_data = log_data;
437
438 RGWZoneParams zone_params(zone.id, zone.name);
439 int ret = zone_params.init(cct, store);
440 if (ret < 0) {
441 ldout(cct, 0) << "WARNING: could not read zone params for zone id=" << zone.id << " name=" << zone.name << dendl;
442 continue;
443 }
444
445 for (map<string, RGWZonePlacementInfo>::iterator iter = zone_params.placement_pools.begin();
446 iter != zone_params.placement_pools.end(); ++iter) {
447 const string& placement_name = iter->first;
448 if (placement_targets.find(placement_name) == placement_targets.end()) {
449 RGWZoneGroupPlacementTarget placement_target;
450 placement_target.name = placement_name;
451 placement_targets[placement_name] = placement_target;
452 }
453 }
454 }
455
456 if (default_placement.empty() && !placement_targets.empty()) {
457 default_placement = placement_targets.begin()->first;
458 }
459 }
460
461 int RGWZoneGroup::remove_zone(const std::string& zone_id)
462 {
463 map<string, RGWZone>::iterator iter = zones.find(zone_id);
464 if (iter == zones.end()) {
465 ldout(cct, 0) << "zone id " << zone_id << " is not a part of zonegroup "
466 << name << dendl;
467 return -ENOENT;
468 }
469
470 zones.erase(iter);
471
472 post_process_params();
473
474 return update();
475 }
476
477 int RGWZoneGroup::read_default_id(string& default_id, bool old_format)
478 {
479 if (realm_id.empty()) {
480 /* try using default realm */
481 RGWRealm realm;
482 int ret = realm.init(cct, store);
483 // no default realm exist
484 if (ret < 0) {
485 return read_id(default_zonegroup_name, default_id);
486 }
487 realm_id = realm.get_id();
488 }
489
490 return RGWSystemMetaObj::read_default_id(default_id, old_format);
491 }
492
493 int RGWZoneGroup::set_as_default(bool exclusive)
494 {
495 if (realm_id.empty()) {
496 /* try using default realm */
497 RGWRealm realm;
498 int ret = realm.init(cct, store);
499 if (ret < 0) {
500 ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl;
501 return -EINVAL;
502 }
503 realm_id = realm.get_id();
504 }
505
506 return RGWSystemMetaObj::set_as_default(exclusive);
507 }
508
509 int RGWSystemMetaObj::init(CephContext *_cct, RGWRados *_store, bool setup_obj, bool old_format)
510 {
511 cct = _cct;
512 store = _store;
513
514 if (!setup_obj)
515 return 0;
516
517 if (old_format && id.empty()) {
518 id = name;
519 }
520
521 if (id.empty()) {
522 int r;
523 if (name.empty()) {
524 name = get_predefined_name(cct);
525 }
526 if (name.empty()) {
527 r = use_default(old_format);
528 if (r < 0) {
529 return r;
530 }
531 } else if (!old_format) {
532 r = read_id(name, id);
533 if (r < 0) {
534 if (r != -ENOENT) {
535 ldout(cct, 0) << "error in read_id for object name: " << name << " : " << cpp_strerror(-r) << dendl;
536 }
537 return r;
538 }
539 }
540 }
541
542 return read_info(id, old_format);
543 }
544
545 int RGWSystemMetaObj::read_default(RGWDefaultSystemMetaObjInfo& default_info, const string& oid)
546 {
547 auto pool = get_pool(cct);
548 bufferlist bl;
549 RGWObjectCtx obj_ctx(store);
550 int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL);
551 if (ret < 0)
552 return ret;
553
554 try {
555 bufferlist::iterator iter = bl.begin();
556 ::decode(default_info, iter);
557 } catch (buffer::error& err) {
558 ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl;
559 return -EIO;
560 }
561
562 return 0;
563 }
564
565 int RGWSystemMetaObj::read_default_id(string& default_id, bool old_format)
566 {
567 RGWDefaultSystemMetaObjInfo default_info;
568
569 int ret = read_default(default_info, get_default_oid(old_format));
570 if (ret < 0) {
571 return ret;
572 }
573
574 default_id = default_info.default_id;
575
576 return 0;
577 }
578
579 int RGWSystemMetaObj::use_default(bool old_format)
580 {
581 return read_default_id(id, old_format);
582 }
583
584 int RGWSystemMetaObj::set_as_default(bool exclusive)
585 {
586 string oid = get_default_oid();
587
588 rgw_pool pool(get_pool(cct));
589 bufferlist bl;
590
591 RGWDefaultSystemMetaObjInfo default_info;
592 default_info.default_id = id;
593
594 ::encode(default_info, bl);
595
596 int ret = rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(),
597 exclusive, NULL, real_time(), NULL);
598 if (ret < 0)
599 return ret;
600
601 return 0;
602 }
603
604 int RGWSystemMetaObj::read_id(const string& obj_name, string& object_id)
605 {
606 rgw_pool pool(get_pool(cct));
607 bufferlist bl;
608
609 string oid = get_names_oid_prefix() + obj_name;
610
611 RGWObjectCtx obj_ctx(store);
612 int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL);
613 if (ret < 0) {
614 return ret;
615 }
616
617 RGWNameToId nameToId;
618 try {
619 bufferlist::iterator iter = bl.begin();
620 ::decode(nameToId, iter);
621 } catch (buffer::error& err) {
622 ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl;
623 return -EIO;
624 }
625 object_id = nameToId.obj_id;
626 return 0;
627 }
628
629 int RGWSystemMetaObj::delete_obj(bool old_format)
630 {
631 rgw_pool pool(get_pool(cct));
632
633 /* check to see if obj is the default */
634 RGWDefaultSystemMetaObjInfo default_info;
635 int ret = read_default(default_info, get_default_oid(old_format));
636 if (ret < 0 && ret != -ENOENT)
637 return ret;
638 if (default_info.default_id == id || (old_format && default_info.default_id == name)) {
639 string oid = get_default_oid(old_format);
640 rgw_raw_obj default_named_obj(pool, oid);
641 ret = store->delete_system_obj(default_named_obj);
642 if (ret < 0) {
643 ldout(cct, 0) << "Error delete default obj name " << name << ": " << cpp_strerror(-ret) << dendl;
644 return ret;
645 }
646 }
647 if (!old_format) {
648 string oid = get_names_oid_prefix() + name;
649 rgw_raw_obj object_name(pool, oid);
650 ret = store->delete_system_obj(object_name);
651 if (ret < 0) {
652 ldout(cct, 0) << "Error delete obj name " << name << ": " << cpp_strerror(-ret) << dendl;
653 return ret;
654 }
655 }
656
657 string oid = get_info_oid_prefix(old_format);
658 if (old_format) {
659 oid += name;
660 } else {
661 oid += id;
662 }
663
664 rgw_raw_obj object_id(pool, oid);
665 ret = store->delete_system_obj(object_id);
666 if (ret < 0) {
667 ldout(cct, 0) << "Error delete object id " << id << ": " << cpp_strerror(-ret) << dendl;
668 }
669
670 return ret;
671 }
672
673 int RGWSystemMetaObj::store_name(bool exclusive)
674 {
675 rgw_pool pool(get_pool(cct));
676 string oid = get_names_oid_prefix() + name;
677
678 RGWNameToId nameToId;
679 nameToId.obj_id = id;
680
681 bufferlist bl;
682 ::encode(nameToId, bl);
683 return rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), exclusive, NULL, real_time(), NULL);
684 }
685
686 int RGWSystemMetaObj::rename(const string& new_name)
687 {
688 string new_id;
689 int ret = read_id(new_name, new_id);
690 if (!ret) {
691 return -EEXIST;
692 }
693 if (ret < 0 && ret != -ENOENT) {
694 ldout(cct, 0) << "Error read_id " << new_name << ": " << cpp_strerror(-ret) << dendl;
695 return ret;
696 }
697 string old_name = name;
698 name = new_name;
699 ret = update();
700 if (ret < 0) {
701 ldout(cct, 0) << "Error storing new obj info " << new_name << ": " << cpp_strerror(-ret) << dendl;
702 return ret;
703 }
704 ret = store_name(true);
705 if (ret < 0) {
706 ldout(cct, 0) << "Error storing new name " << new_name << ": " << cpp_strerror(-ret) << dendl;
707 return ret;
708 }
709 /* delete old name */
710 rgw_pool pool(get_pool(cct));
711 string oid = get_names_oid_prefix() + old_name;
712 rgw_raw_obj old_name_obj(pool, oid);
713 ret = store->delete_system_obj(old_name_obj);
714 if (ret < 0) {
715 ldout(cct, 0) << "Error delete old obj name " << old_name << ": " << cpp_strerror(-ret) << dendl;
716 return ret;
717 }
718
719 return ret;
720 }
721
722 int RGWSystemMetaObj::read_info(const string& obj_id, bool old_format)
723 {
724 rgw_pool pool(get_pool(cct));
725
726 bufferlist bl;
727
728 string oid = get_info_oid_prefix(old_format) + obj_id;
729
730 RGWObjectCtx obj_ctx(store);
731 int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL);
732 if (ret < 0) {
733 ldout(cct, 0) << "failed reading obj info from " << pool << ":" << oid << ": " << cpp_strerror(-ret) << dendl;
734 return ret;
735 }
736
737 try {
738 bufferlist::iterator iter = bl.begin();
739 ::decode(*this, iter);
740 } catch (buffer::error& err) {
741 ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl;
742 return -EIO;
743 }
744
745 return 0;
746 }
747
748 int RGWSystemMetaObj::read()
749 {
750 int ret = read_id(name, id);
751 if (ret < 0) {
752 return ret;
753 }
754
755 return read_info(id);
756 }
757
758 int RGWSystemMetaObj::create(bool exclusive)
759 {
760 int ret;
761
762 /* check to see the name is not used */
763 ret = read_id(name, id);
764 if (exclusive && ret == 0) {
765 ldout(cct, 10) << "ERROR: name " << name << " already in use for obj id " << id << dendl;
766 return -EEXIST;
767 } else if ( ret < 0 && ret != -ENOENT) {
768 ldout(cct, 0) << "failed reading obj id " << id << ": " << cpp_strerror(-ret) << dendl;
769 return ret;
770 }
771
772 if (id.empty()) {
773 /* create unique id */
774 uuid_d new_uuid;
775 char uuid_str[37];
776 new_uuid.generate_random();
777 new_uuid.print(uuid_str);
778 id = uuid_str;
779 }
780
781 ret = store_info(exclusive);
782 if (ret < 0) {
783 ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl;
784 return ret;
785 }
786
787 return store_name(exclusive);
788 }
789
790 int RGWSystemMetaObj::store_info(bool exclusive)
791 {
792 rgw_pool pool(get_pool(cct));
793
794 string oid = get_info_oid_prefix() + id;
795
796 bufferlist bl;
797 ::encode(*this, bl);
798 return rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), exclusive, NULL, real_time(), NULL);
799 }
800
801 int RGWSystemMetaObj::write(bool exclusive)
802 {
803 int ret = store_info(exclusive);
804 if (ret < 0) {
805 ldout(cct, 20) << __func__ << "(): store_info() returned ret=" << ret << dendl;
806 return ret;
807 }
808 ret = store_name(exclusive);
809 if (ret < 0) {
810 ldout(cct, 20) << __func__ << "(): store_name() returned ret=" << ret << dendl;
811 return ret;
812 }
813 return 0;
814 }
815
816
817 const string& RGWRealm::get_predefined_name(CephContext *cct) {
818 return cct->_conf->rgw_realm;
819 }
820
821 int RGWRealm::create(bool exclusive)
822 {
823 int ret = RGWSystemMetaObj::create(exclusive);
824 if (ret < 0) {
825 ldout(cct, 0) << "ERROR creating new realm object " << name << ": " << cpp_strerror(-ret) << dendl;
826 return ret;
827 }
828 // create the control object for watch/notify
829 ret = create_control(exclusive);
830 if (ret < 0) {
831 ldout(cct, 0) << "ERROR creating control for new realm " << name << ": " << cpp_strerror(-ret) << dendl;
832 return ret;
833 }
834 RGWPeriod period;
835 if (current_period.empty()) {
836 /* create new period for the realm */
837 ret = period.init(cct, store, id, name, false);
838 if (ret < 0 ) {
839 return ret;
840 }
841 ret = period.create(true);
842 if (ret < 0) {
843 ldout(cct, 0) << "ERROR: creating new period for realm " << name << ": " << cpp_strerror(-ret) << dendl;
844 return ret;
845 }
846 } else {
847 period = RGWPeriod(current_period, 0);
848 int ret = period.init(cct, store, id, name);
849 if (ret < 0) {
850 ldout(cct, 0) << "ERROR: failed to init period " << current_period << dendl;
851 return ret;
852 }
853 }
854 ret = set_current_period(period);
855 if (ret < 0) {
856 ldout(cct, 0) << "ERROR: failed set current period " << current_period << dendl;
857 return ret;
858 }
859 // try to set as default. may race with another create, so pass exclusive=true
860 // so we don't override an existing default
861 ret = set_as_default(true);
862 if (ret < 0 && ret != -EEXIST) {
863 ldout(cct, 0) << "WARNING: failed to set realm as default realm, ret=" << ret << dendl;
864 }
865
866 return 0;
867 }
868
869 int RGWRealm::delete_obj()
870 {
871 int ret = RGWSystemMetaObj::delete_obj();
872 if (ret < 0) {
873 return ret;
874 }
875 return delete_control();
876 }
877
878 int RGWRealm::create_control(bool exclusive)
879 {
880 auto pool = rgw_pool{get_pool(cct)};
881 auto oid = get_control_oid();
882 return rgw_put_system_obj(store, pool, oid, nullptr, 0, exclusive,
883 nullptr, real_time(), nullptr);
884 }
885
886 int RGWRealm::delete_control()
887 {
888 auto pool = rgw_pool{get_pool(cct)};
889 auto obj = rgw_raw_obj{pool, get_control_oid()};
890 return store->delete_system_obj(obj);
891 }
892
893 rgw_pool RGWRealm::get_pool(CephContext *cct)
894 {
895 if (cct->_conf->rgw_realm_root_pool.empty()) {
896 return rgw_pool(RGW_DEFAULT_REALM_ROOT_POOL);
897 }
898 return rgw_pool(cct->_conf->rgw_realm_root_pool);
899 }
900
901 const string RGWRealm::get_default_oid(bool old_format)
902 {
903 if (cct->_conf->rgw_default_realm_info_oid.empty()) {
904 return default_realm_info_oid;
905 }
906 return cct->_conf->rgw_default_realm_info_oid;
907 }
908
909 const string& RGWRealm::get_names_oid_prefix()
910 {
911 return realm_names_oid_prefix;
912 }
913
914 const string& RGWRealm::get_info_oid_prefix(bool old_format)
915 {
916 return realm_info_oid_prefix;
917 }
918
919 int RGWRealm::set_current_period(RGWPeriod& period)
920 {
921 // update realm epoch to match the period's
922 if (epoch > period.get_realm_epoch()) {
923 ldout(cct, 0) << "ERROR: set_current_period with old realm epoch "
924 << period.get_realm_epoch() << ", current epoch=" << epoch << dendl;
925 return -EINVAL;
926 }
927 if (epoch == period.get_realm_epoch() && current_period != period.get_id()) {
928 ldout(cct, 0) << "ERROR: set_current_period with same realm epoch "
929 << period.get_realm_epoch() << ", but different period id "
930 << period.get_id() << " != " << current_period << dendl;
931 return -EINVAL;
932 }
933
934 epoch = period.get_realm_epoch();
935 current_period = period.get_id();
936
937 int ret = update();
938 if (ret < 0) {
939 ldout(cct, 0) << "ERROR: period update: " << cpp_strerror(-ret) << dendl;
940 return ret;
941 }
942
943 ret = period.reflect();
944 if (ret < 0) {
945 ldout(cct, 0) << "ERROR: period.reflect(): " << cpp_strerror(-ret) << dendl;
946 return ret;
947 }
948
949 return 0;
950 }
951
952 string RGWRealm::get_control_oid()
953 {
954 return get_info_oid_prefix() + id + ".control";
955 }
956
957 int RGWRealm::notify_zone(bufferlist& bl)
958 {
959 // open a context on the realm's pool
960 rgw_pool pool{get_pool(cct)};
961 librados::IoCtx ctx;
962 int r = rgw_init_ioctx(store->get_rados_handle(), pool, ctx);
963 if (r < 0) {
964 ldout(cct, 0) << "Failed to open pool " << pool << dendl;
965 return r;
966 }
967 // send a notify on the realm object
968 r = ctx.notify2(get_control_oid(), bl, 0, nullptr);
969 if (r < 0) {
970 ldout(cct, 0) << "Realm notify failed with " << r << dendl;
971 return r;
972 }
973 return 0;
974 }
975
976 int RGWRealm::notify_new_period(const RGWPeriod& period)
977 {
978 bufferlist bl;
979 // push the period to dependent zonegroups/zones
980 ::encode(RGWRealmNotify::ZonesNeedPeriod, bl);
981 ::encode(period, bl);
982 // reload the gateway with the new period
983 ::encode(RGWRealmNotify::Reload, bl);
984
985 return notify_zone(bl);
986 }
987
988 std::string RGWPeriodConfig::get_oid(const std::string& realm_id)
989 {
990 if (realm_id.empty()) {
991 return "period_config.default";
992 }
993 return "period_config." + realm_id;
994 }
995
996 rgw_pool RGWPeriodConfig::get_pool(CephContext *cct)
997 {
998 const auto& pool_name = cct->_conf->rgw_period_root_pool;
999 if (pool_name.empty()) {
1000 return {RGW_DEFAULT_PERIOD_ROOT_POOL};
1001 }
1002 return {pool_name};
1003 }
1004
1005 int RGWPeriodConfig::read(RGWRados *store, const std::string& realm_id)
1006 {
1007 RGWObjectCtx obj_ctx(store);
1008 const auto& pool = get_pool(store->ctx());
1009 const auto& oid = get_oid(realm_id);
1010 bufferlist bl;
1011
1012 int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, nullptr, nullptr);
1013 if (ret < 0) {
1014 return ret;
1015 }
1016 try {
1017 bufferlist::iterator iter = bl.begin();
1018 ::decode(*this, iter);
1019 } catch (buffer::error& err) {
1020 return -EIO;
1021 }
1022 return 0;
1023 }
1024
1025 int RGWPeriodConfig::write(RGWRados *store, const std::string& realm_id)
1026 {
1027 const auto& pool = get_pool(store->ctx());
1028 const auto& oid = get_oid(realm_id);
1029 bufferlist bl;
1030 ::encode(*this, bl);
1031 return rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(),
1032 false, nullptr, real_time(), nullptr);
1033 }
1034
1035 int RGWPeriod::init(CephContext *_cct, RGWRados *_store, const string& period_realm_id,
1036 const string& period_realm_name, bool setup_obj)
1037 {
1038 cct = _cct;
1039 store = _store;
1040 realm_id = period_realm_id;
1041 realm_name = period_realm_name;
1042
1043 if (!setup_obj)
1044 return 0;
1045
1046 return init(_cct, _store, setup_obj);
1047 }
1048
1049
1050 int RGWPeriod::init(CephContext *_cct, RGWRados *_store, bool setup_obj)
1051 {
1052 cct = _cct;
1053 store = _store;
1054
1055 if (!setup_obj)
1056 return 0;
1057
1058 if (id.empty()) {
1059 RGWRealm realm(realm_id, realm_name);
1060 int ret = realm.init(cct, store);
1061 if (ret < 0) {
1062 ldout(cct, 0) << "RGWPeriod::init failed to init realm " << realm_name << " id " << realm_id << " : " <<
1063 cpp_strerror(-ret) << dendl;
1064 return ret;
1065 }
1066 id = realm.get_current_period();
1067 realm_id = realm.get_id();
1068 }
1069
1070 if (!epoch) {
1071 int ret = use_latest_epoch();
1072 if (ret < 0) {
1073 ldout(cct, 0) << "failed to use_latest_epoch period id " << id << " realm " << realm_name << " id " << realm_id
1074 << " : " << cpp_strerror(-ret) << dendl;
1075 return ret;
1076 }
1077 }
1078
1079 return read_info();
1080 }
1081
1082
1083 int RGWPeriod::get_zonegroup(RGWZoneGroup& zonegroup, const string& zonegroup_id) {
1084 map<string, RGWZoneGroup>::const_iterator iter;
1085 if (!zonegroup_id.empty()) {
1086 iter = period_map.zonegroups.find(zonegroup_id);
1087 } else {
1088 iter = period_map.zonegroups.find("default");
1089 }
1090 if (iter != period_map.zonegroups.end()) {
1091 zonegroup = iter->second;
1092 return 0;
1093 }
1094
1095 return -ENOENT;
1096 }
1097
1098 const string& RGWPeriod::get_latest_epoch_oid()
1099 {
1100 if (cct->_conf->rgw_period_latest_epoch_info_oid.empty()) {
1101 return period_latest_epoch_info_oid;
1102 }
1103 return cct->_conf->rgw_period_latest_epoch_info_oid;
1104 }
1105
1106 const string& RGWPeriod::get_info_oid_prefix()
1107 {
1108 return period_info_oid_prefix;
1109 }
1110
1111 const string RGWPeriod::get_period_oid_prefix()
1112 {
1113 return get_info_oid_prefix() + id;
1114 }
1115
1116 const string RGWPeriod::get_period_oid()
1117 {
1118 std::ostringstream oss;
1119 oss << get_period_oid_prefix();
1120 // skip the epoch for the staging period
1121 if (id != get_staging_id(realm_id))
1122 oss << "." << epoch;
1123 return oss.str();
1124 }
1125
1126 int RGWPeriod::read_latest_epoch(RGWPeriodLatestEpochInfo& info,
1127 RGWObjVersionTracker *objv)
1128 {
1129 string oid = get_period_oid_prefix() + get_latest_epoch_oid();
1130
1131 rgw_pool pool(get_pool(cct));
1132 bufferlist bl;
1133 RGWObjectCtx obj_ctx(store);
1134 int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, objv, nullptr);
1135 if (ret < 0) {
1136 ldout(cct, 1) << "error read_lastest_epoch " << pool << ":" << oid << dendl;
1137 return ret;
1138 }
1139 try {
1140 bufferlist::iterator iter = bl.begin();
1141 ::decode(info, iter);
1142 } catch (buffer::error& err) {
1143 ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl;
1144 return -EIO;
1145 }
1146
1147 return 0;
1148 }
1149
1150 int RGWPeriod::get_latest_epoch(epoch_t& latest_epoch)
1151 {
1152 RGWPeriodLatestEpochInfo info;
1153
1154 int ret = read_latest_epoch(info);
1155 if (ret < 0) {
1156 return ret;
1157 }
1158
1159 latest_epoch = info.epoch;
1160
1161 return 0;
1162 }
1163
1164 int RGWPeriod::use_latest_epoch()
1165 {
1166 RGWPeriodLatestEpochInfo info;
1167 int ret = read_latest_epoch(info);
1168 if (ret < 0) {
1169 return ret;
1170 }
1171
1172 epoch = info.epoch;
1173
1174 return 0;
1175 }
1176
1177 int RGWPeriod::set_latest_epoch(epoch_t epoch, bool exclusive,
1178 RGWObjVersionTracker *objv)
1179 {
1180 string oid = get_period_oid_prefix() + get_latest_epoch_oid();
1181
1182 rgw_pool pool(get_pool(cct));
1183 bufferlist bl;
1184
1185 RGWPeriodLatestEpochInfo info;
1186 info.epoch = epoch;
1187
1188 ::encode(info, bl);
1189
1190 return rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(),
1191 exclusive, objv, real_time(), nullptr);
1192 }
1193
1194 int RGWPeriod::update_latest_epoch(epoch_t epoch)
1195 {
1196 static constexpr int MAX_RETRIES = 20;
1197
1198 for (int i = 0; i < MAX_RETRIES; i++) {
1199 RGWPeriodLatestEpochInfo info;
1200 RGWObjVersionTracker objv;
1201 bool exclusive = false;
1202
1203 // read existing epoch
1204 int r = read_latest_epoch(info, &objv);
1205 if (r == -ENOENT) {
1206 // use an exclusive create to set the epoch atomically
1207 exclusive = true;
1208 ldout(cct, 20) << "creating initial latest_epoch=" << epoch
1209 << " for period=" << id << dendl;
1210 } else if (r < 0) {
1211 ldout(cct, 0) << "ERROR: failed to read latest_epoch" << dendl;
1212 return r;
1213 } else if (epoch <= info.epoch) {
1214 r = -EEXIST; // fail with EEXIST if epoch is not newer
1215 ldout(cct, 1) << "found existing latest_epoch " << info.epoch
1216 << " >= given epoch " << epoch << ", returning r=" << r << dendl;
1217 return r;
1218 } else {
1219 ldout(cct, 20) << "updating latest_epoch from " << info.epoch
1220 << " -> " << epoch << " on period=" << id << dendl;
1221 }
1222
1223 r = set_latest_epoch(epoch, exclusive, &objv);
1224 if (r == -EEXIST) {
1225 continue; // exclusive create raced with another update, retry
1226 } else if (r == -ECANCELED) {
1227 continue; // write raced with a conflicting version, retry
1228 }
1229 if (r < 0) {
1230 ldout(cct, 0) << "ERROR: failed to write latest_epoch" << dendl;
1231 return r;
1232 }
1233 return 0; // return success
1234 }
1235
1236 return -ECANCELED; // fail after max retries
1237 }
1238
1239 int RGWPeriod::delete_obj()
1240 {
1241 rgw_pool pool(get_pool(cct));
1242
1243 // delete the object for each period epoch
1244 for (epoch_t e = 1; e <= epoch; e++) {
1245 RGWPeriod p{get_id(), e};
1246 rgw_raw_obj oid{pool, p.get_period_oid()};
1247 int ret = store->delete_system_obj(oid);
1248 if (ret < 0) {
1249 ldout(cct, 0) << "WARNING: failed to delete period object " << oid
1250 << ": " << cpp_strerror(-ret) << dendl;
1251 }
1252 }
1253
1254 // delete the .latest_epoch object
1255 rgw_raw_obj oid{pool, get_period_oid_prefix() + get_latest_epoch_oid()};
1256 int ret = store->delete_system_obj(oid);
1257 if (ret < 0) {
1258 ldout(cct, 0) << "WARNING: failed to delete period object " << oid
1259 << ": " << cpp_strerror(-ret) << dendl;
1260 }
1261 return ret;
1262 }
1263
1264 int RGWPeriod::read_info()
1265 {
1266 rgw_pool pool(get_pool(cct));
1267
1268 bufferlist bl;
1269
1270 RGWObjectCtx obj_ctx(store);
1271 int ret = rgw_get_system_obj(store, obj_ctx, pool, get_period_oid(), bl, NULL, NULL);
1272 if (ret < 0) {
1273 ldout(cct, 0) << "failed reading obj info from " << pool << ":" << get_period_oid() << ": " << cpp_strerror(-ret) << dendl;
1274 return ret;
1275 }
1276
1277 try {
1278 bufferlist::iterator iter = bl.begin();
1279 ::decode(*this, iter);
1280 } catch (buffer::error& err) {
1281 ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << get_period_oid() << dendl;
1282 return -EIO;
1283 }
1284
1285 return 0;
1286 }
1287
1288 int RGWPeriod::create(bool exclusive)
1289 {
1290 int ret;
1291
1292 /* create unique id */
1293 uuid_d new_uuid;
1294 char uuid_str[37];
1295 new_uuid.generate_random();
1296 new_uuid.print(uuid_str);
1297 id = uuid_str;
1298
1299 epoch = FIRST_EPOCH;
1300
1301 period_map.id = id;
1302
1303 ret = store_info(exclusive);
1304 if (ret < 0) {
1305 ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl;
1306 return ret;
1307 }
1308
1309 ret = set_latest_epoch(epoch);
1310 if (ret < 0) {
1311 ldout(cct, 0) << "ERROR: setting latest epoch " << id << ": " << cpp_strerror(-ret) << dendl;
1312 }
1313
1314 return ret;
1315 }
1316
1317 int RGWPeriod::store_info(bool exclusive)
1318 {
1319 rgw_pool pool(get_pool(cct));
1320
1321 string oid = get_period_oid();
1322 bufferlist bl;
1323 ::encode(*this, bl);
1324
1325 return rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(),
1326 exclusive, NULL, real_time(), NULL);
1327 }
1328
1329 rgw_pool RGWPeriod::get_pool(CephContext *cct)
1330 {
1331 if (cct->_conf->rgw_period_root_pool.empty()) {
1332 return rgw_pool(RGW_DEFAULT_PERIOD_ROOT_POOL);
1333 }
1334 return rgw_pool(cct->_conf->rgw_period_root_pool);
1335 }
1336
1337 int RGWPeriod::add_zonegroup(const RGWZoneGroup& zonegroup)
1338 {
1339 if (zonegroup.realm_id != realm_id) {
1340 return 0;
1341 }
1342 int ret = period_map.update(zonegroup, cct);
1343 if (ret < 0) {
1344 ldout(cct, 0) << "ERROR: updating period map: " << cpp_strerror(-ret) << dendl;
1345 return ret;
1346 }
1347
1348 return store_info(false);
1349 }
1350
1351 int RGWPeriod::update()
1352 {
1353 ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << get_id() << dendl;
1354 list<string> zonegroups;
1355 int ret = store->list_zonegroups(zonegroups);
1356 if (ret < 0) {
1357 ldout(cct, 0) << "ERROR: failed to list zonegroups: " << cpp_strerror(-ret) << dendl;
1358 return ret;
1359 }
1360
1361 // clear zone short ids of removed zones. period_map.update() will add the
1362 // remaining zones back
1363 period_map.short_zone_ids.clear();
1364
1365 for (auto& iter : zonegroups) {
1366 RGWZoneGroup zg(string(), iter);
1367 ret = zg.init(cct, store);
1368 if (ret < 0) {
1369 ldout(cct, 0) << "WARNING: zg.init() failed: " << cpp_strerror(-ret) << dendl;
1370 continue;
1371 }
1372
1373 if (zg.realm_id != realm_id) {
1374 ldout(cct, 20) << "skipping zonegroup " << zg.get_name() << " zone realm id " << zg.realm_id << ", not on our realm " << realm_id << dendl;
1375 continue;
1376 }
1377
1378 if (zg.master_zone.empty()) {
1379 ldout(cct, 0) << "ERROR: zonegroup " << zg.get_name() << " should have a master zone " << dendl;
1380 return -EINVAL;
1381 }
1382
1383 if (zg.is_master_zonegroup()) {
1384 master_zonegroup = zg.get_id();
1385 master_zone = zg.master_zone;
1386 }
1387
1388 int ret = period_map.update(zg, cct);
1389 if (ret < 0) {
1390 return ret;
1391 }
1392 }
1393
1394 ret = period_config.read(store, realm_id);
1395 if (ret < 0 && ret != -ENOENT) {
1396 ldout(cct, 0) << "ERROR: failed to read period config: "
1397 << cpp_strerror(ret) << dendl;
1398 return ret;
1399 }
1400 return 0;
1401 }
1402
1403 int RGWPeriod::reflect()
1404 {
1405 for (auto& iter : period_map.zonegroups) {
1406 RGWZoneGroup& zg = iter.second;
1407 zg.reinit_instance(cct, store);
1408 int r = zg.write(false);
1409 if (r < 0) {
1410 ldout(cct, 0) << "ERROR: failed to store zonegroup info for zonegroup=" << iter.first << ": " << cpp_strerror(-r) << dendl;
1411 return r;
1412 }
1413 if (zg.is_master_zonegroup()) {
1414 // set master as default if no default exists
1415 r = zg.set_as_default(true);
1416 if (r == 0) {
1417 ldout(cct, 1) << "Set the period's master zonegroup " << zg.get_id()
1418 << " as the default" << dendl;
1419 }
1420 }
1421 }
1422
1423 int r = period_config.write(store, realm_id);
1424 if (r < 0) {
1425 ldout(cct, 0) << "ERROR: failed to store period config: "
1426 << cpp_strerror(-r) << dendl;
1427 return r;
1428 }
1429 return 0;
1430 }
1431
1432 void RGWPeriod::fork()
1433 {
1434 ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << id << dendl;
1435 predecessor_uuid = id;
1436 id = get_staging_id(realm_id);
1437 period_map.reset();
1438 realm_epoch++;
1439 }
1440
1441 static int read_sync_status(RGWRados *store, rgw_meta_sync_status *sync_status)
1442 {
1443 // initialize a sync status manager to read the status
1444 RGWMetaSyncStatusManager mgr(store, store->get_async_rados());
1445 int r = mgr.init();
1446 if (r < 0) {
1447 return r;
1448 }
1449 r = mgr.read_sync_status(sync_status);
1450 mgr.stop();
1451 return r;
1452 }
1453
1454 int RGWPeriod::update_sync_status(const RGWPeriod &current_period,
1455 std::ostream& error_stream,
1456 bool force_if_stale)
1457 {
1458 rgw_meta_sync_status status;
1459 int r = read_sync_status(store, &status);
1460 if (r < 0) {
1461 ldout(cct, 0) << "period failed to read sync status: "
1462 << cpp_strerror(-r) << dendl;
1463 return r;
1464 }
1465
1466 std::vector<std::string> markers;
1467
1468 const auto current_epoch = current_period.get_realm_epoch();
1469 if (current_epoch != status.sync_info.realm_epoch) {
1470 // no sync status markers for the current period
1471 assert(current_epoch > status.sync_info.realm_epoch);
1472 const int behind = current_epoch - status.sync_info.realm_epoch;
1473 if (!force_if_stale && current_epoch > 1) {
1474 error_stream << "ERROR: This zone is " << behind << " period(s) behind "
1475 "the current master zone in metadata sync. If this zone is promoted "
1476 "to master, any metadata changes during that time are likely to "
1477 "be lost.\n"
1478 "Waiting for this zone to catch up on metadata sync (see "
1479 "'radosgw-admin sync status') is recommended.\n"
1480 "To promote this zone to master anyway, add the flag "
1481 "--yes-i-really-mean-it." << std::endl;
1482 return -EINVAL;
1483 }
1484 // empty sync status markers - other zones will skip this period during
1485 // incremental metadata sync
1486 markers.resize(status.sync_info.num_shards);
1487 } else {
1488 markers.reserve(status.sync_info.num_shards);
1489 for (auto& i : status.sync_markers) {
1490 auto& marker = i.second;
1491 // filter out markers from other periods
1492 if (marker.realm_epoch != current_epoch) {
1493 marker.marker.clear();
1494 }
1495 markers.emplace_back(std::move(marker.marker));
1496 }
1497 }
1498
1499 std::swap(sync_status, markers);
1500 return 0;
1501 }
1502
1503 int RGWPeriod::commit(RGWRealm& realm, const RGWPeriod& current_period,
1504 std::ostream& error_stream, bool force_if_stale)
1505 {
1506 ldout(cct, 20) << __func__ << " realm " << realm.get_id() << " period " << current_period.get_id() << dendl;
1507 // gateway must be in the master zone to commit
1508 if (master_zone != store->get_zone_params().get_id()) {
1509 error_stream << "Cannot commit period on zone "
1510 << store->get_zone_params().get_id() << ", it must be sent to "
1511 "the period's master zone " << master_zone << '.' << std::endl;
1512 return -EINVAL;
1513 }
1514 // period predecessor must match current period
1515 if (predecessor_uuid != current_period.get_id()) {
1516 error_stream << "Period predecessor " << predecessor_uuid
1517 << " does not match current period " << current_period.get_id()
1518 << ". Use 'period pull' to get the latest period from the master, "
1519 "reapply your changes, and try again." << std::endl;
1520 return -EINVAL;
1521 }
1522 // realm epoch must be 1 greater than current period
1523 if (realm_epoch != current_period.get_realm_epoch() + 1) {
1524 error_stream << "Period's realm epoch " << realm_epoch
1525 << " does not come directly after current realm epoch "
1526 << current_period.get_realm_epoch() << ". Use 'realm pull' to get the "
1527 "latest realm and period from the master zone, reapply your changes, "
1528 "and try again." << std::endl;
1529 return -EINVAL;
1530 }
1531 // did the master zone change?
1532 if (master_zone != current_period.get_master_zone()) {
1533 // store the current metadata sync status in the period
1534 int r = update_sync_status(current_period, error_stream, force_if_stale);
1535 if (r < 0) {
1536 ldout(cct, 0) << "failed to update metadata sync status: "
1537 << cpp_strerror(-r) << dendl;
1538 return r;
1539 }
1540 // create an object with a new period id
1541 r = create(true);
1542 if (r < 0) {
1543 ldout(cct, 0) << "failed to create new period: " << cpp_strerror(-r) << dendl;
1544 return r;
1545 }
1546 // set as current period
1547 r = realm.set_current_period(*this);
1548 if (r < 0) {
1549 ldout(cct, 0) << "failed to update realm's current period: "
1550 << cpp_strerror(-r) << dendl;
1551 return r;
1552 }
1553 ldout(cct, 4) << "Promoted to master zone and committed new period "
1554 << id << dendl;
1555 realm.notify_new_period(*this);
1556 return 0;
1557 }
1558 // period must be based on current epoch
1559 if (epoch != current_period.get_epoch()) {
1560 error_stream << "Period epoch " << epoch << " does not match "
1561 "predecessor epoch " << current_period.get_epoch()
1562 << ". Use 'period pull' to get the latest epoch from the master zone, "
1563 "reapply your changes, and try again." << std::endl;
1564 return -EINVAL;
1565 }
1566 // set period as next epoch
1567 set_id(current_period.get_id());
1568 set_epoch(current_period.get_epoch() + 1);
1569 set_predecessor(current_period.get_predecessor());
1570 realm_epoch = current_period.get_realm_epoch();
1571 // write the period to rados
1572 int r = store_info(false);
1573 if (r < 0) {
1574 ldout(cct, 0) << "failed to store period: " << cpp_strerror(-r) << dendl;
1575 return r;
1576 }
1577 // set as latest epoch
1578 r = update_latest_epoch(epoch);
1579 if (r == -EEXIST) {
1580 // already have this epoch (or a more recent one)
1581 return 0;
1582 }
1583 if (r < 0) {
1584 ldout(cct, 0) << "failed to set latest epoch: " << cpp_strerror(-r) << dendl;
1585 return r;
1586 }
1587 r = reflect();
1588 if (r < 0) {
1589 ldout(cct, 0) << "failed to update local objects: " << cpp_strerror(-r) << dendl;
1590 return r;
1591 }
1592 ldout(cct, 4) << "Committed new epoch " << epoch
1593 << " for period " << id << dendl;
1594 realm.notify_new_period(*this);
1595 return 0;
1596 }
1597
1598 int RGWZoneParams::create_default(bool old_format)
1599 {
1600 name = default_zone_name;
1601
1602 int r = create();
1603 if (r < 0) {
1604 return r;
1605 }
1606
1607 if (old_format) {
1608 name = id;
1609 }
1610
1611 return r;
1612 }
1613
1614
1615 int get_zones_pool_set(CephContext* cct,
1616 RGWRados* store,
1617 const list<string>& zones,
1618 const string& my_zone_id,
1619 set<rgw_pool>& pool_names)
1620 {
1621 for(auto const& iter : zones) {
1622 RGWZoneParams zone(iter);
1623 int r = zone.init(cct, store);
1624 if (r < 0) {
1625 ldout(cct, 0) << "Error: init zone " << iter << ":" << cpp_strerror(-r) << dendl;
1626 return r;
1627 }
1628 if (zone.get_id() != my_zone_id) {
1629 pool_names.insert(zone.domain_root);
1630 pool_names.insert(zone.metadata_heap);
1631 pool_names.insert(zone.control_pool);
1632 pool_names.insert(zone.gc_pool);
1633 pool_names.insert(zone.log_pool);
1634 pool_names.insert(zone.intent_log_pool);
1635 pool_names.insert(zone.usage_log_pool);
1636 pool_names.insert(zone.user_keys_pool);
1637 pool_names.insert(zone.user_email_pool);
1638 pool_names.insert(zone.user_swift_pool);
1639 pool_names.insert(zone.user_uid_pool);
1640 pool_names.insert(zone.roles_pool);
1641 pool_names.insert(zone.reshard_pool);
1642 for(auto& iter : zone.placement_pools) {
1643 pool_names.insert(iter.second.index_pool);
1644 pool_names.insert(iter.second.data_pool);
1645 pool_names.insert(iter.second.data_extra_pool);
1646 }
1647 }
1648 }
1649 return 0;
1650 }
1651
1652 rgw_pool fix_zone_pool_dup(set<rgw_pool> pools,
1653 const string& default_prefix,
1654 const string& default_suffix,
1655 const rgw_pool& suggested_pool)
1656 {
1657 string suggested_name = suggested_pool.to_str();
1658
1659 string prefix = default_prefix;
1660 string suffix = default_suffix;
1661
1662 if (!suggested_pool.empty()) {
1663 prefix = suggested_name.substr(0, suggested_name.find("."));
1664 suffix = suggested_name.substr(prefix.length());
1665 }
1666
1667 rgw_pool pool(prefix + suffix);
1668
1669 if (pools.find(pool) == pools.end()) {
1670 return pool;
1671 } else {
1672 while(true) {
1673 pool = prefix + "_" + std::to_string(std::rand()) + suffix;
1674 if (pools.find(pool) == pools.end()) {
1675 return pool;
1676 }
1677 }
1678 }
1679 }
1680
1681 int RGWZoneParams::fix_pool_names()
1682 {
1683
1684 list<string> zones;
1685 int r = store->list_zones(zones);
1686 if (r < 0) {
1687 ldout(cct, 10) << "WARNING: store->list_zones() returned r=" << r << dendl;
1688 }
1689
1690 set<rgw_pool> pools;
1691 r = get_zones_pool_set(cct, store, zones, id, pools);
1692 if (r < 0) {
1693 ldout(cct, 0) << "Error: get_zones_pool_names" << r << dendl;
1694 return r;
1695 }
1696
1697 domain_root = fix_zone_pool_dup(pools, name, ".rgw.meta:root", domain_root);
1698 if (!metadata_heap.name.empty()) {
1699 metadata_heap = fix_zone_pool_dup(pools, name, ".rgw.meta:heap", metadata_heap);
1700 }
1701 control_pool = fix_zone_pool_dup(pools, name, ".rgw.control", control_pool);
1702 gc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:gc", gc_pool);
1703 lc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:lc", lc_pool);
1704 log_pool = fix_zone_pool_dup(pools, name, ".rgw.log", log_pool);
1705 intent_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:intent", intent_log_pool);
1706 usage_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:usage", usage_log_pool);
1707 user_keys_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.keys", user_keys_pool);
1708 user_email_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.email", user_email_pool);
1709 user_swift_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.swift", user_swift_pool);
1710 user_uid_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.uid", user_uid_pool);
1711 roles_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:roles", roles_pool);
1712 reshard_pool = fix_zone_pool_dup(pools, name, ".rgw.log:reshard", reshard_pool);
1713
1714 for(auto& iter : placement_pools) {
1715 iter.second.index_pool = fix_zone_pool_dup(pools, name, "." + default_bucket_index_pool_suffix,
1716 iter.second.index_pool);
1717 iter.second.data_pool = fix_zone_pool_dup(pools, name, "." + default_storage_pool_suffix,
1718 iter.second.data_pool);
1719 iter.second.data_extra_pool= fix_zone_pool_dup(pools, name, "." + default_storage_extra_pool_suffix,
1720 iter.second.data_extra_pool);
1721 }
1722
1723 return 0;
1724 }
1725
1726 int RGWZoneParams::create(bool exclusive)
1727 {
1728 /* check for old pools config */
1729 rgw_raw_obj obj(domain_root, avail_pools);
1730 int r = store->raw_obj_stat(obj, NULL, NULL, NULL, NULL, NULL, NULL);
1731 if (r < 0) {
1732 ldout(store->ctx(), 10) << "couldn't find old data placement pools config, setting up new ones for the zone" << dendl;
1733 /* a new system, let's set new placement info */
1734 RGWZonePlacementInfo default_placement;
1735 default_placement.index_pool = name + "." + default_bucket_index_pool_suffix;
1736 default_placement.data_pool = name + "." + default_storage_pool_suffix;
1737 default_placement.data_extra_pool = name + "." + default_storage_extra_pool_suffix;
1738 placement_pools["default-placement"] = default_placement;
1739 }
1740
1741 r = fix_pool_names();
1742 if (r < 0) {
1743 ldout(cct, 0) << "ERROR: fix_pool_names returned r=" << r << dendl;
1744 return r;
1745 }
1746
1747 r = RGWSystemMetaObj::create(exclusive);
1748 if (r < 0) {
1749 return r;
1750 }
1751
1752 // try to set as default. may race with another create, so pass exclusive=true
1753 // so we don't override an existing default
1754 r = set_as_default(true);
1755 if (r < 0 && r != -EEXIST) {
1756 ldout(cct, 10) << "WARNING: failed to set zone as default, r=" << r << dendl;
1757 }
1758
1759 return 0;
1760 }
1761
1762 rgw_pool RGWZoneParams::get_pool(CephContext *cct)
1763 {
1764 if (cct->_conf->rgw_zone_root_pool.empty()) {
1765 return rgw_pool(RGW_DEFAULT_ZONE_ROOT_POOL);
1766 }
1767
1768 return rgw_pool(cct->_conf->rgw_zone_root_pool);
1769 }
1770
1771 const string RGWZoneParams::get_default_oid(bool old_format)
1772 {
1773 if (old_format) {
1774 return cct->_conf->rgw_default_zone_info_oid;
1775 }
1776
1777 return cct->_conf->rgw_default_zone_info_oid + "." + realm_id;
1778 }
1779
1780 const string& RGWZoneParams::get_names_oid_prefix()
1781 {
1782 return zone_names_oid_prefix;
1783 }
1784
1785 const string& RGWZoneParams::get_info_oid_prefix(bool old_format)
1786 {
1787 return zone_info_oid_prefix;
1788 }
1789
1790 const string& RGWZoneParams::get_predefined_name(CephContext *cct) {
1791 return cct->_conf->rgw_zone;
1792 }
1793
1794 int RGWZoneParams::init(CephContext *cct, RGWRados *store, bool setup_obj, bool old_format)
1795 {
1796 if (name.empty()) {
1797 name = cct->_conf->rgw_zone;
1798 }
1799
1800 return RGWSystemMetaObj::init(cct, store, setup_obj, old_format);
1801 }
1802
1803 int RGWZoneParams::read_default_id(string& default_id, bool old_format)
1804 {
1805 if (realm_id.empty()) {
1806 /* try using default realm */
1807 RGWRealm realm;
1808 int ret = realm.init(cct, store);
1809 //no default realm exist
1810 if (ret < 0) {
1811 return read_id(default_zone_name, default_id);
1812 }
1813 realm_id = realm.get_id();
1814 }
1815
1816 return RGWSystemMetaObj::read_default_id(default_id, old_format);
1817 }
1818
1819
1820 int RGWZoneParams::set_as_default(bool exclusive)
1821 {
1822 if (realm_id.empty()) {
1823 /* try using default realm */
1824 RGWRealm realm;
1825 int ret = realm.init(cct, store);
1826 if (ret < 0) {
1827 ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl;
1828 return -EINVAL;
1829 }
1830 realm_id = realm.get_id();
1831 }
1832
1833 return RGWSystemMetaObj::set_as_default(exclusive);
1834 }
1835
1836 const string& RGWZoneParams::get_compression_type(const string& placement_rule) const
1837 {
1838 static const std::string NONE{"none"};
1839 auto p = placement_pools.find(placement_rule);
1840 if (p == placement_pools.end()) {
1841 return NONE;
1842 }
1843 const auto& type = p->second.compression_type;
1844 return !type.empty() ? type : NONE;
1845 }
1846
1847 void RGWPeriodMap::encode(bufferlist& bl) const {
1848 ENCODE_START(2, 1, bl);
1849 ::encode(id, bl);
1850 ::encode(zonegroups, bl);
1851 ::encode(master_zonegroup, bl);
1852 ::encode(short_zone_ids, bl);
1853 ENCODE_FINISH(bl);
1854 }
1855
1856 void RGWPeriodMap::decode(bufferlist::iterator& bl) {
1857 DECODE_START(2, bl);
1858 ::decode(id, bl);
1859 ::decode(zonegroups, bl);
1860 ::decode(master_zonegroup, bl);
1861 if (struct_v >= 2) {
1862 ::decode(short_zone_ids, bl);
1863 }
1864 DECODE_FINISH(bl);
1865
1866 zonegroups_by_api.clear();
1867 for (map<string, RGWZoneGroup>::iterator iter = zonegroups.begin();
1868 iter != zonegroups.end(); ++iter) {
1869 RGWZoneGroup& zonegroup = iter->second;
1870 zonegroups_by_api[zonegroup.api_name] = zonegroup;
1871 if (zonegroup.is_master_zonegroup()) {
1872 master_zonegroup = zonegroup.get_id();
1873 }
1874 }
1875 }
1876
1877 // run an MD5 hash on the zone_id and return the first 32 bits
1878 static uint32_t gen_short_zone_id(const std::string zone_id)
1879 {
1880 unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE];
1881 MD5 hash;
1882 hash.Update((const byte *)zone_id.c_str(), zone_id.size());
1883 hash.Final(md5);
1884
1885 uint32_t short_id;
1886 memcpy((char *)&short_id, md5, sizeof(short_id));
1887 return std::max(short_id, 1u);
1888 }
1889
1890 int RGWPeriodMap::update(const RGWZoneGroup& zonegroup, CephContext *cct)
1891 {
1892 if (zonegroup.is_master_zonegroup() && (!master_zonegroup.empty() && zonegroup.get_id() != master_zonegroup)) {
1893 ldout(cct,0) << "Error updating periodmap, multiple master zonegroups configured "<< dendl;
1894 ldout(cct,0) << "master zonegroup: " << master_zonegroup << " and " << zonegroup.get_id() <<dendl;
1895 return -EINVAL;
1896 }
1897 map<string, RGWZoneGroup>::iterator iter = zonegroups.find(zonegroup.get_id());
1898 if (iter != zonegroups.end()) {
1899 RGWZoneGroup& old_zonegroup = iter->second;
1900 if (!old_zonegroup.api_name.empty()) {
1901 zonegroups_by_api.erase(old_zonegroup.api_name);
1902 }
1903 }
1904 zonegroups[zonegroup.get_id()] = zonegroup;
1905
1906 if (!zonegroup.api_name.empty()) {
1907 zonegroups_by_api[zonegroup.api_name] = zonegroup;
1908 }
1909
1910 if (zonegroup.is_master_zonegroup()) {
1911 master_zonegroup = zonegroup.get_id();
1912 } else if (master_zonegroup == zonegroup.get_id()) {
1913 master_zonegroup = "";
1914 }
1915
1916 for (auto& i : zonegroup.zones) {
1917 auto& zone = i.second;
1918 if (short_zone_ids.find(zone.id) != short_zone_ids.end()) {
1919 continue;
1920 }
1921 // calculate the zone's short id
1922 uint32_t short_id = gen_short_zone_id(zone.id);
1923
1924 // search for an existing zone with the same short id
1925 for (auto& s : short_zone_ids) {
1926 if (s.second == short_id) {
1927 ldout(cct, 0) << "New zone '" << zone.name << "' (" << zone.id
1928 << ") generates the same short_zone_id " << short_id
1929 << " as existing zone id " << s.first << dendl;
1930 return -EEXIST;
1931 }
1932 }
1933
1934 short_zone_ids[zone.id] = short_id;
1935 }
1936
1937 return 0;
1938 }
1939
1940 uint32_t RGWPeriodMap::get_zone_short_id(const string& zone_id) const
1941 {
1942 auto i = short_zone_ids.find(zone_id);
1943 if (i == short_zone_ids.end()) {
1944 return 0;
1945 }
1946 return i->second;
1947 }
1948
1949 int RGWZoneGroupMap::read(CephContext *cct, RGWRados *store)
1950 {
1951
1952 RGWPeriod period;
1953 int ret = period.init(cct, store);
1954 if (ret < 0) {
1955 cerr << "failed to read current period info: " << cpp_strerror(ret);
1956 return ret;
1957 }
1958
1959 bucket_quota = period.get_config().bucket_quota;
1960 user_quota = period.get_config().user_quota;
1961 zonegroups = period.get_map().zonegroups;
1962 zonegroups_by_api = period.get_map().zonegroups_by_api;
1963 master_zonegroup = period.get_map().master_zonegroup;
1964
1965 return 0;
1966 }
1967
1968 void RGWRegionMap::encode(bufferlist& bl) const {
1969 ENCODE_START( 3, 1, bl);
1970 ::encode(regions, bl);
1971 ::encode(master_region, bl);
1972 ::encode(bucket_quota, bl);
1973 ::encode(user_quota, bl);
1974 ENCODE_FINISH(bl);
1975 }
1976
1977 void RGWRegionMap::decode(bufferlist::iterator& bl) {
1978 DECODE_START(3, bl);
1979 ::decode(regions, bl);
1980 ::decode(master_region, bl);
1981 if (struct_v >= 2)
1982 ::decode(bucket_quota, bl);
1983 if (struct_v >= 3)
1984 ::decode(user_quota, bl);
1985 DECODE_FINISH(bl);
1986 }
1987
1988 void RGWZoneGroupMap::encode(bufferlist& bl) const {
1989 ENCODE_START( 3, 1, bl);
1990 ::encode(zonegroups, bl);
1991 ::encode(master_zonegroup, bl);
1992 ::encode(bucket_quota, bl);
1993 ::encode(user_quota, bl);
1994 ENCODE_FINISH(bl);
1995 }
1996
1997 void RGWZoneGroupMap::decode(bufferlist::iterator& bl) {
1998 DECODE_START(3, bl);
1999 ::decode(zonegroups, bl);
2000 ::decode(master_zonegroup, bl);
2001 if (struct_v >= 2)
2002 ::decode(bucket_quota, bl);
2003 if (struct_v >= 3)
2004 ::decode(user_quota, bl);
2005 DECODE_FINISH(bl);
2006
2007 zonegroups_by_api.clear();
2008 for (map<string, RGWZoneGroup>::iterator iter = zonegroups.begin();
2009 iter != zonegroups.end(); ++iter) {
2010 RGWZoneGroup& zonegroup = iter->second;
2011 zonegroups_by_api[zonegroup.api_name] = zonegroup;
2012 if (zonegroup.is_master_zonegroup()) {
2013 master_zonegroup = zonegroup.get_name();
2014 }
2015 }
2016 }
2017
2018 void RGWObjVersionTracker::prepare_op_for_read(ObjectReadOperation *op)
2019 {
2020 obj_version *check_objv = version_for_check();
2021
2022 if (check_objv) {
2023 cls_version_check(*op, *check_objv, VER_COND_EQ);
2024 }
2025
2026 cls_version_read(*op, &read_version);
2027 }
2028
2029 void RGWObjVersionTracker::prepare_op_for_write(ObjectWriteOperation *op)
2030 {
2031 obj_version *check_objv = version_for_check();
2032 obj_version *modify_version = version_for_write();
2033
2034 if (check_objv) {
2035 cls_version_check(*op, *check_objv, VER_COND_EQ);
2036 }
2037
2038 if (modify_version) {
2039 cls_version_set(*op, *modify_version);
2040 } else {
2041 cls_version_inc(*op);
2042 }
2043 }
2044
2045 void RGWObjManifest::obj_iterator::operator++()
2046 {
2047 if (manifest->explicit_objs) {
2048 ++explicit_iter;
2049
2050 if (explicit_iter == manifest->objs.end()) {
2051 ofs = manifest->obj_size;
2052 return;
2053 }
2054
2055 update_explicit_pos();
2056
2057 update_location();
2058 return;
2059 }
2060
2061 uint64_t obj_size = manifest->get_obj_size();
2062 uint64_t head_size = manifest->get_head_size();
2063
2064 if (ofs == obj_size) {
2065 return;
2066 }
2067
2068 if (manifest->rules.empty()) {
2069 return;
2070 }
2071
2072 /* are we still pointing at the head? */
2073 if (ofs < head_size) {
2074 rule_iter = manifest->rules.begin();
2075 RGWObjManifestRule *rule = &rule_iter->second;
2076 ofs = MIN(head_size, obj_size);
2077 stripe_ofs = ofs;
2078 cur_stripe = 1;
2079 stripe_size = MIN(obj_size - ofs, rule->stripe_max_size);
2080 if (rule->part_size > 0) {
2081 stripe_size = MIN(stripe_size, rule->part_size);
2082 }
2083 update_location();
2084 return;
2085 }
2086
2087 RGWObjManifestRule *rule = &rule_iter->second;
2088
2089 stripe_ofs += rule->stripe_max_size;
2090 cur_stripe++;
2091 dout(20) << "RGWObjManifest::operator++(): rule->part_size=" << rule->part_size << " rules.size()=" << manifest->rules.size() << dendl;
2092
2093 if (rule->part_size > 0) {
2094 /* multi part, multi stripes object */
2095
2096 dout(20) << "RGWObjManifest::operator++(): stripe_ofs=" << stripe_ofs << " part_ofs=" << part_ofs << " rule->part_size=" << rule->part_size << dendl;
2097
2098 if (stripe_ofs >= part_ofs + rule->part_size) {
2099 /* moved to the next part */
2100 cur_stripe = 0;
2101 part_ofs += rule->part_size;
2102 stripe_ofs = part_ofs;
2103
2104 bool last_rule = (next_rule_iter == manifest->rules.end());
2105 /* move to the next rule? */
2106 if (!last_rule && stripe_ofs >= next_rule_iter->second.start_ofs) {
2107 rule_iter = next_rule_iter;
2108 last_rule = (next_rule_iter == manifest->rules.end());
2109 if (!last_rule) {
2110 ++next_rule_iter;
2111 }
2112 cur_part_id = rule_iter->second.start_part_num;
2113 } else {
2114 cur_part_id++;
2115 }
2116
2117 rule = &rule_iter->second;
2118 }
2119
2120 stripe_size = MIN(rule->part_size - (stripe_ofs - part_ofs), rule->stripe_max_size);
2121 }
2122
2123 cur_override_prefix = rule->override_prefix;
2124
2125 ofs = stripe_ofs;
2126 if (ofs > obj_size) {
2127 ofs = obj_size;
2128 stripe_ofs = ofs;
2129 stripe_size = 0;
2130 }
2131
2132 dout(20) << "RGWObjManifest::operator++(): result: ofs=" << ofs << " stripe_ofs=" << stripe_ofs << " part_ofs=" << part_ofs << " rule->part_size=" << rule->part_size << dendl;
2133 update_location();
2134 }
2135
2136 int RGWObjManifest::generator::create_begin(CephContext *cct, RGWObjManifest *_m, const string& placement_rule, rgw_bucket& _b, rgw_obj& _obj)
2137 {
2138 manifest = _m;
2139
2140 manifest->set_tail_placement(placement_rule, _b);
2141 manifest->set_head(placement_rule, _obj, 0);
2142 last_ofs = 0;
2143
2144 if (manifest->get_prefix().empty()) {
2145 char buf[33];
2146 gen_rand_alphanumeric(cct, buf, sizeof(buf) - 1);
2147
2148 string oid_prefix = ".";
2149 oid_prefix.append(buf);
2150 oid_prefix.append("_");
2151
2152 manifest->set_prefix(oid_prefix);
2153 }
2154
2155 bool found = manifest->get_rule(0, &rule);
2156 if (!found) {
2157 derr << "ERROR: manifest->get_rule() could not find rule" << dendl;
2158 return -EIO;
2159 }
2160
2161 uint64_t head_size = manifest->get_head_size();
2162
2163 if (head_size > 0) {
2164 cur_stripe_size = head_size;
2165 } else {
2166 cur_stripe_size = rule.stripe_max_size;
2167 }
2168
2169 cur_part_id = rule.start_part_num;
2170
2171 manifest->get_implicit_location(cur_part_id, cur_stripe, 0, NULL, &cur_obj);
2172
2173 // Normal object which not generated through copy operation
2174 manifest->set_tail_instance(_obj.key.instance);
2175
2176 manifest->update_iterators();
2177
2178 return 0;
2179 }
2180
2181 int RGWObjManifest::generator::create_next(uint64_t ofs)
2182 {
2183 if (ofs < last_ofs) /* only going forward */
2184 return -EINVAL;
2185
2186 uint64_t max_head_size = manifest->get_max_head_size();
2187
2188 if (ofs < max_head_size) {
2189 manifest->set_head_size(ofs);
2190 }
2191
2192 if (ofs >= max_head_size) {
2193 manifest->set_head_size(max_head_size);
2194 cur_stripe = (ofs - max_head_size) / rule.stripe_max_size;
2195 cur_stripe_size = rule.stripe_max_size;
2196
2197 if (cur_part_id == 0 && max_head_size > 0) {
2198 cur_stripe++;
2199 }
2200 }
2201
2202 last_ofs = ofs;
2203 manifest->set_obj_size(ofs);
2204
2205 manifest->get_implicit_location(cur_part_id, cur_stripe, ofs, NULL, &cur_obj);
2206
2207 manifest->update_iterators();
2208
2209 return 0;
2210 }
2211
2212 const RGWObjManifest::obj_iterator& RGWObjManifest::obj_begin()
2213 {
2214 return begin_iter;
2215 }
2216
2217 const RGWObjManifest::obj_iterator& RGWObjManifest::obj_end()
2218 {
2219 return end_iter;
2220 }
2221
2222 RGWObjManifest::obj_iterator RGWObjManifest::obj_find(uint64_t ofs)
2223 {
2224 if (ofs > obj_size) {
2225 ofs = obj_size;
2226 }
2227 RGWObjManifest::obj_iterator iter(this);
2228 iter.seek(ofs);
2229 return iter;
2230 }
2231
2232 int RGWObjManifest::append(RGWObjManifest& m, RGWZoneGroup& zonegroup, RGWZoneParams& zone_params)
2233 {
2234 if (explicit_objs || m.explicit_objs) {
2235 return append_explicit(m, zonegroup, zone_params);
2236 }
2237
2238 if (rules.empty()) {
2239 *this = m;
2240 return 0;
2241 }
2242
2243 string override_prefix;
2244
2245 if (prefix.empty()) {
2246 prefix = m.prefix;
2247 }
2248
2249 if (prefix != m.prefix) {
2250 override_prefix = m.prefix;
2251 }
2252
2253 map<uint64_t, RGWObjManifestRule>::iterator miter = m.rules.begin();
2254 if (miter == m.rules.end()) {
2255 return append_explicit(m, zonegroup, zone_params);
2256 }
2257
2258 for (; miter != m.rules.end(); ++miter) {
2259 map<uint64_t, RGWObjManifestRule>::reverse_iterator last_rule = rules.rbegin();
2260
2261 RGWObjManifestRule& rule = last_rule->second;
2262
2263 if (rule.part_size == 0) {
2264 rule.part_size = obj_size - rule.start_ofs;
2265 }
2266
2267 RGWObjManifestRule& next_rule = miter->second;
2268 if (!next_rule.part_size) {
2269 next_rule.part_size = m.obj_size - next_rule.start_ofs;
2270 }
2271
2272 string rule_prefix = prefix;
2273 if (!rule.override_prefix.empty()) {
2274 rule_prefix = rule.override_prefix;
2275 }
2276
2277 string next_rule_prefix = m.prefix;
2278 if (!next_rule.override_prefix.empty()) {
2279 next_rule_prefix = next_rule.override_prefix;
2280 }
2281
2282 if (rule.part_size != next_rule.part_size ||
2283 rule.stripe_max_size != next_rule.stripe_max_size ||
2284 rule_prefix != next_rule_prefix) {
2285 if (next_rule_prefix != prefix) {
2286 append_rules(m, miter, &next_rule_prefix);
2287 } else {
2288 append_rules(m, miter, NULL);
2289 }
2290 break;
2291 }
2292
2293 uint64_t expected_part_num = rule.start_part_num + 1;
2294 if (rule.part_size > 0) {
2295 expected_part_num = rule.start_part_num + (obj_size + next_rule.start_ofs - rule.start_ofs) / rule.part_size;
2296 }
2297
2298 if (expected_part_num != next_rule.start_part_num) {
2299 append_rules(m, miter, NULL);
2300 break;
2301 }
2302 }
2303
2304 set_obj_size(obj_size + m.obj_size);
2305
2306 return 0;
2307 }
2308
2309 int RGWObjManifest::append(RGWObjManifest& m, RGWRados *store)
2310 {
2311 return append(m, store->get_zonegroup(), store->get_zone_params());
2312 }
2313
2314 void RGWObjManifest::append_rules(RGWObjManifest& m, map<uint64_t, RGWObjManifestRule>::iterator& miter,
2315 string *override_prefix)
2316 {
2317 for (; miter != m.rules.end(); ++miter) {
2318 RGWObjManifestRule rule = miter->second;
2319 rule.start_ofs += obj_size;
2320 if (override_prefix)
2321 rule.override_prefix = *override_prefix;
2322 rules[rule.start_ofs] = rule;
2323 }
2324 }
2325
2326 void RGWObjManifest::convert_to_explicit(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params)
2327 {
2328 if (explicit_objs) {
2329 return;
2330 }
2331 obj_iterator iter = obj_begin();
2332
2333 while (iter != obj_end()) {
2334 RGWObjManifestPart& part = objs[iter.get_stripe_ofs()];
2335 const rgw_obj_select& os = iter.get_location();
2336 const rgw_raw_obj& raw_loc = os.get_raw_obj(zonegroup, zone_params);
2337 part.loc_ofs = 0;
2338
2339 uint64_t ofs = iter.get_stripe_ofs();
2340
2341 if (ofs == 0) {
2342 part.loc = obj;
2343 } else {
2344 rgw_raw_obj_to_obj(tail_placement.bucket, raw_loc, &part.loc);
2345 }
2346 ++iter;
2347 uint64_t next_ofs = iter.get_stripe_ofs();
2348
2349 part.size = next_ofs - ofs;
2350 }
2351
2352 explicit_objs = true;
2353 rules.clear();
2354 prefix.clear();
2355 }
2356
2357 int RGWObjManifest::append_explicit(RGWObjManifest& m, const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params)
2358 {
2359 if (!explicit_objs) {
2360 convert_to_explicit(zonegroup, zone_params);
2361 }
2362 if (!m.explicit_objs) {
2363 m.convert_to_explicit(zonegroup, zone_params);
2364 }
2365 map<uint64_t, RGWObjManifestPart>::iterator iter;
2366 uint64_t base = obj_size;
2367 for (iter = m.objs.begin(); iter != m.objs.end(); ++iter) {
2368 RGWObjManifestPart& part = iter->second;
2369 objs[base + iter->first] = part;
2370 }
2371 obj_size += m.obj_size;
2372
2373 return 0;
2374 }
2375
2376 bool RGWObjManifest::get_rule(uint64_t ofs, RGWObjManifestRule *rule)
2377 {
2378 if (rules.empty()) {
2379 return false;
2380 }
2381
2382 map<uint64_t, RGWObjManifestRule>::iterator iter = rules.upper_bound(ofs);
2383 if (iter != rules.begin()) {
2384 --iter;
2385 }
2386
2387 *rule = iter->second;
2388
2389 return true;
2390 }
2391
2392 void RGWObjVersionTracker::generate_new_write_ver(CephContext *cct)
2393 {
2394 write_version.ver = 1;
2395 #define TAG_LEN 24
2396
2397 write_version.tag.clear();
2398 append_rand_alpha(cct, write_version.tag, write_version.tag, TAG_LEN);
2399 }
2400
2401 int RGWPutObjProcessor::complete(size_t accounted_size, const string& etag,
2402 real_time *mtime, real_time set_mtime,
2403 map<string, bufferlist>& attrs, real_time delete_at,
2404 const char *if_match, const char *if_nomatch, const string *user_data,
2405 rgw_zone_set *zones_trace)
2406 {
2407 int r = do_complete(accounted_size, etag, mtime, set_mtime, attrs, delete_at, if_match, if_nomatch, user_data, zones_trace);
2408 if (r < 0)
2409 return r;
2410
2411 is_complete = !canceled;
2412 return 0;
2413 }
2414
2415 CephContext *RGWPutObjProcessor::ctx()
2416 {
2417 return store->ctx();
2418 }
2419
2420 RGWPutObjProcessor_Aio::~RGWPutObjProcessor_Aio()
2421 {
2422 drain_pending();
2423
2424 if (is_complete)
2425 return;
2426
2427 set<rgw_raw_obj>::iterator iter;
2428 bool need_to_remove_head = false;
2429 rgw_raw_obj raw_head;
2430
2431 if (!head_obj.empty()) {
2432 store->obj_to_raw(bucket_info.placement_rule, head_obj, &raw_head);
2433 }
2434
2435 /**
2436 * We should delete the object in the "multipart" namespace to avoid race condition.
2437 * Such race condition is caused by the fact that the multipart object is the gatekeeper of a multipart
2438 * upload, when it is deleted, a second upload would start with the same suffix("2/"), therefore, objects
2439 * written by the second upload may be deleted by the first upload.
2440 * details is describled on #11749
2441 *
2442 * The above comment still stands, but instead of searching for a specific object in the multipart
2443 * namespace, we just make sure that we remove the object that is marked as the head object after
2444 * we remove all the other raw objects. Note that we use different call to remove the head object,
2445 * as this one needs to go via the bucket index prepare/complete 2-phase commit scheme.
2446 */
2447 for (iter = written_objs.begin(); iter != written_objs.end(); ++iter) {
2448 const rgw_raw_obj& obj = *iter;
2449 if (!head_obj.empty() && obj == raw_head) {
2450 ldout(store->ctx(), 5) << "NOTE: we should not process the head object (" << obj << ") here" << dendl;
2451 need_to_remove_head = true;
2452 continue;
2453 }
2454
2455 int r = store->delete_raw_obj(obj);
2456 if (r < 0 && r != -ENOENT) {
2457 ldout(store->ctx(), 5) << "WARNING: failed to remove obj (" << obj << "), leaked" << dendl;
2458 }
2459 }
2460
2461 if (need_to_remove_head) {
2462 ldout(store->ctx(), 5) << "NOTE: we are going to process the head obj (" << raw_head << ")" << dendl;
2463 int r = store->delete_obj(obj_ctx, bucket_info, head_obj, 0, 0);
2464 if (r < 0 && r != -ENOENT) {
2465 ldout(store->ctx(), 0) << "WARNING: failed to remove obj (" << raw_head << "), leaked" << dendl;
2466 }
2467 }
2468 }
2469
2470 int RGWPutObjProcessor_Aio::handle_obj_data(rgw_raw_obj& obj, bufferlist& bl, off_t ofs, off_t abs_ofs, void **phandle, bool exclusive)
2471 {
2472 if ((uint64_t)abs_ofs + bl.length() > obj_len)
2473 obj_len = abs_ofs + bl.length();
2474
2475 if (!(obj == last_written_obj)) {
2476 last_written_obj = obj;
2477 }
2478
2479 // For the first call pass -1 as the offset to
2480 // do a write_full.
2481 return store->aio_put_obj_data(NULL, obj, bl, ((ofs != 0) ? ofs : -1), exclusive, phandle);
2482 }
2483
2484 struct put_obj_aio_info RGWPutObjProcessor_Aio::pop_pending()
2485 {
2486 struct put_obj_aio_info info;
2487 info = pending.front();
2488 pending.pop_front();
2489 pending_size -= info.size;
2490 return info;
2491 }
2492
2493 int RGWPutObjProcessor_Aio::wait_pending_front()
2494 {
2495 if (pending.empty()) {
2496 return 0;
2497 }
2498 struct put_obj_aio_info info = pop_pending();
2499 int ret = store->aio_wait(info.handle);
2500
2501 if (ret >= 0) {
2502 add_written_obj(info.obj);
2503 }
2504
2505 return ret;
2506 }
2507
2508 bool RGWPutObjProcessor_Aio::pending_has_completed()
2509 {
2510 if (pending.empty())
2511 return false;
2512
2513 struct put_obj_aio_info& info = pending.front();
2514 return store->aio_completed(info.handle);
2515 }
2516
2517 int RGWPutObjProcessor_Aio::drain_pending()
2518 {
2519 int ret = 0;
2520 while (!pending.empty()) {
2521 int r = wait_pending_front();
2522 if (r < 0)
2523 ret = r;
2524 }
2525 return ret;
2526 }
2527
2528 int RGWPutObjProcessor_Aio::throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait)
2529 {
2530 bool _wait = need_to_wait;
2531
2532 if (handle) {
2533 struct put_obj_aio_info info;
2534 info.handle = handle;
2535 info.obj = obj;
2536 info.size = size;
2537 pending_size += size;
2538 pending.push_back(info);
2539 }
2540 size_t orig_size = pending_size;
2541
2542 /* first drain complete IOs */
2543 while (pending_has_completed()) {
2544 int r = wait_pending_front();
2545 if (r < 0)
2546 return r;
2547
2548 _wait = false;
2549 }
2550
2551 /* resize window in case messages are draining too fast */
2552 if (orig_size - pending_size >= window_size) {
2553 window_size += store->ctx()->_conf->rgw_max_chunk_size;
2554 uint64_t max_window_size = store->ctx()->_conf->rgw_put_obj_max_window_size;
2555 if (window_size > max_window_size) {
2556 window_size = max_window_size;
2557 }
2558 }
2559
2560 /* now throttle. Note that need_to_wait should only affect the first IO operation */
2561 if (pending_size > window_size || _wait) {
2562 int r = wait_pending_front();
2563 if (r < 0)
2564 return r;
2565 }
2566 return 0;
2567 }
2568
2569 int RGWPutObjProcessor_Atomic::write_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool exclusive)
2570 {
2571 if (ofs >= next_part_ofs) {
2572 int r = prepare_next_part(ofs);
2573 if (r < 0) {
2574 return r;
2575 }
2576 }
2577
2578 *pobj = cur_obj;
2579
2580 if (!bl.length()) {
2581 *phandle = nullptr;
2582 return 0;
2583 }
2584
2585 return RGWPutObjProcessor_Aio::handle_obj_data(cur_obj, bl, ofs - cur_part_ofs, ofs, phandle, exclusive);
2586 }
2587
2588 int RGWPutObjProcessor_Aio::prepare(RGWRados *store, string *oid_rand)
2589 {
2590 RGWPutObjProcessor::prepare(store, oid_rand);
2591
2592 window_size = store->ctx()->_conf->rgw_put_obj_min_window_size;
2593
2594 return 0;
2595 }
2596
2597 int RGWPutObjProcessor_Atomic::handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again)
2598 {
2599 *phandle = NULL;
2600 uint64_t max_write_size = MIN(max_chunk_size, (uint64_t)next_part_ofs - data_ofs);
2601
2602 pending_data_bl.claim_append(bl);
2603 if (pending_data_bl.length() < max_write_size) {
2604 *again = false;
2605 return 0;
2606 }
2607
2608 pending_data_bl.splice(0, max_write_size, &bl);
2609
2610 /* do we have enough data pending accumulated that needs to be written? */
2611 *again = (pending_data_bl.length() >= max_chunk_size);
2612
2613 if (!data_ofs && !immutable_head()) {
2614 first_chunk.claim(bl);
2615 obj_len = (uint64_t)first_chunk.length();
2616 int r = prepare_next_part(obj_len);
2617 if (r < 0) {
2618 return r;
2619 }
2620 data_ofs = obj_len;
2621 return 0;
2622 }
2623 off_t write_ofs = data_ofs;
2624 data_ofs = write_ofs + bl.length();
2625 bool exclusive = (!write_ofs && immutable_head()); /* immutable head object, need to verify nothing exists there
2626 we could be racing with another upload, to the same
2627 object and cleanup can be messy */
2628 int ret = write_data(bl, write_ofs, phandle, pobj, exclusive);
2629 if (ret >= 0) { /* we might return, need to clear bl as it was already sent */
2630 bl.clear();
2631 }
2632 return ret;
2633 }
2634
2635
2636 int RGWPutObjProcessor_Atomic::prepare_init(RGWRados *store, string *oid_rand)
2637 {
2638 RGWPutObjProcessor_Aio::prepare(store, oid_rand);
2639
2640 int r = store->get_max_chunk_size(bucket_info.placement_rule, head_obj, &max_chunk_size);
2641 if (r < 0) {
2642 return r;
2643 }
2644
2645 return 0;
2646 }
2647
2648 int RGWPutObjProcessor_Atomic::prepare(RGWRados *store, string *oid_rand)
2649 {
2650 head_obj.init(bucket, obj_str);
2651
2652 int r = prepare_init(store, oid_rand);
2653 if (r < 0) {
2654 return r;
2655 }
2656
2657 if (!version_id.empty()) {
2658 head_obj.key.set_instance(version_id);
2659 } else if (versioned_object) {
2660 store->gen_rand_obj_instance_name(&head_obj);
2661 }
2662
2663 manifest.set_trivial_rule(max_chunk_size, store->ctx()->_conf->rgw_obj_stripe_size);
2664
2665 r = manifest_gen.create_begin(store->ctx(), &manifest, bucket_info.placement_rule, head_obj.bucket, head_obj);
2666 if (r < 0) {
2667 return r;
2668 }
2669
2670 return 0;
2671 }
2672
2673 int RGWPutObjProcessor_Atomic::prepare_next_part(off_t ofs) {
2674
2675 int ret = manifest_gen.create_next(ofs);
2676 if (ret < 0) {
2677 lderr(store->ctx()) << "ERROR: manifest_gen.create_next() returned ret=" << ret << dendl;
2678 return ret;
2679 }
2680 cur_part_ofs = ofs;
2681 next_part_ofs = ofs + manifest_gen.cur_stripe_max_size();
2682 cur_obj = manifest_gen.get_cur_obj(store);
2683
2684 return 0;
2685 }
2686
2687 int RGWPutObjProcessor_Atomic::complete_parts()
2688 {
2689 if (obj_len > (uint64_t)cur_part_ofs) {
2690 return prepare_next_part(obj_len);
2691 }
2692 return 0;
2693 }
2694
2695 int RGWPutObjProcessor_Atomic::complete_writing_data()
2696 {
2697 if (!data_ofs && !immutable_head()) {
2698 /* only claim if pending_data_bl() is not empty. This is needed because we might be called twice
2699 * (e.g., when a retry due to race happens). So a second call to first_chunk.claim() would
2700 * clobber first_chunk
2701 */
2702 if (pending_data_bl.length() > 0) {
2703 first_chunk.claim(pending_data_bl);
2704 }
2705 obj_len = (uint64_t)first_chunk.length();
2706 }
2707 while (pending_data_bl.length()) {
2708 void *handle = nullptr;
2709 rgw_raw_obj obj;
2710 uint64_t max_write_size = MIN(max_chunk_size, (uint64_t)next_part_ofs - data_ofs);
2711 if (max_write_size > pending_data_bl.length()) {
2712 max_write_size = pending_data_bl.length();
2713 }
2714 bufferlist bl;
2715 pending_data_bl.splice(0, max_write_size, &bl);
2716 uint64_t write_len = bl.length();
2717 int r = write_data(bl, data_ofs, &handle, &obj, false);
2718 if (r < 0) {
2719 ldout(store->ctx(), 0) << "ERROR: write_data() returned " << r << dendl;
2720 return r;
2721 }
2722 data_ofs += write_len;
2723 r = throttle_data(handle, obj, write_len, false);
2724 if (r < 0) {
2725 ldout(store->ctx(), 0) << "ERROR: throttle_data() returned " << r << dendl;
2726 return r;
2727 }
2728
2729 if (data_ofs >= next_part_ofs) {
2730 r = prepare_next_part(data_ofs);
2731 if (r < 0) {
2732 ldout(store->ctx(), 0) << "ERROR: prepare_next_part() returned " << r << dendl;
2733 return r;
2734 }
2735 }
2736 }
2737 int r = complete_parts();
2738 if (r < 0) {
2739 return r;
2740 }
2741
2742 r = drain_pending();
2743 if (r < 0)
2744 return r;
2745
2746 return 0;
2747 }
2748
2749 int RGWPutObjProcessor_Atomic::do_complete(size_t accounted_size, const string& etag,
2750 real_time *mtime, real_time set_mtime,
2751 map<string, bufferlist>& attrs,
2752 real_time delete_at,
2753 const char *if_match,
2754 const char *if_nomatch, const string *user_data,
2755 rgw_zone_set *zones_trace) {
2756 int r = complete_writing_data();
2757 if (r < 0)
2758 return r;
2759
2760 obj_ctx.obj.set_atomic(head_obj);
2761
2762 RGWRados::Object op_target(store, bucket_info, obj_ctx, head_obj);
2763
2764 /* some object types shouldn't be versioned, e.g., multipart parts */
2765 op_target.set_versioning_disabled(!versioned_object);
2766
2767 RGWRados::Object::Write obj_op(&op_target);
2768
2769 obj_op.meta.data = &first_chunk;
2770 obj_op.meta.manifest = &manifest;
2771 obj_op.meta.ptag = &unique_tag; /* use req_id as operation tag */
2772 obj_op.meta.if_match = if_match;
2773 obj_op.meta.if_nomatch = if_nomatch;
2774 obj_op.meta.mtime = mtime;
2775 obj_op.meta.set_mtime = set_mtime;
2776 obj_op.meta.owner = bucket_info.owner;
2777 obj_op.meta.flags = PUT_OBJ_CREATE;
2778 obj_op.meta.olh_epoch = olh_epoch;
2779 obj_op.meta.delete_at = delete_at;
2780 obj_op.meta.user_data = user_data;
2781 obj_op.meta.zones_trace = zones_trace;
2782 obj_op.meta.modify_tail = true;
2783
2784 r = obj_op.write_meta(obj_len, accounted_size, attrs);
2785 if (r < 0) {
2786 return r;
2787 }
2788
2789 canceled = obj_op.meta.canceled;
2790
2791 return 0;
2792 }
2793
2794 const char* RGWRados::admin_commands[4][3] = {
2795 { "cache list",
2796 "cache list name=filter,type=CephString,req=false",
2797 "cache list [filter_str]: list object cache, possibly matching substrings" },
2798 { "cache inspect",
2799 "cache inspect name=target,type=CephString,req=true",
2800 "cache inspect target: print cache element" },
2801 { "cache erase",
2802 "cache erase name=target,type=CephString,req=true",
2803 "cache erase target: erase element from cache" },
2804 { "cache zap",
2805 "cache zap",
2806 "cache zap: erase all elements from cache" }
2807 };
2808
2809
2810 int RGWRados::watch(const string& oid, uint64_t *watch_handle, librados::WatchCtx2 *ctx) {
2811 int r = control_pool_ctx.watch2(oid, watch_handle, ctx);
2812 if (r < 0)
2813 return r;
2814 return 0;
2815 }
2816
2817 int RGWRados::unwatch(uint64_t watch_handle)
2818 {
2819 int r = control_pool_ctx.unwatch2(watch_handle);
2820 if (r < 0) {
2821 ldout(cct, 0) << "ERROR: rados->unwatch2() returned r=" << r << dendl;
2822 return r;
2823 }
2824 r = rados[0].watch_flush();
2825 if (r < 0) {
2826 ldout(cct, 0) << "ERROR: rados->watch_flush() returned r=" << r << dendl;
2827 return r;
2828 }
2829 return 0;
2830 }
2831
2832 void RGWRados::add_watcher(int i)
2833 {
2834 ldout(cct, 20) << "add_watcher() i=" << i << dendl;
2835 Mutex::Locker l(watchers_lock);
2836 watchers_set.insert(i);
2837 if (watchers_set.size() == (size_t)num_watchers) {
2838 ldout(cct, 2) << "all " << num_watchers << " watchers are set, enabling cache" << dendl;
2839 set_cache_enabled(true);
2840 }
2841 }
2842
2843 void RGWRados::remove_watcher(int i)
2844 {
2845 ldout(cct, 20) << "remove_watcher() i=" << i << dendl;
2846 Mutex::Locker l(watchers_lock);
2847 size_t orig_size = watchers_set.size();
2848 watchers_set.erase(i);
2849 if (orig_size == (size_t)num_watchers &&
2850 watchers_set.size() < orig_size) { /* actually removed */
2851 ldout(cct, 2) << "removed watcher, disabling cache" << dendl;
2852 set_cache_enabled(false);
2853 }
2854 }
2855
2856 class RGWWatcher : public librados::WatchCtx2 {
2857 RGWRados *rados;
2858 int index;
2859 string oid;
2860 uint64_t watch_handle;
2861
2862 class C_ReinitWatch : public Context {
2863 RGWWatcher *watcher;
2864 public:
2865 explicit C_ReinitWatch(RGWWatcher *_watcher) : watcher(_watcher) {}
2866 void finish(int r) override {
2867 watcher->reinit();
2868 }
2869 };
2870 public:
2871 RGWWatcher(RGWRados *r, int i, const string& o) : rados(r), index(i), oid(o), watch_handle(0) {}
2872 void handle_notify(uint64_t notify_id,
2873 uint64_t cookie,
2874 uint64_t notifier_id,
2875 bufferlist& bl) override {
2876 ldout(rados->ctx(), 10) << "RGWWatcher::handle_notify() "
2877 << " notify_id " << notify_id
2878 << " cookie " << cookie
2879 << " notifier " << notifier_id
2880 << " bl.length()=" << bl.length() << dendl;
2881 rados->watch_cb(notify_id, cookie, notifier_id, bl);
2882
2883 bufferlist reply_bl; // empty reply payload
2884 rados->control_pool_ctx.notify_ack(oid, notify_id, cookie, reply_bl);
2885 }
2886 void handle_error(uint64_t cookie, int err) override {
2887 lderr(rados->ctx()) << "RGWWatcher::handle_error cookie " << cookie
2888 << " err " << cpp_strerror(err) << dendl;
2889 rados->remove_watcher(index);
2890 rados->schedule_context(new C_ReinitWatch(this));
2891 }
2892
2893 void reinit() {
2894 int ret = unregister_watch();
2895 if (ret < 0) {
2896 ldout(rados->ctx(), 0) << "ERROR: unregister_watch() returned ret=" << ret << dendl;
2897 return;
2898 }
2899 ret = register_watch();
2900 if (ret < 0) {
2901 ldout(rados->ctx(), 0) << "ERROR: register_watch() returned ret=" << ret << dendl;
2902 return;
2903 }
2904 }
2905
2906 int unregister_watch() {
2907 int r = rados->unwatch(watch_handle);
2908 if (r < 0) {
2909 return r;
2910 }
2911 rados->remove_watcher(index);
2912 return 0;
2913 }
2914
2915 int register_watch() {
2916 int r = rados->watch(oid, &watch_handle, this);
2917 if (r < 0) {
2918 return r;
2919 }
2920 rados->add_watcher(index);
2921 return 0;
2922 }
2923 };
2924
2925 class RGWMetaNotifierManager : public RGWCoroutinesManager {
2926 RGWRados *store;
2927 RGWHTTPManager http_manager;
2928
2929 public:
2930 RGWMetaNotifierManager(RGWRados *_store) : RGWCoroutinesManager(_store->ctx(), _store->get_cr_registry()), store(_store),
2931 http_manager(store->ctx(), completion_mgr) {
2932 http_manager.set_threaded();
2933 }
2934
2935 int notify_all(map<string, RGWRESTConn *>& conn_map, set<int>& shards) {
2936 rgw_http_param_pair pairs[] = { { "type", "metadata" },
2937 { "notify", NULL },
2938 { NULL, NULL } };
2939
2940 list<RGWCoroutinesStack *> stacks;
2941 for (map<string, RGWRESTConn *>::iterator iter = conn_map.begin(); iter != conn_map.end(); ++iter) {
2942 RGWRESTConn *conn = iter->second;
2943 RGWCoroutinesStack *stack = new RGWCoroutinesStack(store->ctx(), this);
2944 stack->call(new RGWPostRESTResourceCR<set<int>, int>(store->ctx(), conn, &http_manager, "/admin/log", pairs, shards, NULL));
2945
2946 stacks.push_back(stack);
2947 }
2948 return run(stacks);
2949 }
2950 };
2951
2952 class RGWDataNotifierManager : public RGWCoroutinesManager {
2953 RGWRados *store;
2954 RGWHTTPManager http_manager;
2955
2956 public:
2957 RGWDataNotifierManager(RGWRados *_store) : RGWCoroutinesManager(_store->ctx(), _store->get_cr_registry()), store(_store),
2958 http_manager(store->ctx(), completion_mgr) {
2959 http_manager.set_threaded();
2960 }
2961
2962 int notify_all(map<string, RGWRESTConn *>& conn_map, map<int, set<string> >& shards) {
2963 rgw_http_param_pair pairs[] = { { "type", "data" },
2964 { "notify", NULL },
2965 { "source-zone", store->get_zone_params().get_id().c_str() },
2966 { NULL, NULL } };
2967
2968 list<RGWCoroutinesStack *> stacks;
2969 for (map<string, RGWRESTConn *>::iterator iter = conn_map.begin(); iter != conn_map.end(); ++iter) {
2970 RGWRESTConn *conn = iter->second;
2971 RGWCoroutinesStack *stack = new RGWCoroutinesStack(store->ctx(), this);
2972 stack->call(new RGWPostRESTResourceCR<map<int, set<string> >, int>(store->ctx(), conn, &http_manager, "/admin/log", pairs, shards, NULL));
2973
2974 stacks.push_back(stack);
2975 }
2976 return run(stacks);
2977 }
2978 };
2979
2980 class RGWRadosThread {
2981 class Worker : public Thread {
2982 CephContext *cct;
2983 RGWRadosThread *processor;
2984 Mutex lock;
2985 Cond cond;
2986
2987 void wait() {
2988 Mutex::Locker l(lock);
2989 cond.Wait(lock);
2990 };
2991
2992 void wait_interval(const utime_t& wait_time) {
2993 Mutex::Locker l(lock);
2994 cond.WaitInterval(lock, wait_time);
2995 }
2996
2997 public:
2998 Worker(CephContext *_cct, RGWRadosThread *_p) : cct(_cct), processor(_p), lock("RGWRadosThread::Worker") {}
2999 void *entry() override;
3000 void signal() {
3001 Mutex::Locker l(lock);
3002 cond.Signal();
3003 }
3004 };
3005
3006 Worker *worker;
3007
3008 protected:
3009 CephContext *cct;
3010 RGWRados *store;
3011
3012 std::atomic<bool> down_flag = { false };
3013
3014 string thread_name;
3015
3016 virtual uint64_t interval_msec() = 0;
3017 virtual void stop_process() {}
3018 public:
3019 RGWRadosThread(RGWRados *_store, const string& thread_name = "radosgw")
3020 : worker(NULL), cct(_store->ctx()), store(_store), thread_name(thread_name) {}
3021 virtual ~RGWRadosThread() {
3022 stop();
3023 }
3024
3025 virtual int init() { return 0; }
3026 virtual int process() = 0;
3027
3028 bool going_down() { return down_flag; }
3029
3030 void start();
3031 void stop();
3032
3033 void signal() {
3034 if (worker) {
3035 worker->signal();
3036 }
3037 }
3038 };
3039
3040 void RGWRadosThread::start()
3041 {
3042 worker = new Worker(cct, this);
3043 worker->create(thread_name.c_str());
3044 }
3045
3046 void RGWRadosThread::stop()
3047 {
3048 down_flag = true;
3049 stop_process();
3050 if (worker) {
3051 worker->signal();
3052 worker->join();
3053 }
3054 delete worker;
3055 worker = NULL;
3056 }
3057
3058 void *RGWRadosThread::Worker::entry() {
3059 uint64_t msec = processor->interval_msec();
3060 utime_t interval = utime_t(msec / 1000, (msec % 1000) * 1000000);
3061
3062 do {
3063 utime_t start = ceph_clock_now();
3064 int r = processor->process();
3065 if (r < 0) {
3066 dout(0) << "ERROR: processor->process() returned error r=" << r << dendl;
3067 }
3068
3069 if (processor->going_down())
3070 break;
3071
3072 utime_t end = ceph_clock_now();
3073 end -= start;
3074
3075 uint64_t cur_msec = processor->interval_msec();
3076 if (cur_msec != msec) { /* was it reconfigured? */
3077 msec = cur_msec;
3078 interval = utime_t(msec / 1000, (msec % 1000) * 1000000);
3079 }
3080
3081 if (cur_msec > 0) {
3082 if (interval <= end)
3083 continue; // next round
3084
3085 utime_t wait_time = interval;
3086 wait_time -= end;
3087
3088 wait_interval(wait_time);
3089 } else {
3090 wait();
3091 }
3092 } while (!processor->going_down());
3093
3094 return NULL;
3095 }
3096
3097 class RGWMetaNotifier : public RGWRadosThread {
3098 RGWMetaNotifierManager notify_mgr;
3099 RGWMetadataLog *const log;
3100
3101 uint64_t interval_msec() override {
3102 return cct->_conf->rgw_md_notify_interval_msec;
3103 }
3104 public:
3105 RGWMetaNotifier(RGWRados *_store, RGWMetadataLog* log)
3106 : RGWRadosThread(_store, "meta-notifier"), notify_mgr(_store), log(log) {}
3107
3108 int process() override;
3109 };
3110
3111 int RGWMetaNotifier::process()
3112 {
3113 set<int> shards;
3114
3115 log->read_clear_modified(shards);
3116
3117 if (shards.empty()) {
3118 return 0;
3119 }
3120
3121 for (set<int>::iterator iter = shards.begin(); iter != shards.end(); ++iter) {
3122 ldout(cct, 20) << __func__ << "(): notifying mdlog change, shard_id=" << *iter << dendl;
3123 }
3124
3125 notify_mgr.notify_all(store->zone_conn_map, shards);
3126
3127 return 0;
3128 }
3129
3130 class RGWDataNotifier : public RGWRadosThread {
3131 RGWDataNotifierManager notify_mgr;
3132
3133 uint64_t interval_msec() override {
3134 return cct->_conf->get_val<int64_t>("rgw_data_notify_interval_msec");
3135 }
3136 public:
3137 RGWDataNotifier(RGWRados *_store) : RGWRadosThread(_store, "data-notifier"), notify_mgr(_store) {}
3138
3139 int process() override;
3140 };
3141
3142 int RGWDataNotifier::process()
3143 {
3144 if (!store->data_log) {
3145 return 0;
3146 }
3147
3148 map<int, set<string> > shards;
3149
3150 store->data_log->read_clear_modified(shards);
3151
3152 if (shards.empty()) {
3153 return 0;
3154 }
3155
3156 for (map<int, set<string> >::iterator iter = shards.begin(); iter != shards.end(); ++iter) {
3157 ldout(cct, 20) << __func__ << "(): notifying datalog change, shard_id=" << iter->first << ": " << iter->second << dendl;
3158 }
3159
3160 notify_mgr.notify_all(store->zone_data_notify_to_map, shards);
3161
3162 return 0;
3163 }
3164
3165 class RGWSyncProcessorThread : public RGWRadosThread {
3166 public:
3167 RGWSyncProcessorThread(RGWRados *_store, const string& thread_name = "radosgw") : RGWRadosThread(_store, thread_name) {}
3168 RGWSyncProcessorThread(RGWRados *_store) : RGWRadosThread(_store) {}
3169 ~RGWSyncProcessorThread() override {}
3170 int init() override = 0 ;
3171 int process() override = 0;
3172 };
3173
3174 class RGWMetaSyncProcessorThread : public RGWSyncProcessorThread
3175 {
3176 RGWMetaSyncStatusManager sync;
3177
3178 uint64_t interval_msec() override {
3179 return 0; /* no interval associated, it'll run once until stopped */
3180 }
3181 void stop_process() override {
3182 sync.stop();
3183 }
3184 public:
3185 RGWMetaSyncProcessorThread(RGWRados *_store, RGWAsyncRadosProcessor *async_rados)
3186 : RGWSyncProcessorThread(_store, "meta-sync"), sync(_store, async_rados) {}
3187
3188 void wakeup_sync_shards(set<int>& shard_ids) {
3189 for (set<int>::iterator iter = shard_ids.begin(); iter != shard_ids.end(); ++iter) {
3190 sync.wakeup(*iter);
3191 }
3192 }
3193 RGWMetaSyncStatusManager* get_manager() { return &sync; }
3194
3195 int init() override {
3196 int ret = sync.init();
3197 if (ret < 0) {
3198 ldout(store->ctx(), 0) << "ERROR: sync.init() returned " << ret << dendl;
3199 return ret;
3200 }
3201 return 0;
3202 }
3203
3204 int process() override {
3205 sync.run();
3206 return 0;
3207 }
3208 };
3209
3210 class RGWDataSyncProcessorThread : public RGWSyncProcessorThread
3211 {
3212 RGWDataSyncStatusManager sync;
3213 bool initialized;
3214
3215 uint64_t interval_msec() override {
3216 if (initialized) {
3217 return 0; /* no interval associated, it'll run once until stopped */
3218 } else {
3219 #define DATA_SYNC_INIT_WAIT_SEC 20
3220 return DATA_SYNC_INIT_WAIT_SEC * 1000;
3221 }
3222 }
3223 void stop_process() override {
3224 sync.stop();
3225 }
3226 public:
3227 RGWDataSyncProcessorThread(RGWRados *_store, RGWAsyncRadosProcessor *async_rados,
3228 const string& _source_zone,
3229 rgw::BucketChangeObserver *observer)
3230 : RGWSyncProcessorThread(_store, "data-sync"),
3231 sync(_store, async_rados, _source_zone, observer),
3232 initialized(false) {}
3233
3234 void wakeup_sync_shards(map<int, set<string> >& shard_ids) {
3235 for (map<int, set<string> >::iterator iter = shard_ids.begin(); iter != shard_ids.end(); ++iter) {
3236 sync.wakeup(iter->first, iter->second);
3237 }
3238 }
3239 RGWDataSyncStatusManager* get_manager() { return &sync; }
3240
3241 int init() override {
3242 return 0;
3243 }
3244
3245 int process() override {
3246 while (!initialized) {
3247 if (going_down()) {
3248 return 0;
3249 }
3250 int ret = sync.init();
3251 if (ret >= 0) {
3252 initialized = true;
3253 break;
3254 }
3255 /* we'll be back! */
3256 return 0;
3257 }
3258 sync.run();
3259 return 0;
3260 }
3261 };
3262
3263 class RGWSyncLogTrimThread : public RGWSyncProcessorThread
3264 {
3265 RGWCoroutinesManager crs;
3266 RGWRados *store;
3267 rgw::BucketTrimManager *bucket_trim;
3268 RGWHTTPManager http;
3269 const utime_t trim_interval;
3270
3271 uint64_t interval_msec() override { return 0; }
3272 void stop_process() override { crs.stop(); }
3273 public:
3274 RGWSyncLogTrimThread(RGWRados *store, rgw::BucketTrimManager *bucket_trim,
3275 int interval)
3276 : RGWSyncProcessorThread(store, "sync-log-trim"),
3277 crs(store->ctx(), store->get_cr_registry()), store(store),
3278 bucket_trim(bucket_trim),
3279 http(store->ctx(), crs.get_completion_mgr()),
3280 trim_interval(interval, 0)
3281 {}
3282
3283 int init() override {
3284 return http.set_threaded();
3285 }
3286 int process() override {
3287 list<RGWCoroutinesStack*> stacks;
3288 auto meta = new RGWCoroutinesStack(store->ctx(), &crs);
3289 meta->call(create_meta_log_trim_cr(store, &http,
3290 cct->_conf->rgw_md_log_max_shards,
3291 trim_interval));
3292 stacks.push_back(meta);
3293
3294 auto data = new RGWCoroutinesStack(store->ctx(), &crs);
3295 data->call(create_data_log_trim_cr(store, &http,
3296 cct->_conf->rgw_data_log_num_shards,
3297 trim_interval));
3298 stacks.push_back(data);
3299
3300 auto bucket = new RGWCoroutinesStack(store->ctx(), &crs);
3301 bucket->call(bucket_trim->create_bucket_trim_cr(&http));
3302 stacks.push_back(bucket);
3303
3304 crs.run(stacks);
3305 return 0;
3306 }
3307 };
3308
3309 void RGWRados::wakeup_meta_sync_shards(set<int>& shard_ids)
3310 {
3311 Mutex::Locker l(meta_sync_thread_lock);
3312 if (meta_sync_processor_thread) {
3313 meta_sync_processor_thread->wakeup_sync_shards(shard_ids);
3314 }
3315 }
3316
3317 void RGWRados::wakeup_data_sync_shards(const string& source_zone, map<int, set<string> >& shard_ids)
3318 {
3319 ldout(ctx(), 20) << __func__ << ": source_zone=" << source_zone << ", shard_ids=" << shard_ids << dendl;
3320 Mutex::Locker l(data_sync_thread_lock);
3321 map<string, RGWDataSyncProcessorThread *>::iterator iter = data_sync_processor_threads.find(source_zone);
3322 if (iter == data_sync_processor_threads.end()) {
3323 ldout(ctx(), 10) << __func__ << ": couldn't find sync thread for zone " << source_zone << ", skipping async data sync processing" << dendl;
3324 return;
3325 }
3326
3327 RGWDataSyncProcessorThread *thread = iter->second;
3328 assert(thread);
3329 thread->wakeup_sync_shards(shard_ids);
3330 }
3331
3332 RGWMetaSyncStatusManager* RGWRados::get_meta_sync_manager()
3333 {
3334 Mutex::Locker l(meta_sync_thread_lock);
3335 if (meta_sync_processor_thread) {
3336 return meta_sync_processor_thread->get_manager();
3337 }
3338 return nullptr;
3339 }
3340
3341 RGWDataSyncStatusManager* RGWRados::get_data_sync_manager(const std::string& source_zone)
3342 {
3343 Mutex::Locker l(data_sync_thread_lock);
3344 auto thread = data_sync_processor_threads.find(source_zone);
3345 if (thread == data_sync_processor_threads.end()) {
3346 return nullptr;
3347 }
3348 return thread->second->get_manager();
3349 }
3350
3351 int RGWRados::get_required_alignment(const rgw_pool& pool, uint64_t *alignment)
3352 {
3353 IoCtx ioctx;
3354 int r = open_pool_ctx(pool, ioctx);
3355 if (r < 0) {
3356 ldout(cct, 0) << "ERROR: open_pool_ctx() returned " << r << dendl;
3357 return r;
3358 }
3359
3360 bool requires;
3361 r = ioctx.pool_requires_alignment2(&requires);
3362 if (r < 0) {
3363 ldout(cct, 0) << "ERROR: ioctx.pool_requires_alignment2() returned "
3364 << r << dendl;
3365 return r;
3366 }
3367
3368 if (!requires) {
3369 *alignment = 0;
3370 return 0;
3371 }
3372
3373 uint64_t align;
3374 r = ioctx.pool_required_alignment2(&align);
3375 if (r < 0) {
3376 ldout(cct, 0) << "ERROR: ioctx.pool_required_alignment2() returned "
3377 << r << dendl;
3378 return r;
3379 }
3380 if (align != 0) {
3381 ldout(cct, 20) << "required alignment=" << align << dendl;
3382 }
3383 *alignment = align;
3384 return 0;
3385 }
3386
3387 int RGWRados::get_max_chunk_size(const rgw_pool& pool, uint64_t *max_chunk_size)
3388 {
3389 uint64_t alignment = 0;
3390 int r = get_required_alignment(pool, &alignment);
3391 if (r < 0) {
3392 return r;
3393 }
3394
3395 uint64_t config_chunk_size = cct->_conf->rgw_max_chunk_size;
3396
3397 if (alignment == 0) {
3398 *max_chunk_size = config_chunk_size;
3399 return 0;
3400 }
3401
3402 if (config_chunk_size <= alignment) {
3403 *max_chunk_size = alignment;
3404 return 0;
3405 }
3406
3407 *max_chunk_size = config_chunk_size - (config_chunk_size % alignment);
3408
3409 ldout(cct, 20) << "max_chunk_size=" << *max_chunk_size << dendl;
3410
3411 return 0;
3412 }
3413
3414 int RGWRados::get_max_chunk_size(const string& placement_rule, const rgw_obj& obj, uint64_t *max_chunk_size)
3415 {
3416 rgw_pool pool;
3417 if (!get_obj_data_pool(placement_rule, obj, &pool)) {
3418 ldout(cct, 0) << "ERROR: failed to get data pool for object " << obj << dendl;
3419 return -EIO;
3420 }
3421 return get_max_chunk_size(pool, max_chunk_size);
3422 }
3423
3424 class RGWIndexCompletionManager;
3425
3426 struct complete_op_data {
3427 Mutex lock{"complete_op_data"};
3428 AioCompletion *rados_completion{nullptr};
3429 int manager_shard_id{-1};
3430 RGWIndexCompletionManager *manager{nullptr};
3431 rgw_obj obj;
3432 RGWModifyOp op;
3433 string tag;
3434 rgw_bucket_entry_ver ver;
3435 cls_rgw_obj_key key;
3436 rgw_bucket_dir_entry_meta dir_meta;
3437 list<cls_rgw_obj_key> remove_objs;
3438 bool log_op;
3439 uint16_t bilog_op;
3440 rgw_zone_set zones_trace;
3441
3442 bool stopped{false};
3443
3444 void stop() {
3445 Mutex::Locker l(lock);
3446 stopped = true;
3447 }
3448 };
3449
3450 class RGWIndexCompletionThread : public RGWRadosThread {
3451 RGWRados *store;
3452
3453 uint64_t interval_msec() override {
3454 return 0;
3455 }
3456
3457 list<complete_op_data *> completions;
3458
3459 Mutex completions_lock;
3460 public:
3461 RGWIndexCompletionThread(RGWRados *_store)
3462 : RGWRadosThread(_store, "index-complete"), store(_store), completions_lock("RGWIndexCompletionThread::completions_lock") {}
3463
3464 int process() override;
3465
3466 void add_completion(complete_op_data *completion) {
3467 {
3468 Mutex::Locker l(completions_lock);
3469 completions.push_back(completion);
3470 }
3471
3472 signal();
3473 }
3474 };
3475
3476 int RGWIndexCompletionThread::process()
3477 {
3478 list<complete_op_data *> comps;
3479
3480 {
3481 Mutex::Locker l(completions_lock);
3482 completions.swap(comps);
3483 }
3484
3485 for (auto c : comps) {
3486 std::unique_ptr<complete_op_data> up{c};
3487
3488 if (going_down()) {
3489 continue;
3490 }
3491 ldout(store->ctx(), 20) << __func__ << "(): handling completion for key=" << c->key << dendl;
3492
3493 RGWRados::BucketShard bs(store);
3494
3495 int r = bs.init(c->obj.bucket, c->obj);
3496 if (r < 0) {
3497 ldout(cct, 0) << "ERROR: " << __func__ << "(): failed to initialize BucketShard, obj=" << c->obj << " r=" << r << dendl;
3498 /* not much to do */
3499 continue;
3500 }
3501
3502 r = store->guard_reshard(&bs, c->obj, [&](RGWRados::BucketShard *bs) -> int {
3503 librados::ObjectWriteOperation o;
3504 cls_rgw_guard_bucket_resharding(o, -ERR_BUSY_RESHARDING);
3505 cls_rgw_bucket_complete_op(o, c->op, c->tag, c->ver, c->key, c->dir_meta, &c->remove_objs,
3506 c->log_op, c->bilog_op, &c->zones_trace);
3507
3508 return bs->index_ctx.operate(bs->bucket_obj, &o);
3509 });
3510 if (r < 0) {
3511 ldout(cct, 0) << "ERROR: " << __func__ << "(): bucket index completion failed, obj=" << c->obj << " r=" << r << dendl;
3512 /* ignoring error, can't do anything about it */
3513 continue;
3514 }
3515 r = store->data_log->add_entry(bs.bucket, bs.shard_id);
3516 if (r < 0) {
3517 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
3518 }
3519 }
3520
3521 return 0;
3522 }
3523
3524 class RGWIndexCompletionManager {
3525 RGWRados *store{nullptr};
3526 vector<Mutex *> locks;
3527 vector<set<complete_op_data *> > completions;
3528
3529 RGWIndexCompletionThread *completion_thread{nullptr};
3530
3531 int num_shards;
3532
3533 std::atomic<int> cur_shard {0};
3534
3535
3536 public:
3537 RGWIndexCompletionManager(RGWRados *_store) : store(_store) {
3538 num_shards = store->ctx()->_conf->rgw_thread_pool_size;
3539
3540 for (int i = 0; i < num_shards; i++) {
3541 char buf[64];
3542 snprintf(buf, sizeof(buf), "RGWIndexCompletionManager::lock::%d", i);
3543 locks.push_back(new Mutex(buf));
3544 }
3545
3546 completions.resize(num_shards);
3547 }
3548 ~RGWIndexCompletionManager() {
3549 stop();
3550
3551 for (auto l : locks) {
3552 delete l;
3553 }
3554 }
3555
3556 int next_shard() {
3557 int result = cur_shard % num_shards;
3558 cur_shard++;
3559 return result;
3560 }
3561
3562 void create_completion(const rgw_obj& obj,
3563 RGWModifyOp op, string& tag,
3564 rgw_bucket_entry_ver& ver,
3565 const cls_rgw_obj_key& key,
3566 rgw_bucket_dir_entry_meta& dir_meta,
3567 list<cls_rgw_obj_key> *remove_objs, bool log_op,
3568 uint16_t bilog_op,
3569 rgw_zone_set *zones_trace,
3570 complete_op_data **result);
3571 bool handle_completion(completion_t cb, complete_op_data *arg);
3572
3573 int start() {
3574 completion_thread = new RGWIndexCompletionThread(store);
3575 int ret = completion_thread->init();
3576 if (ret < 0) {
3577 return ret;
3578 }
3579 completion_thread->start();
3580 return 0;
3581 }
3582 void stop() {
3583 if (completion_thread) {
3584 completion_thread->stop();
3585 delete completion_thread;
3586 }
3587
3588 for (int i = 0; i < num_shards; ++i) {
3589 Mutex::Locker l(*locks[i]);
3590 for (auto c : completions[i]) {
3591 Mutex::Locker cl(c->lock);
3592 c->stop();
3593 }
3594 }
3595 completions.clear();
3596 }
3597 };
3598
3599 static void obj_complete_cb(completion_t cb, void *arg)
3600 {
3601 complete_op_data *completion = (complete_op_data *)arg;
3602 completion->lock.Lock();
3603 if (completion->stopped) {
3604 completion->lock.Unlock(); /* can drop lock, no one else is referencing us */
3605 delete completion;
3606 return;
3607 }
3608 bool need_delete = completion->manager->handle_completion(cb, completion);
3609 completion->lock.Unlock();
3610 if (need_delete) {
3611 delete completion;
3612 }
3613 }
3614
3615
3616 void RGWIndexCompletionManager::create_completion(const rgw_obj& obj,
3617 RGWModifyOp op, string& tag,
3618 rgw_bucket_entry_ver& ver,
3619 const cls_rgw_obj_key& key,
3620 rgw_bucket_dir_entry_meta& dir_meta,
3621 list<cls_rgw_obj_key> *remove_objs, bool log_op,
3622 uint16_t bilog_op,
3623 rgw_zone_set *zones_trace,
3624 complete_op_data **result)
3625 {
3626 complete_op_data *entry = new complete_op_data;
3627
3628 int shard_id = next_shard();
3629
3630 entry->manager_shard_id = shard_id;
3631 entry->manager = this;
3632 entry->obj = obj;
3633 entry->op = op;
3634 entry->tag = tag;
3635 entry->ver = ver;
3636 entry->key = key;
3637 entry->dir_meta = dir_meta;
3638 entry->log_op = log_op;
3639 entry->bilog_op = bilog_op;
3640
3641 if (remove_objs) {
3642 for (auto iter = remove_objs->begin(); iter != remove_objs->end(); ++iter) {
3643 entry->remove_objs.push_back(*iter);
3644 }
3645 }
3646
3647 if (zones_trace) {
3648 entry->zones_trace = *zones_trace;
3649 } else {
3650 entry->zones_trace.insert(store->get_zone().id);
3651 }
3652
3653 *result = entry;
3654
3655 entry->rados_completion = librados::Rados::aio_create_completion(entry, NULL, obj_complete_cb);
3656
3657 Mutex::Locker l(*locks[shard_id]);
3658 completions[shard_id].insert(entry);
3659 }
3660
3661 bool RGWIndexCompletionManager::handle_completion(completion_t cb, complete_op_data *arg)
3662 {
3663 int shard_id = arg->manager_shard_id;
3664 {
3665 Mutex::Locker l(*locks[shard_id]);
3666
3667 auto& comps = completions[shard_id];
3668
3669 auto iter = comps.find(arg);
3670 if (iter == comps.end()) {
3671 return true;
3672 }
3673
3674 comps.erase(iter);
3675 }
3676
3677 int r = rados_aio_get_return_value(cb);
3678 if (r != -ERR_BUSY_RESHARDING) {
3679 return true;
3680 }
3681 completion_thread->add_completion(arg);
3682 return false;
3683 }
3684
3685 void RGWRados::finalize()
3686 {
3687 auto admin_socket = cct->get_admin_socket();
3688 for (auto cmd : admin_commands) {
3689 int r = admin_socket->unregister_command(cmd[0]);
3690 if (r < 0) {
3691 lderr(cct) << "ERROR: fail to unregister admin socket command (r=" << r
3692 << ")" << dendl;
3693 }
3694 }
3695
3696 if (run_sync_thread) {
3697 Mutex::Locker l(meta_sync_thread_lock);
3698 meta_sync_processor_thread->stop();
3699
3700 Mutex::Locker dl(data_sync_thread_lock);
3701 for (auto iter : data_sync_processor_threads) {
3702 RGWDataSyncProcessorThread *thread = iter.second;
3703 thread->stop();
3704 }
3705 if (sync_log_trimmer) {
3706 sync_log_trimmer->stop();
3707 }
3708 }
3709 if (async_rados) {
3710 async_rados->stop();
3711 }
3712 if (run_sync_thread) {
3713 delete meta_sync_processor_thread;
3714 meta_sync_processor_thread = NULL;
3715 Mutex::Locker dl(data_sync_thread_lock);
3716 for (auto iter : data_sync_processor_threads) {
3717 RGWDataSyncProcessorThread *thread = iter.second;
3718 delete thread;
3719 }
3720 data_sync_processor_threads.clear();
3721 delete sync_log_trimmer;
3722 sync_log_trimmer = nullptr;
3723 bucket_trim = boost::none;
3724 }
3725 if (finisher) {
3726 finisher->stop();
3727 }
3728 if (need_watch_notify()) {
3729 finalize_watch();
3730 }
3731 if (finisher) {
3732 /* delete finisher only after cleaning up watches, as watch error path might call
3733 * into finisher. We stop finisher before finalizing watch to make sure we don't
3734 * actually handle any racing work
3735 */
3736 delete finisher;
3737 }
3738 if (meta_notifier) {
3739 meta_notifier->stop();
3740 delete meta_notifier;
3741 }
3742 if (data_notifier) {
3743 data_notifier->stop();
3744 delete data_notifier;
3745 }
3746 delete data_log;
3747 if (async_rados) {
3748 delete async_rados;
3749 }
3750
3751 delete lc;
3752 lc = NULL;
3753
3754 delete gc;
3755 gc = NULL;
3756
3757 delete obj_expirer;
3758 obj_expirer = NULL;
3759
3760 delete rest_master_conn;
3761
3762 map<string, RGWRESTConn *>::iterator iter;
3763 for (iter = zone_conn_map.begin(); iter != zone_conn_map.end(); ++iter) {
3764 RGWRESTConn *conn = iter->second;
3765 delete conn;
3766 }
3767
3768 for (iter = zonegroup_conn_map.begin(); iter != zonegroup_conn_map.end(); ++iter) {
3769 RGWRESTConn *conn = iter->second;
3770 delete conn;
3771 }
3772 RGWQuotaHandler::free_handler(quota_handler);
3773 if (cr_registry) {
3774 cr_registry->put();
3775 }
3776 delete meta_mgr;
3777 delete binfo_cache;
3778 delete obj_tombstone_cache;
3779 delete sync_modules_manager;
3780
3781 if (reshard_wait.get()) {
3782 reshard_wait->stop();
3783 reshard_wait.reset();
3784 }
3785
3786 if (run_reshard_thread) {
3787 reshard->stop_processor();
3788 }
3789 delete reshard;
3790 delete index_completion_manager;
3791 }
3792
3793 /**
3794 * Initialize the RADOS instance and prepare to do other ops
3795 * Returns 0 on success, -ERR# on failure.
3796 */
3797 int RGWRados::init_rados()
3798 {
3799 int ret = 0;
3800 auto admin_socket = cct->get_admin_socket();
3801 for (auto cmd : admin_commands) {
3802 int r = admin_socket->register_command(cmd[0], cmd[1], this,
3803 cmd[2]);
3804 if (r < 0) {
3805 lderr(cct) << "ERROR: fail to register admin socket command (r=" << r
3806 << ")" << dendl;
3807 return r;
3808 }
3809 }
3810
3811 auto handles = std::vector<librados::Rados>{cct->_conf->rgw_num_rados_handles};
3812
3813 for (auto& r : handles) {
3814 ret = r.init_with_context(cct);
3815 if (ret < 0) {
3816 return ret;
3817 }
3818 ret = r.connect();
3819 if (ret < 0) {
3820 return ret;
3821 }
3822 }
3823
3824 sync_modules_manager = new RGWSyncModulesManager();
3825
3826 rgw_register_sync_modules(sync_modules_manager);
3827
3828 auto crs = std::unique_ptr<RGWCoroutinesManagerRegistry>{
3829 new RGWCoroutinesManagerRegistry(cct)};
3830 ret = crs->hook_to_admin_command("cr dump");
3831 if (ret < 0) {
3832 return ret;
3833 }
3834
3835 meta_mgr = new RGWMetadataManager(cct, this);
3836 data_log = new RGWDataChangesLog(cct, this);
3837 cr_registry = crs.release();
3838
3839 std::swap(handles, rados);
3840 return ret;
3841 }
3842
3843
3844 int RGWRados::register_to_service_map(const string& daemon_type, const map<string, string>& meta)
3845 {
3846 map<string,string> metadata = meta;
3847 metadata["num_handles"] = stringify(rados.size());
3848 metadata["zonegroup_id"] = zonegroup.get_id();
3849 metadata["zonegroup_name"] = zonegroup.get_name();
3850 metadata["zone_name"] = zone_name();
3851 metadata["zone_id"] = zone_id();;
3852 string name = cct->_conf->name.get_id();
3853 if (name.find("rgw.") == 0) {
3854 name = name.substr(4);
3855 }
3856 int ret = rados[0].service_daemon_register(daemon_type, name, metadata);
3857 if (ret < 0) {
3858 ldout(cct, 0) << "ERROR: service_daemon_register() returned ret=" << ret << ": " << cpp_strerror(-ret) << dendl;
3859 return ret;
3860 }
3861
3862 return 0;
3863 }
3864
3865 /**
3866 * Add new connection to connections map
3867 * @param zonegroup_conn_map map which new connection will be added to
3868 * @param zonegroup zonegroup which new connection will connect to
3869 * @param new_connection pointer to new connection instance
3870 */
3871 static void add_new_connection_to_map(map<string, RGWRESTConn *> &zonegroup_conn_map,
3872 const RGWZoneGroup &zonegroup, RGWRESTConn *new_connection)
3873 {
3874 // Delete if connection is already exists
3875 map<string, RGWRESTConn *>::iterator iterZoneGroup = zonegroup_conn_map.find(zonegroup.get_id());
3876 if (iterZoneGroup != zonegroup_conn_map.end()) {
3877 delete iterZoneGroup->second;
3878 }
3879
3880 // Add new connection to connections map
3881 zonegroup_conn_map[zonegroup.get_id()] = new_connection;
3882 }
3883
3884 int RGWRados::convert_regionmap()
3885 {
3886 RGWZoneGroupMap zonegroupmap;
3887
3888 string pool_name = cct->_conf->rgw_zone_root_pool;
3889 if (pool_name.empty()) {
3890 pool_name = RGW_DEFAULT_ZONE_ROOT_POOL;
3891 }
3892 string oid = region_map_oid;
3893
3894 rgw_pool pool(pool_name);
3895 bufferlist bl;
3896 RGWObjectCtx obj_ctx(this);
3897 int ret = rgw_get_system_obj(this, obj_ctx, pool, oid, bl, NULL, NULL);
3898 if (ret < 0 && ret != -ENOENT) {
3899 return ret;
3900 } else if (ret == -ENOENT) {
3901 return 0;
3902 }
3903
3904 try {
3905 bufferlist::iterator iter = bl.begin();
3906 ::decode(zonegroupmap, iter);
3907 } catch (buffer::error& err) {
3908 ldout(cct, 0) << "error decoding regionmap from " << pool << ":" << oid << dendl;
3909 return -EIO;
3910 }
3911
3912 for (map<string, RGWZoneGroup>::iterator iter = zonegroupmap.zonegroups.begin();
3913 iter != zonegroupmap.zonegroups.end(); ++iter) {
3914 RGWZoneGroup& zonegroup = iter->second;
3915 ret = zonegroup.init(cct, this, false);
3916 ret = zonegroup.update();
3917 if (ret < 0 && ret != -ENOENT) {
3918 ldout(cct, 0) << "Error could not update zonegroup " << zonegroup.get_name() << ": " <<
3919 cpp_strerror(-ret) << dendl;
3920 return ret;
3921 } else if (ret == -ENOENT) {
3922 ret = zonegroup.create();
3923 if (ret < 0) {
3924 ldout(cct, 0) << "Error could not create " << zonegroup.get_name() << ": " <<
3925 cpp_strerror(-ret) << dendl;
3926 return ret;
3927 }
3928 }
3929 }
3930
3931 current_period.set_user_quota(zonegroupmap.user_quota);
3932 current_period.set_bucket_quota(zonegroupmap.bucket_quota);
3933
3934 // remove the region_map so we don't try to convert again
3935 rgw_raw_obj obj(pool, oid);
3936 ret = delete_system_obj(obj);
3937 if (ret < 0) {
3938 ldout(cct, 0) << "Error could not remove " << obj
3939 << " after upgrading to zonegroup map: " << cpp_strerror(ret) << dendl;
3940 return ret;
3941 }
3942
3943 return 0;
3944 }
3945
3946 /**
3947 * Replace all region configuration with zonegroup for
3948 * backward compatability
3949 * Returns 0 on success, -ERR# on failure.
3950 */
3951 int RGWRados::replace_region_with_zonegroup()
3952 {
3953 /* copy default region */
3954 /* convert default region to default zonegroup */
3955 string default_oid = cct->_conf->rgw_default_region_info_oid;
3956 if (default_oid.empty()) {
3957 default_oid = default_region_info_oid;
3958 }
3959
3960
3961 RGWZoneGroup default_zonegroup;
3962 rgw_pool pool{default_zonegroup.get_pool(cct)};
3963 string oid = "converted";
3964 bufferlist bl;
3965 RGWObjectCtx obj_ctx(this);
3966
3967 int ret = rgw_get_system_obj(this, obj_ctx, pool ,oid, bl, NULL, NULL);
3968 if (ret < 0 && ret != -ENOENT) {
3969 ldout(cct, 0) << __func__ << " failed to read converted: ret "<< ret << " " << cpp_strerror(-ret)
3970 << dendl;
3971 return ret;
3972 } else if (ret != -ENOENT) {
3973 ldout(cct, 20) << "System already converted " << dendl;
3974 return 0;
3975 }
3976
3977 string default_region;
3978 ret = default_zonegroup.init(cct, this, false, true);
3979 if (ret < 0) {
3980 ldout(cct, 0) << __func__ << " failed init default region: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
3981 return ret;
3982 }
3983 ret = default_zonegroup.read_default_id(default_region, true);
3984 if (ret < 0 && ret != -ENOENT) {
3985 ldout(cct, 0) << __func__ << " failed reading old default region: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
3986 return ret;
3987 }
3988
3989 /* convert regions to zonegroups */
3990 list<string> regions;
3991 ret = list_regions(regions);
3992 if (ret < 0 && ret != -ENOENT) {
3993 ldout(cct, 0) << __func__ << " failed to list regions: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
3994 return ret;
3995 } else if (ret == -ENOENT || regions.empty()) {
3996 RGWZoneParams zoneparams(default_zone_name);
3997 int ret = zoneparams.init(cct, this);
3998 if (ret < 0 && ret != -ENOENT) {
3999 ldout(cct, 0) << __func__ << ": error initializing default zone params: " << cpp_strerror(-ret) << dendl;
4000 return ret;
4001 }
4002 /* update master zone */
4003 RGWZoneGroup default_zg(default_zonegroup_name);
4004 ret = default_zg.init(cct, this);
4005 if (ret < 0 && ret != -ENOENT) {
4006 ldout(cct, 0) << __func__ << ": error in initializing default zonegroup: " << cpp_strerror(-ret) << dendl;
4007 return ret;
4008 }
4009 if (ret != -ENOENT && default_zg.master_zone.empty()) {
4010 default_zg.master_zone = zoneparams.get_id();
4011 return default_zg.update();
4012 }
4013 return 0;
4014 }
4015
4016 string master_region, master_zone;
4017 for (list<string>::iterator iter = regions.begin(); iter != regions.end(); ++iter) {
4018 if (*iter != default_zonegroup_name){
4019 RGWZoneGroup region(*iter);
4020 int ret = region.init(cct, this, true, true);
4021 if (ret < 0) {
4022 ldout(cct, 0) << __func__ << " failed init region "<< *iter << ": " << cpp_strerror(-ret) << dendl;
4023 return ret;
4024 }
4025 if (region.is_master_zonegroup()) {
4026 master_region = region.get_id();
4027 master_zone = region.master_zone;
4028 }
4029 }
4030 }
4031
4032 /* create realm if there is none.
4033 The realm name will be the region and zone concatenated
4034 realm id will be mds of its name */
4035 if (realm.get_id().empty() && !master_region.empty() && !master_zone.empty()) {
4036 string new_realm_name = master_region + "." + master_zone;
4037 unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE];
4038 char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
4039 MD5 hash;
4040 hash.Update((const byte *)new_realm_name.c_str(), new_realm_name.length());
4041 hash.Final(md5);
4042 buf_to_hex(md5, CEPH_CRYPTO_MD5_DIGESTSIZE, md5_str);
4043 string new_realm_id(md5_str);
4044 RGWRealm new_realm(new_realm_id,new_realm_name);
4045 ret = new_realm.init(cct, this, false);
4046 if (ret < 0) {
4047 ldout(cct, 0) << __func__ << " Error initing new realm: " << cpp_strerror(-ret) << dendl;
4048 return ret;
4049 }
4050 ret = new_realm.create();
4051 if (ret < 0 && ret != -EEXIST) {
4052 ldout(cct, 0) << __func__ << " Error creating new realm: " << cpp_strerror(-ret) << dendl;
4053 return ret;
4054 }
4055 ret = new_realm.set_as_default();
4056 if (ret < 0) {
4057 ldout(cct, 0) << __func__ << " Error setting realm as default: " << cpp_strerror(-ret) << dendl;
4058 return ret;
4059 }
4060 ret = realm.init(cct, this);
4061 if (ret < 0) {
4062 ldout(cct, 0) << __func__ << " Error initing realm: " << cpp_strerror(-ret) << dendl;
4063 return ret;
4064 }
4065 ret = current_period.init(cct, this, realm.get_id(), realm.get_name());
4066 if (ret < 0) {
4067 ldout(cct, 0) << __func__ << " Error initing current period: " << cpp_strerror(-ret) << dendl;
4068 return ret;
4069 }
4070 }
4071
4072 list<string>::iterator iter;
4073 /* create zonegroups */
4074 for (iter = regions.begin(); iter != regions.end(); ++iter)
4075 {
4076 ldout(cct, 0) << __func__ << "Converting " << *iter << dendl;
4077 /* check to see if we don't have already a zonegroup with this name */
4078 RGWZoneGroup new_zonegroup(*iter);
4079 ret = new_zonegroup.init(cct , this);
4080 if (ret == 0 && new_zonegroup.get_id() != *iter) {
4081 ldout(cct, 0) << __func__ << " zonegroup "<< *iter << " already exists id " << new_zonegroup.get_id () <<
4082 " skipping conversion " << dendl;
4083 continue;
4084 }
4085 RGWZoneGroup zonegroup(*iter);
4086 zonegroup.set_id(*iter);
4087 int ret = zonegroup.init(cct, this, true, true);
4088 if (ret < 0) {
4089 ldout(cct, 0) << __func__ << " failed init zonegroup: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4090 return ret;
4091 }
4092 zonegroup.realm_id = realm.get_id();
4093 /* fix default region master zone */
4094 if (*iter == default_zonegroup_name && zonegroup.master_zone.empty()) {
4095 ldout(cct, 0) << __func__ << " Setting default zone as master for default region" << dendl;
4096 zonegroup.master_zone = default_zone_name;
4097 }
4098 ret = zonegroup.update();
4099 if (ret < 0 && ret != -EEXIST) {
4100 ldout(cct, 0) << __func__ << " failed to update zonegroup " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
4101 << dendl;
4102 return ret;
4103 }
4104 ret = zonegroup.update_name();
4105 if (ret < 0 && ret != -EEXIST) {
4106 ldout(cct, 0) << __func__ << " failed to update_name for zonegroup " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
4107 << dendl;
4108 return ret;
4109 }
4110 if (zonegroup.get_name() == default_region) {
4111 ret = zonegroup.set_as_default();
4112 if (ret < 0) {
4113 ldout(cct, 0) << __func__ << " failed to set_as_default " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
4114 << dendl;
4115 return ret;
4116 }
4117 }
4118 for (map<string, RGWZone>::const_iterator iter = zonegroup.zones.begin(); iter != zonegroup.zones.end();
4119 ++iter) {
4120 ldout(cct, 0) << __func__ << " Converting zone" << iter->first << dendl;
4121 RGWZoneParams zoneparams(iter->first, iter->first);
4122 zoneparams.set_id(iter->first);
4123 zoneparams.realm_id = realm.get_id();
4124 ret = zoneparams.init(cct, this);
4125 if (ret < 0 && ret != -ENOENT) {
4126 ldout(cct, 0) << __func__ << " failed to init zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
4127 return ret;
4128 } else if (ret == -ENOENT) {
4129 ldout(cct, 0) << __func__ << " zone is part of another cluster " << iter->first << " skipping " << dendl;
4130 continue;
4131 }
4132 zonegroup.realm_id = realm.get_id();
4133 ret = zoneparams.update();
4134 if (ret < 0 && ret != -EEXIST) {
4135 ldout(cct, 0) << __func__ << " failed to update zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
4136 return ret;
4137 }
4138 ret = zoneparams.update_name();
4139 if (ret < 0 && ret != -EEXIST) {
4140 ldout(cct, 0) << __func__ << " failed to init zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
4141 return ret;
4142 }
4143 }
4144
4145 if (!current_period.get_id().empty()) {
4146 ret = current_period.add_zonegroup(zonegroup);
4147 if (ret < 0) {
4148 ldout(cct, 0) << __func__ << " failed to add zonegroup to current_period: " << cpp_strerror(-ret) << dendl;
4149 return ret;
4150 }
4151 }
4152 }
4153
4154 if (!current_period.get_id().empty()) {
4155 ret = current_period.update();
4156 if (ret < 0) {
4157 ldout(cct, 0) << __func__ << " failed to update new period: " << cpp_strerror(-ret) << dendl;
4158 return ret;
4159 }
4160 ret = current_period.store_info(false);
4161 if (ret < 0) {
4162 ldout(cct, 0) << __func__ << " failed to store new period: " << cpp_strerror(-ret) << dendl;
4163 return ret;
4164 }
4165 ret = current_period.reflect();
4166 if (ret < 0) {
4167 ldout(cct, 0) << __func__ << " failed to update local objects: " << cpp_strerror(-ret) << dendl;
4168 return ret;
4169 }
4170 }
4171
4172 for (auto const& iter : regions) {
4173 RGWZoneGroup zonegroup(iter);
4174 int ret = zonegroup.init(cct, this, true, true);
4175 if (ret < 0) {
4176 ldout(cct, 0) << __func__ << " failed init zonegroup" << iter << ": ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4177 return ret;
4178 }
4179 ret = zonegroup.delete_obj(true);
4180 if (ret < 0 && ret != -ENOENT) {
4181 ldout(cct, 0) << __func__ << " failed to delete region " << iter << ": ret "<< ret << " " << cpp_strerror(-ret)
4182 << dendl;
4183 return ret;
4184 }
4185 }
4186
4187 /* mark as converted */
4188 ret = rgw_put_system_obj(this, pool, oid, bl.c_str(), bl.length(),
4189 true, NULL, real_time(), NULL);
4190 if (ret < 0 ) {
4191 ldout(cct, 0) << __func__ << " failed to mark cluster as converted: ret "<< ret << " " << cpp_strerror(-ret)
4192 << dendl;
4193 return ret;
4194 }
4195
4196 return 0;
4197 }
4198
4199 int RGWRados::init_zg_from_period(bool *initialized)
4200 {
4201 *initialized = false;
4202
4203 if (current_period.get_id().empty()) {
4204 return 0;
4205 }
4206
4207 int ret = zonegroup.init(cct, this);
4208 ldout(cct, 20) << "period zonegroup init ret " << ret << dendl;
4209 if (ret == -ENOENT) {
4210 return 0;
4211 }
4212 if (ret < 0) {
4213 ldout(cct, 0) << "failed reading zonegroup info: " << cpp_strerror(-ret) << dendl;
4214 return ret;
4215 }
4216 ldout(cct, 20) << "period zonegroup name " << zonegroup.get_name() << dendl;
4217
4218 map<string, RGWZoneGroup>::const_iterator iter =
4219 current_period.get_map().zonegroups.find(zonegroup.get_id());
4220
4221 if (iter != current_period.get_map().zonegroups.end()) {
4222 ldout(cct, 20) << "using current period zonegroup " << zonegroup.get_name() << dendl;
4223 zonegroup = iter->second;
4224 ret = zonegroup.init(cct, this, false);
4225 if (ret < 0) {
4226 ldout(cct, 0) << "failed init zonegroup: " << " " << cpp_strerror(-ret) << dendl;
4227 return ret;
4228 }
4229 ret = zone_params.init(cct, this);
4230 if (ret < 0 && ret != -ENOENT) {
4231 ldout(cct, 0) << "failed reading zone params info: " << " " << cpp_strerror(-ret) << dendl;
4232 return ret;
4233 } if (ret ==-ENOENT && zonegroup.get_name() == default_zonegroup_name) {
4234 ldout(cct, 10) << " Using default name "<< default_zone_name << dendl;
4235 zone_params.set_name(default_zone_name);
4236 ret = zone_params.init(cct, this);
4237 if (ret < 0 && ret != -ENOENT) {
4238 ldout(cct, 0) << "failed reading zone params info: " << " " << cpp_strerror(-ret) << dendl;
4239 return ret;
4240 }
4241 }
4242 }
4243 for (iter = current_period.get_map().zonegroups.begin();
4244 iter != current_period.get_map().zonegroups.end(); ++iter){
4245 const RGWZoneGroup& zg = iter->second;
4246 // use endpoints from the zonegroup's master zone
4247 auto master = zg.zones.find(zg.master_zone);
4248 if (master == zg.zones.end()) {
4249 // fix missing master zone for a single zone zonegroup
4250 if (zg.master_zone.empty() && zg.zones.size() == 1) {
4251 master = zg.zones.begin();
4252 ldout(cct, 0) << "zonegroup " << zg.get_name() << " missing master_zone, setting zone " <<
4253 master->second.name << " id:" << master->second.id << " as master" << dendl;
4254 if (zonegroup.get_id() == zg.get_id()) {
4255 zonegroup.master_zone = master->second.id;
4256 ret = zonegroup.update();
4257 if (ret < 0) {
4258 ldout(cct, 0) << "error updating zonegroup : " << cpp_strerror(-ret) << dendl;
4259 return ret;
4260 }
4261 } else {
4262 RGWZoneGroup fixed_zg(zg.get_id(),zg.get_name());
4263 ret = fixed_zg.init(cct, this);
4264 if (ret < 0) {
4265 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
4266 return ret;
4267 }
4268 fixed_zg.master_zone = master->second.id;
4269 ret = fixed_zg.update();
4270 if (ret < 0) {
4271 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
4272 return ret;
4273 }
4274 }
4275 } else {
4276 ldout(cct, 0) << "zonegroup " << zg.get_name() << " missing zone for master_zone=" <<
4277 zg.master_zone << dendl;
4278 return -EINVAL;
4279 }
4280 }
4281 const auto& endpoints = master->second.endpoints;
4282 add_new_connection_to_map(zonegroup_conn_map, zg, new RGWRESTConn(cct, this, zg.get_id(), endpoints));
4283 if (!current_period.get_master_zonegroup().empty() &&
4284 zg.get_id() == current_period.get_master_zonegroup()) {
4285 rest_master_conn = new RGWRESTConn(cct, this, zg.get_id(), endpoints);
4286 }
4287 }
4288
4289 *initialized = true;
4290
4291 return 0;
4292 }
4293
4294 int RGWRados::init_zg_from_local(bool *creating_defaults)
4295 {
4296 int ret = zonegroup.init(cct, this);
4297 if ( (ret < 0 && ret != -ENOENT) || (ret == -ENOENT && !cct->_conf->rgw_zonegroup.empty())) {
4298 ldout(cct, 0) << "failed reading zonegroup info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4299 return ret;
4300 } else if (ret == -ENOENT) {
4301 *creating_defaults = true;
4302 ldout(cct, 10) << "Creating default zonegroup " << dendl;
4303 ret = zonegroup.create_default();
4304 if (ret < 0) {
4305 ldout(cct, 0) << "failure in zonegroup create_default: ret "<< ret << " " << cpp_strerror(-ret)
4306 << dendl;
4307 return ret;
4308 }
4309 ret = zonegroup.init(cct, this);
4310 if (ret < 0) {
4311 ldout(cct, 0) << "failure in zonegroup create_default: ret "<< ret << " " << cpp_strerror(-ret)
4312 << dendl;
4313 return ret;
4314 }
4315 }
4316 ldout(cct, 20) << "zonegroup " << zonegroup.get_name() << dendl;
4317 if (zonegroup.is_master_zonegroup()) {
4318 // use endpoints from the zonegroup's master zone
4319 auto master = zonegroup.zones.find(zonegroup.master_zone);
4320 if (master == zonegroup.zones.end()) {
4321 // fix missing master zone for a single zone zonegroup
4322 if (zonegroup.master_zone.empty() && zonegroup.zones.size() == 1) {
4323 master = zonegroup.zones.begin();
4324 ldout(cct, 0) << "zonegroup " << zonegroup.get_name() << " missing master_zone, setting zone " <<
4325 master->second.name << " id:" << master->second.id << " as master" << dendl;
4326 zonegroup.master_zone = master->second.id;
4327 ret = zonegroup.update();
4328 if (ret < 0) {
4329 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
4330 return ret;
4331 }
4332 } else {
4333 ldout(cct, 0) << "zonegroup " << zonegroup.get_name() << " missing zone for "
4334 "master_zone=" << zonegroup.master_zone << dendl;
4335 return -EINVAL;
4336 }
4337 }
4338 const auto& endpoints = master->second.endpoints;
4339 rest_master_conn = new RGWRESTConn(cct, this, zonegroup.get_id(), endpoints);
4340 }
4341
4342 return 0;
4343 }
4344
4345
4346 bool RGWRados::zone_syncs_from(RGWZone& target_zone, RGWZone& source_zone)
4347 {
4348 return target_zone.syncs_from(source_zone.name) &&
4349 sync_modules_manager->supports_data_export(source_zone.tier_type);
4350 }
4351
4352 /**
4353 * Initialize the RADOS instance and prepare to do other ops
4354 * Returns 0 on success, -ERR# on failure.
4355 */
4356 int RGWRados::init_complete()
4357 {
4358 int ret = realm.init(cct, this);
4359 if (ret < 0 && ret != -ENOENT) {
4360 ldout(cct, 0) << "failed reading realm info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4361 return ret;
4362 } else if (ret != -ENOENT) {
4363 ldout(cct, 20) << "realm " << realm.get_name() << " " << realm.get_id() << dendl;
4364 ret = current_period.init(cct, this, realm.get_id(), realm.get_name());
4365 if (ret < 0 && ret != -ENOENT) {
4366 ldout(cct, 0) << "failed reading current period info: " << " " << cpp_strerror(-ret) << dendl;
4367 return ret;
4368 }
4369 ldout(cct, 20) << "current period " << current_period.get_id() << dendl;
4370 }
4371
4372 ret = replace_region_with_zonegroup();
4373 if (ret < 0) {
4374 lderr(cct) << "failed converting region to zonegroup : ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4375 return ret;
4376 }
4377
4378 ret = convert_regionmap();
4379 if (ret < 0) {
4380 lderr(cct) << "failed converting regionmap: " << cpp_strerror(-ret) << dendl;
4381 return ret;
4382 }
4383
4384 bool zg_initialized = false;
4385
4386 if (!current_period.get_id().empty()) {
4387 ret = init_zg_from_period(&zg_initialized);
4388 if (ret < 0) {
4389 return ret;
4390 }
4391 }
4392
4393 bool creating_defaults = false;
4394 bool using_local = (!zg_initialized);
4395 if (using_local) {
4396 ldout(cct, 10) << " cannot find current period zonegroup using local zonegroup" << dendl;
4397 ret = init_zg_from_local(&creating_defaults);
4398 if (ret < 0) {
4399 return ret;
4400 }
4401 // read period_config into current_period
4402 auto& period_config = current_period.get_config();
4403 ret = period_config.read(this, zonegroup.realm_id);
4404 if (ret < 0 && ret != -ENOENT) {
4405 ldout(cct, 0) << "ERROR: failed to read period config: "
4406 << cpp_strerror(ret) << dendl;
4407 return ret;
4408 }
4409 }
4410
4411 ldout(cct, 10) << "Cannot find current period zone using local zone" << dendl;
4412 if (creating_defaults && cct->_conf->rgw_zone.empty()) {
4413 ldout(cct, 10) << " Using default name "<< default_zone_name << dendl;
4414 zone_params.set_name(default_zone_name);
4415 }
4416
4417 ret = zone_params.init(cct, this);
4418 if (ret < 0 && ret != -ENOENT) {
4419 lderr(cct) << "failed reading zone info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
4420 return ret;
4421 }
4422 map<string, RGWZone>::iterator zone_iter = get_zonegroup().zones.find(zone_params.get_id());
4423 if (zone_iter == get_zonegroup().zones.end()) {
4424 if (using_local) {
4425 lderr(cct) << "Cannot find zone id=" << zone_params.get_id() << " (name=" << zone_params.get_name() << ")" << dendl;
4426 return -EINVAL;
4427 }
4428 ldout(cct, 1) << "Cannot find zone id=" << zone_params.get_id() << " (name=" << zone_params.get_name() << "), switching to local zonegroup configuration" << dendl;
4429 ret = init_zg_from_local(&creating_defaults);
4430 if (ret < 0) {
4431 return ret;
4432 }
4433 zone_iter = get_zonegroup().zones.find(zone_params.get_id());
4434 }
4435 if (zone_iter != get_zonegroup().zones.end()) {
4436 zone_public_config = zone_iter->second;
4437 ldout(cct, 20) << "zone " << zone_params.get_name() << dendl;
4438 } else {
4439 lderr(cct) << "Cannot find zone id=" << zone_params.get_id() << " (name=" << zone_params.get_name() << ")" << dendl;
4440 return -EINVAL;
4441 }
4442
4443 zone_short_id = current_period.get_map().get_zone_short_id(zone_params.get_id());
4444
4445 if (run_sync_thread) {
4446 ret = sync_modules_manager->create_instance(cct, zone_public_config.tier_type, zone_params.tier_config, &sync_module);
4447 if (ret < 0) {
4448 lderr(cct) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
4449 return ret;
4450 }
4451 }
4452
4453 writeable_zone = (zone_public_config.tier_type.empty() || zone_public_config.tier_type == "rgw");
4454
4455 init_unique_trans_id_deps();
4456
4457 finisher = new Finisher(cct);
4458 finisher->start();
4459
4460 period_puller.reset(new RGWPeriodPuller(this));
4461 period_history.reset(new RGWPeriodHistory(cct, period_puller.get(),
4462 current_period));
4463
4464 if (need_watch_notify()) {
4465 ret = init_watch();
4466 if (ret < 0) {
4467 lderr(cct) << "ERROR: failed to initialize watch: " << cpp_strerror(-ret) << dendl;
4468 return ret;
4469 }
4470 }
4471
4472 /* first build all zones index */
4473 for (auto ziter : get_zonegroup().zones) {
4474 const string& id = ziter.first;
4475 RGWZone& z = ziter.second;
4476 zone_id_by_name[z.name] = id;
4477 zone_by_id[id] = z;
4478 }
4479
4480 if (zone_by_id.find(zone_id()) == zone_by_id.end()) {
4481 ldout(cct, 0) << "WARNING: could not find zone config in zonegroup for local zone (" << zone_id() << "), will use defaults" << dendl;
4482 }
4483 zone_public_config = zone_by_id[zone_id()];
4484 for (auto ziter : get_zonegroup().zones) {
4485 const string& id = ziter.first;
4486 RGWZone& z = ziter.second;
4487 if (id == zone_id()) {
4488 continue;
4489 }
4490 if (z.endpoints.empty()) {
4491 ldout(cct, 0) << "WARNING: can't generate connection for zone " << z.id << " id " << z.name << ": no endpoints defined" << dendl;
4492 continue;
4493 }
4494 ldout(cct, 20) << "generating connection object for zone " << z.name << " id " << z.id << dendl;
4495 RGWRESTConn *conn = new RGWRESTConn(cct, this, z.id, z.endpoints);
4496 zone_conn_map[id] = conn;
4497 if (zone_syncs_from(zone_public_config, z) ||
4498 zone_syncs_from(z, zone_public_config)) {
4499 if (zone_syncs_from(zone_public_config, z)) {
4500 zone_data_sync_from_map[id] = conn;
4501 }
4502 if (zone_syncs_from(z, zone_public_config)) {
4503 zone_data_notify_to_map[id] = conn;
4504 }
4505 } else {
4506 ldout(cct, 20) << "NOTICE: not syncing to/from zone " << z.name << " id " << z.id << dendl;
4507 }
4508 }
4509
4510 ret = open_root_pool_ctx();
4511 if (ret < 0)
4512 return ret;
4513
4514 ret = open_gc_pool_ctx();
4515 if (ret < 0)
4516 return ret;
4517
4518 ret = open_lc_pool_ctx();
4519 if (ret < 0)
4520 return ret;
4521
4522 ret = open_objexp_pool_ctx();
4523 if (ret < 0)
4524 return ret;
4525
4526 ret = open_reshard_pool_ctx();
4527 if (ret < 0)
4528 return ret;
4529
4530 pools_initialized = true;
4531
4532 gc = new RGWGC();
4533 gc->initialize(cct, this);
4534
4535 obj_expirer = new RGWObjectExpirer(this);
4536
4537 if (use_gc_thread) {
4538 gc->start_processor();
4539 obj_expirer->start_processor();
4540 }
4541
4542 /* no point of running sync thread if we don't have a master zone configured
4543 or there is no rest_master_conn */
4544 if (get_zonegroup().master_zone.empty() || !rest_master_conn
4545 || current_period.get_id().empty()) {
4546 run_sync_thread = false;
4547 }
4548
4549 if (run_sync_thread) {
4550 // initialize the log period history
4551 meta_mgr->init_oldest_log_period();
4552 }
4553
4554 async_rados = new RGWAsyncRadosProcessor(this, cct->_conf->rgw_num_async_rados_threads);
4555 async_rados->start();
4556
4557 ret = meta_mgr->init(current_period.get_id());
4558 if (ret < 0) {
4559 lderr(cct) << "ERROR: failed to initialize metadata log: "
4560 << cpp_strerror(-ret) << dendl;
4561 return ret;
4562 }
4563
4564 if (is_meta_master()) {
4565 auto md_log = meta_mgr->get_log(current_period.get_id());
4566 meta_notifier = new RGWMetaNotifier(this, md_log);
4567 meta_notifier->start();
4568 }
4569
4570 if (run_sync_thread) {
4571 Mutex::Locker l(meta_sync_thread_lock);
4572 meta_sync_processor_thread = new RGWMetaSyncProcessorThread(this, async_rados);
4573 ret = meta_sync_processor_thread->init();
4574 if (ret < 0) {
4575 ldout(cct, 0) << "ERROR: failed to initialize meta sync thread" << dendl;
4576 return ret;
4577 }
4578 meta_sync_processor_thread->start();
4579
4580 // configure the bucket trim manager
4581 rgw::BucketTrimConfig config;
4582 rgw::configure_bucket_trim(cct, config);
4583
4584 bucket_trim.emplace(this, config);
4585 ret = bucket_trim->init();
4586 if (ret < 0) {
4587 ldout(cct, 0) << "ERROR: failed to start bucket trim manager" << dendl;
4588 return ret;
4589 }
4590
4591 Mutex::Locker dl(data_sync_thread_lock);
4592 for (auto iter : zone_data_sync_from_map) {
4593 ldout(cct, 5) << "starting data sync thread for zone " << iter.first << dendl;
4594 auto *thread = new RGWDataSyncProcessorThread(this, async_rados, iter.first,
4595 &*bucket_trim);
4596 ret = thread->init();
4597 if (ret < 0) {
4598 ldout(cct, 0) << "ERROR: failed to initialize data sync thread" << dendl;
4599 return ret;
4600 }
4601 thread->start();
4602 data_sync_processor_threads[iter.first] = thread;
4603 }
4604 auto interval = cct->_conf->rgw_sync_log_trim_interval;
4605 if (interval > 0) {
4606 sync_log_trimmer = new RGWSyncLogTrimThread(this, &*bucket_trim, interval);
4607 ret = sync_log_trimmer->init();
4608 if (ret < 0) {
4609 ldout(cct, 0) << "ERROR: failed to initialize sync log trim thread" << dendl;
4610 return ret;
4611 }
4612 sync_log_trimmer->start();
4613 }
4614 }
4615 data_notifier = new RGWDataNotifier(this);
4616 data_notifier->start();
4617
4618 lc = new RGWLC();
4619 lc->initialize(cct, this);
4620
4621 if (use_lc_thread)
4622 lc->start_processor();
4623
4624 quota_handler = RGWQuotaHandler::generate_handler(this, quota_threads);
4625
4626 bucket_index_max_shards = (cct->_conf->rgw_override_bucket_index_max_shards ? cct->_conf->rgw_override_bucket_index_max_shards :
4627 get_zone().bucket_index_max_shards);
4628 if (bucket_index_max_shards > get_max_bucket_shards()) {
4629 bucket_index_max_shards = get_max_bucket_shards();
4630 ldout(cct, 1) << __func__ << " bucket index max shards is too large, reset to value: "
4631 << get_max_bucket_shards() << dendl;
4632 }
4633 ldout(cct, 20) << __func__ << " bucket index max shards: " << bucket_index_max_shards << dendl;
4634
4635 binfo_cache = new RGWChainedCacheImpl<bucket_info_entry>;
4636 binfo_cache->init(this);
4637
4638 bool need_tombstone_cache = !zone_data_notify_to_map.empty(); /* have zones syncing from us */
4639
4640 if (need_tombstone_cache) {
4641 obj_tombstone_cache = new tombstone_cache_t(cct->_conf->rgw_obj_tombstone_cache_size);
4642 }
4643
4644 reshard_wait = std::make_shared<RGWReshardWait>(this);
4645
4646 reshard = new RGWReshard(this);
4647
4648 /* only the master zone in the zonegroup reshards buckets */
4649 run_reshard_thread = run_reshard_thread && (get_zonegroup().master_zone == zone_public_config.id);
4650 if (run_reshard_thread) {
4651 reshard->start_processor();
4652 }
4653
4654 index_completion_manager = new RGWIndexCompletionManager(this);
4655 ret = index_completion_manager->start();
4656
4657 return ret;
4658 }
4659
4660 /**
4661 * Initialize the RADOS instance and prepare to do other ops
4662 * Returns 0 on success, -ERR# on failure.
4663 */
4664 int RGWRados::initialize()
4665 {
4666 int ret;
4667
4668 ret = init_rados();
4669 if (ret < 0)
4670 return ret;
4671
4672 return init_complete();
4673 }
4674
4675 void RGWRados::finalize_watch()
4676 {
4677 for (int i = 0; i < num_watchers; i++) {
4678 RGWWatcher *watcher = watchers[i];
4679 watcher->unregister_watch();
4680 delete watcher;
4681 }
4682
4683 delete[] notify_oids;
4684 delete[] watchers;
4685 }
4686
4687 void RGWRados::schedule_context(Context *c) {
4688 finisher->queue(c);
4689 }
4690
4691 int RGWRados::list_raw_prefixed_objs(const rgw_pool& pool, const string& prefix, list<string>& result)
4692 {
4693 bool is_truncated;
4694 RGWListRawObjsCtx ctx;
4695 do {
4696 list<string> oids;
4697 int r = list_raw_objects(pool, prefix, 1000,
4698 ctx, oids, &is_truncated);
4699 if (r < 0) {
4700 return r;
4701 }
4702 list<string>::iterator iter;
4703 for (iter = oids.begin(); iter != oids.end(); ++iter) {
4704 string& val = *iter;
4705 if (val.size() > prefix.size())
4706 result.push_back(val.substr(prefix.size()));
4707 }
4708 } while (is_truncated);
4709
4710 return 0;
4711 }
4712
4713 int RGWRados::list_regions(list<string>& regions)
4714 {
4715 RGWZoneGroup zonegroup;
4716
4717 return list_raw_prefixed_objs(zonegroup.get_pool(cct), region_info_oid_prefix, regions);
4718 }
4719
4720 int RGWRados::list_zonegroups(list<string>& zonegroups)
4721 {
4722 RGWZoneGroup zonegroup;
4723
4724 return list_raw_prefixed_objs(zonegroup.get_pool(cct), zonegroup_names_oid_prefix, zonegroups);
4725 }
4726
4727 int RGWRados::list_zones(list<string>& zones)
4728 {
4729 RGWZoneParams zoneparams;
4730
4731 return list_raw_prefixed_objs(zoneparams.get_pool(cct), zone_names_oid_prefix, zones);
4732 }
4733
4734 int RGWRados::list_realms(list<string>& realms)
4735 {
4736 RGWRealm realm(cct, this);
4737 return list_raw_prefixed_objs(realm.get_pool(cct), realm_names_oid_prefix, realms);
4738 }
4739
4740 int RGWRados::list_periods(list<string>& periods)
4741 {
4742 RGWPeriod period;
4743 list<string> raw_periods;
4744 int ret = list_raw_prefixed_objs(period.get_pool(cct), period.get_info_oid_prefix(), raw_periods);
4745 if (ret < 0) {
4746 return ret;
4747 }
4748 for (const auto& oid : raw_periods) {
4749 size_t pos = oid.find(".");
4750 if (pos != std::string::npos) {
4751 periods.push_back(oid.substr(0, pos));
4752 } else {
4753 periods.push_back(oid);
4754 }
4755 }
4756 periods.sort(); // unique() only detects duplicates if they're adjacent
4757 periods.unique();
4758 return 0;
4759 }
4760
4761
4762 int RGWRados::list_periods(const string& current_period, list<string>& periods)
4763 {
4764 int ret = 0;
4765 string period_id = current_period;
4766 while(!period_id.empty()) {
4767 RGWPeriod period(period_id);
4768 ret = period.init(cct, this);
4769 if (ret < 0) {
4770 return ret;
4771 }
4772 periods.push_back(period.get_id());
4773 period_id = period.get_predecessor();
4774 }
4775
4776 return ret;
4777 }
4778
4779 /**
4780 * Open the pool used as root for this gateway
4781 * Returns: 0 on success, -ERR# otherwise.
4782 */
4783 int RGWRados::open_root_pool_ctx()
4784 {
4785 return rgw_init_ioctx(get_rados_handle(), get_zone_params().domain_root, root_pool_ctx, true);
4786 }
4787
4788 int RGWRados::open_gc_pool_ctx()
4789 {
4790 return rgw_init_ioctx(get_rados_handle(), get_zone_params().gc_pool, gc_pool_ctx, true);
4791 }
4792
4793 int RGWRados::open_lc_pool_ctx()
4794 {
4795 return rgw_init_ioctx(get_rados_handle(), get_zone_params().lc_pool, lc_pool_ctx, true);
4796 }
4797
4798 int RGWRados::open_objexp_pool_ctx()
4799 {
4800 return rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, objexp_pool_ctx, true);
4801 }
4802
4803 int RGWRados::open_reshard_pool_ctx()
4804 {
4805 return rgw_init_ioctx(get_rados_handle(), get_zone_params().reshard_pool, reshard_pool_ctx, true);
4806 }
4807
4808 int RGWRados::init_watch()
4809 {
4810 int r = rgw_init_ioctx(&rados[0], get_zone_params().control_pool, control_pool_ctx, true);
4811 if (r < 0) {
4812 return r;
4813 }
4814
4815 num_watchers = cct->_conf->rgw_num_control_oids;
4816
4817 bool compat_oid = (num_watchers == 0);
4818
4819 if (num_watchers <= 0)
4820 num_watchers = 1;
4821
4822 notify_oids = new string[num_watchers];
4823 watchers = new RGWWatcher *[num_watchers];
4824
4825 for (int i=0; i < num_watchers; i++) {
4826 string& notify_oid = notify_oids[i];
4827 notify_oid = notify_oid_prefix;
4828 if (!compat_oid) {
4829 char buf[16];
4830 snprintf(buf, sizeof(buf), ".%d", i);
4831 notify_oid.append(buf);
4832 }
4833 r = control_pool_ctx.create(notify_oid, false);
4834 if (r < 0 && r != -EEXIST)
4835 return r;
4836
4837 RGWWatcher *watcher = new RGWWatcher(this, i, notify_oid);
4838 watchers[i] = watcher;
4839
4840 r = watcher->register_watch();
4841 if (r < 0)
4842 return r;
4843 }
4844
4845 watch_initialized = true;
4846
4847 set_cache_enabled(true);
4848
4849 return 0;
4850 }
4851
4852 void RGWRados::pick_control_oid(const string& key, string& notify_oid)
4853 {
4854 uint32_t r = ceph_str_hash_linux(key.c_str(), key.size());
4855
4856 int i = r % num_watchers;
4857 char buf[16];
4858 snprintf(buf, sizeof(buf), ".%d", i);
4859
4860 notify_oid = notify_oid_prefix;
4861 notify_oid.append(buf);
4862 }
4863
4864 int RGWRados::open_pool_ctx(const rgw_pool& pool, librados::IoCtx& io_ctx)
4865 {
4866 librados::Rados *rad = get_rados_handle();
4867 int r = rgw_init_ioctx(rad, pool, io_ctx);
4868 if (r != -ENOENT)
4869 return r;
4870
4871 if (!pools_initialized)
4872 return r;
4873
4874 r = rad->pool_create(pool.name.c_str());
4875 if (r < 0 && r != -EEXIST)
4876 return r;
4877
4878 r = rgw_init_ioctx(rad, pool, io_ctx);
4879 if (r < 0)
4880 return r;
4881
4882 r = io_ctx.application_enable(pg_pool_t::APPLICATION_NAME_RGW, false);
4883 if (r < 0 && r != -EOPNOTSUPP)
4884 return r;
4885 return 0;
4886 }
4887
4888 void RGWRados::build_bucket_index_marker(const string& shard_id_str, const string& shard_marker,
4889 string *marker) {
4890 if (marker) {
4891 *marker = shard_id_str;
4892 marker->append(BucketIndexShardsManager::KEY_VALUE_SEPARATOR);
4893 marker->append(shard_marker);
4894 }
4895 }
4896
4897 int RGWRados::open_bucket_index_ctx(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx)
4898 {
4899 const rgw_pool& explicit_pool = bucket_info.bucket.explicit_placement.index_pool;
4900
4901 if (!explicit_pool.empty()) {
4902 return open_pool_ctx(explicit_pool, index_ctx);
4903 }
4904
4905 const string *rule = &bucket_info.placement_rule;
4906 if (rule->empty()) {
4907 rule = &zonegroup.default_placement;
4908 }
4909 auto iter = zone_params.placement_pools.find(*rule);
4910 if (iter == zone_params.placement_pools.end()) {
4911 ldout(cct, 0) << "could not find placement rule " << *rule << " within zonegroup " << dendl;
4912 return -EINVAL;
4913 }
4914
4915 int r = open_pool_ctx(iter->second.index_pool, index_ctx);
4916 if (r < 0)
4917 return r;
4918
4919 return 0;
4920 }
4921
4922 /**
4923 * set up a bucket listing.
4924 * handle is filled in.
4925 * Returns 0 on success, -ERR# otherwise.
4926 */
4927 int RGWRados::list_buckets_init(RGWAccessHandle *handle)
4928 {
4929 librados::NObjectIterator *state = new librados::NObjectIterator(root_pool_ctx.nobjects_begin());
4930 *handle = (RGWAccessHandle)state;
4931 return 0;
4932 }
4933
4934 /**
4935 * get the next bucket in the listing.
4936 * obj is filled in,
4937 * handle is updated.
4938 * returns 0 on success, -ERR# otherwise.
4939 */
4940 int RGWRados::list_buckets_next(rgw_bucket_dir_entry& obj, RGWAccessHandle *handle)
4941 {
4942 librados::NObjectIterator *state = (librados::NObjectIterator *)*handle;
4943
4944 do {
4945 if (*state == root_pool_ctx.nobjects_end()) {
4946 delete state;
4947 return -ENOENT;
4948 }
4949
4950 obj.key.name = (*state)->get_oid();
4951 if (obj.key.name[0] == '_') {
4952 obj.key.name = obj.key.name.substr(1);
4953 }
4954
4955 (*state)++;
4956 } while (obj.key.name[0] == '.'); /* skip all entries starting with '.' */
4957
4958 return 0;
4959 }
4960
4961
4962 /**** logs ****/
4963
4964 struct log_list_state {
4965 string prefix;
4966 librados::IoCtx io_ctx;
4967 librados::NObjectIterator obit;
4968 };
4969
4970 int RGWRados::log_list_init(const string& prefix, RGWAccessHandle *handle)
4971 {
4972 log_list_state *state = new log_list_state;
4973 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, state->io_ctx);
4974 if (r < 0) {
4975 delete state;
4976 return r;
4977 }
4978 state->prefix = prefix;
4979 state->obit = state->io_ctx.nobjects_begin();
4980 *handle = (RGWAccessHandle)state;
4981 return 0;
4982 }
4983
4984 int RGWRados::log_list_next(RGWAccessHandle handle, string *name)
4985 {
4986 log_list_state *state = static_cast<log_list_state *>(handle);
4987 while (true) {
4988 if (state->obit == state->io_ctx.nobjects_end()) {
4989 delete state;
4990 return -ENOENT;
4991 }
4992 if (state->prefix.length() &&
4993 state->obit->get_oid().find(state->prefix) != 0) {
4994 state->obit++;
4995 continue;
4996 }
4997 *name = state->obit->get_oid();
4998 state->obit++;
4999 break;
5000 }
5001 return 0;
5002 }
5003
5004 int RGWRados::log_remove(const string& name)
5005 {
5006 librados::IoCtx io_ctx;
5007 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx);
5008 if (r < 0)
5009 return r;
5010 return io_ctx.remove(name);
5011 }
5012
5013 struct log_show_state {
5014 librados::IoCtx io_ctx;
5015 bufferlist bl;
5016 bufferlist::iterator p;
5017 string name;
5018 uint64_t pos;
5019 bool eof;
5020 log_show_state() : pos(0), eof(false) {}
5021 };
5022
5023 int RGWRados::log_show_init(const string& name, RGWAccessHandle *handle)
5024 {
5025 log_show_state *state = new log_show_state;
5026 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, state->io_ctx);
5027 if (r < 0) {
5028 delete state;
5029 return r;
5030 }
5031 state->name = name;
5032 *handle = (RGWAccessHandle)state;
5033 return 0;
5034 }
5035
5036 int RGWRados::log_show_next(RGWAccessHandle handle, rgw_log_entry *entry)
5037 {
5038 log_show_state *state = static_cast<log_show_state *>(handle);
5039 off_t off = state->p.get_off();
5040
5041 ldout(cct, 10) << "log_show_next pos " << state->pos << " bl " << state->bl.length()
5042 << " off " << off
5043 << " eof " << (int)state->eof
5044 << dendl;
5045 // read some?
5046 unsigned chunk = 1024*1024;
5047 if ((state->bl.length() - off) < chunk/2 && !state->eof) {
5048 bufferlist more;
5049 int r = state->io_ctx.read(state->name, more, chunk, state->pos);
5050 if (r < 0)
5051 return r;
5052 state->pos += r;
5053 bufferlist old;
5054 try {
5055 old.substr_of(state->bl, off, state->bl.length() - off);
5056 } catch (buffer::error& err) {
5057 return -EINVAL;
5058 }
5059 state->bl.clear();
5060 state->bl.claim(old);
5061 state->bl.claim_append(more);
5062 state->p = state->bl.begin();
5063 if ((unsigned)r < chunk)
5064 state->eof = true;
5065 ldout(cct, 10) << " read " << r << dendl;
5066 }
5067
5068 if (state->p.end())
5069 return 0; // end of file
5070 try {
5071 ::decode(*entry, state->p);
5072 }
5073 catch (const buffer::error &e) {
5074 return -EINVAL;
5075 }
5076 return 1;
5077 }
5078
5079 /**
5080 * usage_log_hash: get usage log key hash, based on name and index
5081 *
5082 * Get the usage object name. Since a user may have more than 1
5083 * object holding that info (multiple shards), we use index to
5084 * specify that shard number. Once index exceeds max shards it
5085 * wraps.
5086 * If name is not being set, results for all users will be returned
5087 * and index will wrap only after total shards number.
5088 *
5089 * @param cct [in] ceph context
5090 * @param name [in] user name
5091 * @param hash [out] hash value
5092 * @param index [in] shard index number
5093 */
5094 static void usage_log_hash(CephContext *cct, const string& name, string& hash, uint32_t index)
5095 {
5096 uint32_t val = index;
5097
5098 if (!name.empty()) {
5099 int max_user_shards = cct->_conf->rgw_usage_max_user_shards;
5100 val %= max_user_shards;
5101 val += ceph_str_hash_linux(name.c_str(), name.size());
5102 }
5103 char buf[17];
5104 int max_shards = cct->_conf->rgw_usage_max_shards;
5105 snprintf(buf, sizeof(buf), RGW_USAGE_OBJ_PREFIX "%u", (unsigned)(val % max_shards));
5106 hash = buf;
5107 }
5108
5109 int RGWRados::log_usage(map<rgw_user_bucket, RGWUsageBatch>& usage_info)
5110 {
5111 uint32_t index = 0;
5112
5113 map<string, rgw_usage_log_info> log_objs;
5114
5115 string hash;
5116 string last_user;
5117
5118 /* restructure usage map, zone by object hash */
5119 map<rgw_user_bucket, RGWUsageBatch>::iterator iter;
5120 for (iter = usage_info.begin(); iter != usage_info.end(); ++iter) {
5121 const rgw_user_bucket& ub = iter->first;
5122 RGWUsageBatch& info = iter->second;
5123
5124 if (ub.user.empty()) {
5125 ldout(cct, 0) << "WARNING: RGWRados::log_usage(): user name empty (bucket=" << ub.bucket << "), skipping" << dendl;
5126 continue;
5127 }
5128
5129 if (ub.user != last_user) {
5130 /* index *should* be random, but why waste extra cycles
5131 in most cases max user shards is not going to exceed 1,
5132 so just incrementing it */
5133 usage_log_hash(cct, ub.user, hash, index++);
5134 }
5135 last_user = ub.user;
5136 vector<rgw_usage_log_entry>& v = log_objs[hash].entries;
5137
5138 for (auto miter = info.m.begin(); miter != info.m.end(); ++miter) {
5139 v.push_back(miter->second);
5140 }
5141 }
5142
5143 map<string, rgw_usage_log_info>::iterator liter;
5144
5145 for (liter = log_objs.begin(); liter != log_objs.end(); ++liter) {
5146 int r = cls_obj_usage_log_add(liter->first, liter->second);
5147 if (r < 0)
5148 return r;
5149 }
5150 return 0;
5151 }
5152
5153 int RGWRados::read_usage(const rgw_user& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries,
5154 bool *is_truncated, RGWUsageIter& usage_iter, map<rgw_user_bucket, rgw_usage_log_entry>& usage)
5155 {
5156 uint32_t num = max_entries;
5157 string hash, first_hash;
5158 string user_str = user.to_str();
5159 usage_log_hash(cct, user_str, first_hash, 0);
5160
5161 if (usage_iter.index) {
5162 usage_log_hash(cct, user_str, hash, usage_iter.index);
5163 } else {
5164 hash = first_hash;
5165 }
5166
5167 usage.clear();
5168
5169 do {
5170 map<rgw_user_bucket, rgw_usage_log_entry> ret_usage;
5171 map<rgw_user_bucket, rgw_usage_log_entry>::iterator iter;
5172
5173 int ret = cls_obj_usage_log_read(hash, user_str, start_epoch, end_epoch, num,
5174 usage_iter.read_iter, ret_usage, is_truncated);
5175 if (ret == -ENOENT)
5176 goto next;
5177
5178 if (ret < 0)
5179 return ret;
5180
5181 num -= ret_usage.size();
5182
5183 for (iter = ret_usage.begin(); iter != ret_usage.end(); ++iter) {
5184 usage[iter->first].aggregate(iter->second);
5185 }
5186
5187 next:
5188 if (!*is_truncated) {
5189 usage_iter.read_iter.clear();
5190 usage_log_hash(cct, user_str, hash, ++usage_iter.index);
5191 }
5192 } while (num && !*is_truncated && hash != first_hash);
5193 return 0;
5194 }
5195
5196 int RGWRados::trim_usage(rgw_user& user, uint64_t start_epoch, uint64_t end_epoch)
5197 {
5198 uint32_t index = 0;
5199 string hash, first_hash;
5200 string user_str = user.to_str();
5201 usage_log_hash(cct, user_str, first_hash, index);
5202
5203 hash = first_hash;
5204 do {
5205 int ret = cls_obj_usage_log_trim(hash, user_str, start_epoch, end_epoch);
5206
5207 if (ret < 0 && ret != -ENOENT)
5208 return ret;
5209
5210 usage_log_hash(cct, user_str, hash, ++index);
5211 } while (hash != first_hash);
5212
5213 return 0;
5214 }
5215
5216 int RGWRados::key_to_shard_id(const string& key, int max_shards)
5217 {
5218 return rgw_shards_hash(key, max_shards);
5219 }
5220
5221 void RGWRados::shard_name(const string& prefix, unsigned max_shards, const string& key, string& name, int *shard_id)
5222 {
5223 uint32_t val = ceph_str_hash_linux(key.c_str(), key.size());
5224 char buf[16];
5225 if (shard_id) {
5226 *shard_id = val % max_shards;
5227 }
5228 snprintf(buf, sizeof(buf), "%u", (unsigned)(val % max_shards));
5229 name = prefix + buf;
5230 }
5231
5232 void RGWRados::shard_name(const string& prefix, unsigned max_shards, const string& section, const string& key, string& name)
5233 {
5234 uint32_t val = ceph_str_hash_linux(key.c_str(), key.size());
5235 val ^= ceph_str_hash_linux(section.c_str(), section.size());
5236 char buf[16];
5237 snprintf(buf, sizeof(buf), "%u", (unsigned)(val % max_shards));
5238 name = prefix + buf;
5239 }
5240
5241 void RGWRados::shard_name(const string& prefix, unsigned shard_id, string& name)
5242 {
5243 char buf[16];
5244 snprintf(buf, sizeof(buf), "%u", shard_id);
5245 name = prefix + buf;
5246
5247 }
5248
5249 void RGWRados::time_log_prepare_entry(cls_log_entry& entry, const real_time& ut, const string& section, const string& key, bufferlist& bl)
5250 {
5251 cls_log_add_prepare_entry(entry, utime_t(ut), section, key, bl);
5252 }
5253
5254 int RGWRados::time_log_add_init(librados::IoCtx& io_ctx)
5255 {
5256 return rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx, true);
5257
5258 }
5259
5260 int RGWRados::time_log_add(const string& oid, const real_time& ut, const string& section, const string& key, bufferlist& bl)
5261 {
5262 librados::IoCtx io_ctx;
5263
5264 int r = time_log_add_init(io_ctx);
5265 if (r < 0) {
5266 return r;
5267 }
5268
5269 ObjectWriteOperation op;
5270 utime_t t(ut);
5271 cls_log_add(op, t, section, key, bl);
5272
5273 return io_ctx.operate(oid, &op);
5274 }
5275
5276 int RGWRados::time_log_add(const string& oid, list<cls_log_entry>& entries,
5277 librados::AioCompletion *completion, bool monotonic_inc)
5278 {
5279 librados::IoCtx io_ctx;
5280
5281 int r = time_log_add_init(io_ctx);
5282 if (r < 0) {
5283 return r;
5284 }
5285
5286 ObjectWriteOperation op;
5287 cls_log_add(op, entries, monotonic_inc);
5288
5289 if (!completion) {
5290 r = io_ctx.operate(oid, &op);
5291 } else {
5292 r = io_ctx.aio_operate(oid, completion, &op);
5293 }
5294 return r;
5295 }
5296
5297 int RGWRados::time_log_list(const string& oid, const real_time& start_time, const real_time& end_time,
5298 int max_entries, list<cls_log_entry>& entries,
5299 const string& marker,
5300 string *out_marker,
5301 bool *truncated)
5302 {
5303 librados::IoCtx io_ctx;
5304
5305 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx);
5306 if (r < 0)
5307 return r;
5308 librados::ObjectReadOperation op;
5309
5310 utime_t st(start_time);
5311 utime_t et(end_time);
5312
5313 cls_log_list(op, st, et, marker, max_entries, entries,
5314 out_marker, truncated);
5315
5316 bufferlist obl;
5317
5318 int ret = io_ctx.operate(oid, &op, &obl);
5319 if (ret < 0)
5320 return ret;
5321
5322 return 0;
5323 }
5324
5325 int RGWRados::time_log_info(const string& oid, cls_log_header *header)
5326 {
5327 librados::IoCtx io_ctx;
5328
5329 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx);
5330 if (r < 0)
5331 return r;
5332 librados::ObjectReadOperation op;
5333
5334 cls_log_info(op, header);
5335
5336 bufferlist obl;
5337
5338 int ret = io_ctx.operate(oid, &op, &obl);
5339 if (ret < 0)
5340 return ret;
5341
5342 return 0;
5343 }
5344
5345 int RGWRados::time_log_info_async(librados::IoCtx& io_ctx, const string& oid, cls_log_header *header, librados::AioCompletion *completion)
5346 {
5347 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx);
5348 if (r < 0)
5349 return r;
5350
5351 librados::ObjectReadOperation op;
5352
5353 cls_log_info(op, header);
5354
5355 int ret = io_ctx.aio_operate(oid, completion, &op, NULL);
5356 if (ret < 0)
5357 return ret;
5358
5359 return 0;
5360 }
5361
5362 int RGWRados::time_log_trim(const string& oid, const real_time& start_time, const real_time& end_time,
5363 const string& from_marker, const string& to_marker,
5364 librados::AioCompletion *completion)
5365 {
5366 librados::IoCtx io_ctx;
5367
5368 int r = rgw_init_ioctx(get_rados_handle(), get_zone_params().log_pool, io_ctx);
5369 if (r < 0)
5370 return r;
5371
5372 utime_t st(start_time);
5373 utime_t et(end_time);
5374
5375 ObjectWriteOperation op;
5376 cls_log_trim(op, st, et, from_marker, to_marker);
5377
5378 if (!completion) {
5379 r = io_ctx.operate(oid, &op);
5380 } else {
5381 r = io_ctx.aio_operate(oid, completion, &op);
5382 }
5383 return r;
5384 }
5385
5386 string RGWRados::objexp_hint_get_shardname(int shard_num)
5387 {
5388 char buf[32];
5389 snprintf(buf, sizeof(buf), "%010u", (unsigned)shard_num);
5390
5391 string objname("obj_delete_at_hint.");
5392 return objname + buf;
5393 }
5394
5395 int RGWRados::objexp_key_shard(const rgw_obj_index_key& key)
5396 {
5397 string obj_key = key.name + key.instance;
5398 int num_shards = cct->_conf->rgw_objexp_hints_num_shards;
5399 uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
5400 uint32_t sid2 = sid ^ ((sid & 0xFF) << 24);
5401 sid = rgw_shards_mod(sid2, num_shards);
5402 return sid;
5403 }
5404
5405 static string objexp_hint_get_keyext(const string& tenant_name,
5406 const string& bucket_name,
5407 const string& bucket_id,
5408 const rgw_obj_key& obj_key)
5409 {
5410 return tenant_name + (tenant_name.empty() ? "" : ":") + bucket_name + ":" + bucket_id +
5411 ":" + obj_key.name + ":" + obj_key.instance;
5412 }
5413
5414 int RGWRados::objexp_hint_add(const ceph::real_time& delete_at,
5415 const string& tenant_name,
5416 const string& bucket_name,
5417 const string& bucket_id,
5418 const rgw_obj_index_key& obj_key)
5419 {
5420 const string keyext = objexp_hint_get_keyext(tenant_name, bucket_name,
5421 bucket_id, obj_key);
5422 objexp_hint_entry he = {
5423 .tenant = tenant_name,
5424 .bucket_name = bucket_name,
5425 .bucket_id = bucket_id,
5426 .obj_key = obj_key,
5427 .exp_time = delete_at };
5428 bufferlist hebl;
5429 ::encode(he, hebl);
5430 ObjectWriteOperation op;
5431 cls_timeindex_add(op, utime_t(delete_at), keyext, hebl);
5432
5433 string shard_name = objexp_hint_get_shardname(objexp_key_shard(obj_key));
5434 return objexp_pool_ctx.operate(shard_name, &op);
5435 }
5436
5437 void RGWRados::objexp_get_shard(int shard_num,
5438 string& shard) /* out */
5439 {
5440 shard = objexp_hint_get_shardname(shard_num);
5441 }
5442
5443 int RGWRados::objexp_hint_list(const string& oid,
5444 const ceph::real_time& start_time,
5445 const ceph::real_time& end_time,
5446 const int max_entries,
5447 const string& marker,
5448 list<cls_timeindex_entry>& entries, /* out */
5449 string *out_marker, /* out */
5450 bool *truncated) /* out */
5451 {
5452 librados::ObjectReadOperation op;
5453 cls_timeindex_list(op, utime_t(start_time), utime_t(end_time), marker, max_entries, entries,
5454 out_marker, truncated);
5455
5456 bufferlist obl;
5457 int ret = objexp_pool_ctx.operate(oid, &op, &obl);
5458
5459 if ((ret < 0 ) && (ret != -ENOENT)) {
5460 return ret;
5461 }
5462
5463 if ((ret == -ENOENT) && truncated) {
5464 *truncated = false;
5465 }
5466
5467 return 0;
5468 }
5469
5470 int RGWRados::objexp_hint_parse(cls_timeindex_entry &ti_entry, /* in */
5471 objexp_hint_entry& hint_entry) /* out */
5472 {
5473 try {
5474 bufferlist::iterator iter = ti_entry.value.begin();
5475 ::decode(hint_entry, iter);
5476 } catch (buffer::error& err) {
5477 ldout(cct, 0) << "ERROR: couldn't decode avail_pools" << dendl;
5478 }
5479
5480 return 0;
5481 }
5482
5483 int RGWRados::objexp_hint_trim(const string& oid,
5484 const ceph::real_time& start_time,
5485 const ceph::real_time& end_time,
5486 const string& from_marker,
5487 const string& to_marker)
5488 {
5489 int ret = cls_timeindex_trim(objexp_pool_ctx, oid, utime_t(start_time), utime_t(end_time),
5490 from_marker, to_marker);
5491 if ((ret < 0 ) && (ret != -ENOENT)) {
5492 return ret;
5493 }
5494
5495 return 0;
5496 }
5497
5498 int RGWRados::lock_exclusive(rgw_pool& pool, const string& oid, timespan& duration,
5499 string& zone_id, string& owner_id) {
5500 librados::IoCtx io_ctx;
5501
5502 int r = rgw_init_ioctx(get_rados_handle(), pool, io_ctx);
5503 if (r < 0) {
5504 return r;
5505 }
5506 uint64_t msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
5507 utime_t ut(msec / 1000, msec % 1000);
5508
5509 rados::cls::lock::Lock l(log_lock_name);
5510 l.set_duration(ut);
5511 l.set_cookie(owner_id);
5512 l.set_tag(zone_id);
5513 l.set_renew(true);
5514
5515 return l.lock_exclusive(&io_ctx, oid);
5516 }
5517
5518 int RGWRados::unlock(rgw_pool& pool, const string& oid, string& zone_id, string& owner_id) {
5519 librados::IoCtx io_ctx;
5520
5521 int r = rgw_init_ioctx(get_rados_handle(), pool, io_ctx);
5522 if (r < 0) {
5523 return r;
5524 }
5525
5526 rados::cls::lock::Lock l(log_lock_name);
5527 l.set_tag(zone_id);
5528 l.set_cookie(owner_id);
5529
5530 return l.unlock(&io_ctx, oid);
5531 }
5532
5533 int RGWRados::decode_policy(bufferlist& bl, ACLOwner *owner)
5534 {
5535 bufferlist::iterator i = bl.begin();
5536 RGWAccessControlPolicy policy(cct);
5537 try {
5538 policy.decode_owner(i);
5539 } catch (buffer::error& err) {
5540 ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl;
5541 return -EIO;
5542 }
5543 *owner = policy.get_owner();
5544 return 0;
5545 }
5546
5547 int rgw_policy_from_attrset(CephContext *cct, map<string, bufferlist>& attrset, RGWAccessControlPolicy *policy)
5548 {
5549 map<string, bufferlist>::iterator aiter = attrset.find(RGW_ATTR_ACL);
5550 if (aiter == attrset.end())
5551 return -EIO;
5552
5553 bufferlist& bl = aiter->second;
5554 bufferlist::iterator iter = bl.begin();
5555 try {
5556 policy->decode(iter);
5557 } catch (buffer::error& err) {
5558 ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl;
5559 return -EIO;
5560 }
5561 if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) {
5562 RGWAccessControlPolicy_S3 *s3policy = static_cast<RGWAccessControlPolicy_S3 *>(policy);
5563 ldout(cct, 15) << __func__ << " Read AccessControlPolicy";
5564 s3policy->to_xml(*_dout);
5565 *_dout << dendl;
5566 }
5567 return 0;
5568 }
5569
5570
5571 int RGWRados::Bucket::update_bucket_id(const string& new_bucket_id)
5572 {
5573 rgw_bucket bucket = bucket_info.bucket;
5574 bucket.update_bucket_id(new_bucket_id);
5575
5576 RGWObjectCtx obj_ctx(store);
5577
5578 int ret = store->get_bucket_instance_info(obj_ctx, bucket, bucket_info, nullptr, nullptr);
5579 if (ret < 0) {
5580 return ret;
5581 }
5582
5583 return 0;
5584 }
5585
5586 /**
5587 * get listing of the objects in a bucket.
5588 *
5589 * max: maximum number of results to return
5590 * bucket: bucket to list contents of
5591 * prefix: only return results that match this prefix
5592 * delim: do not include results that match this string.
5593 * Any skipped results will have the matching portion of their name
5594 * inserted in common_prefixes with a "true" mark.
5595 * marker: if filled in, begin the listing with this object.
5596 * end_marker: if filled in, end the listing with this object.
5597 * result: the objects are put in here.
5598 * common_prefixes: if delim is filled in, any matching prefixes are placed here.
5599 * is_truncated: if number of objects in the bucket is bigger than max, then truncated.
5600 */
5601 int RGWRados::Bucket::List::list_objects(int64_t max,
5602 vector<rgw_bucket_dir_entry> *result,
5603 map<string, bool> *common_prefixes,
5604 bool *is_truncated)
5605 {
5606 RGWRados *store = target->get_store();
5607 CephContext *cct = store->ctx();
5608 int shard_id = target->get_shard_id();
5609
5610 int count = 0;
5611 bool truncated = true;
5612 int read_ahead = std::max(cct->_conf->rgw_list_bucket_min_readahead,max);
5613
5614 result->clear();
5615
5616 rgw_obj_key marker_obj(params.marker.name, params.marker.instance, params.ns);
5617 rgw_obj_index_key cur_marker;
5618 marker_obj.get_index_key(&cur_marker);
5619
5620 rgw_obj_key end_marker_obj(params.end_marker.name, params.end_marker.instance,
5621 params.ns);
5622 rgw_obj_index_key cur_end_marker;
5623 end_marker_obj.get_index_key(&cur_end_marker);
5624 const bool cur_end_marker_valid = !params.end_marker.empty();
5625
5626 rgw_obj_key prefix_obj(params.prefix);
5627 prefix_obj.ns = params.ns;
5628 string cur_prefix = prefix_obj.get_index_key_name();
5629
5630 string bigger_than_delim;
5631
5632 if (!params.delim.empty()) {
5633 unsigned long val = decode_utf8((unsigned char *)params.delim.c_str(), params.delim.size());
5634 char buf[params.delim.size() + 16];
5635 int r = encode_utf8(val + 1, (unsigned char *)buf);
5636 if (r < 0) {
5637 ldout(cct,0) << "ERROR: encode_utf8() failed" << dendl;
5638 return -EINVAL;
5639 }
5640 buf[r] = '\0';
5641
5642 bigger_than_delim = buf;
5643
5644 /* if marker points at a common prefix, fast forward it into its upperbound string */
5645 int delim_pos = cur_marker.name.find(params.delim, cur_prefix.size());
5646 if (delim_pos >= 0) {
5647 string s = cur_marker.name.substr(0, delim_pos);
5648 s.append(bigger_than_delim);
5649 cur_marker = s;
5650 }
5651 }
5652
5653 string skip_after_delim;
5654 while (truncated && count <= max) {
5655 if (skip_after_delim > cur_marker.name) {
5656 cur_marker = skip_after_delim;
5657 ldout(cct, 20) << "setting cur_marker=" << cur_marker.name << "[" << cur_marker.instance << "]" << dendl;
5658 }
5659 std::map<string, rgw_bucket_dir_entry> ent_map;
5660 int r = store->cls_bucket_list(target->get_bucket_info(), shard_id, cur_marker, cur_prefix,
5661 read_ahead + 1 - count, params.list_versions, ent_map,
5662 &truncated, &cur_marker);
5663 if (r < 0)
5664 return r;
5665
5666 std::map<string, rgw_bucket_dir_entry>::iterator eiter;
5667 for (eiter = ent_map.begin(); eiter != ent_map.end(); ++eiter) {
5668 rgw_bucket_dir_entry& entry = eiter->second;
5669 rgw_obj_index_key index_key = entry.key;
5670
5671 rgw_obj_key obj(index_key);
5672
5673 /* note that parse_raw_oid() here will not set the correct object's instance, as
5674 * rgw_obj_index_key encodes that separately. We don't need to set the instance because it's
5675 * not needed for the checks here and we end up using the raw entry for the return vector
5676 */
5677 bool valid = rgw_obj_key::parse_raw_oid(index_key.name, &obj);
5678 if (!valid) {
5679 ldout(cct, 0) << "ERROR: could not parse object name: " << obj.name << dendl;
5680 continue;
5681 }
5682 bool check_ns = (obj.ns == params.ns);
5683 if (!params.list_versions && !entry.is_visible()) {
5684 continue;
5685 }
5686
5687 if (params.enforce_ns && !check_ns) {
5688 if (!params.ns.empty()) {
5689 /* we've iterated past the namespace we're searching -- done now */
5690 truncated = false;
5691 goto done;
5692 }
5693
5694 /* we're not looking at the namespace this object is in, next! */
5695 continue;
5696 }
5697
5698 if (cur_end_marker_valid && cur_end_marker <= index_key) {
5699 truncated = false;
5700 goto done;
5701 }
5702
5703 if (count < max) {
5704 params.marker = index_key;
5705 next_marker = index_key;
5706 }
5707
5708 if (params.filter && !params.filter->filter(obj.name, index_key.name))
5709 continue;
5710
5711 if (params.prefix.size() && (obj.name.compare(0, params.prefix.size(), params.prefix) != 0))
5712 continue;
5713
5714 if (!params.delim.empty()) {
5715 int delim_pos = obj.name.find(params.delim, params.prefix.size());
5716
5717 if (delim_pos >= 0) {
5718 string prefix_key = obj.name.substr(0, delim_pos + 1);
5719
5720 if (common_prefixes &&
5721 common_prefixes->find(prefix_key) == common_prefixes->end()) {
5722 if (count >= max) {
5723 truncated = true;
5724 goto done;
5725 }
5726 next_marker = prefix_key;
5727 (*common_prefixes)[prefix_key] = true;
5728
5729 int marker_delim_pos = cur_marker.name.find(params.delim, cur_prefix.size());
5730
5731 skip_after_delim = cur_marker.name.substr(0, marker_delim_pos);
5732 skip_after_delim.append(bigger_than_delim);
5733
5734 ldout(cct, 20) << "skip_after_delim=" << skip_after_delim << dendl;
5735
5736 count++;
5737 }
5738
5739 continue;
5740 }
5741 }
5742
5743 if (count >= max) {
5744 truncated = true;
5745 goto done;
5746 }
5747
5748 result->emplace_back(std::move(entry));
5749 count++;
5750 }
5751
5752 // Either the back-end telling us truncated, or we don't consume all
5753 // items returned per the amount caller request
5754 truncated = (truncated || eiter != ent_map.end());
5755 }
5756
5757 done:
5758 if (is_truncated)
5759 *is_truncated = truncated;
5760
5761 return 0;
5762 }
5763
5764 /**
5765 * create a rados pool, associated meta info
5766 * returns 0 on success, -ERR# otherwise.
5767 */
5768 int RGWRados::create_pool(const rgw_pool& pool)
5769 {
5770 int ret = 0;
5771
5772 librados::Rados *rad = get_rados_handle();
5773 ret = rad->pool_create(pool.name.c_str(), 0);
5774 if (ret == -EEXIST)
5775 ret = 0;
5776 else if (ret == -ERANGE) {
5777 ldout(cct, 0)
5778 << __func__
5779 << " ERROR: librados::Rados::pool_create returned " << cpp_strerror(-ret)
5780 << " (this can be due to a pool or placement group misconfiguration, e.g., pg_num < pgp_num)"
5781 << dendl;
5782 }
5783 if (ret < 0)
5784 return ret;
5785
5786 librados::IoCtx io_ctx;
5787 ret = rad->ioctx_create(pool.name.c_str(), io_ctx);
5788 if (ret < 0)
5789 return ret;
5790
5791 ret = io_ctx.application_enable(pg_pool_t::APPLICATION_NAME_RGW, false);
5792 if (ret < 0 && ret != -EOPNOTSUPP)
5793 return ret;
5794 return 0;
5795 }
5796
5797 int RGWRados::init_bucket_index(RGWBucketInfo& bucket_info, int num_shards)
5798 {
5799 librados::IoCtx index_ctx; // context for new bucket
5800
5801 string dir_oid = dir_oid_prefix;
5802 int r = open_bucket_index_ctx(bucket_info, index_ctx);
5803 if (r < 0) {
5804 return r;
5805 }
5806
5807 dir_oid.append(bucket_info.bucket.bucket_id);
5808
5809 map<int, string> bucket_objs;
5810 get_bucket_index_objects(dir_oid, num_shards, bucket_objs);
5811
5812 return CLSRGWIssueBucketIndexInit(index_ctx, bucket_objs, cct->_conf->rgw_bucket_index_max_aio)();
5813 }
5814
5815 void RGWRados::create_bucket_id(string *bucket_id)
5816 {
5817 uint64_t iid = instance_id();
5818 uint64_t bid = next_bucket_id();
5819 char buf[get_zone_params().get_id().size() + 48];
5820 snprintf(buf, sizeof(buf), "%s.%llu.%llu", get_zone_params().get_id().c_str(), (long long)iid, (long long)bid);
5821 *bucket_id = buf;
5822 }
5823
5824 int RGWRados::create_bucket(RGWUserInfo& owner, rgw_bucket& bucket,
5825 const string& zonegroup_id,
5826 const string& placement_rule,
5827 const string& swift_ver_location,
5828 const RGWQuotaInfo * pquota_info,
5829 map<std::string, bufferlist>& attrs,
5830 RGWBucketInfo& info,
5831 obj_version *pobjv,
5832 obj_version *pep_objv,
5833 real_time creation_time,
5834 rgw_bucket *pmaster_bucket,
5835 uint32_t *pmaster_num_shards,
5836 bool exclusive)
5837 {
5838 #define MAX_CREATE_RETRIES 20 /* need to bound retries */
5839 string selected_placement_rule_name;
5840 RGWZonePlacementInfo rule_info;
5841
5842 for (int i = 0; i < MAX_CREATE_RETRIES; i++) {
5843 int ret = 0;
5844 ret = select_bucket_placement(owner, zonegroup_id, placement_rule,
5845 &selected_placement_rule_name, &rule_info);
5846 if (ret < 0)
5847 return ret;
5848
5849 if (!pmaster_bucket) {
5850 create_bucket_id(&bucket.marker);
5851 bucket.bucket_id = bucket.marker;
5852 } else {
5853 bucket.marker = pmaster_bucket->marker;
5854 bucket.bucket_id = pmaster_bucket->bucket_id;
5855 }
5856
5857 RGWObjVersionTracker& objv_tracker = info.objv_tracker;
5858
5859 if (pobjv) {
5860 objv_tracker.write_version = *pobjv;
5861 } else {
5862 objv_tracker.generate_new_write_ver(cct);
5863 }
5864
5865 info.bucket = bucket;
5866 info.owner = owner.user_id;
5867 info.zonegroup = zonegroup_id;
5868 info.placement_rule = selected_placement_rule_name;
5869 info.index_type = rule_info.index_type;
5870 info.swift_ver_location = swift_ver_location;
5871 info.swift_versioning = (!swift_ver_location.empty());
5872 if (pmaster_num_shards) {
5873 info.num_shards = *pmaster_num_shards;
5874 } else {
5875 info.num_shards = bucket_index_max_shards;
5876 }
5877 info.bucket_index_shard_hash_type = RGWBucketInfo::MOD;
5878 info.requester_pays = false;
5879 if (real_clock::is_zero(creation_time)) {
5880 info.creation_time = ceph::real_clock::now();
5881 } else {
5882 info.creation_time = creation_time;
5883 }
5884 if (pquota_info) {
5885 info.quota = *pquota_info;
5886 }
5887
5888 int r = init_bucket_index(info, info.num_shards);
5889 if (r < 0) {
5890 return r;
5891 }
5892
5893 ret = put_linked_bucket_info(info, exclusive, ceph::real_time(), pep_objv, &attrs, true);
5894 if (ret == -EEXIST) {
5895 librados::IoCtx index_ctx;
5896 map<int, string> bucket_objs;
5897 int r = open_bucket_index(info, index_ctx, bucket_objs);
5898 if (r < 0)
5899 return r;
5900
5901 /* we need to reread the info and return it, caller will have a use for it */
5902 RGWObjVersionTracker instance_ver = info.objv_tracker;
5903 info.objv_tracker.clear();
5904 RGWObjectCtx obj_ctx(this);
5905 r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, NULL);
5906 if (r < 0) {
5907 if (r == -ENOENT) {
5908 continue;
5909 }
5910 ldout(cct, 0) << "get_bucket_info returned " << r << dendl;
5911 return r;
5912 }
5913
5914 /* only remove it if it's a different bucket instance */
5915 if (info.bucket.bucket_id != bucket.bucket_id) {
5916 /* remove bucket meta instance */
5917 string entry = bucket.get_key();
5918 r = rgw_bucket_instance_remove_entry(this, entry, &instance_ver);
5919 if (r < 0)
5920 return r;
5921
5922 map<int, string>::const_iterator biter;
5923 for (biter = bucket_objs.begin(); biter != bucket_objs.end(); ++biter) {
5924 // Do best effort removal
5925 index_ctx.remove(biter->second);
5926 }
5927 }
5928 /* ret == -ENOENT here */
5929 }
5930 return ret;
5931 }
5932
5933 /* this is highly unlikely */
5934 ldout(cct, 0) << "ERROR: could not create bucket, continuously raced with bucket creation and removal" << dendl;
5935 return -ENOENT;
5936 }
5937
5938 int RGWRados::select_new_bucket_location(RGWUserInfo& user_info, const string& zonegroup_id, const string& request_rule,
5939 string *pselected_rule_name, RGWZonePlacementInfo *rule_info)
5940
5941 {
5942 /* first check that zonegroup exists within current period. */
5943 RGWZoneGroup zonegroup;
5944 int ret = get_zonegroup(zonegroup_id, zonegroup);
5945 if (ret < 0) {
5946 ldout(cct, 0) << "could not find zonegroup " << zonegroup_id << " in current period" << dendl;
5947 return ret;
5948 }
5949
5950 /* find placement rule. Hierarchy: request rule > user default rule > zonegroup default rule */
5951 std::map<std::string, RGWZoneGroupPlacementTarget>::const_iterator titer;
5952
5953 if (!request_rule.empty()) {
5954 titer = zonegroup.placement_targets.find(request_rule);
5955 if (titer == zonegroup.placement_targets.end()) {
5956 ldout(cct, 0) << "could not find requested placement id " << request_rule
5957 << " within zonegroup " << dendl;
5958 return -ERR_INVALID_LOCATION_CONSTRAINT;
5959 }
5960 } else if (!user_info.default_placement.empty()) {
5961 titer = zonegroup.placement_targets.find(user_info.default_placement);
5962 if (titer == zonegroup.placement_targets.end()) {
5963 ldout(cct, 0) << "could not find user default placement id " << user_info.default_placement
5964 << " within zonegroup " << dendl;
5965 return -ERR_INVALID_LOCATION_CONSTRAINT;
5966 }
5967 } else {
5968 if (zonegroup.default_placement.empty()) { // zonegroup default rule as fallback, it should not be empty.
5969 ldout(cct, 0) << "misconfiguration, zonegroup default placement id should not be empty." << dendl;
5970 return -ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION;
5971 } else {
5972 titer = zonegroup.placement_targets.find(zonegroup.default_placement);
5973 if (titer == zonegroup.placement_targets.end()) {
5974 ldout(cct, 0) << "could not find zonegroup default placement id " << zonegroup.default_placement
5975 << " within zonegroup " << dendl;
5976 return -ERR_INVALID_LOCATION_CONSTRAINT;
5977 }
5978 }
5979 }
5980
5981 /* now check tag for the rule, whether user is permitted to use rule */
5982 const auto& target_rule = titer->second;
5983 if (!target_rule.user_permitted(user_info.placement_tags)) {
5984 ldout(cct, 0) << "user not permitted to use placement rule " << titer->first << dendl;
5985 return -EPERM;
5986 }
5987
5988 if (pselected_rule_name)
5989 *pselected_rule_name = titer->first;
5990
5991 return select_bucket_location_by_rule(titer->first, rule_info);
5992 }
5993
5994 int RGWRados::select_bucket_location_by_rule(const string& location_rule, RGWZonePlacementInfo *rule_info)
5995 {
5996 if (location_rule.empty()) {
5997 /* we can only reach here if we're trying to set a bucket location from a bucket
5998 * created on a different zone, using a legacy / default pool configuration
5999 */
6000 return select_legacy_bucket_placement(rule_info);
6001 }
6002
6003 /*
6004 * make sure that zone has this rule configured. We're
6005 * checking it for the local zone, because that's where this bucket object is going to
6006 * reside.
6007 */
6008 map<string, RGWZonePlacementInfo>::iterator piter = get_zone_params().placement_pools.find(location_rule);
6009 if (piter == get_zone_params().placement_pools.end()) {
6010 /* couldn't find, means we cannot really place data for this bucket in this zone */
6011 if (get_zonegroup().equals(zonegroup.get_id())) {
6012 /* that's a configuration error, zone should have that rule, as we're within the requested
6013 * zonegroup */
6014 return -EINVAL;
6015 } else {
6016 /* oh, well, data is not going to be placed here, bucket object is just a placeholder */
6017 return 0;
6018 }
6019 }
6020
6021 RGWZonePlacementInfo& placement_info = piter->second;
6022
6023 if (rule_info) {
6024 *rule_info = placement_info;
6025 }
6026
6027 return 0;
6028 }
6029
6030 int RGWRados::select_bucket_placement(RGWUserInfo& user_info, const string& zonegroup_id, const string& placement_rule,
6031 string *pselected_rule_name, RGWZonePlacementInfo *rule_info)
6032 {
6033 if (!get_zone_params().placement_pools.empty()) {
6034 return select_new_bucket_location(user_info, zonegroup_id, placement_rule,
6035 pselected_rule_name, rule_info);
6036 }
6037
6038 if (pselected_rule_name) {
6039 pselected_rule_name->clear();
6040 }
6041
6042 return select_legacy_bucket_placement(rule_info);
6043 }
6044
6045 int RGWRados::select_legacy_bucket_placement(RGWZonePlacementInfo *rule_info)
6046 {
6047 bufferlist map_bl;
6048 map<string, bufferlist> m;
6049 string pool_name;
6050 bool write_map = false;
6051
6052 rgw_raw_obj obj(get_zone_params().domain_root, avail_pools);
6053
6054 RGWObjectCtx obj_ctx(this);
6055 int ret = rgw_get_system_obj(this, obj_ctx, get_zone_params().domain_root, avail_pools, map_bl, NULL, NULL);
6056 if (ret < 0) {
6057 goto read_omap;
6058 }
6059
6060 try {
6061 bufferlist::iterator iter = map_bl.begin();
6062 ::decode(m, iter);
6063 } catch (buffer::error& err) {
6064 ldout(cct, 0) << "ERROR: couldn't decode avail_pools" << dendl;
6065 }
6066
6067 read_omap:
6068 if (m.empty()) {
6069 bufferlist header;
6070 ret = omap_get_all(obj, header, m);
6071
6072 write_map = true;
6073 }
6074
6075 if (ret < 0 || m.empty()) {
6076 vector<rgw_pool> pools;
6077 string s = string("default.") + default_storage_pool_suffix;
6078 pools.push_back(rgw_pool(s));
6079 vector<int> retcodes;
6080 bufferlist bl;
6081 ret = create_pools(pools, retcodes);
6082 if (ret < 0)
6083 return ret;
6084 ret = omap_set(obj, s, bl);
6085 if (ret < 0)
6086 return ret;
6087 m[s] = bl;
6088 }
6089
6090 if (write_map) {
6091 bufferlist new_bl;
6092 ::encode(m, new_bl);
6093 ret = put_system_obj_data(NULL, obj, new_bl, -1, false);
6094 if (ret < 0) {
6095 ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl;
6096 }
6097 }
6098
6099 map<string, bufferlist>::iterator miter;
6100 if (m.size() > 1) {
6101 vector<string> v;
6102 for (miter = m.begin(); miter != m.end(); ++miter) {
6103 v.push_back(miter->first);
6104 }
6105
6106 uint32_t r;
6107 ret = get_random_bytes((char *)&r, sizeof(r));
6108 if (ret < 0)
6109 return ret;
6110
6111 int i = r % v.size();
6112 pool_name = v[i];
6113 } else {
6114 miter = m.begin();
6115 pool_name = miter->first;
6116 }
6117
6118 rule_info->data_pool = pool_name;
6119 rule_info->data_extra_pool = pool_name;
6120 rule_info->index_pool = pool_name;
6121 rule_info->index_type = RGWBIType_Normal;
6122
6123 return 0;
6124 }
6125
6126 bool RGWRados::get_obj_data_pool(const string& placement_rule, const rgw_obj& obj, rgw_pool *pool)
6127 {
6128 return rgw_get_obj_data_pool(zonegroup, zone_params, placement_rule, obj, pool);
6129 }
6130
6131 bool RGWRados::obj_to_raw(const string& placement_rule, const rgw_obj& obj, rgw_raw_obj *raw_obj)
6132 {
6133 get_obj_bucket_and_oid_loc(obj, raw_obj->oid, raw_obj->loc);
6134
6135 return get_obj_data_pool(placement_rule, obj, &raw_obj->pool);
6136 }
6137
6138 int RGWRados::update_placement_map()
6139 {
6140 bufferlist header;
6141 map<string, bufferlist> m;
6142 rgw_raw_obj obj(get_zone_params().domain_root, avail_pools);
6143 int ret = omap_get_all(obj, header, m);
6144 if (ret < 0)
6145 return ret;
6146
6147 bufferlist new_bl;
6148 ::encode(m, new_bl);
6149 ret = put_system_obj_data(NULL, obj, new_bl, -1, false);
6150 if (ret < 0) {
6151 ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl;
6152 }
6153
6154 return ret;
6155 }
6156
6157 int RGWRados::add_bucket_placement(const rgw_pool& new_pool)
6158 {
6159 librados::Rados *rad = get_rados_handle();
6160 int ret = rad->pool_lookup(new_pool.name.c_str());
6161 if (ret < 0) // DNE, or something
6162 return ret;
6163
6164 rgw_raw_obj obj(get_zone_params().domain_root, avail_pools);
6165 bufferlist empty_bl;
6166 ret = omap_set(obj, new_pool.to_str(), empty_bl);
6167
6168 // don't care about return value
6169 update_placement_map();
6170
6171 return ret;
6172 }
6173
6174 int RGWRados::remove_bucket_placement(const rgw_pool& old_pool)
6175 {
6176 rgw_raw_obj obj(get_zone_params().domain_root, avail_pools);
6177 int ret = omap_del(obj, old_pool.to_str());
6178
6179 // don't care about return value
6180 update_placement_map();
6181
6182 return ret;
6183 }
6184
6185 int RGWRados::list_placement_set(set<rgw_pool>& names)
6186 {
6187 bufferlist header;
6188 map<string, bufferlist> m;
6189
6190 rgw_raw_obj obj(get_zone_params().domain_root, avail_pools);
6191 int ret = omap_get_all(obj, header, m);
6192 if (ret < 0)
6193 return ret;
6194
6195 names.clear();
6196 map<string, bufferlist>::iterator miter;
6197 for (miter = m.begin(); miter != m.end(); ++miter) {
6198 names.insert(rgw_pool(miter->first));
6199 }
6200
6201 return names.size();
6202 }
6203
6204 int RGWRados::create_pools(vector<rgw_pool>& pools, vector<int>& retcodes)
6205 {
6206 vector<librados::PoolAsyncCompletion *> completions;
6207 vector<int> rets;
6208
6209 librados::Rados *rad = get_rados_handle();
6210 for (auto iter = pools.begin(); iter != pools.end(); ++iter) {
6211 librados::PoolAsyncCompletion *c = librados::Rados::pool_async_create_completion();
6212 completions.push_back(c);
6213 rgw_pool& pool = *iter;
6214 int ret = rad->pool_create_async(pool.name.c_str(), c);
6215 rets.push_back(ret);
6216 }
6217
6218 vector<int>::iterator riter;
6219 vector<librados::PoolAsyncCompletion *>::iterator citer;
6220
6221 bool error = false;
6222 assert(rets.size() == completions.size());
6223 for (riter = rets.begin(), citer = completions.begin(); riter != rets.end(); ++riter, ++citer) {
6224 int r = *riter;
6225 PoolAsyncCompletion *c = *citer;
6226 if (r == 0) {
6227 c->wait();
6228 r = c->get_return_value();
6229 if (r < 0) {
6230 ldout(cct, 0) << "WARNING: async pool_create returned " << r << dendl;
6231 error = true;
6232 }
6233 }
6234 c->release();
6235 retcodes.push_back(r);
6236 }
6237 if (error) {
6238 return 0;
6239 }
6240
6241 std::vector<librados::IoCtx> io_ctxs;
6242 retcodes.clear();
6243 for (auto pool : pools) {
6244 io_ctxs.emplace_back();
6245 int ret = rad->ioctx_create(pool.name.c_str(), io_ctxs.back());
6246 if (ret < 0) {
6247 ldout(cct, 0) << "WARNING: ioctx_create returned " << ret << dendl;
6248 error = true;
6249 }
6250 retcodes.push_back(ret);
6251 }
6252 if (error) {
6253 return 0;
6254 }
6255
6256 completions.clear();
6257 for (auto &io_ctx : io_ctxs) {
6258 librados::PoolAsyncCompletion *c =
6259 librados::Rados::pool_async_create_completion();
6260 completions.push_back(c);
6261 int ret = io_ctx.application_enable_async(pg_pool_t::APPLICATION_NAME_RGW,
6262 false, c);
6263 assert(ret == 0);
6264 }
6265
6266 retcodes.clear();
6267 for (auto c : completions) {
6268 c->wait();
6269 int ret = c->get_return_value();
6270 if (ret == -EOPNOTSUPP) {
6271 ret = 0;
6272 } else if (ret < 0) {
6273 ldout(cct, 0) << "WARNING: async application_enable returned " << ret
6274 << dendl;
6275 error = true;
6276 }
6277 c->release();
6278 retcodes.push_back(ret);
6279 }
6280 return 0;
6281 }
6282
6283 int RGWRados::get_obj_head_ioctx(const RGWBucketInfo& bucket_info, const rgw_obj& obj, librados::IoCtx *ioctx)
6284 {
6285 string oid, key;
6286 get_obj_bucket_and_oid_loc(obj, oid, key);
6287
6288 rgw_pool pool;
6289 if (!get_obj_data_pool(bucket_info.placement_rule, obj, &pool)) {
6290 ldout(cct, 0) << "ERROR: cannot get data pool for obj=" << obj << ", probably misconfiguration" << dendl;
6291 return -EIO;
6292 }
6293
6294 int r = open_pool_ctx(pool, *ioctx);
6295 if (r < 0) {
6296 return r;
6297 }
6298
6299 ioctx->locator_set_key(key);
6300
6301 return 0;
6302 }
6303
6304 int RGWRados::get_obj_head_ref(const RGWBucketInfo& bucket_info, const rgw_obj& obj, rgw_rados_ref *ref)
6305 {
6306 get_obj_bucket_and_oid_loc(obj, ref->oid, ref->key);
6307
6308 rgw_pool pool;
6309 if (!get_obj_data_pool(bucket_info.placement_rule, obj, &pool)) {
6310 ldout(cct, 0) << "ERROR: cannot get data pool for obj=" << obj << ", probably misconfiguration" << dendl;
6311 return -EIO;
6312 }
6313
6314 int r = open_pool_ctx(pool, ref->ioctx);
6315 if (r < 0) {
6316 return r;
6317 }
6318
6319 ref->ioctx.locator_set_key(ref->key);
6320
6321 return 0;
6322 }
6323
6324 int RGWRados::get_raw_obj_ref(const rgw_raw_obj& obj, rgw_rados_ref *ref)
6325 {
6326 ref->oid = obj.oid;
6327 ref->key = obj.loc;
6328
6329 int r;
6330
6331 if (ref->oid.empty()) {
6332 ref->oid = obj.pool.to_str();
6333 ref->pool = get_zone_params().domain_root;
6334 } else {
6335 ref->pool = obj.pool;
6336 }
6337 r = open_pool_ctx(ref->pool, ref->ioctx);
6338 if (r < 0)
6339 return r;
6340
6341 ref->ioctx.locator_set_key(ref->key);
6342
6343 return 0;
6344 }
6345
6346 int RGWRados::get_system_obj_ref(const rgw_raw_obj& obj, rgw_rados_ref *ref)
6347 {
6348 return get_raw_obj_ref(obj, ref);
6349 }
6350
6351 /*
6352 * fixes an issue where head objects were supposed to have a locator created, but ended
6353 * up without one
6354 */
6355 int RGWRados::fix_head_obj_locator(const RGWBucketInfo& bucket_info, bool copy_obj, bool remove_bad, rgw_obj_key& key)
6356 {
6357 const rgw_bucket& bucket = bucket_info.bucket;
6358 string oid;
6359 string locator;
6360
6361 rgw_obj obj(bucket, key);
6362
6363 get_obj_bucket_and_oid_loc(obj, oid, locator);
6364
6365 if (locator.empty()) {
6366 ldout(cct, 20) << "object does not have a locator, nothing to fix" << dendl;
6367 return 0;
6368 }
6369
6370 librados::IoCtx ioctx;
6371
6372 int ret = get_obj_head_ioctx(bucket_info, obj, &ioctx);
6373 if (ret < 0) {
6374 cerr << "ERROR: get_obj_head_ioctx() returned ret=" << ret << std::endl;
6375 return ret;
6376 }
6377 ioctx.locator_set_key(string()); /* override locator for this object, use empty locator */
6378
6379 uint64_t size;
6380 bufferlist data;
6381
6382 struct timespec mtime_ts;
6383 map<string, bufferlist> attrs;
6384 librados::ObjectReadOperation op;
6385 op.getxattrs(&attrs, NULL);
6386 op.stat2(&size, &mtime_ts, NULL);
6387 #define HEAD_SIZE 512 * 1024
6388 op.read(0, HEAD_SIZE, &data, NULL);
6389
6390 ret = ioctx.operate(oid, &op, NULL);
6391 if (ret < 0) {
6392 lderr(cct) << "ERROR: ioctx.operate(oid=" << oid << ") returned ret=" << ret << dendl;
6393 return ret;
6394 }
6395
6396 if (size > HEAD_SIZE) {
6397 lderr(cct) << "ERROR: returned object size (" << size << ") > HEAD_SIZE (" << HEAD_SIZE << ")" << dendl;
6398 return -EIO;
6399 }
6400
6401 if (size != data.length()) {
6402 lderr(cct) << "ERROR: returned object size (" << size << ") != data.length() (" << data.length() << ")" << dendl;
6403 return -EIO;
6404 }
6405
6406 if (copy_obj) {
6407 librados::ObjectWriteOperation wop;
6408
6409 wop.mtime2(&mtime_ts);
6410
6411 map<string, bufferlist>::iterator iter;
6412 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
6413 wop.setxattr(iter->first.c_str(), iter->second);
6414 }
6415
6416 wop.write(0, data);
6417
6418 ioctx.locator_set_key(locator);
6419 ioctx.operate(oid, &wop);
6420 }
6421
6422 if (remove_bad) {
6423 ioctx.locator_set_key(string());
6424
6425 ret = ioctx.remove(oid);
6426 if (ret < 0) {
6427 lderr(cct) << "ERROR: failed to remove original bad object" << dendl;
6428 return ret;
6429 }
6430 }
6431
6432 return 0;
6433 }
6434
6435 int RGWRados::move_rados_obj(librados::IoCtx& src_ioctx,
6436 const string& src_oid, const string& src_locator,
6437 librados::IoCtx& dst_ioctx,
6438 const string& dst_oid, const string& dst_locator)
6439 {
6440
6441 #define COPY_BUF_SIZE (4 * 1024 * 1024)
6442 bool done = false;
6443 uint64_t chunk_size = COPY_BUF_SIZE;
6444 uint64_t ofs = 0;
6445 int ret = 0;
6446 real_time mtime;
6447 struct timespec mtime_ts;
6448 uint64_t size;
6449
6450 if (src_oid == dst_oid && src_locator == dst_locator) {
6451 return 0;
6452 }
6453
6454 src_ioctx.locator_set_key(src_locator);
6455 dst_ioctx.locator_set_key(dst_locator);
6456
6457 do {
6458 bufferlist data;
6459 ObjectReadOperation rop;
6460 ObjectWriteOperation wop;
6461
6462 if (ofs == 0) {
6463 rop.stat2(&size, &mtime_ts, NULL);
6464 mtime = real_clock::from_timespec(mtime_ts);
6465 }
6466 rop.read(ofs, chunk_size, &data, NULL);
6467 ret = src_ioctx.operate(src_oid, &rop, NULL);
6468 if (ret < 0) {
6469 goto done_err;
6470 }
6471
6472 if (data.length() == 0) {
6473 break;
6474 }
6475
6476 if (ofs == 0) {
6477 wop.create(true); /* make it exclusive */
6478 wop.mtime2(&mtime_ts);
6479 mtime = real_clock::from_timespec(mtime_ts);
6480 }
6481 wop.write(ofs, data);
6482 ret = dst_ioctx.operate(dst_oid, &wop);
6483 ofs += data.length();
6484 done = data.length() != chunk_size;
6485 } while (!done);
6486
6487 if (ofs != size) {
6488 lderr(cct) << "ERROR: " << __func__ << ": copying " << src_oid << " -> " << dst_oid
6489 << ": expected " << size << " bytes to copy, ended up with " << ofs << dendl;
6490 ret = -EIO;
6491 goto done_err;
6492 }
6493
6494 src_ioctx.remove(src_oid);
6495
6496 return 0;
6497
6498 done_err:
6499 lderr(cct) << "ERROR: failed to copy " << src_oid << " -> " << dst_oid << dendl;
6500 return ret;
6501 }
6502
6503 /*
6504 * fixes an issue where head objects were supposed to have a locator created, but ended
6505 * up without one
6506 */
6507 int RGWRados::fix_tail_obj_locator(const RGWBucketInfo& bucket_info, rgw_obj_key& key, bool fix, bool *need_fix)
6508 {
6509 const rgw_bucket& bucket = bucket_info.bucket;
6510 rgw_obj obj(bucket, key);
6511
6512 if (need_fix) {
6513 *need_fix = false;
6514 }
6515
6516 rgw_rados_ref ref;
6517 int r = get_obj_head_ref(bucket_info, obj, &ref);
6518 if (r < 0) {
6519 return r;
6520 }
6521
6522 RGWObjState *astate = NULL;
6523 RGWObjectCtx rctx(this);
6524 r = get_obj_state(&rctx, bucket_info, obj, &astate, false);
6525 if (r < 0)
6526 return r;
6527
6528 if (astate->has_manifest) {
6529 RGWObjManifest::obj_iterator miter;
6530 RGWObjManifest& manifest = astate->manifest;
6531 for (miter = manifest.obj_begin(); miter != manifest.obj_end(); ++miter) {
6532 rgw_raw_obj raw_loc = miter.get_location().get_raw_obj(this);
6533 rgw_obj loc;
6534 string oid;
6535 string locator;
6536
6537 rgw_raw_obj_to_obj(manifest.get_tail_placement().bucket, raw_loc, &loc);
6538
6539 if (loc.key.ns.empty()) {
6540 /* continue, we're only interested in tail objects */
6541 continue;
6542 }
6543
6544 get_obj_bucket_and_oid_loc(loc, oid, locator);
6545 ref.ioctx.locator_set_key(locator);
6546
6547 ldout(cct, 20) << __func__ << ": key=" << key << " oid=" << oid << " locator=" << locator << dendl;
6548
6549 r = ref.ioctx.stat(oid, NULL, NULL);
6550 if (r != -ENOENT) {
6551 continue;
6552 }
6553
6554 string bad_loc;
6555 prepend_bucket_marker(bucket, loc.key.name, bad_loc);
6556
6557 /* create a new ioctx with the bad locator */
6558 librados::IoCtx src_ioctx;
6559 src_ioctx.dup(ref.ioctx);
6560 src_ioctx.locator_set_key(bad_loc);
6561
6562 r = src_ioctx.stat(oid, NULL, NULL);
6563 if (r != 0) {
6564 /* cannot find a broken part */
6565 continue;
6566 }
6567 ldout(cct, 20) << __func__ << ": found bad object part: " << loc << dendl;
6568 if (need_fix) {
6569 *need_fix = true;
6570 }
6571 if (fix) {
6572 r = move_rados_obj(src_ioctx, oid, bad_loc, ref.ioctx, oid, locator);
6573 if (r < 0) {
6574 lderr(cct) << "ERROR: copy_rados_obj() on oid=" << oid << " returned r=" << r << dendl;
6575 }
6576 }
6577 }
6578 }
6579
6580 return 0;
6581 }
6582
6583 int RGWRados::BucketShard::init(const rgw_bucket& _bucket, const rgw_obj& obj)
6584 {
6585 bucket = _bucket;
6586
6587 RGWObjectCtx obj_ctx(store);
6588
6589 RGWBucketInfo bucket_info;
6590 int ret = store->get_bucket_instance_info(obj_ctx, bucket, bucket_info, NULL, NULL);
6591 if (ret < 0) {
6592 return ret;
6593 }
6594
6595 ret = store->open_bucket_index_shard(bucket_info, index_ctx, obj.get_hash_object(), &bucket_obj, &shard_id);
6596 if (ret < 0) {
6597 ldout(store->ctx(), 0) << "ERROR: open_bucket_index_shard() returned ret=" << ret << dendl;
6598 return ret;
6599 }
6600 ldout(store->ctx(), 20) << " bucket index object: " << bucket_obj << dendl;
6601
6602 return 0;
6603 }
6604
6605 int RGWRados::BucketShard::init(const rgw_bucket& _bucket, int sid)
6606 {
6607 bucket = _bucket;
6608 shard_id = sid;
6609
6610 RGWObjectCtx obj_ctx(store);
6611
6612 RGWBucketInfo bucket_info;
6613 int ret = store->get_bucket_instance_info(obj_ctx, bucket, bucket_info, NULL, NULL);
6614 if (ret < 0) {
6615 return ret;
6616 }
6617
6618 ret = store->open_bucket_index_shard(bucket_info, index_ctx, shard_id, &bucket_obj);
6619 if (ret < 0) {
6620 ldout(store->ctx(), 0) << "ERROR: open_bucket_index_shard() returned ret=" << ret << dendl;
6621 return ret;
6622 }
6623 ldout(store->ctx(), 20) << " bucket index object: " << bucket_obj << dendl;
6624
6625 return 0;
6626 }
6627
6628 int RGWRados::BucketShard::init(const RGWBucketInfo& bucket_info, int sid)
6629 {
6630 bucket = bucket_info.bucket;
6631 shard_id = sid;
6632
6633 int ret = store->open_bucket_index_shard(bucket_info, index_ctx, shard_id, &bucket_obj);
6634 if (ret < 0) {
6635 ldout(store->ctx(), 0) << "ERROR: open_bucket_index_shard() returned ret=" << ret << dendl;
6636 return ret;
6637 }
6638 ldout(store->ctx(), 20) << " bucket index object: " << bucket_obj << dendl;
6639
6640 return 0;
6641 }
6642
6643
6644 /* Execute @handler on last item in bucket listing for bucket specified
6645 * in @bucket_info. @obj_prefix and @obj_delim narrow down the listing
6646 * to objects matching these criterias. */
6647 int RGWRados::on_last_entry_in_listing(RGWBucketInfo& bucket_info,
6648 const std::string& obj_prefix,
6649 const std::string& obj_delim,
6650 std::function<int(const rgw_bucket_dir_entry&)> handler)
6651 {
6652 RGWRados::Bucket target(this, bucket_info);
6653 RGWRados::Bucket::List list_op(&target);
6654
6655 list_op.params.prefix = obj_prefix;
6656 list_op.params.delim = obj_delim;
6657
6658 ldout(cct, 20) << "iterating listing for bucket=" << bucket_info.bucket.name
6659 << ", obj_prefix=" << obj_prefix
6660 << ", obj_delim=" << obj_delim
6661 << dendl;
6662
6663 bool is_truncated = false;
6664
6665 boost::optional<rgw_bucket_dir_entry> last_entry;
6666 /* We need to rewind to the last object in a listing. */
6667 do {
6668 /* List bucket entries in chunks. */
6669 static constexpr int MAX_LIST_OBJS = 100;
6670 std::vector<rgw_bucket_dir_entry> entries(MAX_LIST_OBJS);
6671
6672 int ret = list_op.list_objects(MAX_LIST_OBJS, &entries, nullptr,
6673 &is_truncated);
6674 if (ret < 0) {
6675 return ret;
6676 } else if (!entries.empty()) {
6677 last_entry = entries.back();
6678 }
6679 } while (is_truncated);
6680
6681 if (last_entry) {
6682 return handler(*last_entry);
6683 }
6684
6685 /* Empty listing - no items we can run handler on. */
6686 return 0;
6687 }
6688
6689
6690 int RGWRados::swift_versioning_copy(RGWObjectCtx& obj_ctx,
6691 const rgw_user& user,
6692 RGWBucketInfo& bucket_info,
6693 rgw_obj& obj)
6694 {
6695 if (! swift_versioning_enabled(bucket_info)) {
6696 return 0;
6697 }
6698
6699 obj_ctx.obj.set_atomic(obj);
6700
6701 RGWObjState * state = nullptr;
6702 int r = get_obj_state(&obj_ctx, bucket_info, obj, &state, false);
6703 if (r < 0) {
6704 return r;
6705 }
6706
6707 if (!state->exists) {
6708 return 0;
6709 }
6710
6711 string client_id;
6712 string op_id;
6713
6714 const string& src_name = obj.get_oid();
6715 char buf[src_name.size() + 32];
6716 struct timespec ts = ceph::real_clock::to_timespec(state->mtime);
6717 snprintf(buf, sizeof(buf), "%03x%s/%lld.%06ld", (int)src_name.size(),
6718 src_name.c_str(), (long long)ts.tv_sec, ts.tv_nsec / 1000);
6719
6720 RGWBucketInfo dest_bucket_info;
6721
6722 r = get_bucket_info(obj_ctx, bucket_info.bucket.tenant, bucket_info.swift_ver_location, dest_bucket_info, NULL, NULL);
6723 if (r < 0) {
6724 ldout(cct, 10) << "failed to read dest bucket info: r=" << r << dendl;
6725 if (r == -ENOENT) {
6726 return -ERR_PRECONDITION_FAILED;
6727 }
6728 return r;
6729 }
6730
6731 if (dest_bucket_info.owner != bucket_info.owner) {
6732 return -ERR_PRECONDITION_FAILED;
6733 }
6734
6735 rgw_obj dest_obj(dest_bucket_info.bucket, buf);
6736 obj_ctx.obj.set_atomic(dest_obj);
6737
6738 string no_zone;
6739
6740 r = copy_obj(obj_ctx,
6741 user,
6742 client_id,
6743 op_id,
6744 NULL, /* req_info *info */
6745 no_zone,
6746 dest_obj,
6747 obj,
6748 dest_bucket_info,
6749 bucket_info,
6750 NULL, /* time_t *src_mtime */
6751 NULL, /* time_t *mtime */
6752 NULL, /* const time_t *mod_ptr */
6753 NULL, /* const time_t *unmod_ptr */
6754 false, /* bool high_precision_time */
6755 NULL, /* const char *if_match */
6756 NULL, /* const char *if_nomatch */
6757 RGWRados::ATTRSMOD_NONE,
6758 true, /* bool copy_if_newer */
6759 state->attrset,
6760 RGW_OBJ_CATEGORY_MAIN,
6761 0, /* uint64_t olh_epoch */
6762 real_time(), /* time_t delete_at */
6763 NULL, /* string *version_id */
6764 NULL, /* string *ptag */
6765 NULL, /* string *petag */
6766 NULL, /* void (*progress_cb)(off_t, void *) */
6767 NULL); /* void *progress_data */
6768 if (r == -ECANCELED || r == -ENOENT) {
6769 /* Has already been overwritten, meaning another rgw process already
6770 * copied it out */
6771 return 0;
6772 }
6773
6774 return r;
6775 }
6776
6777 int RGWRados::swift_versioning_restore(RGWObjectCtx& obj_ctx,
6778 const rgw_user& user,
6779 RGWBucketInfo& bucket_info,
6780 rgw_obj& obj,
6781 bool& restored) /* out */
6782 {
6783 if (! swift_versioning_enabled(bucket_info)) {
6784 return 0;
6785 }
6786
6787 /* Bucket info of the bucket that stores previous versions of our object. */
6788 RGWBucketInfo archive_binfo;
6789
6790 int ret = get_bucket_info(obj_ctx, bucket_info.bucket.tenant,
6791 bucket_info.swift_ver_location, archive_binfo,
6792 nullptr, nullptr);
6793 if (ret < 0) {
6794 return ret;
6795 }
6796
6797 /* Abort the operation if the bucket storing our archive belongs to someone
6798 * else. This is a limitation in comparison to Swift as we aren't taking ACLs
6799 * into consideration. For we can live with that.
6800 *
6801 * TODO: delegate this check to un upper layer and compare with ACLs. */
6802 if (bucket_info.owner != archive_binfo.owner) {
6803 return -EPERM;
6804 }
6805
6806 /* This code will be executed on latest version of the object. */
6807 const auto handler = [&](const rgw_bucket_dir_entry& entry) -> int {
6808 std::string no_client_id;
6809 std::string no_op_id;
6810 std::string no_zone;
6811
6812 /* We don't support object versioning of Swift API on those buckets that
6813 * are already versioned using the S3 mechanism. This affects also bucket
6814 * storing archived objects. Otherwise the delete operation would create
6815 * a deletion marker. */
6816 if (archive_binfo.versioned()) {
6817 restored = false;
6818 return -ERR_PRECONDITION_FAILED;
6819 }
6820
6821 /* We are requesting ATTRSMOD_NONE so the attr attribute is perfectly
6822 * irrelevant and may be safely skipped. */
6823 std::map<std::string, ceph::bufferlist> no_attrs;
6824
6825 rgw_obj archive_obj(archive_binfo.bucket, entry.key);
6826 obj_ctx.obj.set_atomic(archive_obj);
6827 obj_ctx.obj.set_atomic(obj);
6828
6829 int ret = copy_obj(obj_ctx,
6830 user,
6831 no_client_id,
6832 no_op_id,
6833 nullptr, /* req_info *info */
6834 no_zone,
6835 obj, /* dest obj */
6836 archive_obj, /* src obj */
6837 bucket_info, /* dest bucket info */
6838 archive_binfo, /* src bucket info */
6839 nullptr, /* time_t *src_mtime */
6840 nullptr, /* time_t *mtime */
6841 nullptr, /* const time_t *mod_ptr */
6842 nullptr, /* const time_t *unmod_ptr */
6843 false, /* bool high_precision_time */
6844 nullptr, /* const char *if_match */
6845 nullptr, /* const char *if_nomatch */
6846 RGWRados::ATTRSMOD_NONE,
6847 true, /* bool copy_if_newer */
6848 no_attrs,
6849 RGW_OBJ_CATEGORY_MAIN,
6850 0, /* uint64_t olh_epoch */
6851 real_time(), /* time_t delete_at */
6852 nullptr, /* string *version_id */
6853 nullptr, /* string *ptag */
6854 nullptr, /* string *petag */
6855 nullptr, /* void (*progress_cb)(off_t, void *) */
6856 nullptr); /* void *progress_data */
6857 if (ret == -ECANCELED || ret == -ENOENT) {
6858 /* Has already been overwritten, meaning another rgw process already
6859 * copied it out */
6860 return 0;
6861 } else if (ret < 0) {
6862 return ret;
6863 } else {
6864 restored = true;
6865 }
6866
6867 /* Need to remove the archived copy. */
6868 ret = delete_obj(obj_ctx, archive_binfo, archive_obj,
6869 archive_binfo.versioning_status());
6870
6871 return ret;
6872 };
6873
6874 const std::string& obj_name = obj.get_oid();
6875 const auto prefix = boost::str(boost::format("%03x%s") % obj_name.size()
6876 % obj_name);
6877
6878 return on_last_entry_in_listing(archive_binfo, prefix, std::string(),
6879 handler);
6880 }
6881
6882 /**
6883 * Write/overwrite an object to the bucket storage.
6884 * bucket: the bucket to store the object in
6885 * obj: the object name/key
6886 * data: the object contents/value
6887 * size: the amount of data to write (data must be this long)
6888 * accounted_size: original size of data before compression, encryption
6889 * mtime: if non-NULL, writes the given mtime to the bucket storage
6890 * attrs: all the given attrs are written to bucket storage for the given object
6891 * exclusive: create object exclusively
6892 * Returns: 0 on success, -ERR# otherwise.
6893 */
6894 int RGWRados::Object::Write::_do_write_meta(uint64_t size, uint64_t accounted_size,
6895 map<string, bufferlist>& attrs,
6896 bool assume_noent, bool modify_tail,
6897 void *_index_op)
6898 {
6899 RGWRados::Bucket::UpdateIndex *index_op = static_cast<RGWRados::Bucket::UpdateIndex *>(_index_op);
6900 RGWRados *store = target->get_store();
6901
6902 ObjectWriteOperation op;
6903
6904 RGWObjState *state;
6905 int r = target->get_state(&state, false, assume_noent);
6906 if (r < 0)
6907 return r;
6908
6909 rgw_obj& obj = target->get_obj();
6910
6911 if (obj.get_oid().empty()) {
6912 ldout(store->ctx(), 0) << "ERROR: " << __func__ << "(): cannot write object with empty name" << dendl;
6913 return -EIO;
6914 }
6915
6916 rgw_rados_ref ref;
6917 r = store->get_obj_head_ref(target->get_bucket_info(), obj, &ref);
6918 if (r < 0)
6919 return r;
6920
6921 bool is_olh = state->is_olh;
6922
6923 bool reset_obj = (meta.flags & PUT_OBJ_CREATE) != 0;
6924
6925 const string *ptag = meta.ptag;
6926 if (!ptag && !index_op->get_optag()->empty()) {
6927 ptag = index_op->get_optag();
6928 }
6929 r = target->prepare_atomic_modification(op, reset_obj, ptag, meta.if_match, meta.if_nomatch, false, modify_tail);
6930 if (r < 0)
6931 return r;
6932
6933 if (real_clock::is_zero(meta.set_mtime)) {
6934 meta.set_mtime = real_clock::now();
6935 }
6936
6937 if (state->is_olh) {
6938 op.setxattr(RGW_ATTR_OLH_ID_TAG, state->olh_tag);
6939 }
6940
6941 struct timespec mtime_ts = real_clock::to_timespec(meta.set_mtime);
6942 op.mtime2(&mtime_ts);
6943
6944 if (meta.data) {
6945 /* if we want to overwrite the data, we also want to overwrite the
6946 xattrs, so just remove the object */
6947 op.write_full(*meta.data);
6948 }
6949
6950 string etag;
6951 string content_type;
6952 bufferlist acl_bl;
6953
6954 map<string, bufferlist>::iterator iter;
6955 if (meta.rmattrs) {
6956 for (iter = meta.rmattrs->begin(); iter != meta.rmattrs->end(); ++iter) {
6957 const string& name = iter->first;
6958 op.rmxattr(name.c_str());
6959 }
6960 }
6961
6962 if (meta.manifest) {
6963 /* remove existing manifest attr */
6964 iter = attrs.find(RGW_ATTR_MANIFEST);
6965 if (iter != attrs.end())
6966 attrs.erase(iter);
6967
6968 bufferlist bl;
6969 ::encode(*meta.manifest, bl);
6970 op.setxattr(RGW_ATTR_MANIFEST, bl);
6971 }
6972
6973 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
6974 const string& name = iter->first;
6975 bufferlist& bl = iter->second;
6976
6977 if (!bl.length())
6978 continue;
6979
6980 op.setxattr(name.c_str(), bl);
6981
6982 if (name.compare(RGW_ATTR_ETAG) == 0) {
6983 etag = bl.c_str();
6984 } else if (name.compare(RGW_ATTR_CONTENT_TYPE) == 0) {
6985 content_type = bl.c_str();
6986 } else if (name.compare(RGW_ATTR_ACL) == 0) {
6987 acl_bl = bl;
6988 }
6989 }
6990 if (attrs.find(RGW_ATTR_PG_VER) == attrs.end()) {
6991 cls_rgw_obj_store_pg_ver(op, RGW_ATTR_PG_VER);
6992 }
6993
6994 if (attrs.find(RGW_ATTR_SOURCE_ZONE) == attrs.end()) {
6995 bufferlist bl;
6996 ::encode(store->get_zone_short_id(), bl);
6997 op.setxattr(RGW_ATTR_SOURCE_ZONE, bl);
6998 }
6999
7000 if (!op.size())
7001 return 0;
7002
7003 uint64_t epoch;
7004 int64_t poolid;
7005 bool orig_exists;
7006 uint64_t orig_size;
7007
7008 if (!reset_obj) { //Multipart upload, it has immutable head.
7009 orig_exists = false;
7010 orig_size = 0;
7011 } else {
7012 orig_exists = state->exists;
7013 orig_size = state->accounted_size;
7014 }
7015
7016 bool versioned_target = (meta.olh_epoch > 0 || !obj.key.instance.empty());
7017
7018 bool versioned_op = (target->versioning_enabled() || is_olh || versioned_target);
7019
7020 if (versioned_op) {
7021 index_op->set_bilog_flags(RGW_BILOG_FLAG_VERSIONED_OP);
7022 }
7023
7024 if (!index_op->is_prepared()) {
7025 r = index_op->prepare(CLS_RGW_OP_ADD, &state->write_tag);
7026 if (r < 0)
7027 return r;
7028 }
7029
7030 r = ref.ioctx.operate(ref.oid, &op);
7031 if (r < 0) { /* we can expect to get -ECANCELED if object was replaced under,
7032 or -ENOENT if was removed, or -EEXIST if it did not exist
7033 before and now it does */
7034 if (r == -EEXIST && assume_noent) {
7035 target->invalidate_state();
7036 return r;
7037 }
7038 goto done_cancel;
7039 }
7040
7041 epoch = ref.ioctx.get_last_version();
7042 poolid = ref.ioctx.get_id();
7043
7044 r = target->complete_atomic_modification();
7045 if (r < 0) {
7046 ldout(store->ctx(), 0) << "ERROR: complete_atomic_modification returned r=" << r << dendl;
7047 }
7048
7049 r = index_op->complete(poolid, epoch, size, accounted_size,
7050 meta.set_mtime, etag, content_type, &acl_bl,
7051 meta.category, meta.remove_objs, meta.user_data);
7052 if (r < 0)
7053 goto done_cancel;
7054
7055 if (meta.mtime) {
7056 *meta.mtime = meta.set_mtime;
7057 }
7058
7059 /* note that index_op was using state so we couldn't invalidate it earlier */
7060 target->invalidate_state();
7061 state = NULL;
7062
7063 if (versioned_op) {
7064 r = store->set_olh(target->get_ctx(), target->get_bucket_info(), obj, false, NULL, meta.olh_epoch, real_time(), false, meta.zones_trace);
7065 if (r < 0) {
7066 return r;
7067 }
7068 }
7069
7070 if (!real_clock::is_zero(meta.delete_at)) {
7071 rgw_obj_index_key obj_key;
7072 obj.key.get_index_key(&obj_key);
7073
7074 r = store->objexp_hint_add(meta.delete_at,
7075 obj.bucket.tenant, obj.bucket.name, obj.bucket.bucket_id, obj_key);
7076 if (r < 0) {
7077 ldout(store->ctx(), 0) << "ERROR: objexp_hint_add() returned r=" << r << ", object will not get removed" << dendl;
7078 /* ignoring error, nothing we can do at this point */
7079 }
7080 }
7081 meta.canceled = false;
7082
7083 /* update quota cache */
7084 if (meta.completeMultipart){
7085 store->quota_handler->update_stats(meta.owner, obj.bucket, (orig_exists ? 0 : 1),
7086 0, orig_size);
7087 }
7088 else {
7089 store->quota_handler->update_stats(meta.owner, obj.bucket, (orig_exists ? 0 : 1),
7090 accounted_size, orig_size);
7091 }
7092 return 0;
7093
7094 done_cancel:
7095 int ret = index_op->cancel();
7096 if (ret < 0) {
7097 ldout(store->ctx(), 0) << "ERROR: index_op.cancel()() returned ret=" << ret << dendl;
7098 }
7099
7100 meta.canceled = true;
7101
7102 /* we lost in a race. There are a few options:
7103 * - existing object was rewritten (ECANCELED)
7104 * - non existing object was created (EEXIST)
7105 * - object was removed (ENOENT)
7106 * should treat it as a success
7107 */
7108 if (meta.if_match == NULL && meta.if_nomatch == NULL) {
7109 if (r == -ECANCELED || r == -ENOENT || r == -EEXIST) {
7110 r = 0;
7111 }
7112 } else {
7113 if (meta.if_match != NULL) {
7114 // only overwrite existing object
7115 if (strcmp(meta.if_match, "*") == 0) {
7116 if (r == -ENOENT) {
7117 r = -ERR_PRECONDITION_FAILED;
7118 } else if (r == -ECANCELED) {
7119 r = 0;
7120 }
7121 }
7122 }
7123
7124 if (meta.if_nomatch != NULL) {
7125 // only create a new object
7126 if (strcmp(meta.if_nomatch, "*") == 0) {
7127 if (r == -EEXIST) {
7128 r = -ERR_PRECONDITION_FAILED;
7129 } else if (r == -ENOENT) {
7130 r = 0;
7131 }
7132 }
7133 }
7134 }
7135
7136 return r;
7137 }
7138
7139 int RGWRados::Object::Write::write_meta(uint64_t size, uint64_t accounted_size,
7140 map<string, bufferlist>& attrs)
7141 {
7142 RGWBucketInfo& bucket_info = target->get_bucket_info();
7143
7144 RGWRados::Bucket bop(target->get_store(), bucket_info);
7145 RGWRados::Bucket::UpdateIndex index_op(&bop, target->get_obj());
7146 index_op.set_zones_trace(meta.zones_trace);
7147
7148 bool assume_noent = (meta.if_match == NULL && meta.if_nomatch == NULL);
7149 int r;
7150 if (assume_noent) {
7151 r = _do_write_meta(size, accounted_size, attrs, assume_noent, meta.modify_tail, (void *)&index_op);
7152 if (r == -EEXIST) {
7153 assume_noent = false;
7154 }
7155 }
7156 if (!assume_noent) {
7157 r = _do_write_meta(size, accounted_size, attrs, assume_noent, meta.modify_tail, (void *)&index_op);
7158 }
7159 return r;
7160 }
7161
7162 /** Write/overwrite a system object. */
7163 int RGWRados::put_system_obj_impl(rgw_raw_obj& obj, uint64_t size, real_time *mtime,
7164 map<std::string, bufferlist>& attrs, int flags,
7165 bufferlist& data,
7166 RGWObjVersionTracker *objv_tracker,
7167 real_time set_mtime /* 0 for don't set */)
7168 {
7169 rgw_rados_ref ref;
7170 int r = get_system_obj_ref(obj, &ref);
7171 if (r < 0)
7172 return r;
7173
7174 ObjectWriteOperation op;
7175
7176 if (flags & PUT_OBJ_EXCL) {
7177 if (!(flags & PUT_OBJ_CREATE))
7178 return -EINVAL;
7179 op.create(true); // exclusive create
7180 } else {
7181 op.remove();
7182 op.set_op_flags2(LIBRADOS_OP_FLAG_FAILOK);
7183 op.create(false);
7184 }
7185
7186 if (objv_tracker) {
7187 objv_tracker->prepare_op_for_write(&op);
7188 }
7189
7190 if (real_clock::is_zero(set_mtime)) {
7191 set_mtime = real_clock::now();
7192 }
7193
7194 struct timespec mtime_ts = real_clock::to_timespec(set_mtime);
7195 op.mtime2(&mtime_ts);
7196 op.write_full(data);
7197
7198 bufferlist acl_bl;
7199
7200 for (map<string, bufferlist>::iterator iter = attrs.begin(); iter != attrs.end(); ++iter) {
7201 const string& name = iter->first;
7202 bufferlist& bl = iter->second;
7203
7204 if (!bl.length())
7205 continue;
7206
7207 op.setxattr(name.c_str(), bl);
7208 }
7209
7210 r = ref.ioctx.operate(ref.oid, &op);
7211 if (r < 0) {
7212 return r;
7213 }
7214
7215 if (objv_tracker) {
7216 objv_tracker->apply_write();
7217 }
7218
7219 if (mtime) {
7220 *mtime = set_mtime;
7221 }
7222
7223 return 0;
7224 }
7225
7226 int RGWRados::put_system_obj_data(void *ctx, rgw_raw_obj& obj, bufferlist& bl,
7227 off_t ofs, bool exclusive,
7228 RGWObjVersionTracker *objv_tracker)
7229 {
7230 rgw_rados_ref ref;
7231 int r = get_system_obj_ref(obj, &ref);
7232 if (r < 0) {
7233 return r;
7234 }
7235
7236 ObjectWriteOperation op;
7237
7238 if (exclusive)
7239 op.create(true);
7240
7241 if (objv_tracker) {
7242 objv_tracker->prepare_op_for_write(&op);
7243 }
7244 if (ofs == -1) {
7245 op.write_full(bl);
7246 } else {
7247 op.write(ofs, bl);
7248 }
7249 r = ref.ioctx.operate(ref.oid, &op);
7250 if (r < 0)
7251 return r;
7252
7253 if (objv_tracker) {
7254 objv_tracker->apply_write();
7255 }
7256 return 0;
7257 }
7258
7259 /**
7260 * Write/overwrite an object to the bucket storage.
7261 * bucket: the bucket to store the object in
7262 * obj: the object name/key
7263 * data: the object contents/value
7264 * offset: the offet to write to in the object
7265 * If this is -1, we will overwrite the whole object.
7266 * size: the amount of data to write (data must be this long)
7267 * attrs: all the given attrs are written to bucket storage for the given object
7268 * Returns: 0 on success, -ERR# otherwise.
7269 */
7270
7271 int RGWRados::aio_put_obj_data(void *ctx, rgw_raw_obj& obj, bufferlist& bl,
7272 off_t ofs, bool exclusive,
7273 void **handle)
7274 {
7275 rgw_rados_ref ref;
7276 int r = get_raw_obj_ref(obj, &ref);
7277 if (r < 0) {
7278 return r;
7279 }
7280
7281 AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL);
7282 *handle = c;
7283
7284 ObjectWriteOperation op;
7285
7286 if (exclusive)
7287 op.create(true);
7288
7289 if (ofs == -1) {
7290 op.write_full(bl);
7291 } else {
7292 op.write(ofs, bl);
7293 }
7294 r = ref.ioctx.aio_operate(ref.oid, c, &op);
7295 if (r < 0)
7296 return r;
7297
7298 return 0;
7299 }
7300
7301 int RGWRados::aio_wait(void *handle)
7302 {
7303 AioCompletion *c = (AioCompletion *)handle;
7304 c->wait_for_safe();
7305 int ret = c->get_return_value();
7306 c->release();
7307 return ret;
7308 }
7309
7310 bool RGWRados::aio_completed(void *handle)
7311 {
7312 AioCompletion *c = (AioCompletion *)handle;
7313 return c->is_safe();
7314 }
7315
7316 class RGWRadosPutObj : public RGWGetDataCB
7317 {
7318 CephContext* cct;
7319 rgw_obj obj;
7320 RGWPutObjDataProcessor *filter;
7321 boost::optional<RGWPutObj_Compress>& compressor;
7322 CompressorRef& plugin;
7323 RGWPutObjProcessor_Atomic *processor;
7324 RGWOpStateSingleOp *opstate;
7325 void (*progress_cb)(off_t, void *);
7326 void *progress_data;
7327 bufferlist extra_data_bl;
7328 uint64_t extra_data_left;
7329 uint64_t data_len;
7330 map<string, bufferlist> src_attrs;
7331 public:
7332 RGWRadosPutObj(CephContext* cct,
7333 CompressorRef& plugin,
7334 boost::optional<RGWPutObj_Compress>& compressor,
7335 RGWPutObjProcessor_Atomic *p,
7336 RGWOpStateSingleOp *_ops,
7337 void (*_progress_cb)(off_t, void *),
7338 void *_progress_data) :
7339 cct(cct),
7340 filter(p),
7341 compressor(compressor),
7342 plugin(plugin),
7343 processor(p),
7344 opstate(_ops),
7345 progress_cb(_progress_cb),
7346 progress_data(_progress_data),
7347 extra_data_left(0),
7348 data_len(0) {}
7349
7350 int process_attrs(void) {
7351 if (extra_data_bl.length()) {
7352 JSONParser jp;
7353 if (!jp.parse(extra_data_bl.c_str(), extra_data_bl.length())) {
7354 ldout(cct, 0) << "failed to parse response extra data. len=" << extra_data_bl.length() << " data=" << extra_data_bl.c_str() << dendl;
7355 return -EIO;
7356 }
7357
7358 JSONDecoder::decode_json("attrs", src_attrs, &jp);
7359
7360 src_attrs.erase(RGW_ATTR_COMPRESSION);
7361 src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout
7362 }
7363
7364 if (plugin && src_attrs.find(RGW_ATTR_CRYPT_MODE) == src_attrs.end()) {
7365 //do not compress if object is encrypted
7366 compressor = boost::in_place(cct, plugin, filter);
7367 filter = &*compressor;
7368 }
7369 return 0;
7370 }
7371
7372 int handle_data(bufferlist& bl, off_t ofs, off_t len) override {
7373 if (progress_cb) {
7374 progress_cb(ofs, progress_data);
7375 }
7376 if (extra_data_left) {
7377 size_t extra_len = bl.length();
7378 if (extra_len > extra_data_left)
7379 extra_len = extra_data_left;
7380
7381 bufferlist extra;
7382 bl.splice(0, extra_len, &extra);
7383 extra_data_bl.append(extra);
7384
7385 extra_data_left -= extra_len;
7386 if (extra_data_left == 0) {
7387 int res = process_attrs();
7388 if (res < 0)
7389 return res;
7390 }
7391 if (bl.length() == 0) {
7392 return 0;
7393 }
7394 ofs += extra_len;
7395 }
7396 // adjust ofs based on extra_data_len, so the result is a logical offset
7397 // into the object data
7398 assert(uint64_t(ofs) >= extra_data_len);
7399 ofs -= extra_data_len;
7400
7401 data_len += bl.length();
7402 bool again = false;
7403
7404 bool need_opstate = true;
7405
7406 do {
7407 void *handle = NULL;
7408 rgw_raw_obj obj;
7409 uint64_t size = bl.length();
7410 int ret = filter->handle_data(bl, ofs, &handle, &obj, &again);
7411 if (ret < 0)
7412 return ret;
7413
7414 if (need_opstate && opstate) {
7415 /* need to update opstate repository with new state. This is ratelimited, so we're not
7416 * really doing it every time
7417 */
7418 ret = opstate->renew_state();
7419 if (ret < 0) {
7420 ldout(cct, 0) << "ERROR: RGWRadosPutObj::handle_data(): failed to renew op state ret=" << ret << dendl;
7421 int r = filter->throttle_data(handle, obj, size, false);
7422 if (r < 0) {
7423 ldout(cct, 0) << "ERROR: RGWRadosPutObj::handle_data(): processor->throttle_data() returned " << r << dendl;
7424 }
7425 /* could not renew state! might have been marked as cancelled */
7426 return ret;
7427 }
7428 need_opstate = false;
7429 }
7430
7431 ret = filter->throttle_data(handle, obj, size, false);
7432 if (ret < 0)
7433 return ret;
7434 } while (again);
7435
7436 return 0;
7437 }
7438
7439 bufferlist& get_extra_data() { return extra_data_bl; }
7440
7441 map<string, bufferlist>& get_attrs() { return src_attrs; }
7442
7443 void set_extra_data_len(uint64_t len) override {
7444 extra_data_left = len;
7445 RGWGetDataCB::set_extra_data_len(len);
7446 }
7447
7448 uint64_t get_data_len() {
7449 return data_len;
7450 }
7451
7452 int complete(const string& etag, real_time *mtime, real_time set_mtime,
7453 map<string, bufferlist>& attrs, real_time delete_at, rgw_zone_set *zones_trace) {
7454 return processor->complete(data_len, etag, mtime, set_mtime, attrs, delete_at, NULL, NULL, NULL, zones_trace);
7455 }
7456
7457 bool is_canceled() {
7458 return processor->is_canceled();
7459 }
7460 };
7461
7462 /*
7463 * prepare attrset depending on attrs_mod.
7464 */
7465 static void set_copy_attrs(map<string, bufferlist>& src_attrs,
7466 map<string, bufferlist>& attrs,
7467 RGWRados::AttrsMod attrs_mod)
7468 {
7469 switch (attrs_mod) {
7470 case RGWRados::ATTRSMOD_NONE:
7471 attrs = src_attrs;
7472 break;
7473 case RGWRados::ATTRSMOD_REPLACE:
7474 if (!attrs[RGW_ATTR_ETAG].length()) {
7475 attrs[RGW_ATTR_ETAG] = src_attrs[RGW_ATTR_ETAG];
7476 }
7477 if (!attrs[RGW_ATTR_TAIL_TAG].length()) {
7478 auto ttiter = src_attrs.find(RGW_ATTR_TAIL_TAG);
7479 if (ttiter != src_attrs.end()) {
7480 attrs[RGW_ATTR_TAIL_TAG] = src_attrs[RGW_ATTR_TAIL_TAG];
7481 }
7482 }
7483 break;
7484 case RGWRados::ATTRSMOD_MERGE:
7485 for (map<string, bufferlist>::iterator it = src_attrs.begin(); it != src_attrs.end(); ++it) {
7486 if (attrs.find(it->first) == attrs.end()) {
7487 attrs[it->first] = it->second;
7488 }
7489 }
7490 break;
7491 }
7492 }
7493
7494 int RGWRados::rewrite_obj(RGWBucketInfo& dest_bucket_info, rgw_obj& obj)
7495 {
7496 map<string, bufferlist> attrset;
7497
7498 real_time mtime;
7499 uint64_t obj_size;
7500 RGWObjectCtx rctx(this);
7501
7502 RGWRados::Object op_target(this, dest_bucket_info, rctx, obj);
7503 RGWRados::Object::Read read_op(&op_target);
7504
7505 read_op.params.attrs = &attrset;
7506 read_op.params.lastmod = &mtime;
7507 read_op.params.obj_size = &obj_size;
7508
7509 int ret = read_op.prepare();
7510 if (ret < 0)
7511 return ret;
7512
7513 attrset.erase(RGW_ATTR_ID_TAG);
7514 attrset.erase(RGW_ATTR_TAIL_TAG);
7515
7516 uint64_t max_chunk_size;
7517
7518 ret = get_max_chunk_size(dest_bucket_info.placement_rule, obj, &max_chunk_size);
7519 if (ret < 0) {
7520 ldout(cct, 0) << "ERROR: failed to get max_chunk_size() for bucket " << obj.bucket << dendl;
7521 return ret;
7522 }
7523
7524 return copy_obj_data(rctx, dest_bucket_info, read_op, obj_size - 1, obj, obj,
7525 max_chunk_size, NULL, mtime, attrset,
7526 RGW_OBJ_CATEGORY_MAIN, 0, real_time(),
7527 (obj.key.instance.empty() ? NULL : &(obj.key.instance)),
7528 NULL, NULL);
7529 }
7530
7531 struct obj_time_weight {
7532 real_time mtime;
7533 uint32_t zone_short_id;
7534 uint64_t pg_ver;
7535 bool high_precision;
7536
7537 obj_time_weight() : zone_short_id(0), pg_ver(0), high_precision(false) {}
7538
7539 bool compare_low_precision(const obj_time_weight& rhs) {
7540 struct timespec l = ceph::real_clock::to_timespec(mtime);
7541 struct timespec r = ceph::real_clock::to_timespec(rhs.mtime);
7542 l.tv_nsec = 0;
7543 r.tv_nsec = 0;
7544 if (l > r) {
7545 return false;
7546 }
7547 if (l < r) {
7548 return true;
7549 }
7550 if (zone_short_id != rhs.zone_short_id) {
7551 return (zone_short_id < rhs.zone_short_id);
7552 }
7553 return (pg_ver < rhs.pg_ver);
7554
7555 }
7556
7557 bool operator<(const obj_time_weight& rhs) {
7558 if (!high_precision || !rhs.high_precision) {
7559 return compare_low_precision(rhs);
7560 }
7561 if (mtime > rhs.mtime) {
7562 return false;
7563 }
7564 if (mtime < rhs.mtime) {
7565 return true;
7566 }
7567 if (zone_short_id != rhs.zone_short_id) {
7568 return (zone_short_id < rhs.zone_short_id);
7569 }
7570 return (pg_ver < rhs.pg_ver);
7571 }
7572
7573 void init(const real_time& _mtime, uint32_t _short_id, uint64_t _pg_ver) {
7574 mtime = _mtime;
7575 zone_short_id = _short_id;
7576 pg_ver = _pg_ver;
7577 }
7578
7579 void init(RGWObjState *state) {
7580 mtime = state->mtime;
7581 zone_short_id = state->zone_short_id;
7582 pg_ver = state->pg_ver;
7583 }
7584 };
7585
7586 inline ostream& operator<<(ostream& out, const obj_time_weight &o) {
7587 out << o.mtime;
7588
7589 if (o.zone_short_id != 0 || o.pg_ver != 0) {
7590 out << "[zid=" << o.zone_short_id << ", pgv=" << o.pg_ver << "]";
7591 }
7592
7593 return out;
7594 }
7595
7596 class RGWGetExtraDataCB : public RGWGetDataCB {
7597 bufferlist extra_data;
7598 public:
7599 RGWGetExtraDataCB() {}
7600 int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override {
7601 if (extra_data.length() < extra_data_len) {
7602 off_t max = extra_data_len - extra_data.length();
7603 if (max > bl_len) {
7604 max = bl_len;
7605 }
7606 bl.splice(0, max, &extra_data);
7607 }
7608 return bl_len;
7609 }
7610
7611 bufferlist& get_extra_data() {
7612 return extra_data;
7613 }
7614 };
7615
7616 int RGWRados::stat_remote_obj(RGWObjectCtx& obj_ctx,
7617 const rgw_user& user_id,
7618 const string& client_id,
7619 req_info *info,
7620 const string& source_zone,
7621 rgw_obj& src_obj,
7622 RGWBucketInfo& src_bucket_info,
7623 real_time *src_mtime,
7624 uint64_t *psize,
7625 const real_time *mod_ptr,
7626 const real_time *unmod_ptr,
7627 bool high_precision_time,
7628 const char *if_match,
7629 const char *if_nomatch,
7630 map<string, bufferlist> *pattrs,
7631 string *version_id,
7632 string *ptag,
7633 string *petag)
7634 {
7635 /* source is in a different zonegroup, copy from there */
7636
7637 RGWRESTStreamRWRequest *in_stream_req;
7638 string tag;
7639 map<string, bufferlist> src_attrs;
7640 append_rand_alpha(cct, tag, tag, 32);
7641 obj_time_weight set_mtime_weight;
7642 set_mtime_weight.high_precision = high_precision_time;
7643
7644 RGWRESTConn *conn;
7645 if (source_zone.empty()) {
7646 if (src_bucket_info.zonegroup.empty()) {
7647 /* source is in the master zonegroup */
7648 conn = rest_master_conn;
7649 } else {
7650 map<string, RGWRESTConn *>::iterator iter = zonegroup_conn_map.find(src_bucket_info.zonegroup);
7651 if (iter == zonegroup_conn_map.end()) {
7652 ldout(cct, 0) << "could not find zonegroup connection to zonegroup: " << source_zone << dendl;
7653 return -ENOENT;
7654 }
7655 conn = iter->second;
7656 }
7657 } else {
7658 map<string, RGWRESTConn *>::iterator iter = zone_conn_map.find(source_zone);
7659 if (iter == zone_conn_map.end()) {
7660 ldout(cct, 0) << "could not find zone connection to zone: " << source_zone << dendl;
7661 return -ENOENT;
7662 }
7663 conn = iter->second;
7664 }
7665
7666 RGWGetExtraDataCB cb;
7667 string etag;
7668 map<string, string> req_headers;
7669 real_time set_mtime;
7670
7671 const real_time *pmod = mod_ptr;
7672
7673 obj_time_weight dest_mtime_weight;
7674
7675 constexpr bool prepend_meta = true;
7676 constexpr bool get_op = true;
7677 constexpr bool rgwx_stat = true;
7678 constexpr bool sync_manifest = true;
7679 constexpr bool skip_decrypt = true;
7680 int ret = conn->get_obj(user_id, info, src_obj, pmod, unmod_ptr,
7681 dest_mtime_weight.zone_short_id, dest_mtime_weight.pg_ver,
7682 prepend_meta, get_op, rgwx_stat,
7683 sync_manifest, skip_decrypt, &cb, &in_stream_req);
7684 if (ret < 0) {
7685 return ret;
7686 }
7687
7688 ret = conn->complete_request(in_stream_req, etag, &set_mtime, psize, req_headers);
7689 if (ret < 0) {
7690 return ret;
7691 }
7692
7693 bufferlist& extra_data_bl = cb.get_extra_data();
7694 if (extra_data_bl.length()) {
7695 JSONParser jp;
7696 if (!jp.parse(extra_data_bl.c_str(), extra_data_bl.length())) {
7697 ldout(cct, 0) << "failed to parse response extra data. len=" << extra_data_bl.length() << " data=" << extra_data_bl.c_str() << dendl;
7698 return -EIO;
7699 }
7700
7701 JSONDecoder::decode_json("attrs", src_attrs, &jp);
7702
7703 src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout
7704 }
7705
7706 if (src_mtime) {
7707 *src_mtime = set_mtime;
7708 }
7709
7710 if (petag) {
7711 map<string, bufferlist>::iterator iter = src_attrs.find(RGW_ATTR_ETAG);
7712 if (iter != src_attrs.end()) {
7713 bufferlist& etagbl = iter->second;
7714 *petag = etagbl.to_str();
7715 }
7716 }
7717
7718 if (pattrs) {
7719 *pattrs = src_attrs;
7720 }
7721
7722 return 0;
7723 }
7724
7725 int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
7726 const rgw_user& user_id,
7727 const string& client_id,
7728 const string& op_id,
7729 bool record_op_state,
7730 req_info *info,
7731 const string& source_zone,
7732 rgw_obj& dest_obj,
7733 rgw_obj& src_obj,
7734 RGWBucketInfo& dest_bucket_info,
7735 RGWBucketInfo& src_bucket_info,
7736 real_time *src_mtime,
7737 real_time *mtime,
7738 const real_time *mod_ptr,
7739 const real_time *unmod_ptr,
7740 bool high_precision_time,
7741 const char *if_match,
7742 const char *if_nomatch,
7743 AttrsMod attrs_mod,
7744 bool copy_if_newer,
7745 map<string, bufferlist>& attrs,
7746 RGWObjCategory category,
7747 uint64_t olh_epoch,
7748 real_time delete_at,
7749 string *version_id,
7750 string *ptag,
7751 ceph::buffer::list *petag,
7752 void (*progress_cb)(off_t, void *),
7753 void *progress_data,
7754 rgw_zone_set *zones_trace)
7755 {
7756 /* source is in a different zonegroup, copy from there */
7757
7758 RGWRESTStreamRWRequest *in_stream_req;
7759 string tag;
7760 int i;
7761 append_rand_alpha(cct, tag, tag, 32);
7762 obj_time_weight set_mtime_weight;
7763 set_mtime_weight.high_precision = high_precision_time;
7764
7765 RGWPutObjProcessor_Atomic processor(obj_ctx,
7766 dest_bucket_info, dest_obj.bucket, dest_obj.key.name,
7767 cct->_conf->rgw_obj_stripe_size, tag, dest_bucket_info.versioning_enabled());
7768 if (version_id && *version_id != "null") {
7769 processor.set_version_id(*version_id);
7770 }
7771 processor.set_olh_epoch(olh_epoch);
7772 int ret = processor.prepare(this, NULL);
7773 if (ret < 0) {
7774 return ret;
7775 }
7776
7777 RGWRESTConn *conn;
7778 if (source_zone.empty()) {
7779 if (dest_bucket_info.zonegroup.empty()) {
7780 /* source is in the master zonegroup */
7781 conn = rest_master_conn;
7782 } else {
7783 map<string, RGWRESTConn *>::iterator iter = zonegroup_conn_map.find(src_bucket_info.zonegroup);
7784 if (iter == zonegroup_conn_map.end()) {
7785 ldout(cct, 0) << "could not find zonegroup connection to zonegroup: " << source_zone << dendl;
7786 return -ENOENT;
7787 }
7788 conn = iter->second;
7789 }
7790 } else {
7791 map<string, RGWRESTConn *>::iterator iter = zone_conn_map.find(source_zone);
7792 if (iter == zone_conn_map.end()) {
7793 ldout(cct, 0) << "could not find zone connection to zone: " << source_zone << dendl;
7794 return -ENOENT;
7795 }
7796 conn = iter->second;
7797 }
7798
7799 string obj_name = dest_obj.bucket.name + "/" + dest_obj.get_oid();
7800
7801 RGWOpStateSingleOp *opstate = NULL;
7802
7803 if (record_op_state) {
7804 opstate = new RGWOpStateSingleOp(this, client_id, op_id, obj_name);
7805
7806 ret = opstate->set_state(RGWOpState::OPSTATE_IN_PROGRESS);
7807 if (ret < 0) {
7808 ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
7809 delete opstate;
7810 return ret;
7811 }
7812 }
7813
7814 boost::optional<RGWPutObj_Compress> compressor;
7815 CompressorRef plugin;
7816
7817 const auto& compression_type = zone_params.get_compression_type(
7818 dest_bucket_info.placement_rule);
7819 if (compression_type != "none") {
7820 plugin = Compressor::create(cct, compression_type);
7821 if (!plugin) {
7822 ldout(cct, 1) << "Cannot load plugin for compression type "
7823 << compression_type << dendl;
7824 }
7825 }
7826
7827 RGWRadosPutObj cb(cct, plugin, compressor, &processor, opstate, progress_cb, progress_data);
7828
7829 string etag;
7830 map<string, string> req_headers;
7831 real_time set_mtime;
7832
7833 RGWObjState *dest_state = NULL;
7834
7835 const real_time *pmod = mod_ptr;
7836
7837 obj_time_weight dest_mtime_weight;
7838
7839 if (copy_if_newer) {
7840 /* need to get mtime for destination */
7841 ret = get_obj_state(&obj_ctx, dest_bucket_info, dest_obj, &dest_state, false);
7842 if (ret < 0)
7843 goto set_err_state;
7844
7845 if (!real_clock::is_zero(dest_state->mtime)) {
7846 dest_mtime_weight.init(dest_state);
7847 pmod = &dest_mtime_weight.mtime;
7848 }
7849 }
7850
7851 static constexpr bool prepend_meta = true;
7852 static constexpr bool get_op = true;
7853 static constexpr bool rgwx_stat = false;
7854 static constexpr bool sync_manifest = true;
7855 static constexpr bool skip_decrypt = true;
7856 ret = conn->get_obj(user_id, info, src_obj, pmod, unmod_ptr,
7857 dest_mtime_weight.zone_short_id, dest_mtime_weight.pg_ver,
7858 prepend_meta, get_op, rgwx_stat,
7859 sync_manifest, skip_decrypt, &cb, &in_stream_req);
7860 if (ret < 0) {
7861 goto set_err_state;
7862 }
7863
7864 ret = conn->complete_request(in_stream_req, etag, &set_mtime, nullptr, req_headers);
7865 if (ret < 0) {
7866 goto set_err_state;
7867 }
7868 if (compressor && compressor->is_compressed()) {
7869 bufferlist tmp;
7870 RGWCompressionInfo cs_info;
7871 cs_info.compression_type = plugin->get_type_name();
7872 cs_info.orig_size = cb.get_data_len();
7873 cs_info.blocks = move(compressor->get_compression_blocks());
7874 ::encode(cs_info, tmp);
7875 cb.get_attrs()[RGW_ATTR_COMPRESSION] = tmp;
7876 }
7877
7878 if (source_zone.empty()) { /* need to preserve expiration if copy in the same zonegroup */
7879 cb.get_attrs().erase(RGW_ATTR_DELETE_AT);
7880 } else {
7881 map<string, bufferlist>::iterator iter = cb.get_attrs().find(RGW_ATTR_DELETE_AT);
7882 if (iter != cb.get_attrs().end()) {
7883 try {
7884 ::decode(delete_at, iter->second);
7885 } catch (buffer::error& err) {
7886 ldout(cct, 0) << "ERROR: failed to decode delete_at field in intra zone copy" << dendl;
7887 }
7888 }
7889 }
7890
7891 if (src_mtime) {
7892 *src_mtime = set_mtime;
7893 }
7894
7895 if (petag) {
7896 const auto iter = cb.get_attrs().find(RGW_ATTR_ETAG);
7897 if (iter != cb.get_attrs().end()) {
7898 *petag = iter->second;
7899 }
7900 }
7901
7902 if (source_zone.empty()) {
7903 set_copy_attrs(cb.get_attrs(), attrs, attrs_mod);
7904 } else {
7905 attrs = cb.get_attrs();
7906 }
7907
7908 if (copy_if_newer) {
7909 uint64_t pg_ver = 0;
7910 auto i = attrs.find(RGW_ATTR_PG_VER);
7911 if (i != attrs.end() && i->second.length() > 0) {
7912 bufferlist::iterator iter = i->second.begin();
7913 try {
7914 ::decode(pg_ver, iter);
7915 } catch (buffer::error& err) {
7916 ldout(ctx(), 0) << "ERROR: failed to decode pg ver attribute, ignoring" << dendl;
7917 /* non critical error */
7918 }
7919 }
7920 set_mtime_weight.init(set_mtime, get_zone_short_id(), pg_ver);
7921 }
7922
7923 #define MAX_COMPLETE_RETRY 100
7924 for (i = 0; i < MAX_COMPLETE_RETRY; i++) {
7925 ret = cb.complete(etag, mtime, set_mtime, attrs, delete_at, zones_trace);
7926 if (ret < 0) {
7927 goto set_err_state;
7928 }
7929 if (copy_if_newer && cb.is_canceled()) {
7930 ldout(cct, 20) << "raced with another write of obj: " << dest_obj << dendl;
7931 obj_ctx.obj.invalidate(dest_obj); /* object was overwritten */
7932 ret = get_obj_state(&obj_ctx, dest_bucket_info, dest_obj, &dest_state, false);
7933 if (ret < 0) {
7934 ldout(cct, 0) << "ERROR: " << __func__ << ": get_err_state() returned ret=" << ret << dendl;
7935 goto set_err_state;
7936 }
7937 dest_mtime_weight.init(dest_state);
7938 dest_mtime_weight.high_precision = high_precision_time;
7939 if (!dest_state->exists ||
7940 dest_mtime_weight < set_mtime_weight) {
7941 ldout(cct, 20) << "retrying writing object mtime=" << set_mtime << " dest_state->mtime=" << dest_state->mtime << " dest_state->exists=" << dest_state->exists << dendl;
7942 continue;
7943 } else {
7944 ldout(cct, 20) << "not retrying writing object mtime=" << set_mtime << " dest_state->mtime=" << dest_state->mtime << " dest_state->exists=" << dest_state->exists << dendl;
7945 }
7946 }
7947 break;
7948 }
7949
7950 if (i == MAX_COMPLETE_RETRY) {
7951 ldout(cct, 0) << "ERROR: retried object completion too many times, something is wrong!" << dendl;
7952 ret = -EIO;
7953 goto set_err_state;
7954 }
7955
7956 if (opstate) {
7957 ret = opstate->set_state(RGWOpState::OPSTATE_COMPLETE);
7958 if (ret < 0) {
7959 ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
7960 }
7961 delete opstate;
7962 }
7963
7964 return 0;
7965 set_err_state:
7966 if (copy_if_newer && ret == -ERR_NOT_MODIFIED) {
7967 ret = 0;
7968 }
7969 if (opstate) {
7970 RGWOpState::OpState state;
7971 if (ret < 0) {
7972 state = RGWOpState::OPSTATE_ERROR;
7973 } else {
7974 state = RGWOpState::OPSTATE_COMPLETE;
7975 }
7976 int r = opstate->set_state(state);
7977 if (r < 0) {
7978 ldout(cct, 0) << "ERROR: failed to set opstate r=" << ret << dendl;
7979 }
7980 delete opstate;
7981 }
7982 return ret;
7983 }
7984
7985
7986 int RGWRados::copy_obj_to_remote_dest(RGWObjState *astate,
7987 map<string, bufferlist>& src_attrs,
7988 RGWRados::Object::Read& read_op,
7989 const rgw_user& user_id,
7990 rgw_obj& dest_obj,
7991 real_time *mtime)
7992 {
7993 string etag;
7994
7995 RGWRESTStreamWriteRequest *out_stream_req;
7996
7997 int ret = rest_master_conn->put_obj_init(user_id, dest_obj, astate->size, src_attrs, &out_stream_req);
7998 if (ret < 0) {
7999 return ret;
8000 }
8001
8002 ret = read_op.iterate(0, astate->size - 1, out_stream_req->get_out_cb());
8003 if (ret < 0) {
8004 delete out_stream_req;
8005 return ret;
8006 }
8007
8008 ret = rest_master_conn->complete_request(out_stream_req, etag, mtime);
8009 if (ret < 0)
8010 return ret;
8011
8012 return 0;
8013 }
8014
8015 /**
8016 * Copy an object.
8017 * dest_obj: the object to copy into
8018 * src_obj: the object to copy from
8019 * attrs: usage depends on attrs_mod parameter
8020 * attrs_mod: the modification mode of the attrs, may have the following values:
8021 * ATTRSMOD_NONE - the attributes of the source object will be
8022 * copied without modifications, attrs parameter is ignored;
8023 * ATTRSMOD_REPLACE - new object will have the attributes provided by attrs
8024 * parameter, source object attributes are not copied;
8025 * ATTRSMOD_MERGE - any conflicting meta keys on the source object's attributes
8026 * are overwritten by values contained in attrs parameter.
8027 * err: stores any errors resulting from the get of the original object
8028 * Returns: 0 on success, -ERR# otherwise.
8029 */
8030 int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
8031 const rgw_user& user_id,
8032 const string& client_id,
8033 const string& op_id,
8034 req_info *info,
8035 const string& source_zone,
8036 rgw_obj& dest_obj,
8037 rgw_obj& src_obj,
8038 RGWBucketInfo& dest_bucket_info,
8039 RGWBucketInfo& src_bucket_info,
8040 real_time *src_mtime,
8041 real_time *mtime,
8042 const real_time *mod_ptr,
8043 const real_time *unmod_ptr,
8044 bool high_precision_time,
8045 const char *if_match,
8046 const char *if_nomatch,
8047 AttrsMod attrs_mod,
8048 bool copy_if_newer,
8049 map<string, bufferlist>& attrs,
8050 RGWObjCategory category,
8051 uint64_t olh_epoch,
8052 real_time delete_at,
8053 string *version_id,
8054 string *ptag,
8055 ceph::buffer::list *petag,
8056 void (*progress_cb)(off_t, void *),
8057 void *progress_data)
8058 {
8059 int ret;
8060 uint64_t obj_size;
8061 rgw_obj shadow_obj = dest_obj;
8062 string shadow_oid;
8063
8064 bool remote_src;
8065 bool remote_dest;
8066
8067 append_rand_alpha(cct, dest_obj.get_oid(), shadow_oid, 32);
8068 shadow_obj.init_ns(dest_obj.bucket, shadow_oid, shadow_ns);
8069
8070 remote_dest = !get_zonegroup().equals(dest_bucket_info.zonegroup);
8071 remote_src = !get_zonegroup().equals(src_bucket_info.zonegroup);
8072
8073 if (remote_src && remote_dest) {
8074 ldout(cct, 0) << "ERROR: can't copy object when both src and dest buckets are remote" << dendl;
8075 return -EINVAL;
8076 }
8077
8078 ldout(cct, 5) << "Copy object " << src_obj.bucket << ":" << src_obj.get_oid() << " => " << dest_obj.bucket << ":" << dest_obj.get_oid() << dendl;
8079
8080 if (remote_src || !source_zone.empty()) {
8081 return fetch_remote_obj(obj_ctx, user_id, client_id, op_id, true, info, source_zone,
8082 dest_obj, src_obj, dest_bucket_info, src_bucket_info, src_mtime, mtime, mod_ptr,
8083 unmod_ptr, high_precision_time,
8084 if_match, if_nomatch, attrs_mod, copy_if_newer, attrs, category,
8085 olh_epoch, delete_at, version_id, ptag, petag, progress_cb, progress_data);
8086 }
8087
8088 map<string, bufferlist> src_attrs;
8089 RGWRados::Object src_op_target(this, src_bucket_info, obj_ctx, src_obj);
8090 RGWRados::Object::Read read_op(&src_op_target);
8091
8092 read_op.conds.mod_ptr = mod_ptr;
8093 read_op.conds.unmod_ptr = unmod_ptr;
8094 read_op.conds.high_precision_time = high_precision_time;
8095 read_op.conds.if_match = if_match;
8096 read_op.conds.if_nomatch = if_nomatch;
8097 read_op.params.attrs = &src_attrs;
8098 read_op.params.lastmod = src_mtime;
8099 read_op.params.obj_size = &obj_size;
8100
8101 ret = read_op.prepare();
8102 if (ret < 0) {
8103 return ret;
8104 }
8105
8106 src_attrs[RGW_ATTR_ACL] = attrs[RGW_ATTR_ACL];
8107 src_attrs.erase(RGW_ATTR_DELETE_AT);
8108
8109 set_copy_attrs(src_attrs, attrs, attrs_mod);
8110 attrs.erase(RGW_ATTR_ID_TAG);
8111 attrs.erase(RGW_ATTR_PG_VER);
8112 attrs.erase(RGW_ATTR_SOURCE_ZONE);
8113 map<string, bufferlist>::iterator cmp = src_attrs.find(RGW_ATTR_COMPRESSION);
8114 if (cmp != src_attrs.end())
8115 attrs[RGW_ATTR_COMPRESSION] = cmp->second;
8116
8117 RGWObjManifest manifest;
8118 RGWObjState *astate = NULL;
8119
8120 ret = get_obj_state(&obj_ctx, src_bucket_info, src_obj, &astate);
8121 if (ret < 0) {
8122 return ret;
8123 }
8124
8125 vector<rgw_raw_obj> ref_objs;
8126
8127 if (remote_dest) {
8128 /* dest is in a different zonegroup, copy it there */
8129 return copy_obj_to_remote_dest(astate, attrs, read_op, user_id, dest_obj, mtime);
8130 }
8131 uint64_t max_chunk_size;
8132
8133 ret = get_max_chunk_size(dest_bucket_info.placement_rule, dest_obj, &max_chunk_size);
8134 if (ret < 0) {
8135 ldout(cct, 0) << "ERROR: failed to get max_chunk_size() for bucket " << dest_obj.bucket << dendl;
8136 return ret;
8137 }
8138
8139 rgw_pool src_pool;
8140 rgw_pool dest_pool;
8141 if (!get_obj_data_pool(src_bucket_info.placement_rule, src_obj, &src_pool)) {
8142 ldout(cct, 0) << "ERROR: failed to locate data pool for " << src_obj << dendl;
8143 return -EIO;
8144 }
8145 if (!get_obj_data_pool(dest_bucket_info.placement_rule, dest_obj, &dest_pool)) {
8146 ldout(cct, 0) << "ERROR: failed to locate data pool for " << dest_obj << dendl;
8147 return -EIO;
8148 }
8149
8150
8151 bool copy_data = !astate->has_manifest || (src_pool != dest_pool);
8152 bool copy_first = false;
8153 if (astate->has_manifest) {
8154 if (!astate->manifest.has_tail()) {
8155 copy_data = true;
8156 } else {
8157 uint64_t head_size = astate->manifest.get_head_size();
8158
8159 if (head_size > 0) {
8160 if (head_size > max_chunk_size) {
8161 copy_data = true;
8162 } else {
8163 copy_first = true;
8164 }
8165 }
8166 }
8167 }
8168
8169 if (petag) {
8170 const auto iter = attrs.find(RGW_ATTR_ETAG);
8171 if (iter != attrs.end()) {
8172 *petag = iter->second;
8173 }
8174 }
8175
8176 if (copy_data) { /* refcounting tail wouldn't work here, just copy the data */
8177 return copy_obj_data(obj_ctx, dest_bucket_info, read_op, obj_size - 1, dest_obj, src_obj,
8178 max_chunk_size, mtime, real_time(), attrs, category, olh_epoch, delete_at,
8179 version_id, ptag, petag);
8180 }
8181
8182 RGWObjManifest::obj_iterator miter = astate->manifest.obj_begin();
8183
8184 if (copy_first) { // we need to copy first chunk, not increase refcount
8185 ++miter;
8186 }
8187
8188 rgw_rados_ref ref;
8189 ret = get_raw_obj_ref(miter.get_location().get_raw_obj(this), &ref);
8190 if (ret < 0) {
8191 return ret;
8192 }
8193
8194 bool versioned_dest = dest_bucket_info.versioning_enabled();
8195
8196 if (version_id && !version_id->empty()) {
8197 versioned_dest = true;
8198 dest_obj.key.set_instance(*version_id);
8199 } else if (versioned_dest) {
8200 gen_rand_obj_instance_name(&dest_obj);
8201 }
8202
8203 bufferlist first_chunk;
8204
8205 bool copy_itself = (dest_obj == src_obj);
8206 RGWObjManifest *pmanifest;
8207 ldout(cct, 20) << "dest_obj=" << dest_obj << " src_obj=" << src_obj << " copy_itself=" << (int)copy_itself << dendl;
8208
8209 RGWRados::Object dest_op_target(this, dest_bucket_info, obj_ctx, dest_obj);
8210 RGWRados::Object::Write write_op(&dest_op_target);
8211
8212 string tag;
8213
8214 if (ptag) {
8215 tag = *ptag;
8216 }
8217
8218 if (tag.empty()) {
8219 append_rand_alpha(cct, tag, tag, 32);
8220 }
8221
8222 if (!copy_itself) {
8223 attrs.erase(RGW_ATTR_TAIL_TAG);
8224 manifest = astate->manifest;
8225 const rgw_bucket_placement& tail_placement = manifest.get_tail_placement();
8226 if (tail_placement.bucket.name.empty()) {
8227 manifest.set_tail_placement(tail_placement.placement_rule, src_obj.bucket);
8228 }
8229 string ref_tag;
8230 for (; miter != astate->manifest.obj_end(); ++miter) {
8231 ObjectWriteOperation op;
8232 ref_tag = tag + '\0';
8233 cls_refcount_get(op, ref_tag, true);
8234 const rgw_raw_obj& loc = miter.get_location().get_raw_obj(this);
8235 ref.ioctx.locator_set_key(loc.loc);
8236
8237 ret = ref.ioctx.operate(loc.oid, &op);
8238 if (ret < 0) {
8239 goto done_ret;
8240 }
8241
8242 ref_objs.push_back(loc);
8243 }
8244
8245 pmanifest = &manifest;
8246 } else {
8247 pmanifest = &astate->manifest;
8248 /* don't send the object's tail for garbage collection */
8249 astate->keep_tail = true;
8250 }
8251
8252 if (copy_first) {
8253 ret = read_op.read(0, max_chunk_size, first_chunk);
8254 if (ret < 0) {
8255 goto done_ret;
8256 }
8257
8258 pmanifest->set_head(dest_bucket_info.placement_rule, dest_obj, first_chunk.length());
8259 } else {
8260 pmanifest->set_head(dest_bucket_info.placement_rule, dest_obj, 0);
8261 }
8262
8263 write_op.meta.data = &first_chunk;
8264 write_op.meta.manifest = pmanifest;
8265 write_op.meta.ptag = &tag;
8266 write_op.meta.owner = dest_bucket_info.owner;
8267 write_op.meta.mtime = mtime;
8268 write_op.meta.flags = PUT_OBJ_CREATE;
8269 write_op.meta.category = category;
8270 write_op.meta.olh_epoch = olh_epoch;
8271 write_op.meta.delete_at = delete_at;
8272 write_op.meta.modify_tail = !copy_itself;
8273
8274 ret = write_op.write_meta(obj_size, astate->accounted_size, attrs);
8275 if (ret < 0) {
8276 goto done_ret;
8277 }
8278
8279 return 0;
8280
8281 done_ret:
8282 if (!copy_itself) {
8283 vector<rgw_raw_obj>::iterator riter;
8284
8285 /* rollback reference */
8286 for (riter = ref_objs.begin(); riter != ref_objs.end(); ++riter) {
8287 ObjectWriteOperation op;
8288 cls_refcount_put(op, tag, true);
8289
8290 ref.ioctx.locator_set_key(riter->loc);
8291
8292 int r = ref.ioctx.operate(riter->oid, &op);
8293 if (r < 0) {
8294 ldout(cct, 0) << "ERROR: cleanup after error failed to drop reference on obj=" << *riter << dendl;
8295 }
8296 }
8297 }
8298 return ret;
8299 }
8300
8301
8302 int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
8303 RGWBucketInfo& dest_bucket_info,
8304 RGWRados::Object::Read& read_op, off_t end,
8305 rgw_obj& dest_obj,
8306 rgw_obj& src_obj,
8307 uint64_t max_chunk_size,
8308 real_time *mtime,
8309 real_time set_mtime,
8310 map<string, bufferlist>& attrs,
8311 RGWObjCategory category,
8312 uint64_t olh_epoch,
8313 real_time delete_at,
8314 string *version_id,
8315 string *ptag,
8316 ceph::buffer::list *petag)
8317 {
8318 bufferlist first_chunk;
8319 RGWObjManifest manifest;
8320
8321 string tag;
8322 append_rand_alpha(cct, tag, tag, 32);
8323
8324 RGWPutObjProcessor_Atomic processor(obj_ctx,
8325 dest_bucket_info, dest_obj.bucket, dest_obj.key.name,
8326 cct->_conf->rgw_obj_stripe_size, tag, dest_bucket_info.versioning_enabled());
8327 if (version_id) {
8328 processor.set_version_id(*version_id);
8329 }
8330 processor.set_olh_epoch(olh_epoch);
8331 int ret = processor.prepare(this, NULL);
8332 if (ret < 0)
8333 return ret;
8334
8335 off_t ofs = 0;
8336
8337 do {
8338 bufferlist bl;
8339 ret = read_op.read(ofs, end, bl);
8340
8341 uint64_t read_len = ret;
8342 bool again;
8343
8344 do {
8345 void *handle;
8346 rgw_raw_obj obj;
8347
8348 ret = processor.handle_data(bl, ofs, &handle, &obj, &again);
8349 if (ret < 0) {
8350 return ret;
8351 }
8352 ret = processor.throttle_data(handle, obj, read_len, false);
8353 if (ret < 0)
8354 return ret;
8355 } while (again);
8356
8357 ofs += read_len;
8358 } while (ofs <= end);
8359
8360 string etag;
8361 auto iter = attrs.find(RGW_ATTR_ETAG);
8362 if (iter != attrs.end()) {
8363 bufferlist& bl = iter->second;
8364 etag = string(bl.c_str(), bl.length());
8365 if (petag) {
8366 *petag = bl;
8367 }
8368 }
8369
8370 uint64_t accounted_size;
8371 {
8372 bool compressed{false};
8373 RGWCompressionInfo cs_info;
8374 ret = rgw_compression_info_from_attrset(attrs, compressed, cs_info);
8375 if (ret < 0) {
8376 ldout(cct, 0) << "ERROR: failed to read compression info" << dendl;
8377 return ret;
8378 }
8379 // pass original size if compressed
8380 accounted_size = compressed ? cs_info.orig_size : ofs;
8381 }
8382
8383 return processor.complete(accounted_size, etag, mtime, set_mtime, attrs, delete_at);
8384 }
8385
8386 bool RGWRados::is_meta_master()
8387 {
8388 if (!get_zonegroup().is_master_zonegroup()) {
8389 return false;
8390 }
8391
8392 return (get_zonegroup().master_zone == zone_public_config.id);
8393 }
8394
8395 /**
8396 * Check to see if the bucket metadata could be synced
8397 * bucket: the bucket to check
8398 * Returns false is the bucket is not synced
8399 */
8400 bool RGWRados::is_syncing_bucket_meta(const rgw_bucket& bucket)
8401 {
8402
8403 /* no current period */
8404 if (current_period.get_id().empty()) {
8405 return false;
8406 }
8407
8408 /* zonegroup is not master zonegroup */
8409 if (!get_zonegroup().is_master_zonegroup()) {
8410 return false;
8411 }
8412
8413 /* single zonegroup and a single zone */
8414 if (current_period.is_single_zonegroup() && get_zonegroup().zones.size() == 1) {
8415 return false;
8416 }
8417
8418 /* zone is not master */
8419 if (get_zonegroup().master_zone.compare(zone_public_config.id) != 0) {
8420 return false;
8421 }
8422
8423 return true;
8424 }
8425
8426 int RGWRados::check_bucket_empty(RGWBucketInfo& bucket_info)
8427 {
8428 std::map<string, rgw_bucket_dir_entry> ent_map;
8429 rgw_obj_index_key marker;
8430 string prefix;
8431 bool is_truncated;
8432
8433 do {
8434 #define NUM_ENTRIES 1000
8435 int r = cls_bucket_list(bucket_info, RGW_NO_SHARD, marker, prefix, NUM_ENTRIES, true, ent_map,
8436 &is_truncated, &marker);
8437 if (r < 0)
8438 return r;
8439
8440 string ns;
8441 std::map<string, rgw_bucket_dir_entry>::iterator eiter;
8442 for (eiter = ent_map.begin(); eiter != ent_map.end(); ++eiter) {
8443 rgw_obj_key obj;
8444
8445 if (rgw_obj_key::oid_to_key_in_ns(eiter->second.key.name, &obj, ns))
8446 return -ENOTEMPTY;
8447 }
8448 } while (is_truncated);
8449 return 0;
8450 }
8451
8452 /**
8453 * Delete a bucket.
8454 * bucket: the name of the bucket to delete
8455 * Returns 0 on success, -ERR# otherwise.
8456 */
8457 int RGWRados::delete_bucket(RGWBucketInfo& bucket_info, RGWObjVersionTracker& objv_tracker, bool check_empty)
8458 {
8459 const rgw_bucket& bucket = bucket_info.bucket;
8460 librados::IoCtx index_ctx;
8461 map<int, string> bucket_objs;
8462 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs);
8463 if (r < 0)
8464 return r;
8465
8466 if (check_empty) {
8467 r = check_bucket_empty(bucket_info);
8468 if (r < 0) {
8469 return r;
8470 }
8471 }
8472
8473 r = rgw_bucket_delete_bucket_obj(this, bucket.tenant, bucket.name, objv_tracker);
8474 if (r < 0)
8475 return r;
8476
8477 /* if the bucket is not synced we can remove the meta file */
8478 if (!is_syncing_bucket_meta(bucket)) {
8479 RGWObjVersionTracker objv_tracker;
8480 string entry = bucket.get_key();
8481 r= rgw_bucket_instance_remove_entry(this, entry, &objv_tracker);
8482 if (r < 0) {
8483 return r;
8484 }
8485 /* remove bucket index objects*/
8486 map<int, string>::const_iterator biter;
8487 for (biter = bucket_objs.begin(); biter != bucket_objs.end(); ++biter) {
8488 index_ctx.remove(biter->second);
8489 }
8490 }
8491 return 0;
8492 }
8493
8494 int RGWRados::set_bucket_owner(rgw_bucket& bucket, ACLOwner& owner)
8495 {
8496 RGWBucketInfo info;
8497 map<string, bufferlist> attrs;
8498 RGWObjectCtx obj_ctx(this);
8499 int r;
8500 if (bucket.bucket_id.empty()) {
8501 r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, &attrs);
8502 } else {
8503 r = get_bucket_instance_info(obj_ctx, bucket, info, nullptr, &attrs);
8504 }
8505 if (r < 0) {
8506 ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl;
8507 return r;
8508 }
8509
8510 info.owner = owner.get_id();
8511
8512 r = put_bucket_instance_info(info, false, real_time(), &attrs);
8513 if (r < 0) {
8514 ldout(cct, 0) << "NOTICE: put_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl;
8515 return r;
8516 }
8517
8518 return 0;
8519 }
8520
8521
8522 int RGWRados::set_buckets_enabled(vector<rgw_bucket>& buckets, bool enabled)
8523 {
8524 int ret = 0;
8525
8526 vector<rgw_bucket>::iterator iter;
8527
8528 for (iter = buckets.begin(); iter != buckets.end(); ++iter) {
8529 rgw_bucket& bucket = *iter;
8530 if (enabled)
8531 ldout(cct, 20) << "enabling bucket name=" << bucket.name << dendl;
8532 else
8533 ldout(cct, 20) << "disabling bucket name=" << bucket.name << dendl;
8534
8535 RGWBucketInfo info;
8536 map<string, bufferlist> attrs;
8537 RGWObjectCtx obj_ctx(this);
8538 int r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, &attrs);
8539 if (r < 0) {
8540 ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << ", skipping bucket" << dendl;
8541 ret = r;
8542 continue;
8543 }
8544 if (enabled) {
8545 info.flags &= ~BUCKET_SUSPENDED;
8546 } else {
8547 info.flags |= BUCKET_SUSPENDED;
8548 }
8549
8550 r = put_bucket_instance_info(info, false, real_time(), &attrs);
8551 if (r < 0) {
8552 ldout(cct, 0) << "NOTICE: put_bucket_info on bucket=" << bucket.name << " returned err=" << r << ", skipping bucket" << dendl;
8553 ret = r;
8554 continue;
8555 }
8556 }
8557 return ret;
8558 }
8559
8560 int RGWRados::bucket_suspended(rgw_bucket& bucket, bool *suspended)
8561 {
8562 RGWBucketInfo bucket_info;
8563 RGWObjectCtx obj_ctx(this);
8564 int ret = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, bucket_info, NULL);
8565 if (ret < 0) {
8566 return ret;
8567 }
8568
8569 *suspended = ((bucket_info.flags & BUCKET_SUSPENDED) != 0);
8570 return 0;
8571 }
8572
8573 int RGWRados::Object::complete_atomic_modification()
8574 {
8575 if (!state->has_manifest || state->keep_tail)
8576 return 0;
8577
8578 cls_rgw_obj_chain chain;
8579 store->update_gc_chain(obj, state->manifest, &chain);
8580
8581 if (chain.empty()) {
8582 return 0;
8583 }
8584
8585 string tag = (state->tail_tag.length() > 0 ? state->tail_tag.to_str() : state->obj_tag.to_str());
8586 return store->gc->send_chain(chain, tag, false); // do it async
8587 }
8588
8589 void RGWRados::update_gc_chain(rgw_obj& head_obj, RGWObjManifest& manifest, cls_rgw_obj_chain *chain)
8590 {
8591 RGWObjManifest::obj_iterator iter;
8592 rgw_raw_obj raw_head;
8593 obj_to_raw(manifest.get_head_placement_rule(), head_obj, &raw_head);
8594 for (iter = manifest.obj_begin(); iter != manifest.obj_end(); ++iter) {
8595 const rgw_raw_obj& mobj = iter.get_location().get_raw_obj(this);
8596 if (mobj == raw_head)
8597 continue;
8598 cls_rgw_obj_key key(mobj.oid);
8599 chain->push_obj(mobj.pool.to_str(), key, mobj.loc);
8600 }
8601 }
8602
8603 int RGWRados::send_chain_to_gc(cls_rgw_obj_chain& chain, const string& tag, bool sync)
8604 {
8605 return gc->send_chain(chain, tag, sync);
8606 }
8607
8608 int RGWRados::open_bucket_index(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx, string& bucket_oid)
8609 {
8610 const rgw_bucket& bucket = bucket_info.bucket;
8611 int r = open_bucket_index_ctx(bucket_info, index_ctx);
8612 if (r < 0)
8613 return r;
8614
8615 if (bucket.bucket_id.empty()) {
8616 ldout(cct, 0) << "ERROR: empty bucket id for bucket operation" << dendl;
8617 return -EIO;
8618 }
8619
8620 bucket_oid = dir_oid_prefix;
8621 bucket_oid.append(bucket.bucket_id);
8622
8623 return 0;
8624 }
8625
8626 int RGWRados::open_bucket_index_base(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx,
8627 string& bucket_oid_base) {
8628 const rgw_bucket& bucket = bucket_info.bucket;
8629 int r = open_bucket_index_ctx(bucket_info, index_ctx);
8630 if (r < 0)
8631 return r;
8632
8633 if (bucket.bucket_id.empty()) {
8634 ldout(cct, 0) << "ERROR: empty bucket_id for bucket operation" << dendl;
8635 return -EIO;
8636 }
8637
8638 bucket_oid_base = dir_oid_prefix;
8639 bucket_oid_base.append(bucket.bucket_id);
8640
8641 return 0;
8642
8643 }
8644
8645 int RGWRados::open_bucket_index(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx,
8646 map<int, string>& bucket_objs, int shard_id, map<int, string> *bucket_instance_ids) {
8647 string bucket_oid_base;
8648 int ret = open_bucket_index_base(bucket_info, index_ctx, bucket_oid_base);
8649 if (ret < 0) {
8650 return ret;
8651 }
8652
8653 get_bucket_index_objects(bucket_oid_base, bucket_info.num_shards, bucket_objs, shard_id);
8654 if (bucket_instance_ids) {
8655 get_bucket_instance_ids(bucket_info, shard_id, bucket_instance_ids);
8656 }
8657 return 0;
8658 }
8659
8660 template<typename T>
8661 int RGWRados::open_bucket_index(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx,
8662 map<int, string>& oids, map<int, T>& bucket_objs,
8663 int shard_id, map<int, string> *bucket_instance_ids)
8664 {
8665 int ret = open_bucket_index(bucket_info, index_ctx, oids, shard_id, bucket_instance_ids);
8666 if (ret < 0)
8667 return ret;
8668
8669 map<int, string>::const_iterator iter = oids.begin();
8670 for (; iter != oids.end(); ++iter) {
8671 bucket_objs[iter->first] = T();
8672 }
8673 return 0;
8674 }
8675
8676 int RGWRados::open_bucket_index_shard(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx,
8677 const string& obj_key, string *bucket_obj, int *shard_id)
8678 {
8679 string bucket_oid_base;
8680 int ret = open_bucket_index_base(bucket_info, index_ctx, bucket_oid_base);
8681 if (ret < 0)
8682 return ret;
8683
8684 RGWObjectCtx obj_ctx(this);
8685
8686 ret = get_bucket_index_object(bucket_oid_base, obj_key, bucket_info.num_shards,
8687 (RGWBucketInfo::BIShardsHashType)bucket_info.bucket_index_shard_hash_type, bucket_obj, shard_id);
8688 if (ret < 0) {
8689 ldout(cct, 10) << "get_bucket_index_object() returned ret=" << ret << dendl;
8690 return ret;
8691 }
8692 return 0;
8693 }
8694
8695 int RGWRados::open_bucket_index_shard(const RGWBucketInfo& bucket_info, librados::IoCtx& index_ctx,
8696 int shard_id, string *bucket_obj)
8697 {
8698 string bucket_oid_base;
8699 int ret = open_bucket_index_base(bucket_info, index_ctx, bucket_oid_base);
8700 if (ret < 0)
8701 return ret;
8702
8703 RGWObjectCtx obj_ctx(this);
8704
8705 get_bucket_index_object(bucket_oid_base, bucket_info.num_shards,
8706 shard_id, bucket_obj);
8707 return 0;
8708 }
8709
8710 static void accumulate_raw_stats(const rgw_bucket_dir_header& header,
8711 map<RGWObjCategory, RGWStorageStats>& stats)
8712 {
8713 for (const auto& pair : header.stats) {
8714 const RGWObjCategory category = static_cast<RGWObjCategory>(pair.first);
8715 const rgw_bucket_category_stats& header_stats = pair.second;
8716
8717 RGWStorageStats& s = stats[category];
8718
8719 s.category = category;
8720 s.size += header_stats.total_size;
8721 s.size_rounded += header_stats.total_size_rounded;
8722 s.size_utilized += header_stats.actual_size;
8723 s.num_objects += header_stats.num_entries;
8724 }
8725 }
8726
8727 int RGWRados::bucket_check_index(RGWBucketInfo& bucket_info,
8728 map<RGWObjCategory, RGWStorageStats> *existing_stats,
8729 map<RGWObjCategory, RGWStorageStats> *calculated_stats)
8730 {
8731 librados::IoCtx index_ctx;
8732 // key - bucket index object id
8733 // value - bucket index check OP returned result with the given bucket index object (shard)
8734 map<int, string> oids;
8735 map<int, struct rgw_cls_check_index_ret> bucket_objs_ret;
8736
8737 int ret = open_bucket_index(bucket_info, index_ctx, oids, bucket_objs_ret);
8738 if (ret < 0) {
8739 return ret;
8740 }
8741
8742 ret = CLSRGWIssueBucketCheck(index_ctx, oids, bucket_objs_ret, cct->_conf->rgw_bucket_index_max_aio)();
8743 if (ret < 0) {
8744 return ret;
8745 }
8746
8747 // Aggregate results (from different shards if there is any)
8748 map<int, struct rgw_cls_check_index_ret>::iterator iter;
8749 for (iter = bucket_objs_ret.begin(); iter != bucket_objs_ret.end(); ++iter) {
8750 accumulate_raw_stats(iter->second.existing_header, *existing_stats);
8751 accumulate_raw_stats(iter->second.calculated_header, *calculated_stats);
8752 }
8753
8754 return 0;
8755 }
8756
8757 int RGWRados::bucket_rebuild_index(RGWBucketInfo& bucket_info)
8758 {
8759 librados::IoCtx index_ctx;
8760 map<int, string> bucket_objs;
8761
8762 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs);
8763 if (r < 0) {
8764 return r;
8765 }
8766
8767 return CLSRGWIssueBucketRebuild(index_ctx, bucket_objs, cct->_conf->rgw_bucket_index_max_aio)();
8768 }
8769
8770 int RGWRados::bucket_set_reshard(RGWBucketInfo& bucket_info, const cls_rgw_bucket_instance_entry& entry)
8771 {
8772 librados::IoCtx index_ctx;
8773 map<int, string> bucket_objs;
8774
8775 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs);
8776 if (r < 0) {
8777 return r;
8778 }
8779
8780 return CLSRGWIssueSetBucketResharding(index_ctx, bucket_objs, entry, cct->_conf->rgw_bucket_index_max_aio)();
8781 }
8782
8783 int RGWRados::defer_gc(void *ctx, const RGWBucketInfo& bucket_info, const rgw_obj& obj)
8784 {
8785 RGWObjectCtx *rctx = static_cast<RGWObjectCtx *>(ctx);
8786 std::string oid, key;
8787 get_obj_bucket_and_oid_loc(obj, oid, key);
8788 if (!rctx)
8789 return 0;
8790
8791 RGWObjState *state = NULL;
8792
8793 int r = get_obj_state(rctx, bucket_info, obj, &state, false);
8794 if (r < 0)
8795 return r;
8796
8797 if (!state->is_atomic) {
8798 ldout(cct, 20) << "state for obj=" << obj << " is not atomic, not deferring gc operation" << dendl;
8799 return -EINVAL;
8800 }
8801
8802 string tag;
8803
8804 if (state->tail_tag.length() > 0) {
8805 tag = state->tail_tag.c_str();
8806 } else if (state->obj_tag.length() > 0) {
8807 tag = state->obj_tag.c_str();
8808 } else {
8809 ldout(cct, 20) << "state->obj_tag is empty, not deferring gc operation" << dendl;
8810 return -EINVAL;
8811 }
8812
8813 ldout(cct, 0) << "defer chain tag=" << tag << dendl;
8814
8815 return gc->defer_chain(tag, false);
8816 }
8817
8818 void RGWRados::remove_rgw_head_obj(ObjectWriteOperation& op)
8819 {
8820 list<string> prefixes;
8821 prefixes.push_back(RGW_ATTR_OLH_PREFIX);
8822 cls_rgw_remove_obj(op, prefixes);
8823 }
8824
8825 void RGWRados::cls_obj_check_prefix_exist(ObjectOperation& op, const string& prefix, bool fail_if_exist)
8826 {
8827 cls_rgw_obj_check_attrs_prefix(op, prefix, fail_if_exist);
8828 }
8829
8830 void RGWRados::cls_obj_check_mtime(ObjectOperation& op, const real_time& mtime, bool high_precision_time, RGWCheckMTimeType type)
8831 {
8832 cls_rgw_obj_check_mtime(op, mtime, high_precision_time, type);
8833 }
8834
8835
8836 /**
8837 * Delete an object.
8838 * bucket: name of the bucket storing the object
8839 * obj: name of the object to delete
8840 * Returns: 0 on success, -ERR# otherwise.
8841 */
8842 int RGWRados::Object::Delete::delete_obj()
8843 {
8844 RGWRados *store = target->get_store();
8845 rgw_obj& src_obj = target->get_obj();
8846 const string& instance = src_obj.key.instance;
8847 rgw_obj obj = src_obj;
8848
8849 if (instance == "null") {
8850 obj.key.instance.clear();
8851 }
8852
8853 bool explicit_marker_version = (!params.marker_version_id.empty());
8854
8855 if (params.versioning_status & BUCKET_VERSIONED || explicit_marker_version) {
8856 if (instance.empty() || explicit_marker_version) {
8857 rgw_obj marker = obj;
8858
8859 if (!params.marker_version_id.empty()) {
8860 if (params.marker_version_id != "null") {
8861 marker.key.set_instance(params.marker_version_id);
8862 }
8863 } else if ((params.versioning_status & BUCKET_VERSIONS_SUSPENDED) == 0) {
8864 store->gen_rand_obj_instance_name(&marker);
8865 }
8866
8867 result.version_id = marker.key.instance;
8868 result.delete_marker = true;
8869
8870 struct rgw_bucket_dir_entry_meta meta;
8871
8872 meta.owner = params.obj_owner.get_id().to_str();
8873 meta.owner_display_name = params.obj_owner.get_display_name();
8874
8875 if (real_clock::is_zero(params.mtime)) {
8876 meta.mtime = real_clock::now();
8877 } else {
8878 meta.mtime = params.mtime;
8879 }
8880
8881 int r = store->set_olh(target->get_ctx(), target->get_bucket_info(), marker, true, &meta, params.olh_epoch, params.unmod_since, params.high_precision_time, params.zones_trace);
8882 if (r < 0) {
8883 return r;
8884 }
8885 } else {
8886 rgw_bucket_dir_entry dirent;
8887
8888 int r = store->bi_get_instance(target->get_bucket_info(), obj, &dirent);
8889 if (r < 0) {
8890 return r;
8891 }
8892 result.delete_marker = dirent.is_delete_marker();
8893 r = store->unlink_obj_instance(target->get_ctx(), target->get_bucket_info(), obj, params.olh_epoch, params.zones_trace);
8894 if (r < 0) {
8895 return r;
8896 }
8897 result.version_id = instance;
8898 }
8899
8900 BucketShard *bs;
8901 int r = target->get_bucket_shard(&bs);
8902 if (r < 0) {
8903 ldout(store->ctx(), 5) << "failed to get BucketShard object: r=" << r << dendl;
8904 return r;
8905 }
8906
8907 if (target->bucket_info.datasync_flag_enabled()) {
8908 r = store->data_log->add_entry(bs->bucket, bs->shard_id);
8909 if (r < 0) {
8910 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
8911 return r;
8912 }
8913 }
8914
8915 return 0;
8916 }
8917
8918 rgw_rados_ref ref;
8919 int r = store->get_obj_head_ref(target->get_bucket_info(), obj, &ref);
8920 if (r < 0) {
8921 return r;
8922 }
8923
8924 RGWObjState *state;
8925 r = target->get_state(&state, false);
8926 if (r < 0)
8927 return r;
8928
8929 ObjectWriteOperation op;
8930
8931 if (!real_clock::is_zero(params.unmod_since)) {
8932 struct timespec ctime = ceph::real_clock::to_timespec(state->mtime);
8933 struct timespec unmod = ceph::real_clock::to_timespec(params.unmod_since);
8934 if (!params.high_precision_time) {
8935 ctime.tv_nsec = 0;
8936 unmod.tv_nsec = 0;
8937 }
8938
8939 ldout(store->ctx(), 10) << "If-UnModified-Since: " << params.unmod_since << " Last-Modified: " << ctime << dendl;
8940 if (ctime > unmod) {
8941 return -ERR_PRECONDITION_FAILED;
8942 }
8943
8944 /* only delete object if mtime is less than or equal to params.unmod_since */
8945 store->cls_obj_check_mtime(op, params.unmod_since, params.high_precision_time, CLS_RGW_CHECK_TIME_MTIME_LE);
8946 }
8947 uint64_t obj_size = state->size;
8948
8949 if (!real_clock::is_zero(params.expiration_time)) {
8950 bufferlist bl;
8951 real_time delete_at;
8952
8953 if (state->get_attr(RGW_ATTR_DELETE_AT, bl)) {
8954 try {
8955 bufferlist::iterator iter = bl.begin();
8956 ::decode(delete_at, iter);
8957 } catch (buffer::error& err) {
8958 ldout(store->ctx(), 0) << "ERROR: couldn't decode RGW_ATTR_DELETE_AT" << dendl;
8959 return -EIO;
8960 }
8961
8962 if (params.expiration_time != delete_at) {
8963 return -ERR_PRECONDITION_FAILED;
8964 }
8965 } else {
8966 return -ERR_PRECONDITION_FAILED;
8967 }
8968 }
8969
8970 if (!state->exists) {
8971 target->invalidate_state();
8972 return -ENOENT;
8973 }
8974
8975 r = target->prepare_atomic_modification(op, false, NULL, NULL, NULL, true, false);
8976 if (r < 0)
8977 return r;
8978
8979 RGWBucketInfo& bucket_info = target->get_bucket_info();
8980
8981 RGWRados::Bucket bop(store, bucket_info);
8982 RGWRados::Bucket::UpdateIndex index_op(&bop, obj);
8983
8984 index_op.set_zones_trace(params.zones_trace);
8985 index_op.set_bilog_flags(params.bilog_flags);
8986
8987 r = index_op.prepare(CLS_RGW_OP_DEL, &state->write_tag);
8988 if (r < 0)
8989 return r;
8990
8991 store->remove_rgw_head_obj(op);
8992 r = ref.ioctx.operate(ref.oid, &op);
8993 bool need_invalidate = false;
8994 if (r == -ECANCELED) {
8995 /* raced with another operation, we can regard it as removed */
8996 need_invalidate = true;
8997 r = 0;
8998 }
8999
9000 int64_t poolid = ref.ioctx.get_id();
9001 if (r >= 0) {
9002 tombstone_cache_t *obj_tombstone_cache = store->get_tombstone_cache();
9003 if (obj_tombstone_cache) {
9004 tombstone_entry entry{*state};
9005 obj_tombstone_cache->add(obj, entry);
9006 }
9007 r = index_op.complete_del(poolid, ref.ioctx.get_last_version(), state->mtime, params.remove_objs);
9008
9009 int ret = target->complete_atomic_modification();
9010 if (ret < 0) {
9011 ldout(store->ctx(), 0) << "ERROR: complete_atomic_modification returned ret=" << ret << dendl;
9012 }
9013 /* other than that, no need to propagate error */
9014 } else {
9015 int ret = index_op.cancel();
9016 if (ret < 0) {
9017 ldout(store->ctx(), 0) << "ERROR: index_op.cancel() returned ret=" << ret << dendl;
9018 }
9019 }
9020
9021 if (need_invalidate) {
9022 target->invalidate_state();
9023 }
9024
9025 if (r < 0)
9026 return r;
9027
9028 /* update quota cache */
9029 store->quota_handler->update_stats(params.bucket_owner, obj.bucket, -1, 0, obj_size);
9030
9031 return 0;
9032 }
9033
9034 int RGWRados::delete_obj(RGWObjectCtx& obj_ctx,
9035 const RGWBucketInfo& bucket_info,
9036 const rgw_obj& obj,
9037 int versioning_status,
9038 uint16_t bilog_flags,
9039 const real_time& expiration_time,
9040 rgw_zone_set *zones_trace)
9041 {
9042 RGWRados::Object del_target(this, bucket_info, obj_ctx, obj);
9043 RGWRados::Object::Delete del_op(&del_target);
9044
9045 del_op.params.bucket_owner = bucket_info.owner;
9046 del_op.params.versioning_status = versioning_status;
9047 del_op.params.bilog_flags = bilog_flags;
9048 del_op.params.expiration_time = expiration_time;
9049 del_op.params.zones_trace = zones_trace;
9050
9051 return del_op.delete_obj();
9052 }
9053
9054 int RGWRados::delete_raw_obj(const rgw_raw_obj& obj)
9055 {
9056 rgw_rados_ref ref;
9057 int r = get_raw_obj_ref(obj, &ref);
9058 if (r < 0) {
9059 return r;
9060 }
9061
9062 ObjectWriteOperation op;
9063
9064 op.remove();
9065 r = ref.ioctx.operate(ref.oid, &op);
9066 if (r < 0)
9067 return r;
9068
9069 return 0;
9070 }
9071
9072 int RGWRados::delete_system_obj(rgw_raw_obj& obj, RGWObjVersionTracker *objv_tracker)
9073 {
9074 if (obj.empty()) {
9075 ldout(cct, 1) << "delete_system_obj got empty object name "
9076 << obj << ", returning EINVAL" << dendl;
9077 return -EINVAL;
9078 }
9079 rgw_rados_ref ref;
9080 int r = get_raw_obj_ref(obj, &ref);
9081 if (r < 0) {
9082 return r;
9083 }
9084
9085 ObjectWriteOperation op;
9086
9087 if (objv_tracker) {
9088 objv_tracker->prepare_op_for_write(&op);
9089 }
9090
9091 op.remove();
9092 r = ref.ioctx.operate(ref.oid, &op);
9093 if (r < 0)
9094 return r;
9095
9096 return 0;
9097 }
9098
9099 int RGWRados::delete_obj_index(const rgw_obj& obj)
9100 {
9101 std::string oid, key;
9102 get_obj_bucket_and_oid_loc(obj, oid, key);
9103
9104 RGWObjectCtx obj_ctx(this);
9105
9106 RGWBucketInfo bucket_info;
9107 int ret = get_bucket_instance_info(obj_ctx, obj.bucket, bucket_info, NULL, NULL);
9108 if (ret < 0) {
9109 ldout(cct, 0) << "ERROR: " << __func__ << "() get_bucket_instance_info(bucket=" << obj.bucket << ") returned ret=" << ret << dendl;
9110 return ret;
9111 }
9112
9113 RGWRados::Bucket bop(this, bucket_info);
9114 RGWRados::Bucket::UpdateIndex index_op(&bop, obj);
9115
9116 real_time removed_mtime;
9117 int r = index_op.complete_del(-1 /* pool */, 0, removed_mtime, NULL);
9118
9119 return r;
9120 }
9121
9122 static void generate_fake_tag(RGWRados *store, map<string, bufferlist>& attrset, RGWObjManifest& manifest, bufferlist& manifest_bl, bufferlist& tag_bl)
9123 {
9124 string tag;
9125
9126 RGWObjManifest::obj_iterator mi = manifest.obj_begin();
9127 if (mi != manifest.obj_end()) {
9128 if (manifest.has_tail()) // first object usually points at the head, let's skip to a more unique part
9129 ++mi;
9130 tag = mi.get_location().get_raw_obj(store).oid;
9131 tag.append("_");
9132 }
9133
9134 unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE];
9135 char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
9136 MD5 hash;
9137 hash.Update((const byte *)manifest_bl.c_str(), manifest_bl.length());
9138
9139 map<string, bufferlist>::iterator iter = attrset.find(RGW_ATTR_ETAG);
9140 if (iter != attrset.end()) {
9141 bufferlist& bl = iter->second;
9142 hash.Update((const byte *)bl.c_str(), bl.length());
9143 }
9144
9145 hash.Final(md5);
9146 buf_to_hex(md5, CEPH_CRYPTO_MD5_DIGESTSIZE, md5_str);
9147 tag.append(md5_str);
9148
9149 ldout(store->ctx(), 10) << "generate_fake_tag new tag=" << tag << dendl;
9150
9151 tag_bl.append(tag.c_str(), tag.size() + 1);
9152 }
9153
9154 static bool is_olh(map<string, bufferlist>& attrs)
9155 {
9156 map<string, bufferlist>::iterator iter = attrs.find(RGW_ATTR_OLH_INFO);
9157 return (iter != attrs.end());
9158 }
9159
9160 static bool has_olh_tag(map<string, bufferlist>& attrs)
9161 {
9162 map<string, bufferlist>::iterator iter = attrs.find(RGW_ATTR_OLH_ID_TAG);
9163 return (iter != attrs.end());
9164 }
9165
9166 int RGWRados::get_olh_target_state(RGWObjectCtx& obj_ctx, const RGWBucketInfo& bucket_info, const rgw_obj& obj,
9167 RGWObjState *olh_state, RGWObjState **target_state)
9168 {
9169 assert(olh_state->is_olh);
9170
9171 rgw_obj target;
9172 int r = RGWRados::follow_olh(bucket_info, obj_ctx, olh_state, obj, &target); /* might return -EAGAIN */
9173 if (r < 0) {
9174 return r;
9175 }
9176 r = get_obj_state(&obj_ctx, bucket_info, target, target_state, false);
9177 if (r < 0) {
9178 return r;
9179 }
9180
9181 return 0;
9182 }
9183
9184 int RGWRados::get_system_obj_state_impl(RGWObjectCtx *rctx, rgw_raw_obj& obj, RGWRawObjState **state, RGWObjVersionTracker *objv_tracker)
9185 {
9186 if (obj.empty()) {
9187 return -EINVAL;
9188 }
9189
9190 RGWRawObjState *s = rctx->raw.get_state(obj);
9191 ldout(cct, 20) << "get_system_obj_state: rctx=" << (void *)rctx << " obj=" << obj << " state=" << (void *)s << " s->prefetch_data=" << s->prefetch_data << dendl;
9192 *state = s;
9193 if (s->has_attrs) {
9194 return 0;
9195 }
9196
9197 s->obj = obj;
9198
9199 int r = raw_obj_stat(obj, &s->size, &s->mtime, &s->epoch, &s->attrset, (s->prefetch_data ? &s->data : NULL), objv_tracker);
9200 if (r == -ENOENT) {
9201 s->exists = false;
9202 s->has_attrs = true;
9203 s->mtime = real_time();
9204 return 0;
9205 }
9206 if (r < 0)
9207 return r;
9208
9209 s->exists = true;
9210 s->has_attrs = true;
9211 s->obj_tag = s->attrset[RGW_ATTR_ID_TAG];
9212
9213 if (s->obj_tag.length())
9214 ldout(cct, 20) << "get_system_obj_state: setting s->obj_tag to "
9215 << s->obj_tag.c_str() << dendl;
9216 else
9217 ldout(cct, 20) << "get_system_obj_state: s->obj_tag was set empty" << dendl;
9218
9219 return 0;
9220 }
9221
9222 int RGWRados::get_system_obj_state(RGWObjectCtx *rctx, rgw_raw_obj& obj, RGWRawObjState **state, RGWObjVersionTracker *objv_tracker)
9223 {
9224 int ret;
9225
9226 do {
9227 ret = get_system_obj_state_impl(rctx, obj, state, objv_tracker);
9228 } while (ret == -EAGAIN);
9229
9230 return ret;
9231 }
9232
9233 int RGWRados::get_obj_state_impl(RGWObjectCtx *rctx, const RGWBucketInfo& bucket_info, const rgw_obj& obj,
9234 RGWObjState **state, bool follow_olh, bool assume_noent)
9235 {
9236 if (obj.empty()) {
9237 return -EINVAL;
9238 }
9239
9240 bool need_follow_olh = follow_olh && obj.key.instance.empty();
9241
9242 RGWObjState *s = rctx->obj.get_state(obj);
9243 ldout(cct, 20) << "get_obj_state: rctx=" << (void *)rctx << " obj=" << obj << " state=" << (void *)s << " s->prefetch_data=" << s->prefetch_data << dendl;
9244 *state = s;
9245 if (s->has_attrs) {
9246 if (s->is_olh && need_follow_olh) {
9247 return get_olh_target_state(*rctx, bucket_info, obj, s, state);
9248 }
9249 return 0;
9250 }
9251
9252 s->obj = obj;
9253
9254 rgw_raw_obj raw_obj;
9255 obj_to_raw(bucket_info.placement_rule, obj, &raw_obj);
9256
9257 int r = -ENOENT;
9258
9259 if (!assume_noent) {
9260 r = RGWRados::raw_obj_stat(raw_obj, &s->size, &s->mtime, &s->epoch, &s->attrset, (s->prefetch_data ? &s->data : NULL), NULL);
9261 }
9262
9263 if (r == -ENOENT) {
9264 s->exists = false;
9265 s->has_attrs = true;
9266 tombstone_entry entry;
9267 if (obj_tombstone_cache && obj_tombstone_cache->find(obj, entry)) {
9268 s->mtime = entry.mtime;
9269 s->zone_short_id = entry.zone_short_id;
9270 s->pg_ver = entry.pg_ver;
9271 ldout(cct, 20) << __func__ << "(): found obj in tombstone cache: obj=" << obj
9272 << " mtime=" << s->mtime << " pgv=" << s->pg_ver << dendl;
9273 } else {
9274 s->mtime = real_time();
9275 }
9276 return 0;
9277 }
9278 if (r < 0)
9279 return r;
9280
9281 s->exists = true;
9282 s->has_attrs = true;
9283 s->accounted_size = s->size;
9284
9285 auto iter = s->attrset.find(RGW_ATTR_COMPRESSION);
9286 const bool compressed = (iter != s->attrset.end());
9287 if (compressed) {
9288 // use uncompressed size for accounted_size
9289 try {
9290 RGWCompressionInfo info;
9291 auto p = iter->second.begin();
9292 ::decode(info, p);
9293 s->accounted_size = info.orig_size;
9294 } catch (buffer::error&) {
9295 dout(0) << "ERROR: could not decode compression info for object: " << obj << dendl;
9296 return -EIO;
9297 }
9298 }
9299
9300 iter = s->attrset.find(RGW_ATTR_SHADOW_OBJ);
9301 if (iter != s->attrset.end()) {
9302 bufferlist bl = iter->second;
9303 bufferlist::iterator it = bl.begin();
9304 it.copy(bl.length(), s->shadow_obj);
9305 s->shadow_obj[bl.length()] = '\0';
9306 }
9307 s->obj_tag = s->attrset[RGW_ATTR_ID_TAG];
9308 auto ttiter = s->attrset.find(RGW_ATTR_TAIL_TAG);
9309 if (ttiter != s->attrset.end()) {
9310 s->tail_tag = s->attrset[RGW_ATTR_TAIL_TAG];
9311 }
9312
9313 bufferlist manifest_bl = s->attrset[RGW_ATTR_MANIFEST];
9314 if (manifest_bl.length()) {
9315 bufferlist::iterator miter = manifest_bl.begin();
9316 try {
9317 ::decode(s->manifest, miter);
9318 s->has_manifest = true;
9319 s->manifest.set_head(bucket_info.placement_rule, obj, s->size); /* patch manifest to reflect the head we just read, some manifests might be
9320 broken due to old bugs */
9321 s->size = s->manifest.get_obj_size();
9322 if (!compressed)
9323 s->accounted_size = s->size;
9324 } catch (buffer::error& err) {
9325 ldout(cct, 0) << "ERROR: couldn't decode manifest" << dendl;
9326 return -EIO;
9327 }
9328 ldout(cct, 10) << "manifest: total_size = " << s->manifest.get_obj_size() << dendl;
9329 if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20) && s->manifest.has_explicit_objs()) {
9330 RGWObjManifest::obj_iterator mi;
9331 for (mi = s->manifest.obj_begin(); mi != s->manifest.obj_end(); ++mi) {
9332 ldout(cct, 20) << "manifest: ofs=" << mi.get_ofs() << " loc=" << mi.get_location().get_raw_obj(this) << dendl;
9333 }
9334 }
9335
9336 if (!s->obj_tag.length()) {
9337 /*
9338 * Uh oh, something's wrong, object with manifest should have tag. Let's
9339 * create one out of the manifest, would be unique
9340 */
9341 generate_fake_tag(this, s->attrset, s->manifest, manifest_bl, s->obj_tag);
9342 s->fake_tag = true;
9343 }
9344 }
9345 map<string, bufferlist>::iterator aiter = s->attrset.find(RGW_ATTR_PG_VER);
9346 if (aiter != s->attrset.end()) {
9347 bufferlist& pg_ver_bl = aiter->second;
9348 if (pg_ver_bl.length()) {
9349 bufferlist::iterator pgbl = pg_ver_bl.begin();
9350 try {
9351 ::decode(s->pg_ver, pgbl);
9352 } catch (buffer::error& err) {
9353 ldout(cct, 0) << "ERROR: couldn't decode pg ver attr for object " << s->obj << ", non-critical error, ignoring" << dendl;
9354 }
9355 }
9356 }
9357 aiter = s->attrset.find(RGW_ATTR_SOURCE_ZONE);
9358 if (aiter != s->attrset.end()) {
9359 bufferlist& zone_short_id_bl = aiter->second;
9360 if (zone_short_id_bl.length()) {
9361 bufferlist::iterator zbl = zone_short_id_bl.begin();
9362 try {
9363 ::decode(s->zone_short_id, zbl);
9364 } catch (buffer::error& err) {
9365 ldout(cct, 0) << "ERROR: couldn't decode zone short id attr for object " << s->obj << ", non-critical error, ignoring" << dendl;
9366 }
9367 }
9368 }
9369 if (s->obj_tag.length())
9370 ldout(cct, 20) << "get_obj_state: setting s->obj_tag to " << s->obj_tag.c_str() << dendl;
9371 else
9372 ldout(cct, 20) << "get_obj_state: s->obj_tag was set empty" << dendl;
9373
9374 /* an object might not be olh yet, but could have olh id tag, so we should set it anyway if
9375 * it exist, and not only if is_olh() returns true
9376 */
9377 iter = s->attrset.find(RGW_ATTR_OLH_ID_TAG);
9378 if (iter != s->attrset.end()) {
9379 s->olh_tag = iter->second;
9380 }
9381
9382 if (is_olh(s->attrset)) {
9383 s->is_olh = true;
9384
9385 ldout(cct, 20) << __func__ << ": setting s->olh_tag to " << string(s->olh_tag.c_str(), s->olh_tag.length()) << dendl;
9386
9387 if (need_follow_olh) {
9388 return get_olh_target_state(*rctx, bucket_info, obj, s, state);
9389 }
9390 }
9391
9392 return 0;
9393 }
9394
9395 int RGWRados::get_obj_state(RGWObjectCtx *rctx, const RGWBucketInfo& bucket_info, const rgw_obj& obj, RGWObjState **state,
9396 bool follow_olh, bool assume_noent)
9397 {
9398 int ret;
9399
9400 do {
9401 ret = get_obj_state_impl(rctx, bucket_info, obj, state, follow_olh, assume_noent);
9402 } while (ret == -EAGAIN);
9403
9404 return ret;
9405 }
9406
9407 int RGWRados::Object::get_manifest(RGWObjManifest **pmanifest)
9408 {
9409 RGWObjState *astate;
9410 int r = get_state(&astate, true);
9411 if (r < 0) {
9412 return r;
9413 }
9414
9415 *pmanifest = &astate->manifest;
9416
9417 return 0;
9418 }
9419
9420 int RGWRados::Object::Read::get_attr(const char *name, bufferlist& dest)
9421 {
9422 RGWObjState *state;
9423 int r = source->get_state(&state, true);
9424 if (r < 0)
9425 return r;
9426 if (!state->exists)
9427 return -ENOENT;
9428 if (!state->get_attr(name, dest))
9429 return -ENODATA;
9430
9431 return 0;
9432 }
9433
9434
9435 int RGWRados::Object::Stat::stat_async()
9436 {
9437 RGWObjectCtx& ctx = source->get_ctx();
9438 rgw_obj& obj = source->get_obj();
9439 RGWRados *store = source->get_store();
9440
9441 RGWObjState *s = ctx.obj.get_state(obj); /* calling this one directly because otherwise a sync request will be sent */
9442 result.obj = obj;
9443 if (s->has_attrs) {
9444 state.ret = 0;
9445 result.size = s->size;
9446 result.mtime = ceph::real_clock::to_timespec(s->mtime);
9447 result.attrs = s->attrset;
9448 result.has_manifest = s->has_manifest;
9449 result.manifest = s->manifest;
9450 return 0;
9451 }
9452
9453 string oid;
9454 string loc;
9455 get_obj_bucket_and_oid_loc(obj, oid, loc);
9456
9457 int r = store->get_obj_head_ioctx(source->get_bucket_info(), obj, &state.io_ctx);
9458 if (r < 0) {
9459 return r;
9460 }
9461
9462 librados::ObjectReadOperation op;
9463 op.stat2(&result.size, &result.mtime, NULL);
9464 op.getxattrs(&result.attrs, NULL);
9465 state.completion = librados::Rados::aio_create_completion(NULL, NULL, NULL);
9466 state.io_ctx.locator_set_key(loc);
9467 r = state.io_ctx.aio_operate(oid, state.completion, &op, NULL);
9468 if (r < 0) {
9469 ldout(store->ctx(), 5) << __func__
9470 << ": ERROR: aio_operate() returned ret=" << r
9471 << dendl;
9472 return r;
9473 }
9474
9475 return 0;
9476 }
9477
9478
9479 int RGWRados::Object::Stat::wait()
9480 {
9481 if (!state.completion) {
9482 return state.ret;
9483 }
9484
9485 state.completion->wait_for_safe();
9486 state.ret = state.completion->get_return_value();
9487 state.completion->release();
9488
9489 if (state.ret != 0) {
9490 return state.ret;
9491 }
9492
9493 return finish();
9494 }
9495
9496 int RGWRados::Object::Stat::finish()
9497 {
9498 map<string, bufferlist>::iterator iter = result.attrs.find(RGW_ATTR_MANIFEST);
9499 if (iter != result.attrs.end()) {
9500 bufferlist& bl = iter->second;
9501 bufferlist::iterator biter = bl.begin();
9502 try {
9503 ::decode(result.manifest, biter);
9504 } catch (buffer::error& err) {
9505 RGWRados *store = source->get_store();
9506 ldout(store->ctx(), 0) << "ERROR: " << __func__ << ": failed to decode manifest" << dendl;
9507 return -EIO;
9508 }
9509 result.has_manifest = true;
9510 }
9511
9512 return 0;
9513 }
9514
9515 /**
9516 * Get an attribute for a system object.
9517 * obj: the object to get attr
9518 * name: name of the attr to retrieve
9519 * dest: bufferlist to store the result in
9520 * Returns: 0 on success, -ERR# otherwise.
9521 */
9522 int RGWRados::system_obj_get_attr(rgw_raw_obj& obj, const char *name, bufferlist& dest)
9523 {
9524 rgw_rados_ref ref;
9525 int r = get_system_obj_ref(obj, &ref);
9526 if (r < 0) {
9527 return r;
9528 }
9529
9530 ObjectReadOperation op;
9531
9532 int rval;
9533 op.getxattr(name, &dest, &rval);
9534
9535 r = ref.ioctx.operate(ref.oid, &op, NULL);
9536 if (r < 0)
9537 return r;
9538
9539 return 0;
9540 }
9541
9542 int RGWRados::append_atomic_test(RGWObjectCtx *rctx,
9543 const RGWBucketInfo& bucket_info, const rgw_obj& obj,
9544 ObjectOperation& op, RGWObjState **pstate)
9545 {
9546 if (!rctx)
9547 return 0;
9548
9549 int r = get_obj_state(rctx, bucket_info, obj, pstate, false);
9550 if (r < 0)
9551 return r;
9552
9553 RGWObjState *state = *pstate;
9554
9555 if (!state->is_atomic) {
9556 ldout(cct, 20) << "state for obj=" << obj << " is not atomic, not appending atomic test" << dendl;
9557 return 0;
9558 }
9559
9560 if (state->obj_tag.length() > 0 && !state->fake_tag) {// check for backward compatibility
9561 op.cmpxattr(RGW_ATTR_ID_TAG, LIBRADOS_CMPXATTR_OP_EQ, state->obj_tag);
9562 } else {
9563 ldout(cct, 20) << "state->obj_tag is empty, not appending atomic test" << dendl;
9564 }
9565 return 0;
9566 }
9567
9568 int RGWRados::Object::get_state(RGWObjState **pstate, bool follow_olh, bool assume_noent)
9569 {
9570 return store->get_obj_state(&ctx, bucket_info, obj, pstate, follow_olh, assume_noent);
9571 }
9572
9573 void RGWRados::Object::invalidate_state()
9574 {
9575 ctx.obj.invalidate(obj);
9576 }
9577
9578 void RGWRados::SystemObject::invalidate_state()
9579 {
9580 ctx.raw.invalidate(obj);
9581 }
9582
9583 int RGWRados::Object::prepare_atomic_modification(ObjectWriteOperation& op, bool reset_obj, const string *ptag,
9584 const char *if_match, const char *if_nomatch, bool removal_op,
9585 bool modify_tail)
9586 {
9587 int r = get_state(&state, false);
9588 if (r < 0)
9589 return r;
9590
9591 bool need_guard = (state->has_manifest || (state->obj_tag.length() != 0) ||
9592 if_match != NULL || if_nomatch != NULL) &&
9593 (!state->fake_tag);
9594
9595 if (!state->is_atomic) {
9596 ldout(store->ctx(), 20) << "prepare_atomic_modification: state is not atomic. state=" << (void *)state << dendl;
9597
9598 if (reset_obj) {
9599 op.create(false);
9600 store->remove_rgw_head_obj(op); // we're not dropping reference here, actually removing object
9601 }
9602
9603 return 0;
9604 }
9605
9606 if (need_guard) {
9607 /* first verify that the object wasn't replaced under */
9608 if (if_nomatch == NULL || strcmp(if_nomatch, "*") != 0) {
9609 op.cmpxattr(RGW_ATTR_ID_TAG, LIBRADOS_CMPXATTR_OP_EQ, state->obj_tag);
9610 // FIXME: need to add FAIL_NOTEXIST_OK for racing deletion
9611 }
9612
9613 if (if_match) {
9614 if (strcmp(if_match, "*") == 0) {
9615 // test the object is existing
9616 if (!state->exists) {
9617 return -ERR_PRECONDITION_FAILED;
9618 }
9619 } else {
9620 bufferlist bl;
9621 if (!state->get_attr(RGW_ATTR_ETAG, bl) ||
9622 strncmp(if_match, bl.c_str(), bl.length()) != 0) {
9623 return -ERR_PRECONDITION_FAILED;
9624 }
9625 }
9626 }
9627
9628 if (if_nomatch) {
9629 if (strcmp(if_nomatch, "*") == 0) {
9630 // test the object is NOT existing
9631 if (state->exists) {
9632 return -ERR_PRECONDITION_FAILED;
9633 }
9634 } else {
9635 bufferlist bl;
9636 if (!state->get_attr(RGW_ATTR_ETAG, bl) ||
9637 strncmp(if_nomatch, bl.c_str(), bl.length()) == 0) {
9638 return -ERR_PRECONDITION_FAILED;
9639 }
9640 }
9641 }
9642 }
9643
9644 if (reset_obj) {
9645 if (state->exists) {
9646 op.create(false);
9647 store->remove_rgw_head_obj(op);
9648 } else {
9649 op.create(true);
9650 }
9651 }
9652
9653 if (removal_op) {
9654 /* the object is being removed, no need to update its tag */
9655 return 0;
9656 }
9657
9658 if (ptag) {
9659 state->write_tag = *ptag;
9660 } else {
9661 append_rand_alpha(store->ctx(), state->write_tag, state->write_tag, 32);
9662 }
9663 bufferlist bl;
9664 bl.append(state->write_tag.c_str(), state->write_tag.size() + 1);
9665
9666 ldout(store->ctx(), 10) << "setting object write_tag=" << state->write_tag << dendl;
9667
9668 op.setxattr(RGW_ATTR_ID_TAG, bl);
9669 if (modify_tail) {
9670 op.setxattr(RGW_ATTR_TAIL_TAG, bl);
9671 }
9672
9673 return 0;
9674 }
9675
9676 int RGWRados::system_obj_set_attr(void *ctx, rgw_raw_obj& obj, const char *name, bufferlist& bl,
9677 RGWObjVersionTracker *objv_tracker)
9678 {
9679 map<string, bufferlist> attrs;
9680 attrs[name] = bl;
9681 return system_obj_set_attrs(ctx, obj, attrs, NULL, objv_tracker);
9682 }
9683
9684 int RGWRados::system_obj_set_attrs(void *ctx, rgw_raw_obj& obj,
9685 map<string, bufferlist>& attrs,
9686 map<string, bufferlist>* rmattrs,
9687 RGWObjVersionTracker *objv_tracker)
9688 {
9689 rgw_rados_ref ref;
9690 int r = get_system_obj_ref(obj, &ref);
9691 if (r < 0) {
9692 return r;
9693 }
9694 ObjectWriteOperation op;
9695
9696 if (objv_tracker) {
9697 objv_tracker->prepare_op_for_write(&op);
9698 }
9699
9700 map<string, bufferlist>::iterator iter;
9701 if (rmattrs) {
9702 for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) {
9703 const string& name = iter->first;
9704 op.rmxattr(name.c_str());
9705 }
9706 }
9707
9708 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
9709 const string& name = iter->first;
9710 bufferlist& bl = iter->second;
9711
9712 if (!bl.length())
9713 continue;
9714
9715 op.setxattr(name.c_str(), bl);
9716 }
9717
9718 if (!op.size())
9719 return 0;
9720
9721 bufferlist bl;
9722
9723 r = ref.ioctx.operate(ref.oid, &op);
9724 if (r < 0)
9725 return r;
9726
9727 return 0;
9728 }
9729
9730 /**
9731 * Set an attr on an object.
9732 * bucket: name of the bucket holding the object
9733 * obj: name of the object to set the attr on
9734 * name: the attr to set
9735 * bl: the contents of the attr
9736 * Returns: 0 on success, -ERR# otherwise.
9737 */
9738 int RGWRados::set_attr(void *ctx, const RGWBucketInfo& bucket_info, rgw_obj& obj, const char *name, bufferlist& bl)
9739 {
9740 map<string, bufferlist> attrs;
9741 attrs[name] = bl;
9742 return set_attrs(ctx, bucket_info, obj, attrs, NULL);
9743 }
9744
9745 int RGWRados::set_attrs(void *ctx, const RGWBucketInfo& bucket_info, rgw_obj& obj,
9746 map<string, bufferlist>& attrs,
9747 map<string, bufferlist>* rmattrs)
9748 {
9749 rgw_rados_ref ref;
9750 int r = get_obj_head_ref(bucket_info, obj, &ref);
9751 if (r < 0) {
9752 return r;
9753 }
9754 RGWObjectCtx *rctx = static_cast<RGWObjectCtx *>(ctx);
9755
9756 ObjectWriteOperation op;
9757 RGWObjState *state = NULL;
9758
9759 r = append_atomic_test(rctx, bucket_info, obj, op, &state);
9760 if (r < 0)
9761 return r;
9762
9763 map<string, bufferlist>::iterator iter;
9764 if (rmattrs) {
9765 for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) {
9766 const string& name = iter->first;
9767 op.rmxattr(name.c_str());
9768 }
9769 }
9770
9771 const rgw_bucket& bucket = obj.bucket;
9772
9773 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
9774 const string& name = iter->first;
9775 bufferlist& bl = iter->second;
9776
9777 if (!bl.length())
9778 continue;
9779
9780 op.setxattr(name.c_str(), bl);
9781
9782 if (name.compare(RGW_ATTR_DELETE_AT) == 0) {
9783 real_time ts;
9784 try {
9785 ::decode(ts, bl);
9786
9787 rgw_obj_index_key obj_key;
9788 obj.key.get_index_key(&obj_key);
9789
9790 objexp_hint_add(ts, bucket.tenant, bucket.name, bucket.bucket_id, obj_key);
9791 } catch (buffer::error& err) {
9792 ldout(cct, 0) << "ERROR: failed to decode " RGW_ATTR_DELETE_AT << " attr" << dendl;
9793 }
9794 }
9795 }
9796
9797 if (!op.size())
9798 return 0;
9799
9800 RGWObjectCtx obj_ctx(this);
9801
9802 bufferlist bl;
9803 RGWRados::Bucket bop(this, bucket_info);
9804 RGWRados::Bucket::UpdateIndex index_op(&bop, obj);
9805
9806 if (state) {
9807 string tag;
9808 append_rand_alpha(cct, tag, tag, 32);
9809 state->write_tag = tag;
9810 r = index_op.prepare(CLS_RGW_OP_ADD, &state->write_tag);
9811
9812 if (r < 0)
9813 return r;
9814
9815 bl.append(tag.c_str(), tag.size() + 1);
9816 op.setxattr(RGW_ATTR_ID_TAG, bl);
9817 }
9818
9819
9820 real_time mtime = real_clock::now();
9821 struct timespec mtime_ts = real_clock::to_timespec(mtime);
9822 op.mtime2(&mtime_ts);
9823 r = ref.ioctx.operate(ref.oid, &op);
9824 if (state) {
9825 if (r >= 0) {
9826 bufferlist acl_bl = attrs[RGW_ATTR_ACL];
9827 bufferlist etag_bl = attrs[RGW_ATTR_ETAG];
9828 bufferlist content_type_bl = attrs[RGW_ATTR_CONTENT_TYPE];
9829 string etag(etag_bl.c_str(), etag_bl.length());
9830 string content_type(content_type_bl.c_str(), content_type_bl.length());
9831 uint64_t epoch = ref.ioctx.get_last_version();
9832 int64_t poolid = ref.ioctx.get_id();
9833 r = index_op.complete(poolid, epoch, state->size, state->accounted_size,
9834 mtime, etag, content_type, &acl_bl,
9835 RGW_OBJ_CATEGORY_MAIN, NULL);
9836 } else {
9837 int ret = index_op.cancel();
9838 if (ret < 0) {
9839 ldout(cct, 0) << "ERROR: complete_update_index_cancel() returned ret=" << ret << dendl;
9840 }
9841 }
9842 }
9843 if (r < 0)
9844 return r;
9845
9846 if (state) {
9847 state->obj_tag.swap(bl);
9848 if (rmattrs) {
9849 for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) {
9850 state->attrset.erase(iter->first);
9851 }
9852 }
9853 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
9854 state->attrset[iter->first] = iter->second;
9855 }
9856 }
9857
9858 return 0;
9859 }
9860
9861 int RGWRados::Object::Read::prepare()
9862 {
9863 RGWRados *store = source->get_store();
9864 CephContext *cct = store->ctx();
9865
9866 bufferlist etag;
9867
9868 map<string, bufferlist>::iterator iter;
9869
9870 RGWObjState *astate;
9871 int r = source->get_state(&astate, true);
9872 if (r < 0)
9873 return r;
9874
9875 if (!astate->exists) {
9876 return -ENOENT;
9877 }
9878
9879 const RGWBucketInfo& bucket_info = source->get_bucket_info();
9880
9881 state.obj = astate->obj;
9882 store->obj_to_raw(bucket_info.placement_rule, state.obj, &state.head_obj);
9883
9884 r = store->get_obj_head_ioctx(bucket_info, state.obj, &state.io_ctx);
9885 if (r < 0) {
9886 return r;
9887 }
9888 if (params.attrs) {
9889 *params.attrs = astate->attrset;
9890 if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) {
9891 for (iter = params.attrs->begin(); iter != params.attrs->end(); ++iter) {
9892 ldout(cct, 20) << "Read xattr: " << iter->first << dendl;
9893 }
9894 }
9895 }
9896
9897 /* Convert all times go GMT to make them compatible */
9898 if (conds.mod_ptr || conds.unmod_ptr) {
9899 obj_time_weight src_weight;
9900 src_weight.init(astate);
9901 src_weight.high_precision = conds.high_precision_time;
9902
9903 obj_time_weight dest_weight;
9904 dest_weight.high_precision = conds.high_precision_time;
9905
9906 if (conds.mod_ptr) {
9907 dest_weight.init(*conds.mod_ptr, conds.mod_zone_id, conds.mod_pg_ver);
9908 ldout(cct, 10) << "If-Modified-Since: " << dest_weight << " Last-Modified: " << src_weight << dendl;
9909 if (!(dest_weight < src_weight)) {
9910 return -ERR_NOT_MODIFIED;
9911 }
9912 }
9913
9914 if (conds.unmod_ptr) {
9915 dest_weight.init(*conds.unmod_ptr, conds.mod_zone_id, conds.mod_pg_ver);
9916 ldout(cct, 10) << "If-UnModified-Since: " << dest_weight << " Last-Modified: " << src_weight << dendl;
9917 if (dest_weight < src_weight) {
9918 return -ERR_PRECONDITION_FAILED;
9919 }
9920 }
9921 }
9922 if (conds.if_match || conds.if_nomatch) {
9923 r = get_attr(RGW_ATTR_ETAG, etag);
9924 if (r < 0)
9925 return r;
9926
9927 if (conds.if_match) {
9928 string if_match_str = rgw_string_unquote(conds.if_match);
9929 ldout(cct, 10) << "ETag: " << etag.c_str() << " " << " If-Match: " << if_match_str << dendl;
9930 if (if_match_str.compare(etag.c_str()) != 0) {
9931 return -ERR_PRECONDITION_FAILED;
9932 }
9933 }
9934
9935 if (conds.if_nomatch) {
9936 string if_nomatch_str = rgw_string_unquote(conds.if_nomatch);
9937 ldout(cct, 10) << "ETag: " << etag.c_str() << " " << " If-NoMatch: " << if_nomatch_str << dendl;
9938 if (if_nomatch_str.compare(etag.c_str()) == 0) {
9939 return -ERR_NOT_MODIFIED;
9940 }
9941 }
9942 }
9943
9944 if (params.obj_size)
9945 *params.obj_size = astate->size;
9946 if (params.lastmod)
9947 *params.lastmod = astate->mtime;
9948
9949 return 0;
9950 }
9951
9952 int RGWRados::Object::Read::range_to_ofs(uint64_t obj_size, int64_t &ofs, int64_t &end)
9953 {
9954 if (ofs < 0) {
9955 ofs += obj_size;
9956 if (ofs < 0)
9957 ofs = 0;
9958 end = obj_size - 1;
9959 } else if (end < 0) {
9960 end = obj_size - 1;
9961 }
9962
9963 if (obj_size > 0) {
9964 if (ofs >= (off_t)obj_size) {
9965 return -ERANGE;
9966 }
9967 if (end >= (off_t)obj_size) {
9968 end = obj_size - 1;
9969 }
9970 }
9971 return 0;
9972 }
9973
9974 int RGWRados::SystemObject::get_state(RGWRawObjState **pstate, RGWObjVersionTracker *objv_tracker)
9975 {
9976 return store->get_system_obj_state(&ctx, obj, pstate, objv_tracker);
9977 }
9978
9979 int RGWRados::stat_system_obj(RGWObjectCtx& obj_ctx,
9980 RGWRados::SystemObject::Read::GetObjState& state,
9981 rgw_raw_obj& obj,
9982 map<string, bufferlist> *attrs,
9983 real_time *lastmod,
9984 uint64_t *obj_size,
9985 RGWObjVersionTracker *objv_tracker)
9986 {
9987 RGWRawObjState *astate = NULL;
9988
9989 int r = get_system_obj_state(&obj_ctx, obj, &astate, objv_tracker);
9990 if (r < 0)
9991 return r;
9992
9993 if (!astate->exists) {
9994 return -ENOENT;
9995 }
9996
9997 if (attrs) {
9998 *attrs = astate->attrset;
9999 if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) {
10000 map<string, bufferlist>::iterator iter;
10001 for (iter = attrs->begin(); iter != attrs->end(); ++iter) {
10002 ldout(cct, 20) << "Read xattr: " << iter->first << dendl;
10003 }
10004 }
10005 }
10006
10007 if (obj_size)
10008 *obj_size = astate->size;
10009 if (lastmod)
10010 *lastmod = astate->mtime;
10011
10012 return 0;
10013 }
10014
10015
10016 int RGWRados::Bucket::UpdateIndex::guard_reshard(BucketShard **pbs, std::function<int(BucketShard *)> call)
10017 {
10018 RGWRados *store = target->get_store();
10019 BucketShard *bs;
10020 int r;
10021
10022 #define NUM_RESHARD_RETRIES 10
10023 for (int i = 0; i < NUM_RESHARD_RETRIES; ++i) {
10024 int ret = get_bucket_shard(&bs);
10025 if (ret < 0) {
10026 ldout(store->ctx(), 5) << "failed to get BucketShard object: ret=" << ret << dendl;
10027 return ret;
10028 }
10029 r = call(bs);
10030 if (r != -ERR_BUSY_RESHARDING) {
10031 break;
10032 }
10033 ldout(store->ctx(), 0) << "NOTICE: resharding operation on bucket index detected, blocking" << dendl;
10034 string new_bucket_id;
10035 r = store->block_while_resharding(bs, &new_bucket_id);
10036 if (r == -ERR_BUSY_RESHARDING) {
10037 continue;
10038 }
10039 if (r < 0) {
10040 return r;
10041 }
10042 ldout(store->ctx(), 20) << "reshard completion identified, new_bucket_id=" << new_bucket_id << dendl;
10043 i = 0; /* resharding is finished, make sure we can retry */
10044 r = target->update_bucket_id(new_bucket_id);
10045 if (r < 0) {
10046 ldout(store->ctx(), 0) << "ERROR: update_bucket_id() new_bucket_id=" << new_bucket_id << " returned r=" << r << dendl;
10047 return r;
10048 }
10049 invalidate_bs();
10050 }
10051
10052 if (r < 0) {
10053 return r;
10054 }
10055
10056 if (pbs) {
10057 *pbs = bs;
10058 }
10059
10060 return 0;
10061 }
10062
10063 int RGWRados::SystemObject::Read::stat(RGWObjVersionTracker *objv_tracker)
10064 {
10065 RGWRados *store = source->get_store();
10066 rgw_raw_obj& obj = source->get_obj();
10067
10068 return store->stat_system_obj(source->get_ctx(), state, obj, stat_params.attrs,
10069 stat_params.lastmod, stat_params.obj_size, objv_tracker);
10070 }
10071
10072 int RGWRados::Bucket::UpdateIndex::prepare(RGWModifyOp op, const string *write_tag)
10073 {
10074 if (blind) {
10075 return 0;
10076 }
10077 RGWRados *store = target->get_store();
10078
10079 if (write_tag && write_tag->length()) {
10080 optag = string(write_tag->c_str(), write_tag->length());
10081 } else {
10082 if (optag.empty()) {
10083 append_rand_alpha(store->ctx(), optag, optag, 32);
10084 }
10085 }
10086
10087 int r = guard_reshard(nullptr, [&](BucketShard *bs) -> int {
10088 return store->cls_obj_prepare_op(*bs, op, optag, obj, bilog_flags, zones_trace);
10089 });
10090
10091 if (r < 0) {
10092 return r;
10093 }
10094 prepared = true;
10095
10096 return 0;
10097 }
10098
10099 int RGWRados::Bucket::UpdateIndex::complete(int64_t poolid, uint64_t epoch,
10100 uint64_t size, uint64_t accounted_size,
10101 ceph::real_time& ut, const string& etag,
10102 const string& content_type,
10103 bufferlist *acl_bl,
10104 RGWObjCategory category,
10105 list<rgw_obj_index_key> *remove_objs, const string *user_data)
10106 {
10107 if (blind) {
10108 return 0;
10109 }
10110 RGWRados *store = target->get_store();
10111 BucketShard *bs;
10112
10113 int ret = get_bucket_shard(&bs);
10114 if (ret < 0) {
10115 ldout(store->ctx(), 5) << "failed to get BucketShard object: ret=" << ret << dendl;
10116 return ret;
10117 }
10118
10119 rgw_bucket_dir_entry ent;
10120 obj.key.get_index_key(&ent.key);
10121 ent.meta.size = size;
10122 ent.meta.accounted_size = accounted_size;
10123 ent.meta.mtime = ut;
10124 ent.meta.etag = etag;
10125 if (user_data)
10126 ent.meta.user_data = *user_data;
10127
10128 ACLOwner owner;
10129 if (acl_bl && acl_bl->length()) {
10130 int ret = store->decode_policy(*acl_bl, &owner);
10131 if (ret < 0) {
10132 ldout(store->ctx(), 0) << "WARNING: could not decode policy ret=" << ret << dendl;
10133 }
10134 }
10135 ent.meta.owner = owner.get_id().to_str();
10136 ent.meta.owner_display_name = owner.get_display_name();
10137 ent.meta.content_type = content_type;
10138
10139 ret = store->cls_obj_complete_add(*bs, obj, optag, poolid, epoch, ent, category, remove_objs, bilog_flags, zones_trace);
10140
10141 if (target->bucket_info.datasync_flag_enabled()) {
10142 int r = store->data_log->add_entry(bs->bucket, bs->shard_id);
10143 if (r < 0) {
10144 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
10145 }
10146 }
10147
10148 return ret;
10149 }
10150
10151 int RGWRados::Bucket::UpdateIndex::complete_del(int64_t poolid, uint64_t epoch,
10152 real_time& removed_mtime,
10153 list<rgw_obj_index_key> *remove_objs)
10154 {
10155 if (blind) {
10156 return 0;
10157 }
10158 RGWRados *store = target->get_store();
10159 BucketShard *bs;
10160
10161 int ret = get_bucket_shard(&bs);
10162 if (ret < 0) {
10163 ldout(store->ctx(), 5) << "failed to get BucketShard object: ret=" << ret << dendl;
10164 return ret;
10165 }
10166
10167 ret = store->cls_obj_complete_del(*bs, optag, poolid, epoch, obj, removed_mtime, remove_objs, bilog_flags, zones_trace);
10168
10169 if (target->bucket_info.datasync_flag_enabled()) {
10170 int r = store->data_log->add_entry(bs->bucket, bs->shard_id);
10171 if (r < 0) {
10172 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
10173 }
10174 }
10175
10176 return ret;
10177 }
10178
10179
10180 int RGWRados::Bucket::UpdateIndex::cancel()
10181 {
10182 if (blind) {
10183 return 0;
10184 }
10185 RGWRados *store = target->get_store();
10186 BucketShard *bs;
10187
10188 int ret = guard_reshard(&bs, [&](BucketShard *bs) -> int {
10189 return store->cls_obj_complete_cancel(*bs, optag, obj, bilog_flags, zones_trace);
10190 });
10191
10192 /*
10193 * need to update data log anyhow, so that whoever follows needs to update its internal markers
10194 * for following the specific bucket shard log. Otherwise they end up staying behind, and users
10195 * have no way to tell that they're all caught up
10196 */
10197 if (target->bucket_info.datasync_flag_enabled()) {
10198 int r = store->data_log->add_entry(bs->bucket, bs->shard_id);
10199 if (r < 0) {
10200 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
10201 }
10202 }
10203
10204 return ret;
10205 }
10206
10207 int RGWRados::Object::Read::read(int64_t ofs, int64_t end, bufferlist& bl)
10208 {
10209 RGWRados *store = source->get_store();
10210 CephContext *cct = store->ctx();
10211
10212 rgw_raw_obj read_obj;
10213 uint64_t read_ofs = ofs;
10214 uint64_t len, read_len;
10215 bool reading_from_head = true;
10216 ObjectReadOperation op;
10217
10218 bool merge_bl = false;
10219 bufferlist *pbl = &bl;
10220 bufferlist read_bl;
10221 uint64_t max_chunk_size;
10222
10223 RGWObjState *astate;
10224 int r = source->get_state(&astate, true);
10225 if (r < 0)
10226 return r;
10227
10228 if (end < 0)
10229 len = 0;
10230 else
10231 len = end - ofs + 1;
10232
10233 if (astate->has_manifest && astate->manifest.has_tail()) {
10234 /* now get the relevant object part */
10235 RGWObjManifest::obj_iterator iter = astate->manifest.obj_find(ofs);
10236
10237 uint64_t stripe_ofs = iter.get_stripe_ofs();
10238 read_obj = iter.get_location().get_raw_obj(store);
10239 len = min(len, iter.get_stripe_size() - (ofs - stripe_ofs));
10240 read_ofs = iter.location_ofs() + (ofs - stripe_ofs);
10241 reading_from_head = (read_obj == state.head_obj);
10242 } else {
10243 read_obj = state.head_obj;
10244 }
10245
10246 r = store->get_max_chunk_size(read_obj.pool, &max_chunk_size);
10247 if (r < 0) {
10248 ldout(cct, 0) << "ERROR: failed to get max_chunk_size() for pool " << read_obj.pool << dendl;
10249 return r;
10250 }
10251
10252 if (len > max_chunk_size)
10253 len = max_chunk_size;
10254
10255
10256 state.io_ctx.locator_set_key(read_obj.loc);
10257
10258 read_len = len;
10259
10260 if (reading_from_head) {
10261 /* only when reading from the head object do we need to do the atomic test */
10262 r = store->append_atomic_test(&source->get_ctx(), source->get_bucket_info(), state.obj, op, &astate);
10263 if (r < 0)
10264 return r;
10265
10266 if (astate && astate->prefetch_data) {
10267 if (!ofs && astate->data.length() >= len) {
10268 bl = astate->data;
10269 return bl.length();
10270 }
10271
10272 if (ofs < astate->data.length()) {
10273 unsigned copy_len = min((uint64_t)astate->data.length() - ofs, len);
10274 astate->data.copy(ofs, copy_len, bl);
10275 read_len -= copy_len;
10276 read_ofs += copy_len;
10277 if (!read_len)
10278 return bl.length();
10279
10280 merge_bl = true;
10281 pbl = &read_bl;
10282 }
10283 }
10284 }
10285
10286 ldout(cct, 20) << "rados->read obj-ofs=" << ofs << " read_ofs=" << read_ofs << " read_len=" << read_len << dendl;
10287 op.read(read_ofs, read_len, pbl, NULL);
10288
10289 r = state.io_ctx.operate(read_obj.oid, &op, NULL);
10290 ldout(cct, 20) << "rados->read r=" << r << " bl.length=" << bl.length() << dendl;
10291
10292 if (r < 0) {
10293 return r;
10294 }
10295
10296 if (merge_bl) {
10297 bl.append(read_bl);
10298 }
10299
10300 return bl.length();
10301 }
10302
10303 int RGWRados::SystemObject::Read::GetObjState::get_ref(RGWRados *store, rgw_raw_obj& obj, rgw_rados_ref **pref)
10304 {
10305 if (!has_ref) {
10306 int r = store->get_raw_obj_ref(obj, &ref);
10307 if (r < 0) {
10308 return r;
10309 }
10310 has_ref = true;
10311 }
10312 *pref = &ref;
10313 return 0;
10314
10315 }
10316
10317 int RGWRados::get_system_obj(RGWObjectCtx& obj_ctx, RGWRados::SystemObject::Read::GetObjState& read_state,
10318 RGWObjVersionTracker *objv_tracker, rgw_raw_obj& obj,
10319 bufferlist& bl, off_t ofs, off_t end,
10320 map<string, bufferlist> *attrs,
10321 rgw_cache_entry_info *cache_info,
10322 boost::optional<obj_version>)
10323 {
10324 uint64_t len;
10325 ObjectReadOperation op;
10326
10327 if (end < 0)
10328 len = 0;
10329 else
10330 len = end - ofs + 1;
10331
10332 if (objv_tracker) {
10333 objv_tracker->prepare_op_for_read(&op);
10334 }
10335
10336 ldout(cct, 20) << "rados->read ofs=" << ofs << " len=" << len << dendl;
10337 op.read(ofs, len, &bl, NULL);
10338
10339 if (attrs) {
10340 op.getxattrs(attrs, NULL);
10341 }
10342
10343 rgw_rados_ref *ref;
10344 int r = read_state.get_ref(this, obj, &ref);
10345 if (r < 0) {
10346 ldout(cct, 20) << "read_state.get_ref() on obj=" << obj << " returned " << r << dendl;
10347 return r;
10348 }
10349 r = ref->ioctx.operate(ref->oid, &op, NULL);
10350 if (r < 0) {
10351 ldout(cct, 20) << "rados->read r=" << r << " bl.length=" << bl.length() << dendl;
10352 return r;
10353 }
10354 ldout(cct, 20) << "rados->read r=" << r << " bl.length=" << bl.length() << dendl;
10355
10356 uint64_t op_ver = ref->ioctx.get_last_version();
10357
10358 if (read_state.last_ver > 0 &&
10359 read_state.last_ver != op_ver) {
10360 ldout(cct, 5) << "raced with an object write, abort" << dendl;
10361 return -ECANCELED;
10362 }
10363
10364 read_state.last_ver = op_ver;
10365
10366 return bl.length();
10367 }
10368
10369 int RGWRados::SystemObject::Read::read(int64_t ofs, int64_t end, bufferlist& bl,
10370 RGWObjVersionTracker *objv_tracker,
10371 boost::optional<obj_version> refresh_version)
10372 {
10373 RGWRados *store = source->get_store();
10374 rgw_raw_obj& obj = source->get_obj();
10375
10376 return store->get_system_obj(source->get_ctx(), state, objv_tracker, obj, bl,
10377 ofs, end, read_params.attrs,
10378 read_params.cache_info, refresh_version);
10379 }
10380
10381 int RGWRados::SystemObject::Read::get_attr(const char *name, bufferlist& dest)
10382 {
10383 RGWRados *store = source->get_store();
10384 rgw_raw_obj& obj = source->get_obj();
10385
10386 return store->system_obj_get_attr(obj, name, dest);
10387 }
10388
10389 struct get_obj_data;
10390
10391 struct get_obj_aio_data {
10392 struct get_obj_data *op_data;
10393 off_t ofs;
10394 off_t len;
10395 };
10396
10397 struct get_obj_io {
10398 off_t len;
10399 bufferlist bl;
10400 };
10401
10402 static void _get_obj_aio_completion_cb(completion_t cb, void *arg);
10403
10404 struct get_obj_data : public RefCountedObject {
10405 CephContext *cct;
10406 RGWRados *rados;
10407 RGWObjectCtx *ctx;
10408 IoCtx io_ctx;
10409 map<off_t, get_obj_io> io_map;
10410 map<off_t, librados::AioCompletion *> completion_map;
10411 uint64_t total_read;
10412 Mutex lock;
10413 Mutex data_lock;
10414 list<get_obj_aio_data> aio_data;
10415 RGWGetDataCB *client_cb;
10416 std::atomic<bool> cancelled = { false };
10417 std::atomic<int64_t> err_code = { 0 };
10418 Throttle throttle;
10419 list<bufferlist> read_list;
10420
10421 explicit get_obj_data(CephContext *_cct)
10422 : cct(_cct),
10423 rados(NULL), ctx(NULL),
10424 total_read(0), lock("get_obj_data"), data_lock("get_obj_data::data_lock"),
10425 client_cb(NULL),
10426 throttle(cct, "get_obj_data", cct->_conf->rgw_get_obj_window_size, false) {}
10427 ~get_obj_data() override { }
10428 void set_cancelled(int r) {
10429 cancelled = true;
10430 err_code = r;
10431 }
10432
10433 bool is_cancelled() {
10434 return cancelled;
10435 }
10436
10437 int get_err_code() {
10438 return err_code;
10439 }
10440
10441 int wait_next_io(bool *done) {
10442 lock.Lock();
10443 map<off_t, librados::AioCompletion *>::iterator iter = completion_map.begin();
10444 if (iter == completion_map.end()) {
10445 *done = true;
10446 lock.Unlock();
10447 return 0;
10448 }
10449 off_t cur_ofs = iter->first;
10450 librados::AioCompletion *c = iter->second;
10451 lock.Unlock();
10452
10453 c->wait_for_safe_and_cb();
10454 int r = c->get_return_value();
10455
10456 lock.Lock();
10457 completion_map.erase(cur_ofs);
10458
10459 if (completion_map.empty()) {
10460 *done = true;
10461 }
10462 lock.Unlock();
10463
10464 c->release();
10465
10466 return r;
10467 }
10468
10469 void add_io(off_t ofs, off_t len, bufferlist **pbl, AioCompletion **pc) {
10470 Mutex::Locker l(lock);
10471
10472 const auto& io_iter = io_map.insert(
10473 map<off_t, get_obj_io>::value_type(ofs, get_obj_io()));
10474
10475 assert(io_iter.second); // assert new insertion
10476
10477 get_obj_io& io = (io_iter.first)->second;
10478 *pbl = &io.bl;
10479
10480 struct get_obj_aio_data aio;
10481 aio.ofs = ofs;
10482 aio.len = len;
10483 aio.op_data = this;
10484
10485 aio_data.push_back(aio);
10486
10487 struct get_obj_aio_data *paio_data = &aio_data.back(); /* last element */
10488
10489 librados::AioCompletion *c = librados::Rados::aio_create_completion((void *)paio_data, NULL, _get_obj_aio_completion_cb);
10490 completion_map[ofs] = c;
10491
10492 *pc = c;
10493
10494 /* we have a reference per IO, plus one reference for the calling function.
10495 * reference is dropped for each callback, plus when we're done iterating
10496 * over the parts */
10497 get();
10498 }
10499
10500 void cancel_io(off_t ofs) {
10501 ldout(cct, 20) << "get_obj_data::cancel_io() ofs=" << ofs << dendl;
10502 lock.Lock();
10503 map<off_t, AioCompletion *>::iterator iter = completion_map.find(ofs);
10504 if (iter != completion_map.end()) {
10505 AioCompletion *c = iter->second;
10506 c->release();
10507 completion_map.erase(ofs);
10508 io_map.erase(ofs);
10509 }
10510 lock.Unlock();
10511
10512 /* we don't drop a reference here -- e.g., not calling d->put(), because we still
10513 * need IoCtx to live, as io callback may still be called
10514 */
10515 }
10516
10517 void cancel_all_io() {
10518 ldout(cct, 20) << "get_obj_data::cancel_all_io()" << dendl;
10519 Mutex::Locker l(lock);
10520 for (map<off_t, librados::AioCompletion *>::iterator iter = completion_map.begin();
10521 iter != completion_map.end(); ++iter) {
10522 librados::AioCompletion *c = iter->second;
10523 c->release();
10524 }
10525 }
10526
10527 int get_complete_ios(off_t ofs, list<bufferlist>& bl_list) {
10528 Mutex::Locker l(lock);
10529
10530 map<off_t, get_obj_io>::iterator liter = io_map.begin();
10531
10532 if (liter == io_map.end() ||
10533 liter->first != ofs) {
10534 return 0;
10535 }
10536
10537 map<off_t, librados::AioCompletion *>::iterator aiter;
10538 aiter = completion_map.find(ofs);
10539 if (aiter == completion_map.end()) {
10540 /* completion map does not hold this io, it was cancelled */
10541 return 0;
10542 }
10543
10544 AioCompletion *completion = aiter->second;
10545 int r = completion->get_return_value();
10546 if (r < 0)
10547 return r;
10548
10549 for (; aiter != completion_map.end(); ++aiter) {
10550 completion = aiter->second;
10551 if (!completion->is_safe()) {
10552 /* reached a request that is not yet complete, stop */
10553 break;
10554 }
10555
10556 r = completion->get_return_value();
10557 if (r < 0) {
10558 set_cancelled(r); /* mark it as cancelled, so that we don't continue processing next operations */
10559 return r;
10560 }
10561
10562 total_read += r;
10563
10564 map<off_t, get_obj_io>::iterator old_liter = liter++;
10565 bl_list.push_back(old_liter->second.bl);
10566 io_map.erase(old_liter);
10567 }
10568
10569 return 0;
10570 }
10571 };
10572
10573 static int _get_obj_iterate_cb(const RGWBucketInfo& bucket_info, const rgw_obj& obj, const rgw_raw_obj& read_obj, off_t obj_ofs, off_t read_ofs, off_t len, bool is_head_obj, RGWObjState *astate, void *arg)
10574 {
10575 struct get_obj_data *d = (struct get_obj_data *)arg;
10576
10577 return d->rados->get_obj_iterate_cb(d->ctx, astate, bucket_info, obj, read_obj, obj_ofs, read_ofs, len, is_head_obj, arg);
10578 }
10579
10580 static void _get_obj_aio_completion_cb(completion_t cb, void *arg)
10581 {
10582 struct get_obj_aio_data *aio_data = (struct get_obj_aio_data *)arg;
10583 struct get_obj_data *d = aio_data->op_data;
10584
10585 d->rados->get_obj_aio_completion_cb(cb, arg);
10586 }
10587
10588
10589 void RGWRados::get_obj_aio_completion_cb(completion_t c, void *arg)
10590 {
10591 struct get_obj_aio_data *aio_data = (struct get_obj_aio_data *)arg;
10592 struct get_obj_data *d = aio_data->op_data;
10593 off_t ofs = aio_data->ofs;
10594 off_t len = aio_data->len;
10595
10596 list<bufferlist> bl_list;
10597 list<bufferlist>::iterator iter;
10598 int r;
10599
10600 ldout(cct, 20) << "get_obj_aio_completion_cb: io completion ofs=" << ofs << " len=" << len << dendl;
10601 d->throttle.put(len);
10602
10603 r = rados_aio_get_return_value(c);
10604 if (r < 0) {
10605 ldout(cct, 0) << "ERROR: got unexpected error when trying to read object: " << r << dendl;
10606 d->set_cancelled(r);
10607 goto done;
10608 }
10609
10610 if (d->is_cancelled()) {
10611 goto done;
10612 }
10613
10614 d->data_lock.Lock();
10615
10616 r = d->get_complete_ios(ofs, bl_list);
10617 if (r < 0) {
10618 goto done_unlock;
10619 }
10620
10621 d->read_list.splice(d->read_list.end(), bl_list);
10622
10623 done_unlock:
10624 d->data_lock.Unlock();
10625 done:
10626 d->put();
10627 return;
10628 }
10629
10630 int RGWRados::flush_read_list(struct get_obj_data *d)
10631 {
10632 d->data_lock.Lock();
10633 list<bufferlist> l;
10634 l.swap(d->read_list);
10635 d->get();
10636 d->read_list.clear();
10637
10638 d->data_lock.Unlock();
10639
10640 int r = 0;
10641
10642 list<bufferlist>::iterator iter;
10643 for (iter = l.begin(); iter != l.end(); ++iter) {
10644 bufferlist& bl = *iter;
10645 r = d->client_cb->handle_data(bl, 0, bl.length());
10646 if (r < 0) {
10647 dout(0) << "ERROR: flush_read_list(): d->client_cb->handle_data() returned " << r << dendl;
10648 break;
10649 }
10650 }
10651
10652 d->data_lock.Lock();
10653 d->put();
10654 if (r < 0) {
10655 d->set_cancelled(r);
10656 }
10657 d->data_lock.Unlock();
10658 return r;
10659 }
10660
10661 int RGWRados::get_obj_iterate_cb(RGWObjectCtx *ctx, RGWObjState *astate,
10662 const RGWBucketInfo& bucket_info,
10663 const rgw_obj& obj,
10664 const rgw_raw_obj& read_obj,
10665 off_t obj_ofs,
10666 off_t read_ofs, off_t len,
10667 bool is_head_obj, void *arg)
10668 {
10669 RGWObjectCtx *rctx = static_cast<RGWObjectCtx *>(ctx);
10670 ObjectReadOperation op;
10671 struct get_obj_data *d = (struct get_obj_data *)arg;
10672 string oid, key;
10673 bufferlist *pbl;
10674 AioCompletion *c;
10675
10676 int r;
10677
10678 if (is_head_obj) {
10679 /* only when reading from the head object do we need to do the atomic test */
10680 r = append_atomic_test(rctx, bucket_info, obj, op, &astate);
10681 if (r < 0)
10682 return r;
10683
10684 if (astate &&
10685 obj_ofs < astate->data.length()) {
10686 unsigned chunk_len = min((uint64_t)astate->data.length() - obj_ofs, (uint64_t)len);
10687
10688 d->data_lock.Lock();
10689 r = d->client_cb->handle_data(astate->data, obj_ofs, chunk_len);
10690 d->data_lock.Unlock();
10691 if (r < 0)
10692 return r;
10693
10694 d->lock.Lock();
10695 d->total_read += chunk_len;
10696 d->lock.Unlock();
10697
10698 len -= chunk_len;
10699 read_ofs += chunk_len;
10700 obj_ofs += chunk_len;
10701 if (!len)
10702 return 0;
10703 }
10704 }
10705
10706 d->throttle.get(len);
10707 if (d->is_cancelled()) {
10708 return d->get_err_code();
10709 }
10710
10711 /* add io after we check that we're not cancelled, otherwise we're going to have trouble
10712 * cleaning up
10713 */
10714 d->add_io(obj_ofs, len, &pbl, &c);
10715
10716 ldout(cct, 20) << "rados->get_obj_iterate_cb oid=" << read_obj.oid << " obj-ofs=" << obj_ofs << " read_ofs=" << read_ofs << " len=" << len << dendl;
10717 op.read(read_ofs, len, pbl, NULL);
10718
10719 librados::IoCtx io_ctx(d->io_ctx);
10720 io_ctx.locator_set_key(read_obj.loc);
10721
10722 r = io_ctx.aio_operate(read_obj.oid, c, &op, NULL);
10723 if (r < 0) {
10724 ldout(cct, 0) << "rados->aio_operate r=" << r << dendl;
10725 goto done_err;
10726 }
10727
10728 // Flush data to client if there is any
10729 r = flush_read_list(d);
10730 if (r < 0)
10731 return r;
10732
10733 return 0;
10734
10735 done_err:
10736 ldout(cct, 20) << "cancelling io r=" << r << " obj_ofs=" << obj_ofs << dendl;
10737 d->set_cancelled(r);
10738 d->cancel_io(obj_ofs);
10739
10740 return r;
10741 }
10742
10743 int RGWRados::Object::Read::iterate(int64_t ofs, int64_t end, RGWGetDataCB *cb)
10744 {
10745 RGWRados *store = source->get_store();
10746 CephContext *cct = store->ctx();
10747
10748 struct get_obj_data *data = new get_obj_data(cct);
10749 bool done = false;
10750
10751 RGWObjectCtx& obj_ctx = source->get_ctx();
10752
10753 data->rados = store;
10754 data->io_ctx.dup(state.io_ctx);
10755 data->client_cb = cb;
10756
10757 int r = store->iterate_obj(obj_ctx, source->get_bucket_info(), state.obj, ofs, end, cct->_conf->rgw_get_obj_max_req_size, _get_obj_iterate_cb, (void *)data);
10758 if (r < 0) {
10759 data->cancel_all_io();
10760 goto done;
10761 }
10762
10763 while (!done) {
10764 r = data->wait_next_io(&done);
10765 if (r < 0) {
10766 dout(10) << "get_obj_iterate() r=" << r << ", canceling all io" << dendl;
10767 data->cancel_all_io();
10768 break;
10769 }
10770 r = store->flush_read_list(data);
10771 if (r < 0) {
10772 dout(10) << "get_obj_iterate() r=" << r << ", canceling all io" << dendl;
10773 data->cancel_all_io();
10774 break;
10775 }
10776 }
10777
10778 done:
10779 data->put();
10780 return r;
10781 }
10782
10783 int RGWRados::iterate_obj(RGWObjectCtx& obj_ctx,
10784 const RGWBucketInfo& bucket_info, const rgw_obj& obj,
10785 off_t ofs, off_t end,
10786 uint64_t max_chunk_size,
10787 int (*iterate_obj_cb)(const RGWBucketInfo&, const rgw_obj& obj,
10788 const rgw_raw_obj&, off_t, off_t, off_t, bool,
10789 RGWObjState *, void *),
10790 void *arg)
10791 {
10792 rgw_raw_obj head_obj;
10793 rgw_raw_obj read_obj;
10794 uint64_t read_ofs = ofs;
10795 uint64_t len;
10796 bool reading_from_head = true;
10797 RGWObjState *astate = NULL;
10798
10799 obj_to_raw(bucket_info.placement_rule, obj, &head_obj);
10800
10801 int r = get_obj_state(&obj_ctx, bucket_info, obj, &astate, false);
10802 if (r < 0) {
10803 return r;
10804 }
10805
10806 if (end < 0)
10807 len = 0;
10808 else
10809 len = end - ofs + 1;
10810
10811 if (astate->has_manifest) {
10812 /* now get the relevant object stripe */
10813 RGWObjManifest::obj_iterator iter = astate->manifest.obj_find(ofs);
10814
10815 RGWObjManifest::obj_iterator obj_end = astate->manifest.obj_end();
10816
10817 for (; iter != obj_end && ofs <= end; ++iter) {
10818 off_t stripe_ofs = iter.get_stripe_ofs();
10819 off_t next_stripe_ofs = stripe_ofs + iter.get_stripe_size();
10820
10821 while (ofs < next_stripe_ofs && ofs <= end) {
10822 read_obj = iter.get_location().get_raw_obj(this);
10823 uint64_t read_len = min(len, iter.get_stripe_size() - (ofs - stripe_ofs));
10824 read_ofs = iter.location_ofs() + (ofs - stripe_ofs);
10825
10826 if (read_len > max_chunk_size) {
10827 read_len = max_chunk_size;
10828 }
10829
10830 reading_from_head = (read_obj == head_obj);
10831 r = iterate_obj_cb(bucket_info, obj, read_obj, ofs, read_ofs, read_len, reading_from_head, astate, arg);
10832 if (r < 0) {
10833 return r;
10834 }
10835
10836 len -= read_len;
10837 ofs += read_len;
10838 }
10839 }
10840 } else {
10841 while (ofs <= end) {
10842 read_obj = head_obj;
10843 uint64_t read_len = min(len, max_chunk_size);
10844
10845 r = iterate_obj_cb(bucket_info, obj, read_obj, ofs, ofs, read_len, reading_from_head, astate, arg);
10846 if (r < 0) {
10847 return r;
10848 }
10849
10850 len -= read_len;
10851 ofs += read_len;
10852 }
10853 }
10854
10855 return 0;
10856 }
10857
10858 int RGWRados::obj_operate(const RGWBucketInfo& bucket_info, const rgw_obj& obj, ObjectWriteOperation *op)
10859 {
10860 rgw_rados_ref ref;
10861 int r = get_obj_head_ref(bucket_info, obj, &ref);
10862 if (r < 0) {
10863 return r;
10864 }
10865
10866 return ref.ioctx.operate(ref.oid, op);
10867 }
10868
10869 int RGWRados::obj_operate(const RGWBucketInfo& bucket_info, const rgw_obj& obj, ObjectReadOperation *op)
10870 {
10871 rgw_rados_ref ref;
10872 int r = get_obj_head_ref(bucket_info, obj, &ref);
10873 if (r < 0) {
10874 return r;
10875 }
10876
10877 bufferlist outbl;
10878
10879 return ref.ioctx.operate(ref.oid, op, &outbl);
10880 }
10881
10882 int RGWRados::olh_init_modification_impl(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& olh_obj, string *op_tag)
10883 {
10884 ObjectWriteOperation op;
10885
10886 assert(olh_obj.key.instance.empty());
10887
10888 bool has_tag = (state.exists && has_olh_tag(state.attrset));
10889
10890 if (!state.exists) {
10891 op.create(true);
10892 } else {
10893 op.assert_exists();
10894 struct timespec mtime_ts = real_clock::to_timespec(state.mtime);
10895 op.mtime2(&mtime_ts);
10896 }
10897
10898 /*
10899 * 3 possible cases: olh object doesn't exist, it exists as an olh, it exists as a regular object.
10900 * If it exists as a regular object we'll need to transform it into an olh. We'll do it in two
10901 * steps, first change its tag and set the olh pending attrs. Once write is done we'll need to
10902 * truncate it, remove extra attrs, and send it to the garbage collection. The bucket index olh
10903 * log will reflect that.
10904 *
10905 * Need to generate separate olh and obj tags, as olh can be colocated with object data. obj_tag
10906 * is used for object data instance, olh_tag for olh instance.
10907 */
10908 if (has_tag) {
10909 /* guard against racing writes */
10910 bucket_index_guard_olh_op(state, op);
10911 }
10912
10913 if (!has_tag) {
10914 /* obj tag */
10915 string obj_tag;
10916 int ret = gen_rand_alphanumeric_lower(cct, &obj_tag, 32);
10917 if (ret < 0) {
10918 ldout(cct, 0) << "ERROR: gen_rand_alphanumeric_lower() returned ret=" << ret << dendl;
10919 return ret;
10920 }
10921 bufferlist bl;
10922 bl.append(obj_tag.c_str(), obj_tag.size());
10923 op.setxattr(RGW_ATTR_ID_TAG, bl);
10924
10925 state.attrset[RGW_ATTR_ID_TAG] = bl;
10926 state.obj_tag = bl;
10927
10928 /* olh tag */
10929 string olh_tag;
10930 ret = gen_rand_alphanumeric_lower(cct, &olh_tag, 32);
10931 if (ret < 0) {
10932 ldout(cct, 0) << "ERROR: gen_rand_alphanumeric_lower() returned ret=" << ret << dendl;
10933 return ret;
10934 }
10935 bufferlist olh_bl;
10936 olh_bl.append(olh_tag.c_str(), olh_tag.size());
10937 op.setxattr(RGW_ATTR_OLH_ID_TAG, olh_bl);
10938
10939 state.attrset[RGW_ATTR_OLH_ID_TAG] = olh_bl;
10940 state.olh_tag = olh_bl;
10941 state.is_olh = true;
10942
10943 bufferlist verbl;
10944 op.setxattr(RGW_ATTR_OLH_VER, verbl);
10945 }
10946
10947 bufferlist bl;
10948 RGWOLHPendingInfo pending_info;
10949 pending_info.time = real_clock::now();
10950 ::encode(pending_info, bl);
10951
10952 #define OLH_PENDING_TAG_LEN 32
10953 /* tag will start with current time epoch, this so that entries are sorted by time */
10954 char buf[32];
10955 utime_t ut(pending_info.time);
10956 snprintf(buf, sizeof(buf), "%016llx", (unsigned long long)ut.sec());
10957 *op_tag = buf;
10958
10959 string s;
10960 int ret = gen_rand_alphanumeric_lower(cct, &s, OLH_PENDING_TAG_LEN - op_tag->size());
10961 if (ret < 0) {
10962 ldout(cct, 0) << "ERROR: gen_rand_alphanumeric_lower() returned ret=" << ret << dendl;
10963 return ret;
10964 }
10965 op_tag->append(s);
10966
10967 string attr_name = RGW_ATTR_OLH_PENDING_PREFIX;
10968 attr_name.append(*op_tag);
10969
10970 op.setxattr(attr_name.c_str(), bl);
10971
10972 ret = obj_operate(bucket_info, olh_obj, &op);
10973 if (ret < 0) {
10974 return ret;
10975 }
10976
10977 state.exists = true;
10978 state.attrset[attr_name] = bl;
10979
10980 return 0;
10981 }
10982
10983 int RGWRados::olh_init_modification(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& obj, string *op_tag)
10984 {
10985 int ret;
10986
10987 ret = olh_init_modification_impl(bucket_info, state, obj, op_tag);
10988 if (ret == -EEXIST) {
10989 ret = -ECANCELED;
10990 }
10991
10992 return ret;
10993 }
10994
10995 int RGWRados::guard_reshard(BucketShard *bs, const rgw_obj& obj_instance, std::function<int(BucketShard *)> call)
10996 {
10997 rgw_obj obj;
10998 const rgw_obj *pobj = &obj_instance;
10999 int r;
11000
11001 for (int i = 0; i < NUM_RESHARD_RETRIES; ++i) {
11002 r = bs->init(pobj->bucket, *pobj);
11003 if (r < 0) {
11004 ldout(cct, 5) << "bs.init() returned ret=" << r << dendl;
11005 return r;
11006 }
11007 r = call(bs);
11008 if (r != -ERR_BUSY_RESHARDING) {
11009 break;
11010 }
11011 ldout(cct, 0) << "NOTICE: resharding operation on bucket index detected, blocking" << dendl;
11012 string new_bucket_id;
11013 r = block_while_resharding(bs, &new_bucket_id);
11014 if (r == -ERR_BUSY_RESHARDING) {
11015 continue;
11016 }
11017 if (r < 0) {
11018 return r;
11019 }
11020 ldout(cct, 20) << "reshard completion identified, new_bucket_id=" << new_bucket_id << dendl;
11021 i = 0; /* resharding is finished, make sure we can retry */
11022
11023 obj = *pobj;
11024 obj.bucket.update_bucket_id(new_bucket_id);
11025 pobj = &obj;
11026 }
11027
11028 if (r < 0) {
11029 return r;
11030 }
11031
11032 return 0;
11033 }
11034
11035 int RGWRados::block_while_resharding(RGWRados::BucketShard *bs, string *new_bucket_id)
11036 {
11037 std::shared_ptr<RGWReshardWait> waiter = reshard_wait;
11038
11039 return waiter->block_while_resharding(bs, new_bucket_id);
11040 }
11041
11042 int RGWRados::bucket_index_link_olh(const RGWBucketInfo& bucket_info, RGWObjState& olh_state, const rgw_obj& obj_instance,
11043 bool delete_marker,
11044 const string& op_tag,
11045 struct rgw_bucket_dir_entry_meta *meta,
11046 uint64_t olh_epoch,
11047 real_time unmod_since, bool high_precision_time, rgw_zone_set *_zones_trace)
11048 {
11049 rgw_rados_ref ref;
11050 int r = get_obj_head_ref(bucket_info, obj_instance, &ref);
11051 if (r < 0) {
11052 return r;
11053 }
11054
11055 rgw_zone_set zones_trace;
11056 if (_zones_trace) {
11057 zones_trace = *_zones_trace;
11058 } else {
11059 zones_trace.insert(get_zone().id);
11060 }
11061
11062 BucketShard bs(this);
11063
11064 cls_rgw_obj_key key(obj_instance.key.get_index_key_name(), obj_instance.key.instance);
11065 r = guard_reshard(&bs, obj_instance, [&](BucketShard *bs) -> int {
11066 librados::ObjectWriteOperation op;
11067 cls_rgw_guard_bucket_resharding(op, -ERR_BUSY_RESHARDING);
11068 return cls_rgw_bucket_link_olh(bs->index_ctx, op,
11069 bs->bucket_obj, key, olh_state.olh_tag, delete_marker, op_tag, meta, olh_epoch,
11070 unmod_since, high_precision_time,
11071 get_zone().log_data, zones_trace);
11072 });
11073 if (r < 0) {
11074 ldout(cct, 20) << "cls_rgw_bucket_link_olh() returned r=" << r << dendl;
11075 return r;
11076 }
11077
11078 return 0;
11079 }
11080
11081 void RGWRados::bucket_index_guard_olh_op(RGWObjState& olh_state, ObjectOperation& op)
11082 {
11083 ldout(cct, 20) << __func__ << "(): olh_state.olh_tag=" << string(olh_state.olh_tag.c_str(), olh_state.olh_tag.length()) << dendl;
11084 op.cmpxattr(RGW_ATTR_OLH_ID_TAG, CEPH_OSD_CMPXATTR_OP_EQ, olh_state.olh_tag);
11085 }
11086
11087 int RGWRados::bucket_index_unlink_instance(const RGWBucketInfo& bucket_info, const rgw_obj& obj_instance,
11088 const string& op_tag, const string& olh_tag, uint64_t olh_epoch, rgw_zone_set *_zones_trace)
11089 {
11090 rgw_rados_ref ref;
11091 int r = get_obj_head_ref(bucket_info, obj_instance, &ref);
11092 if (r < 0) {
11093 return r;
11094 }
11095
11096 rgw_zone_set zones_trace;
11097 if (_zones_trace) {
11098 zones_trace = *_zones_trace;
11099 }
11100 zones_trace.insert(get_zone().id);
11101
11102 BucketShard bs(this);
11103
11104 cls_rgw_obj_key key(obj_instance.key.get_index_key_name(), obj_instance.key.instance);
11105 r = guard_reshard(&bs, obj_instance, [&](BucketShard *bs) -> int {
11106 librados::ObjectWriteOperation op;
11107 cls_rgw_guard_bucket_resharding(op, -ERR_BUSY_RESHARDING);
11108 return cls_rgw_bucket_unlink_instance(bs->index_ctx, op, bs->bucket_obj, key, op_tag,
11109 olh_tag, olh_epoch, get_zone().log_data, zones_trace);
11110 });
11111 if (r < 0) {
11112 ldout(cct, 20) << "cls_rgw_bucket_link_olh() returned r=" << r << dendl;
11113 return r;
11114 }
11115
11116 return 0;
11117 }
11118
11119 int RGWRados::bucket_index_read_olh_log(const RGWBucketInfo& bucket_info, RGWObjState& state,
11120 const rgw_obj& obj_instance, uint64_t ver_marker,
11121 map<uint64_t, vector<rgw_bucket_olh_log_entry> > *log,
11122 bool *is_truncated)
11123 {
11124 rgw_rados_ref ref;
11125 int r = get_obj_head_ref(bucket_info, obj_instance, &ref);
11126 if (r < 0) {
11127 return r;
11128 }
11129
11130 BucketShard bs(this);
11131 int ret = bs.init(obj_instance.bucket, obj_instance);
11132 if (ret < 0) {
11133 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
11134 return ret;
11135 }
11136
11137 string olh_tag(state.olh_tag.c_str(), state.olh_tag.length());
11138
11139 cls_rgw_obj_key key(obj_instance.key.get_index_key_name(), string());
11140
11141 ret = guard_reshard(&bs, obj_instance, [&](BucketShard *bs) -> int {
11142 ObjectReadOperation op;
11143 cls_rgw_guard_bucket_resharding(op, -ERR_BUSY_RESHARDING);
11144 return cls_rgw_get_olh_log(bs->index_ctx, bs->bucket_obj, op,
11145 key, ver_marker, olh_tag, log, is_truncated);
11146 });
11147 if (ret < 0) {
11148 ldout(cct, 20) << "cls_rgw_get_olh_log() returned r=" << r << dendl;
11149 return ret;
11150 }
11151
11152 return 0;
11153 }
11154
11155 int RGWRados::bucket_index_trim_olh_log(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& obj_instance, uint64_t ver)
11156 {
11157 rgw_rados_ref ref;
11158 int r = get_obj_head_ref(bucket_info, obj_instance, &ref);
11159 if (r < 0) {
11160 return r;
11161 }
11162
11163 BucketShard bs(this);
11164 int ret = bs.init(obj_instance.bucket, obj_instance);
11165 if (ret < 0) {
11166 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
11167 return ret;
11168 }
11169
11170 string olh_tag(state.olh_tag.c_str(), state.olh_tag.length());
11171
11172 cls_rgw_obj_key key(obj_instance.key.get_index_key_name(), string());
11173
11174 ret = guard_reshard(&bs, obj_instance, [&](BucketShard *pbs) -> int {
11175 ObjectWriteOperation op;
11176 cls_rgw_guard_bucket_resharding(op, -ERR_BUSY_RESHARDING);
11177 cls_rgw_trim_olh_log(op, key, ver, olh_tag);
11178 return pbs->index_ctx.operate(pbs->bucket_obj, &op);
11179 });
11180 if (ret < 0) {
11181 ldout(cct, 20) << "cls_rgw_trim_olh_log() returned r=" << ret << dendl;
11182 return ret;
11183 }
11184
11185 return 0;
11186 }
11187
11188 int RGWRados::bucket_index_clear_olh(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& obj_instance)
11189 {
11190 rgw_rados_ref ref;
11191 int r = get_obj_head_ref(bucket_info, obj_instance, &ref);
11192 if (r < 0) {
11193 return r;
11194 }
11195
11196 BucketShard bs(this);
11197
11198 string olh_tag(state.olh_tag.c_str(), state.olh_tag.length());
11199
11200 cls_rgw_obj_key key(obj_instance.key.get_index_key_name(), string());
11201
11202 int ret = guard_reshard(&bs, obj_instance, [&](BucketShard *pbs) -> int {
11203 ObjectWriteOperation op;
11204 cls_rgw_guard_bucket_resharding(op, -ERR_BUSY_RESHARDING);
11205 return cls_rgw_clear_olh(pbs->index_ctx, op, pbs->bucket_obj, key, olh_tag);
11206 });
11207 if (ret < 0) {
11208 ldout(cct, 5) << "cls_rgw_clear_olh() returned ret=" << ret << dendl;
11209 return ret;
11210 }
11211
11212 return 0;
11213 }
11214
11215 int RGWRados::apply_olh_log(RGWObjectCtx& obj_ctx, RGWObjState& state, const RGWBucketInfo& bucket_info, const rgw_obj& obj,
11216 bufferlist& olh_tag, map<uint64_t, vector<rgw_bucket_olh_log_entry> >& log,
11217 uint64_t *plast_ver, rgw_zone_set* zones_trace)
11218 {
11219 if (log.empty()) {
11220 return 0;
11221 }
11222
11223 librados::ObjectWriteOperation op;
11224
11225 uint64_t last_ver = log.rbegin()->first;
11226 *plast_ver = last_ver;
11227
11228 map<uint64_t, vector<rgw_bucket_olh_log_entry> >::iterator iter = log.begin();
11229
11230 op.cmpxattr(RGW_ATTR_OLH_ID_TAG, CEPH_OSD_CMPXATTR_OP_EQ, olh_tag);
11231 op.cmpxattr(RGW_ATTR_OLH_VER, CEPH_OSD_CMPXATTR_OP_GT, last_ver);
11232
11233 struct timespec mtime_ts = real_clock::to_timespec(state.mtime);
11234 op.mtime2(&mtime_ts);
11235
11236 bool need_to_link = false;
11237 cls_rgw_obj_key key;
11238 bool delete_marker = false;
11239 list<cls_rgw_obj_key> remove_instances;
11240 bool need_to_remove = false;
11241
11242 for (iter = log.begin(); iter != log.end(); ++iter) {
11243 vector<rgw_bucket_olh_log_entry>::iterator viter = iter->second.begin();
11244 for (; viter != iter->second.end(); ++viter) {
11245 rgw_bucket_olh_log_entry& entry = *viter;
11246
11247 ldout(cct, 20) << "olh_log_entry: op=" << (int)entry.op
11248 << " key=" << entry.key.name << "[" << entry.key.instance << "] "
11249 << (entry.delete_marker ? "(delete)" : "") << dendl;
11250 switch (entry.op) {
11251 case CLS_RGW_OLH_OP_REMOVE_INSTANCE:
11252 remove_instances.push_back(entry.key);
11253 break;
11254 case CLS_RGW_OLH_OP_LINK_OLH:
11255 need_to_link = true;
11256 need_to_remove = false;
11257 key = entry.key;
11258 delete_marker = entry.delete_marker;
11259 break;
11260 case CLS_RGW_OLH_OP_UNLINK_OLH:
11261 need_to_remove = true;
11262 need_to_link = false;
11263 break;
11264 default:
11265 ldout(cct, 0) << "ERROR: apply_olh_log: invalid op: " << (int)entry.op << dendl;
11266 return -EIO;
11267 }
11268 string attr_name = RGW_ATTR_OLH_PENDING_PREFIX;
11269 attr_name.append(entry.op_tag);
11270 op.rmxattr(attr_name.c_str());
11271 }
11272 }
11273
11274 rgw_rados_ref ref;
11275 int r = get_obj_head_ref(bucket_info, obj, &ref);
11276 if (r < 0) {
11277 return r;
11278 }
11279
11280 const rgw_bucket& bucket = obj.bucket;
11281
11282 if (need_to_link) {
11283 rgw_obj target(bucket, key);
11284 RGWOLHInfo info;
11285 info.target = target;
11286 info.removed = delete_marker;
11287 bufferlist bl;
11288 ::encode(info, bl);
11289 op.setxattr(RGW_ATTR_OLH_INFO, bl);
11290 }
11291
11292 /* first remove object instances */
11293 for (list<cls_rgw_obj_key>::iterator liter = remove_instances.begin();
11294 liter != remove_instances.end(); ++liter) {
11295 cls_rgw_obj_key& key = *liter;
11296 rgw_obj obj_instance(bucket, key);
11297 int ret = delete_obj(obj_ctx, bucket_info, obj_instance, 0, RGW_BILOG_FLAG_VERSIONED_OP, ceph::real_time(), zones_trace);
11298 if (ret < 0 && ret != -ENOENT) {
11299 ldout(cct, 0) << "ERROR: delete_obj() returned " << ret << " obj_instance=" << obj_instance << dendl;
11300 return ret;
11301 }
11302 }
11303
11304 /* update olh object */
11305 r = ref.ioctx.operate(ref.oid, &op);
11306 if (r == -ECANCELED) {
11307 r = 0;
11308 }
11309 if (r < 0) {
11310 ldout(cct, 0) << "ERROR: could not apply olh update, r=" << r << dendl;
11311 return r;
11312 }
11313
11314 r = bucket_index_trim_olh_log(bucket_info, state, obj, last_ver);
11315 if (r < 0) {
11316 ldout(cct, 0) << "ERROR: could not trim olh log, r=" << r << dendl;
11317 return r;
11318 }
11319
11320 if (need_to_remove) {
11321 ObjectWriteOperation rm_op;
11322
11323 rm_op.cmpxattr(RGW_ATTR_OLH_ID_TAG, CEPH_OSD_CMPXATTR_OP_EQ, olh_tag);
11324 rm_op.cmpxattr(RGW_ATTR_OLH_VER, CEPH_OSD_CMPXATTR_OP_GT, last_ver);
11325 cls_obj_check_prefix_exist(rm_op, RGW_ATTR_OLH_PENDING_PREFIX, true); /* fail if found one of these, pending modification */
11326 rm_op.remove();
11327
11328 r = ref.ioctx.operate(ref.oid, &rm_op);
11329 if (r == -ECANCELED) {
11330 return 0; /* someone else won this race */
11331 } else {
11332 /*
11333 * only clear if was successful, otherwise we might clobber pending operations on this object
11334 */
11335 r = bucket_index_clear_olh(bucket_info, state, obj);
11336 if (r < 0) {
11337 ldout(cct, 0) << "ERROR: could not clear bucket index olh entries r=" << r << dendl;
11338 return r;
11339 }
11340 }
11341 }
11342
11343 return 0;
11344 }
11345
11346 /*
11347 * read olh log and apply it
11348 */
11349 int RGWRados::update_olh(RGWObjectCtx& obj_ctx, RGWObjState *state, const RGWBucketInfo& bucket_info, const rgw_obj& obj, rgw_zone_set *zones_trace)
11350 {
11351 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
11352 bool is_truncated;
11353 uint64_t ver_marker = 0;
11354
11355 do {
11356 int ret = bucket_index_read_olh_log(bucket_info, *state, obj, ver_marker, &log, &is_truncated);
11357 if (ret < 0) {
11358 return ret;
11359 }
11360 ret = apply_olh_log(obj_ctx, *state, bucket_info, obj, state->olh_tag, log, &ver_marker, zones_trace);
11361 if (ret < 0) {
11362 return ret;
11363 }
11364 } while (is_truncated);
11365
11366 return 0;
11367 }
11368
11369 int RGWRados::set_olh(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& target_obj, bool delete_marker, rgw_bucket_dir_entry_meta *meta,
11370 uint64_t olh_epoch, real_time unmod_since, bool high_precision_time, rgw_zone_set *zones_trace)
11371 {
11372 string op_tag;
11373
11374 rgw_obj olh_obj = target_obj;
11375 olh_obj.key.instance.clear();
11376
11377 RGWObjState *state = NULL;
11378
11379 int ret = 0;
11380 int i;
11381
11382 #define MAX_ECANCELED_RETRY 100
11383 for (i = 0; i < MAX_ECANCELED_RETRY; i++) {
11384 if (ret == -ECANCELED) {
11385 obj_ctx.obj.invalidate(olh_obj);
11386 }
11387
11388 ret = get_obj_state(&obj_ctx, bucket_info, olh_obj, &state, false); /* don't follow olh */
11389 if (ret < 0) {
11390 return ret;
11391 }
11392
11393 ret = olh_init_modification(bucket_info, *state, olh_obj, &op_tag);
11394 if (ret < 0) {
11395 ldout(cct, 20) << "olh_init_modification() target_obj=" << target_obj << " delete_marker=" << (int)delete_marker << " returned " << ret << dendl;
11396 if (ret == -ECANCELED) {
11397 continue;
11398 }
11399 return ret;
11400 }
11401 ret = bucket_index_link_olh(bucket_info, *state, target_obj, delete_marker, op_tag, meta, olh_epoch, unmod_since, high_precision_time, zones_trace);
11402 if (ret < 0) {
11403 ldout(cct, 20) << "bucket_index_link_olh() target_obj=" << target_obj << " delete_marker=" << (int)delete_marker << " returned " << ret << dendl;
11404 if (ret == -ECANCELED) {
11405 continue;
11406 }
11407 return ret;
11408 }
11409 break;
11410 }
11411
11412 if (i == MAX_ECANCELED_RETRY) {
11413 ldout(cct, 0) << "ERROR: exceeded max ECANCELED retries, aborting (EIO)" << dendl;
11414 return -EIO;
11415 }
11416
11417 ret = update_olh(obj_ctx, state, bucket_info, olh_obj);
11418 if (ret == -ECANCELED) { /* already did what we needed, no need to retry, raced with another user */
11419 ret = 0;
11420 }
11421 if (ret < 0) {
11422 ldout(cct, 20) << "update_olh() target_obj=" << target_obj << " returned " << ret << dendl;
11423 return ret;
11424 }
11425
11426 return 0;
11427 }
11428
11429 int RGWRados::unlink_obj_instance(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& target_obj,
11430 uint64_t olh_epoch, rgw_zone_set *zones_trace)
11431 {
11432 string op_tag;
11433
11434 rgw_obj olh_obj = target_obj;
11435 olh_obj.key.instance.clear();
11436
11437 RGWObjState *state = NULL;
11438
11439 int ret = 0;
11440 int i;
11441
11442 for (i = 0; i < MAX_ECANCELED_RETRY; i++) {
11443 if (ret == -ECANCELED) {
11444 obj_ctx.obj.invalidate(olh_obj);
11445 }
11446
11447 ret = get_obj_state(&obj_ctx, bucket_info, olh_obj, &state, false); /* don't follow olh */
11448 if (ret < 0)
11449 return ret;
11450
11451 ret = olh_init_modification(bucket_info, *state, olh_obj, &op_tag);
11452 if (ret < 0) {
11453 ldout(cct, 20) << "olh_init_modification() target_obj=" << target_obj << " returned " << ret << dendl;
11454 if (ret == -ECANCELED) {
11455 continue;
11456 }
11457 return ret;
11458 }
11459
11460 string olh_tag(state->olh_tag.c_str(), state->olh_tag.length());
11461
11462 ret = bucket_index_unlink_instance(bucket_info, target_obj, op_tag, olh_tag, olh_epoch, zones_trace);
11463 if (ret < 0) {
11464 ldout(cct, 20) << "bucket_index_unlink_instance() target_obj=" << target_obj << " returned " << ret << dendl;
11465 if (ret == -ECANCELED) {
11466 continue;
11467 }
11468 return ret;
11469 }
11470 break;
11471 }
11472
11473 if (i == MAX_ECANCELED_RETRY) {
11474 ldout(cct, 0) << "ERROR: exceeded max ECANCELED retries, aborting (EIO)" << dendl;
11475 return -EIO;
11476 }
11477
11478 ret = update_olh(obj_ctx, state, bucket_info, olh_obj, zones_trace);
11479 if (ret == -ECANCELED) { /* already did what we needed, no need to retry, raced with another user */
11480 return 0;
11481 }
11482 if (ret < 0) {
11483 ldout(cct, 20) << "update_olh() target_obj=" << target_obj << " returned " << ret << dendl;
11484 return ret;
11485 }
11486
11487 return 0;
11488 }
11489
11490 void RGWRados::gen_rand_obj_instance_name(rgw_obj *target_obj)
11491 {
11492 #define OBJ_INSTANCE_LEN 32
11493 char buf[OBJ_INSTANCE_LEN + 1];
11494
11495 gen_rand_alphanumeric_no_underscore(cct, buf, OBJ_INSTANCE_LEN); /* don't want it to get url escaped,
11496 no underscore for instance name due to the way we encode the raw keys */
11497
11498 target_obj->key.set_instance(buf);
11499 }
11500
11501 static void filter_attrset(map<string, bufferlist>& unfiltered_attrset, const string& check_prefix,
11502 map<string, bufferlist> *attrset)
11503 {
11504 attrset->clear();
11505 map<string, bufferlist>::iterator iter;
11506 for (iter = unfiltered_attrset.lower_bound(check_prefix);
11507 iter != unfiltered_attrset.end(); ++iter) {
11508 if (!boost::algorithm::starts_with(iter->first, check_prefix))
11509 break;
11510 (*attrset)[iter->first] = iter->second;
11511 }
11512 }
11513
11514 int RGWRados::get_olh(const RGWBucketInfo& bucket_info, const rgw_obj& obj, RGWOLHInfo *olh)
11515 {
11516 map<string, bufferlist> unfiltered_attrset;
11517
11518 ObjectReadOperation op;
11519 op.getxattrs(&unfiltered_attrset, NULL);
11520
11521 bufferlist outbl;
11522 int r = obj_operate(bucket_info, obj, &op);
11523
11524 if (r < 0) {
11525 return r;
11526 }
11527 map<string, bufferlist> attrset;
11528
11529 filter_attrset(unfiltered_attrset, RGW_ATTR_OLH_PREFIX, &attrset);
11530
11531 map<string, bufferlist>::iterator iter = attrset.find(RGW_ATTR_OLH_INFO);
11532 if (iter == attrset.end()) { /* not an olh */
11533 return -EINVAL;
11534 }
11535
11536 try {
11537 bufferlist::iterator biter = iter->second.begin();
11538 ::decode(*olh, biter);
11539 } catch (buffer::error& err) {
11540 ldout(cct, 0) << "ERROR: failed to decode olh info" << dendl;
11541 return -EIO;
11542 }
11543
11544 return 0;
11545 }
11546
11547 void RGWRados::check_pending_olh_entries(map<string, bufferlist>& pending_entries,
11548 map<string, bufferlist> *rm_pending_entries)
11549 {
11550 map<string, bufferlist>::iterator iter = pending_entries.begin();
11551
11552 real_time now = real_clock::now();
11553
11554 while (iter != pending_entries.end()) {
11555 bufferlist::iterator biter = iter->second.begin();
11556 RGWOLHPendingInfo pending_info;
11557 try {
11558 ::decode(pending_info, biter);
11559 } catch (buffer::error& err) {
11560 /* skipping bad entry, we could remove it but it might hide a bug */
11561 ldout(cct, 0) << "ERROR: failed to decode pending entry " << iter->first << dendl;
11562 ++iter;
11563 continue;
11564 }
11565
11566 map<string, bufferlist>::iterator cur_iter = iter;
11567 ++iter;
11568 if (now - pending_info.time >= make_timespan(cct->_conf->rgw_olh_pending_timeout_sec)) {
11569 (*rm_pending_entries)[cur_iter->first] = cur_iter->second;
11570 pending_entries.erase(cur_iter);
11571 } else {
11572 /* entries names are sorted by time (rounded to a second) */
11573 break;
11574 }
11575 }
11576 }
11577
11578 int RGWRados::remove_olh_pending_entries(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& olh_obj, map<string, bufferlist>& pending_attrs)
11579 {
11580 ObjectWriteOperation op;
11581
11582 bucket_index_guard_olh_op(state, op);
11583
11584 for (map<string, bufferlist>::iterator iter = pending_attrs.begin(); iter != pending_attrs.end(); ++iter) {
11585 op.rmxattr(iter->first.c_str());
11586 }
11587
11588 rgw_rados_ref ref;
11589 int r = get_obj_head_ref(bucket_info, olh_obj, &ref);
11590 if (r < 0) {
11591 return r;
11592 }
11593
11594 /* update olh object */
11595 r = ref.ioctx.operate(ref.oid, &op);
11596 if (r == -ENOENT || r == -ECANCELED) {
11597 /* raced with some other change, shouldn't sweat about it */
11598 r = 0;
11599 }
11600 if (r < 0) {
11601 ldout(cct, 0) << "ERROR: could not apply olh update, r=" << r << dendl;
11602 return r;
11603 }
11604
11605 return 0;
11606 }
11607
11608 int RGWRados::follow_olh(const RGWBucketInfo& bucket_info, RGWObjectCtx& obj_ctx, RGWObjState *state, const rgw_obj& olh_obj, rgw_obj *target)
11609 {
11610 map<string, bufferlist> pending_entries;
11611 filter_attrset(state->attrset, RGW_ATTR_OLH_PENDING_PREFIX, &pending_entries);
11612
11613 map<string, bufferlist> rm_pending_entries;
11614 check_pending_olh_entries(pending_entries, &rm_pending_entries);
11615
11616 if (!rm_pending_entries.empty()) {
11617 int ret = remove_olh_pending_entries(bucket_info, *state, olh_obj, rm_pending_entries);
11618 if (ret < 0) {
11619 ldout(cct, 20) << "ERROR: rm_pending_entries returned ret=" << ret << dendl;
11620 return ret;
11621 }
11622 }
11623 if (!pending_entries.empty()) {
11624 ldout(cct, 20) << __func__ << "(): found pending entries, need to update_olh() on bucket=" << olh_obj.bucket << dendl;
11625
11626 int ret = update_olh(obj_ctx, state, bucket_info, olh_obj);
11627 if (ret < 0) {
11628 return ret;
11629 }
11630 }
11631
11632 map<string, bufferlist>::iterator iter = state->attrset.find(RGW_ATTR_OLH_INFO);
11633 assert(iter != state->attrset.end());
11634 RGWOLHInfo olh;
11635 try {
11636 bufferlist::iterator biter = iter->second.begin();
11637 ::decode(olh, biter);
11638 } catch (buffer::error& err) {
11639 ldout(cct, 0) << "ERROR: failed to decode olh info" << dendl;
11640 return -EIO;
11641 }
11642
11643 if (olh.removed) {
11644 return -ENOENT;
11645 }
11646
11647 *target = olh.target;
11648
11649 return 0;
11650 }
11651
11652 int RGWRados::raw_obj_stat(rgw_raw_obj& obj, uint64_t *psize, real_time *pmtime, uint64_t *epoch,
11653 map<string, bufferlist> *attrs, bufferlist *first_chunk,
11654 RGWObjVersionTracker *objv_tracker)
11655 {
11656 rgw_rados_ref ref;
11657 int r = get_raw_obj_ref(obj, &ref);
11658 if (r < 0) {
11659 return r;
11660 }
11661
11662 map<string, bufferlist> unfiltered_attrset;
11663 uint64_t size = 0;
11664 struct timespec mtime_ts;
11665
11666 ObjectReadOperation op;
11667 if (objv_tracker) {
11668 objv_tracker->prepare_op_for_read(&op);
11669 }
11670 if (attrs) {
11671 op.getxattrs(&unfiltered_attrset, NULL);
11672 }
11673 if (psize || pmtime) {
11674 op.stat2(&size, &mtime_ts, NULL);
11675 }
11676 if (first_chunk) {
11677 op.read(0, cct->_conf->rgw_max_chunk_size, first_chunk, NULL);
11678 }
11679 bufferlist outbl;
11680 r = ref.ioctx.operate(ref.oid, &op, &outbl);
11681
11682 if (epoch) {
11683 *epoch = ref.ioctx.get_last_version();
11684 }
11685
11686 if (r < 0)
11687 return r;
11688
11689 if (psize)
11690 *psize = size;
11691 if (pmtime)
11692 *pmtime = ceph::real_clock::from_timespec(mtime_ts);
11693 if (attrs) {
11694 filter_attrset(unfiltered_attrset, RGW_ATTR_PREFIX, attrs);
11695 }
11696
11697 return 0;
11698 }
11699
11700 int RGWRados::get_bucket_stats(RGWBucketInfo& bucket_info, int shard_id, string *bucket_ver, string *master_ver,
11701 map<RGWObjCategory, RGWStorageStats>& stats, string *max_marker, bool *syncstopped)
11702 {
11703 map<string, rgw_bucket_dir_header> headers;
11704 map<int, string> bucket_instance_ids;
11705 int r = cls_bucket_head(bucket_info, shard_id, headers, &bucket_instance_ids);
11706 if (r < 0) {
11707 return r;
11708 }
11709
11710 assert(headers.size() == bucket_instance_ids.size());
11711
11712 map<string, rgw_bucket_dir_header>::iterator iter = headers.begin();
11713 map<int, string>::iterator viter = bucket_instance_ids.begin();
11714 BucketIndexShardsManager ver_mgr;
11715 BucketIndexShardsManager master_ver_mgr;
11716 BucketIndexShardsManager marker_mgr;
11717 char buf[64];
11718 for(; iter != headers.end(); ++iter, ++viter) {
11719 accumulate_raw_stats(iter->second, stats);
11720 snprintf(buf, sizeof(buf), "%lu", (unsigned long)iter->second.ver);
11721 ver_mgr.add(viter->first, string(buf));
11722 snprintf(buf, sizeof(buf), "%lu", (unsigned long)iter->second.master_ver);
11723 master_ver_mgr.add(viter->first, string(buf));
11724 if (shard_id >= 0) {
11725 *max_marker = iter->second.max_marker;
11726 } else {
11727 marker_mgr.add(viter->first, iter->second.max_marker);
11728 }
11729 if (syncstopped != NULL)
11730 *syncstopped = iter->second.syncstopped;
11731 }
11732 ver_mgr.to_string(bucket_ver);
11733 master_ver_mgr.to_string(master_ver);
11734 if (shard_id < 0) {
11735 marker_mgr.to_string(max_marker);
11736 }
11737 return 0;
11738 }
11739
11740 int RGWRados::get_bi_log_status(RGWBucketInfo& bucket_info, int shard_id,
11741 map<int, string>& markers)
11742 {
11743 map<string, rgw_bucket_dir_header> headers;
11744 map<int, string> bucket_instance_ids;
11745 int r = cls_bucket_head(bucket_info, shard_id, headers, &bucket_instance_ids);
11746 if (r < 0)
11747 return r;
11748
11749 assert(headers.size() == bucket_instance_ids.size());
11750
11751 map<string, rgw_bucket_dir_header>::iterator iter = headers.begin();
11752 map<int, string>::iterator viter = bucket_instance_ids.begin();
11753
11754 for(; iter != headers.end(); ++iter, ++viter) {
11755 if (shard_id >= 0) {
11756 markers[shard_id] = iter->second.max_marker;
11757 } else {
11758 markers[viter->first] = iter->second.max_marker;
11759 }
11760 }
11761 return 0;
11762 }
11763
11764 class RGWGetBucketStatsContext : public RGWGetDirHeader_CB {
11765 RGWGetBucketStats_CB *cb;
11766 uint32_t pendings;
11767 map<RGWObjCategory, RGWStorageStats> stats;
11768 int ret_code;
11769 bool should_cb;
11770 Mutex lock;
11771
11772 public:
11773 RGWGetBucketStatsContext(RGWGetBucketStats_CB *_cb, uint32_t _pendings)
11774 : cb(_cb), pendings(_pendings), stats(), ret_code(0), should_cb(true),
11775 lock("RGWGetBucketStatsContext") {}
11776
11777 void handle_response(int r, rgw_bucket_dir_header& header) override {
11778 Mutex::Locker l(lock);
11779 if (should_cb) {
11780 if ( r >= 0) {
11781 accumulate_raw_stats(header, stats);
11782 } else {
11783 ret_code = r;
11784 }
11785
11786 // Are we all done?
11787 if (--pendings == 0) {
11788 if (!ret_code) {
11789 cb->set_response(&stats);
11790 }
11791 cb->handle_response(ret_code);
11792 cb->put();
11793 }
11794 }
11795 }
11796
11797 void unset_cb() {
11798 Mutex::Locker l(lock);
11799 should_cb = false;
11800 }
11801 };
11802
11803 int RGWRados::get_bucket_stats_async(RGWBucketInfo& bucket_info, int shard_id, RGWGetBucketStats_CB *ctx)
11804 {
11805 int num_aio = 0;
11806 RGWGetBucketStatsContext *get_ctx = new RGWGetBucketStatsContext(ctx, bucket_info.num_shards ? : 1);
11807 assert(get_ctx);
11808 int r = cls_bucket_head_async(bucket_info, shard_id, get_ctx, &num_aio);
11809 if (r < 0) {
11810 ctx->put();
11811 if (num_aio) {
11812 get_ctx->unset_cb();
11813 }
11814 }
11815 get_ctx->put();
11816 return r;
11817 }
11818
11819 class RGWGetUserStatsContext : public RGWGetUserHeader_CB {
11820 RGWGetUserStats_CB *cb;
11821
11822 public:
11823 explicit RGWGetUserStatsContext(RGWGetUserStats_CB * const cb)
11824 : cb(cb) {}
11825
11826 void handle_response(int r, cls_user_header& header) override {
11827 const cls_user_stats& hs = header.stats;
11828 if (r >= 0) {
11829 RGWStorageStats stats;
11830
11831 stats.size = hs.total_bytes;
11832 stats.size_rounded = hs.total_bytes_rounded;
11833 stats.num_objects = hs.total_entries;
11834
11835 cb->set_response(stats);
11836 }
11837
11838 cb->handle_response(r);
11839
11840 cb->put();
11841 }
11842 };
11843
11844 int RGWRados::get_user_stats(const rgw_user& user, RGWStorageStats& stats)
11845 {
11846 string user_str = user.to_str();
11847
11848 cls_user_header header;
11849 int r = cls_user_get_header(user_str, &header);
11850 if (r < 0)
11851 return r;
11852
11853 const cls_user_stats& hs = header.stats;
11854
11855 stats.size = hs.total_bytes;
11856 stats.size_rounded = hs.total_bytes_rounded;
11857 stats.num_objects = hs.total_entries;
11858
11859 return 0;
11860 }
11861
11862 int RGWRados::get_user_stats_async(const rgw_user& user, RGWGetUserStats_CB *ctx)
11863 {
11864 string user_str = user.to_str();
11865
11866 RGWGetUserStatsContext *get_ctx = new RGWGetUserStatsContext(ctx);
11867 int r = cls_user_get_header_async(user_str, get_ctx);
11868 if (r < 0) {
11869 ctx->put();
11870 delete get_ctx;
11871 return r;
11872 }
11873
11874 return 0;
11875 }
11876
11877 void RGWRados::get_bucket_meta_oid(const rgw_bucket& bucket, string& oid)
11878 {
11879 oid = RGW_BUCKET_INSTANCE_MD_PREFIX + bucket.get_key(':');
11880 }
11881
11882 void RGWRados::get_bucket_instance_obj(const rgw_bucket& bucket, rgw_raw_obj& obj)
11883 {
11884 if (!bucket.oid.empty()) {
11885 obj.init(get_zone_params().domain_root, bucket.oid);
11886 } else {
11887 string oid;
11888 get_bucket_meta_oid(bucket, oid);
11889 obj.init(get_zone_params().domain_root, oid);
11890 }
11891 }
11892
11893 int RGWRados::get_bucket_instance_info(RGWObjectCtx& obj_ctx, const string& meta_key, RGWBucketInfo& info,
11894 real_time *pmtime, map<string, bufferlist> *pattrs)
11895 {
11896 size_t pos = meta_key.find(':');
11897 if (pos == string::npos) {
11898 return -EINVAL;
11899 }
11900 string oid = RGW_BUCKET_INSTANCE_MD_PREFIX + meta_key;
11901 rgw_bucket_instance_key_to_oid(oid);
11902
11903 return get_bucket_instance_from_oid(obj_ctx, oid, info, pmtime, pattrs);
11904 }
11905
11906 int RGWRados::get_bucket_instance_info(RGWObjectCtx& obj_ctx, const rgw_bucket& bucket, RGWBucketInfo& info,
11907 real_time *pmtime, map<string, bufferlist> *pattrs)
11908 {
11909 string oid;
11910 if (bucket.oid.empty()) {
11911 get_bucket_meta_oid(bucket, oid);
11912 } else {
11913 oid = bucket.oid;
11914 }
11915
11916 return get_bucket_instance_from_oid(obj_ctx, oid, info, pmtime, pattrs);
11917 }
11918
11919 int RGWRados::get_bucket_instance_from_oid(RGWObjectCtx& obj_ctx, const string& oid, RGWBucketInfo& info,
11920 real_time *pmtime, map<string, bufferlist> *pattrs,
11921 rgw_cache_entry_info *cache_info,
11922 boost::optional<obj_version> refresh_version)
11923 {
11924 ldout(cct, 20) << "reading from " << get_zone_params().domain_root << ":" << oid << dendl;
11925
11926 bufferlist epbl;
11927
11928 int ret = rgw_get_system_obj(this, obj_ctx, get_zone_params().domain_root,
11929 oid, epbl, &info.objv_tracker, pmtime, pattrs,
11930 cache_info, refresh_version);
11931 if (ret < 0) {
11932 return ret;
11933 }
11934
11935 bufferlist::iterator iter = epbl.begin();
11936 try {
11937 ::decode(info, iter);
11938 } catch (buffer::error& err) {
11939 ldout(cct, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl;
11940 return -EIO;
11941 }
11942 info.bucket.oid = oid;
11943 return 0;
11944 }
11945
11946 int RGWRados::get_bucket_entrypoint_info(RGWObjectCtx& obj_ctx,
11947 const string& tenant_name,
11948 const string& bucket_name,
11949 RGWBucketEntryPoint& entry_point,
11950 RGWObjVersionTracker *objv_tracker,
11951 real_time *pmtime,
11952 map<string, bufferlist> *pattrs,
11953 rgw_cache_entry_info *cache_info,
11954 boost::optional<obj_version> refresh_version)
11955 {
11956 bufferlist bl;
11957 string bucket_entry;
11958
11959 rgw_make_bucket_entry_name(tenant_name, bucket_name, bucket_entry);
11960 int ret = rgw_get_system_obj(this, obj_ctx, get_zone_params().domain_root,
11961 bucket_entry, bl, objv_tracker, pmtime, pattrs,
11962 cache_info, refresh_version);
11963 if (ret < 0) {
11964 return ret;
11965 }
11966
11967 bufferlist::iterator iter = bl.begin();
11968 try {
11969 ::decode(entry_point, iter);
11970 } catch (buffer::error& err) {
11971 ldout(cct, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl;
11972 return -EIO;
11973 }
11974 return 0;
11975 }
11976
11977 int RGWRados::convert_old_bucket_info(RGWObjectCtx& obj_ctx,
11978 const string& tenant_name,
11979 const string& bucket_name)
11980 {
11981 RGWBucketEntryPoint entry_point;
11982 real_time ep_mtime;
11983 RGWObjVersionTracker ot;
11984 map<string, bufferlist> attrs;
11985 RGWBucketInfo info;
11986
11987 ldout(cct, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket_name << dendl;
11988
11989 int ret = get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, entry_point, &ot, &ep_mtime, &attrs);
11990 if (ret < 0) {
11991 ldout(cct, 0) << "ERROR: get_bucket_entrypoint_info() returned " << ret << " bucket=" << bucket_name << dendl;
11992 return ret;
11993 }
11994
11995 if (!entry_point.has_bucket_info) {
11996 /* already converted! */
11997 return 0;
11998 }
11999
12000 info = entry_point.old_bucket_info;
12001 info.bucket.oid = bucket_name;
12002 info.ep_objv = ot.read_version;
12003
12004 ot.generate_new_write_ver(cct);
12005
12006 ret = put_linked_bucket_info(info, false, ep_mtime, &ot.write_version, &attrs, true);
12007 if (ret < 0) {
12008 ldout(cct, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret << dendl;
12009 return ret;
12010 }
12011
12012 return 0;
12013 }
12014
12015 int RGWRados::_get_bucket_info(RGWObjectCtx& obj_ctx,
12016 const string& tenant,
12017 const string& bucket_name,
12018 RGWBucketInfo& info,
12019 real_time *pmtime,
12020 map<string, bufferlist> *pattrs,
12021 boost::optional<obj_version> refresh_version)
12022 {
12023 bucket_info_entry e;
12024 string bucket_entry;
12025 rgw_make_bucket_entry_name(tenant, bucket_name, bucket_entry);
12026
12027
12028 if (binfo_cache->find(bucket_entry, &e)) {
12029 if (refresh_version &&
12030 e.info.objv_tracker.read_version.compare(&(*refresh_version))) {
12031 lderr(cct) << "WARNING: The bucket info cache is inconsistent. This is "
12032 << "a failure that should be debugged. I am a nice machine, "
12033 << "so I will try to recover." << dendl;
12034 binfo_cache->invalidate(bucket_entry);
12035 }
12036 info = e.info;
12037 if (pattrs)
12038 *pattrs = e.attrs;
12039 if (pmtime)
12040 *pmtime = e.mtime;
12041 return 0;
12042 }
12043
12044 RGWBucketEntryPoint entry_point;
12045 real_time ep_mtime;
12046 RGWObjVersionTracker ot;
12047 rgw_cache_entry_info entry_cache_info;
12048 int ret = get_bucket_entrypoint_info(obj_ctx, tenant, bucket_name,
12049 entry_point, &ot, &ep_mtime, pattrs,
12050 &entry_cache_info, refresh_version);
12051 if (ret < 0) {
12052 /* only init these fields */
12053 info.bucket.tenant = tenant;
12054 info.bucket.name = bucket_name;
12055 return ret;
12056 }
12057
12058 if (entry_point.has_bucket_info) {
12059 info = entry_point.old_bucket_info;
12060 info.bucket.oid = bucket_name;
12061 info.bucket.tenant = tenant;
12062 info.ep_objv = ot.read_version;
12063 ldout(cct, 20) << "rgw_get_bucket_info: old bucket info, bucket=" << info.bucket << " owner " << info.owner << dendl;
12064 return 0;
12065 }
12066
12067 /* data is in the bucket instance object, we need to get attributes from there, clear everything
12068 * that we got
12069 */
12070 if (pattrs) {
12071 pattrs->clear();
12072 }
12073
12074 ldout(cct, 20) << "rgw_get_bucket_info: bucket instance: " << entry_point.bucket << dendl;
12075
12076
12077 /* read bucket instance info */
12078
12079 string oid;
12080 get_bucket_meta_oid(entry_point.bucket, oid);
12081
12082 rgw_cache_entry_info cache_info;
12083
12084 ret = get_bucket_instance_from_oid(obj_ctx, oid, e.info, &e.mtime, &e.attrs,
12085 &cache_info, refresh_version);
12086 e.info.ep_objv = ot.read_version;
12087 info = e.info;
12088 if (ret < 0) {
12089 lderr(cct) << "ERROR: get_bucket_instance_from_oid failed: " << ret << dendl;
12090 info.bucket.tenant = tenant;
12091 info.bucket.name = bucket_name;
12092 // XXX and why return anything in case of an error anyway?
12093 return ret;
12094 }
12095
12096 if (pmtime)
12097 *pmtime = e.mtime;
12098 if (pattrs)
12099 *pattrs = e.attrs;
12100
12101 list<rgw_cache_entry_info *> cache_info_entries;
12102 cache_info_entries.push_back(&entry_cache_info);
12103 cache_info_entries.push_back(&cache_info);
12104
12105
12106 /* chain to both bucket entry point and bucket instance */
12107 if (!binfo_cache->put(this, bucket_entry, &e, cache_info_entries)) {
12108 ldout(cct, 20) << "couldn't put binfo cache entry, might have raced with data changes" << dendl;
12109 }
12110
12111 if (refresh_version &&
12112 refresh_version->compare(&info.objv_tracker.read_version)) {
12113 lderr(cct) << "WARNING: The OSD has the same version I have. Something may "
12114 << "have gone squirrelly. An administrator may have forced a "
12115 << "change; otherwise there is a problem somewhere." << dendl;
12116 }
12117
12118 return 0;
12119 }
12120
12121 int RGWRados::get_bucket_info(RGWObjectCtx& obj_ctx,
12122 const string& tenant, const string& bucket_name,
12123 RGWBucketInfo& info,
12124 real_time *pmtime, map<string, bufferlist> *pattrs)
12125 {
12126 return _get_bucket_info(obj_ctx, tenant, bucket_name, info, pmtime,
12127 pattrs, boost::none);
12128 }
12129
12130 int RGWRados::try_refresh_bucket_info(RGWBucketInfo& info,
12131 ceph::real_time *pmtime,
12132 map<string, bufferlist> *pattrs)
12133 {
12134 RGWObjectCtx obj_ctx(this);
12135
12136 return _get_bucket_info(obj_ctx, info.bucket.tenant, info.bucket.name,
12137 info, pmtime, pattrs, info.objv_tracker.read_version);
12138 }
12139
12140 int RGWRados::put_bucket_entrypoint_info(const string& tenant_name, const string& bucket_name, RGWBucketEntryPoint& entry_point,
12141 bool exclusive, RGWObjVersionTracker& objv_tracker, real_time mtime,
12142 map<string, bufferlist> *pattrs)
12143 {
12144 bufferlist epbl;
12145 ::encode(entry_point, epbl);
12146 string bucket_entry;
12147 rgw_make_bucket_entry_name(tenant_name, bucket_name, bucket_entry);
12148 return rgw_bucket_store_info(this, bucket_entry, epbl, exclusive, pattrs, &objv_tracker, mtime);
12149 }
12150
12151 int RGWRados::put_bucket_instance_info(RGWBucketInfo& info, bool exclusive,
12152 real_time mtime, map<string, bufferlist> *pattrs)
12153 {
12154 info.has_instance_obj = true;
12155 bufferlist bl;
12156
12157 ::encode(info, bl);
12158
12159 string key = info.bucket.get_key(); /* when we go through meta api, we don't use oid directly */
12160 int ret = rgw_bucket_instance_store_info(this, key, bl, exclusive, pattrs, &info.objv_tracker, mtime);
12161 if (ret == -EEXIST) {
12162 /* well, if it's exclusive we shouldn't overwrite it, because we might race with another
12163 * bucket operation on this specific bucket (e.g., being synced from the master), but
12164 * since bucket instace meta object is unique for this specific bucket instace, we don't
12165 * need to return an error.
12166 * A scenario where we'd get -EEXIST here, is in a multi-zone config, we're not on the
12167 * master, creating a bucket, sending bucket creation to the master, we create the bucket
12168 * locally, while in the sync thread we sync the new bucket.
12169 */
12170 ret = 0;
12171 }
12172 return ret;
12173 }
12174
12175 int RGWRados::put_linked_bucket_info(RGWBucketInfo& info, bool exclusive, real_time mtime, obj_version *pep_objv,
12176 map<string, bufferlist> *pattrs, bool create_entry_point)
12177 {
12178 bool create_head = !info.has_instance_obj || create_entry_point;
12179
12180 int ret = put_bucket_instance_info(info, exclusive, mtime, pattrs);
12181 if (ret < 0) {
12182 return ret;
12183 }
12184
12185 if (!create_head)
12186 return 0; /* done! */
12187
12188 RGWBucketEntryPoint entry_point;
12189 entry_point.bucket = info.bucket;
12190 entry_point.owner = info.owner;
12191 entry_point.creation_time = info.creation_time;
12192 entry_point.linked = true;
12193 RGWObjVersionTracker ot;
12194 if (pep_objv && !pep_objv->tag.empty()) {
12195 ot.write_version = *pep_objv;
12196 } else {
12197 ot.generate_new_write_ver(cct);
12198 if (pep_objv) {
12199 *pep_objv = ot.write_version;
12200 }
12201 }
12202 ret = put_bucket_entrypoint_info(info.bucket.tenant, info.bucket.name, entry_point, exclusive, ot, mtime, NULL);
12203 if (ret < 0)
12204 return ret;
12205
12206 return 0;
12207 }
12208
12209 int RGWRados::omap_get_vals(rgw_raw_obj& obj, bufferlist& header, const string& marker, uint64_t count, std::map<string, bufferlist>& m)
12210 {
12211 rgw_rados_ref ref;
12212 int r = get_raw_obj_ref(obj, &ref);
12213 if (r < 0) {
12214 return r;
12215 }
12216
12217 r = ref.ioctx.omap_get_vals(ref.oid, marker, count, &m);
12218 if (r < 0)
12219 return r;
12220
12221 return 0;
12222
12223 }
12224
12225 int RGWRados::omap_get_all(rgw_raw_obj& obj, bufferlist& header,
12226 std::map<string, bufferlist>& m)
12227 {
12228 rgw_rados_ref ref;
12229 int r = get_raw_obj_ref(obj, &ref);
12230 if (r < 0) {
12231 return r;
12232 }
12233
12234 #define MAX_OMAP_GET_ENTRIES 1024
12235 const int count = MAX_OMAP_GET_ENTRIES;
12236 string start_after;
12237
12238 while (true) {
12239 std::map<string, bufferlist> t;
12240 r = ref.ioctx.omap_get_vals(ref.oid, start_after, count, &t);
12241 if (r < 0) {
12242 return r;
12243 }
12244 if (t.empty()) {
12245 break;
12246 }
12247 start_after = t.rbegin()->first;
12248 m.insert(t.begin(), t.end());
12249 }
12250 return 0;
12251 }
12252
12253 int RGWRados::omap_set(rgw_raw_obj& obj, const std::string& key, bufferlist& bl)
12254 {
12255 rgw_rados_ref ref;
12256 int r = get_raw_obj_ref(obj, &ref);
12257 if (r < 0) {
12258 return r;
12259 }
12260 ldout(cct, 15) << "omap_set obj=" << obj << " key=" << key << dendl;
12261
12262 map<string, bufferlist> m;
12263 m[key] = bl;
12264
12265 r = ref.ioctx.omap_set(ref.oid, m);
12266
12267 return r;
12268 }
12269
12270 int RGWRados::omap_set(rgw_raw_obj& obj, std::map<std::string, bufferlist>& m)
12271 {
12272 rgw_rados_ref ref;
12273 int r = get_raw_obj_ref(obj, &ref);
12274 if (r < 0) {
12275 return r;
12276 }
12277
12278 r = ref.ioctx.omap_set(ref.oid, m);
12279
12280 return r;
12281 }
12282
12283 int RGWRados::omap_del(rgw_raw_obj& obj, const std::string& key)
12284 {
12285 rgw_rados_ref ref;
12286 int r = get_raw_obj_ref(obj, &ref);
12287 if (r < 0) {
12288 return r;
12289 }
12290
12291 set<string> k;
12292 k.insert(key);
12293
12294 r = ref.ioctx.omap_rm_keys(ref.oid, k);
12295 return r;
12296 }
12297
12298 int RGWRados::update_containers_stats(map<string, RGWBucketEnt>& m)
12299 {
12300 RGWObjectCtx obj_ctx(this);
12301
12302 map<string, RGWBucketEnt>::iterator iter;
12303 for (iter = m.begin(); iter != m.end(); ++iter) {
12304 RGWBucketEnt& ent = iter->second;
12305 rgw_bucket& bucket = ent.bucket;
12306 ent.count = 0;
12307 ent.size = 0;
12308 ent.size_rounded = 0;
12309
12310 map<string, rgw_bucket_dir_header> headers;
12311
12312 RGWBucketInfo bucket_info;
12313 int ret = get_bucket_instance_info(obj_ctx, bucket, bucket_info, NULL, NULL);
12314 if (ret < 0) {
12315 return ret;
12316 }
12317
12318 int r = cls_bucket_head(bucket_info, RGW_NO_SHARD, headers);
12319 if (r < 0)
12320 return r;
12321
12322 map<string, rgw_bucket_dir_header>::iterator hiter = headers.begin();
12323 for (; hiter != headers.end(); ++hiter) {
12324 RGWObjCategory category = main_category;
12325 map<uint8_t, struct rgw_bucket_category_stats>::iterator iter = (hiter->second.stats).find((uint8_t)category);
12326 if (iter != hiter->second.stats.end()) {
12327 struct rgw_bucket_category_stats& stats = iter->second;
12328 ent.count += stats.num_entries;
12329 ent.size += stats.total_size;
12330 ent.size_rounded += stats.total_size_rounded;
12331 }
12332 }
12333
12334 // fill in placement_rule from the bucket instance for use in swift's
12335 // per-storage policy statistics
12336 ent.placement_rule = std::move(bucket_info.placement_rule);
12337 }
12338
12339 return m.size();
12340 }
12341
12342 int RGWRados::append_async(rgw_raw_obj& obj, size_t size, bufferlist& bl)
12343 {
12344 rgw_rados_ref ref;
12345 int r = get_raw_obj_ref(obj, &ref);
12346 if (r < 0) {
12347 return r;
12348 }
12349 librados::Rados *rad = get_rados_handle();
12350 librados::AioCompletion *completion = rad->aio_create_completion(NULL, NULL, NULL);
12351
12352 r = ref.ioctx.aio_append(ref.oid, completion, bl, size);
12353 completion->release();
12354 return r;
12355 }
12356
12357 int RGWRados::distribute(const string& key, bufferlist& bl)
12358 {
12359 /*
12360 * we were called before watch was initialized. This can only happen if we're updating some system
12361 * config object (e.g., zone info) during init. Don't try to distribute the cache info for these
12362 * objects, they're currently only read on startup anyway.
12363 */
12364 if (!watch_initialized)
12365 return 0;
12366
12367 string notify_oid;
12368 pick_control_oid(key, notify_oid);
12369
12370 ldout(cct, 10) << "distributing notification oid=" << notify_oid << " bl.length()=" << bl.length() << dendl;
12371 return control_pool_ctx.notify2(notify_oid, bl, 0, NULL);
12372 }
12373
12374 int RGWRados::pool_iterate_begin(const rgw_pool& pool, RGWPoolIterCtx& ctx)
12375 {
12376 librados::IoCtx& io_ctx = ctx.io_ctx;
12377 librados::NObjectIterator& iter = ctx.iter;
12378
12379 int r = open_pool_ctx(pool, io_ctx);
12380 if (r < 0)
12381 return r;
12382
12383 iter = io_ctx.nobjects_begin();
12384
12385 return 0;
12386 }
12387
12388 int RGWRados::pool_iterate_begin(const rgw_pool& pool, const string& cursor, RGWPoolIterCtx& ctx)
12389 {
12390 librados::IoCtx& io_ctx = ctx.io_ctx;
12391 librados::NObjectIterator& iter = ctx.iter;
12392
12393 int r = open_pool_ctx(pool, io_ctx);
12394 if (r < 0)
12395 return r;
12396
12397 librados::ObjectCursor oc;
12398 if (!oc.from_str(cursor)) {
12399 ldout(cct, 10) << "failed to parse cursor: " << cursor << dendl;
12400 return -EINVAL;
12401 }
12402
12403 iter = io_ctx.nobjects_begin(oc);
12404
12405 return 0;
12406 }
12407
12408 string RGWRados::pool_iterate_get_cursor(RGWPoolIterCtx& ctx)
12409 {
12410 return ctx.iter.get_cursor().to_str();
12411 }
12412
12413 int RGWRados::pool_iterate(RGWPoolIterCtx& ctx, uint32_t num, vector<rgw_bucket_dir_entry>& objs,
12414 bool *is_truncated, RGWAccessListFilter *filter)
12415 {
12416 librados::IoCtx& io_ctx = ctx.io_ctx;
12417 librados::NObjectIterator& iter = ctx.iter;
12418
12419 if (iter == io_ctx.nobjects_end())
12420 return -ENOENT;
12421
12422 uint32_t i;
12423
12424 for (i = 0; i < num && iter != io_ctx.nobjects_end(); ++i, ++iter) {
12425 rgw_bucket_dir_entry e;
12426
12427 string oid = iter->get_oid();
12428 ldout(cct, 20) << "RGWRados::pool_iterate: got " << oid << dendl;
12429
12430 // fill it in with initial values; we may correct later
12431 if (filter && !filter->filter(oid, oid))
12432 continue;
12433
12434 e.key = oid;
12435 objs.push_back(e);
12436 }
12437
12438 if (is_truncated)
12439 *is_truncated = (iter != io_ctx.nobjects_end());
12440
12441 return objs.size();
12442 }
12443 struct RGWAccessListFilterPrefix : public RGWAccessListFilter {
12444 string prefix;
12445
12446 explicit RGWAccessListFilterPrefix(const string& _prefix) : prefix(_prefix) {}
12447 bool filter(string& name, string& key) override {
12448 return (prefix.compare(key.substr(0, prefix.size())) == 0);
12449 }
12450 };
12451
12452 int RGWRados::list_raw_objects_init(const rgw_pool& pool, const string& marker, RGWListRawObjsCtx *ctx)
12453 {
12454 if (!ctx->initialized) {
12455 int r = pool_iterate_begin(pool, marker, ctx->iter_ctx);
12456 if (r < 0) {
12457 ldout(cct, 10) << "failed to list objects pool_iterate_begin() returned r=" << r << dendl;
12458 return r;
12459 }
12460 ctx->initialized = true;
12461 }
12462 return 0;
12463 }
12464
12465 int RGWRados::list_raw_objects_next(const string& prefix_filter, int max,
12466 RGWListRawObjsCtx& ctx, list<string>& oids,
12467 bool *is_truncated)
12468 {
12469 if (!ctx.initialized) {
12470 return -EINVAL;
12471 }
12472 RGWAccessListFilterPrefix filter(prefix_filter);
12473 vector<rgw_bucket_dir_entry> objs;
12474 int r = pool_iterate(ctx.iter_ctx, max, objs, is_truncated, &filter);
12475 if (r < 0) {
12476 if(r != -ENOENT)
12477 ldout(cct, 10) << "failed to list objects pool_iterate returned r=" << r << dendl;
12478 return r;
12479 }
12480
12481 vector<rgw_bucket_dir_entry>::iterator iter;
12482 for (iter = objs.begin(); iter != objs.end(); ++iter) {
12483 oids.push_back(iter->key.name);
12484 }
12485
12486 return oids.size();
12487 }
12488
12489 int RGWRados::list_raw_objects(const rgw_pool& pool, const string& prefix_filter,
12490 int max, RGWListRawObjsCtx& ctx, list<string>& oids,
12491 bool *is_truncated)
12492 {
12493 if (!ctx.initialized) {
12494 int r = list_raw_objects_init(pool, string(), &ctx);
12495 if (r < 0) {
12496 return r;
12497 }
12498 }
12499
12500 return list_raw_objects_next(prefix_filter, max, ctx, oids, is_truncated);
12501 }
12502
12503 string RGWRados::list_raw_objs_get_cursor(RGWListRawObjsCtx& ctx)
12504 {
12505 return pool_iterate_get_cursor(ctx.iter_ctx);
12506 }
12507
12508 int RGWRados::list_bi_log_entries(RGWBucketInfo& bucket_info, int shard_id, string& marker, uint32_t max,
12509 std::list<rgw_bi_log_entry>& result, bool *truncated)
12510 {
12511 ldout(cct, 20) << __func__ << ": " << bucket_info.bucket << " marker " << marker << " shard_id=" << shard_id << " max " << max << dendl;
12512 result.clear();
12513
12514 librados::IoCtx index_ctx;
12515 map<int, string> oids;
12516 map<int, cls_rgw_bi_log_list_ret> bi_log_lists;
12517 map<int, string> bucket_instance_ids;
12518 int r = open_bucket_index(bucket_info, index_ctx, oids, shard_id, &bucket_instance_ids);
12519 if (r < 0)
12520 return r;
12521
12522 BucketIndexShardsManager marker_mgr;
12523 bool has_shards = (oids.size() > 1 || shard_id >= 0);
12524 // If there are multiple shards for the bucket index object, the marker
12525 // should have the pattern '{shard_id_1}#{shard_marker_1},{shard_id_2}#
12526 // {shard_marker_2}...', if there is no sharding, the bi_log_list should
12527 // only contain one record, and the key is the bucket instance id.
12528 r = marker_mgr.from_string(marker, shard_id);
12529 if (r < 0)
12530 return r;
12531
12532 r = CLSRGWIssueBILogList(index_ctx, marker_mgr, max, oids, bi_log_lists, cct->_conf->rgw_bucket_index_max_aio)();
12533 if (r < 0)
12534 return r;
12535
12536 map<int, list<rgw_bi_log_entry>::iterator> vcurrents;
12537 map<int, list<rgw_bi_log_entry>::iterator> vends;
12538 if (truncated) {
12539 *truncated = false;
12540 }
12541 map<int, cls_rgw_bi_log_list_ret>::iterator miter = bi_log_lists.begin();
12542 for (; miter != bi_log_lists.end(); ++miter) {
12543 int shard_id = miter->first;
12544 vcurrents[shard_id] = miter->second.entries.begin();
12545 vends[shard_id] = miter->second.entries.end();
12546 if (truncated) {
12547 *truncated = (*truncated || miter->second.truncated);
12548 }
12549 }
12550
12551 size_t total = 0;
12552 bool has_more = true;
12553 map<int, list<rgw_bi_log_entry>::iterator>::iterator viter;
12554 map<int, list<rgw_bi_log_entry>::iterator>::iterator eiter;
12555 while (total < max && has_more) {
12556 has_more = false;
12557
12558 viter = vcurrents.begin();
12559 eiter = vends.begin();
12560
12561 for (; total < max && viter != vcurrents.end(); ++viter, ++eiter) {
12562 assert (eiter != vends.end());
12563
12564 int shard_id = viter->first;
12565 list<rgw_bi_log_entry>::iterator& liter = viter->second;
12566
12567 if (liter == eiter->second){
12568 continue;
12569 }
12570 rgw_bi_log_entry& entry = *(liter);
12571 if (has_shards) {
12572 char buf[16];
12573 snprintf(buf, sizeof(buf), "%d", shard_id);
12574 string tmp_id;
12575 build_bucket_index_marker(buf, entry.id, &tmp_id);
12576 entry.id.swap(tmp_id);
12577 }
12578 marker_mgr.add(shard_id, entry.id);
12579 result.push_back(entry);
12580 total++;
12581 has_more = true;
12582 ++liter;
12583 }
12584 }
12585
12586 if (truncated) {
12587 for (viter = vcurrents.begin(), eiter = vends.begin(); viter != vcurrents.end(); ++viter, ++eiter) {
12588 assert (eiter != vends.end());
12589 *truncated = (*truncated || (viter->second != eiter->second));
12590 }
12591 }
12592
12593 // Refresh marker, if there are multiple shards, the output will look like
12594 // '{shard_oid_1}#{shard_marker_1},{shard_oid_2}#{shard_marker_2}...',
12595 // if there is no sharding, the simply marker (without oid) is returned
12596 if (has_shards) {
12597 marker_mgr.to_string(&marker);
12598 } else {
12599 if (!result.empty()) {
12600 marker = result.rbegin()->id;
12601 }
12602 }
12603
12604 return 0;
12605 }
12606
12607 int RGWRados::trim_bi_log_entries(RGWBucketInfo& bucket_info, int shard_id, string& start_marker, string& end_marker)
12608 {
12609 librados::IoCtx index_ctx;
12610 map<int, string> bucket_objs;
12611
12612 BucketIndexShardsManager start_marker_mgr;
12613 BucketIndexShardsManager end_marker_mgr;
12614
12615 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs, shard_id);
12616 if (r < 0) {
12617 return r;
12618 }
12619
12620 r = start_marker_mgr.from_string(start_marker, shard_id);
12621 if (r < 0) {
12622 return r;
12623 }
12624
12625 r = end_marker_mgr.from_string(end_marker, shard_id);
12626 if (r < 0) {
12627 return r;
12628 }
12629
12630 return CLSRGWIssueBILogTrim(index_ctx, start_marker_mgr, end_marker_mgr, bucket_objs,
12631 cct->_conf->rgw_bucket_index_max_aio)();
12632
12633 return r;
12634 }
12635
12636 int RGWRados::resync_bi_log_entries(RGWBucketInfo& bucket_info, int shard_id)
12637 {
12638 librados::IoCtx index_ctx;
12639 map<int, string> bucket_objs;
12640 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs, shard_id);
12641 if (r < 0)
12642 return r;
12643
12644 return CLSRGWIssueResyncBucketBILog(index_ctx, bucket_objs, cct->_conf->rgw_bucket_index_max_aio)();
12645 }
12646
12647 int RGWRados::stop_bi_log_entries(RGWBucketInfo& bucket_info, int shard_id)
12648 {
12649 librados::IoCtx index_ctx;
12650 map<int, string> bucket_objs;
12651 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs, shard_id);
12652 if (r < 0)
12653 return r;
12654
12655 return CLSRGWIssueBucketBILogStop(index_ctx, bucket_objs, cct->_conf->rgw_bucket_index_max_aio)();
12656 }
12657
12658 int RGWRados::bi_get_instance(const RGWBucketInfo& bucket_info, rgw_obj& obj, rgw_bucket_dir_entry *dirent)
12659 {
12660 rgw_rados_ref ref;
12661 int r = get_obj_head_ref(bucket_info, obj, &ref);
12662 if (r < 0) {
12663 return r;
12664 }
12665
12666 rgw_cls_bi_entry bi_entry;
12667 r = bi_get(obj.bucket, obj, InstanceIdx, &bi_entry);
12668 if (r < 0 && r != -ENOENT) {
12669 ldout(cct, 0) << "ERROR: bi_get() returned r=" << r << dendl;
12670 }
12671 if (r < 0) {
12672 return r;
12673 }
12674 bufferlist::iterator iter = bi_entry.data.begin();
12675 try {
12676 ::decode(*dirent, iter);
12677 } catch (buffer::error& err) {
12678 ldout(cct, 0) << "ERROR: failed to decode bi_entry()" << dendl;
12679 return -EIO;
12680 }
12681
12682 return 0;
12683 }
12684
12685 int RGWRados::bi_get(rgw_bucket& bucket, rgw_obj& obj, BIIndexType index_type, rgw_cls_bi_entry *entry)
12686 {
12687 BucketShard bs(this);
12688 int ret = bs.init(bucket, obj);
12689 if (ret < 0) {
12690 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
12691 return ret;
12692 }
12693
12694 cls_rgw_obj_key key(obj.key.get_index_key_name(), obj.key.instance);
12695
12696 ret = cls_rgw_bi_get(bs.index_ctx, bs.bucket_obj, index_type, key, entry);
12697 if (ret < 0)
12698 return ret;
12699
12700 return 0;
12701 }
12702
12703 void RGWRados::bi_put(ObjectWriteOperation& op, BucketShard& bs, rgw_cls_bi_entry& entry)
12704 {
12705 cls_rgw_bi_put(op, bs.bucket_obj, entry);
12706 }
12707
12708 int RGWRados::bi_put(BucketShard& bs, rgw_cls_bi_entry& entry)
12709 {
12710 int ret = cls_rgw_bi_put(bs.index_ctx, bs.bucket_obj, entry);
12711 if (ret < 0)
12712 return ret;
12713
12714 return 0;
12715 }
12716
12717 int RGWRados::bi_put(rgw_bucket& bucket, rgw_obj& obj, rgw_cls_bi_entry& entry)
12718 {
12719 BucketShard bs(this);
12720 int ret = bs.init(bucket, obj);
12721 if (ret < 0) {
12722 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
12723 return ret;
12724 }
12725
12726 return bi_put(bs, entry);
12727 }
12728
12729 int RGWRados::bi_list(rgw_bucket& bucket, const string& obj_name, const string& marker, uint32_t max, list<rgw_cls_bi_entry> *entries, bool *is_truncated)
12730 {
12731 rgw_obj obj(bucket, obj_name);
12732 BucketShard bs(this);
12733 int ret = bs.init(bucket, obj);
12734 if (ret < 0) {
12735 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
12736 return ret;
12737 }
12738
12739 ret = cls_rgw_bi_list(bs.index_ctx, bs.bucket_obj, obj_name, marker, max, entries, is_truncated);
12740 if (ret == -ENOENT) {
12741 *is_truncated = false;
12742 }
12743 if (ret < 0)
12744 return ret;
12745
12746 return 0;
12747 }
12748
12749 int RGWRados::bi_list(BucketShard& bs, const string& filter_obj, const string& marker, uint32_t max, list<rgw_cls_bi_entry> *entries, bool *is_truncated)
12750 {
12751 int ret = cls_rgw_bi_list(bs.index_ctx, bs.bucket_obj, filter_obj, marker, max, entries, is_truncated);
12752 if (ret < 0)
12753 return ret;
12754
12755 return 0;
12756 }
12757
12758 int RGWRados::bi_remove(BucketShard& bs)
12759 {
12760 int ret = bs.index_ctx.remove(bs.bucket_obj);
12761 if (ret == -ENOENT) {
12762 ret = 0;
12763 }
12764 if (ret < 0) {
12765 ldout(cct, 5) << "bs.index_ctx.remove(" << bs.bucket_obj << ") returned ret=" << ret << dendl;
12766 return ret;
12767 }
12768
12769 return 0;
12770 }
12771
12772 int RGWRados::bi_list(rgw_bucket& bucket, int shard_id, const string& filter_obj, const string& marker, uint32_t max, list<rgw_cls_bi_entry> *entries, bool *is_truncated)
12773 {
12774 BucketShard bs(this);
12775 int ret = bs.init(bucket, shard_id);
12776 if (ret < 0) {
12777 ldout(cct, 5) << "bs.init() returned ret=" << ret << dendl;
12778 return ret;
12779 }
12780
12781 return bi_list(bs, filter_obj, marker, max, entries, is_truncated);
12782 }
12783
12784 int RGWRados::gc_operate(string& oid, librados::ObjectWriteOperation *op)
12785 {
12786 return gc_pool_ctx.operate(oid, op);
12787 }
12788
12789 int RGWRados::gc_aio_operate(string& oid, librados::ObjectWriteOperation *op)
12790 {
12791 AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL);
12792 int r = gc_pool_ctx.aio_operate(oid, c, op);
12793 c->release();
12794 return r;
12795 }
12796
12797 int RGWRados::gc_operate(string& oid, librados::ObjectReadOperation *op, bufferlist *pbl)
12798 {
12799 return gc_pool_ctx.operate(oid, op, pbl);
12800 }
12801
12802 int RGWRados::list_gc_objs(int *index, string& marker, uint32_t max, bool expired_only, std::list<cls_rgw_gc_obj_info>& result, bool *truncated)
12803 {
12804 return gc->list(index, marker, max, expired_only, result, truncated);
12805 }
12806
12807 int RGWRados::process_gc()
12808 {
12809 return gc->process();
12810 }
12811
12812 int RGWRados::list_lc_progress(const string& marker, uint32_t max_entries, map<string, int> *progress_map)
12813 {
12814 return lc->list_lc_progress(marker, max_entries, progress_map);
12815 }
12816
12817 int RGWRados::process_lc()
12818 {
12819 return lc->process();
12820 }
12821
12822 int RGWRados::process_expire_objects()
12823 {
12824 obj_expirer->inspect_all_shards(utime_t(), ceph_clock_now());
12825 return 0;
12826 }
12827
12828 int RGWRados::cls_rgw_init_index(librados::IoCtx& index_ctx, librados::ObjectWriteOperation& op, string& oid)
12829 {
12830 bufferlist in;
12831 cls_rgw_bucket_init(op);
12832 return index_ctx.operate(oid, &op);
12833 }
12834
12835 int RGWRados::cls_obj_prepare_op(BucketShard& bs, RGWModifyOp op, string& tag,
12836 rgw_obj& obj, uint16_t bilog_flags, rgw_zone_set *_zones_trace)
12837 {
12838 rgw_zone_set zones_trace;
12839 if (_zones_trace) {
12840 zones_trace = *_zones_trace;
12841 }
12842 else {
12843 zones_trace.insert(get_zone().id);
12844 }
12845
12846 ObjectWriteOperation o;
12847 cls_rgw_obj_key key(obj.key.get_index_key_name(), obj.key.instance);
12848 cls_rgw_guard_bucket_resharding(o, -ERR_BUSY_RESHARDING);
12849 cls_rgw_bucket_prepare_op(o, op, tag, key, obj.key.get_loc(), get_zone().log_data, bilog_flags, zones_trace);
12850 return bs.index_ctx.operate(bs.bucket_obj, &o);
12851 }
12852
12853 int RGWRados::cls_obj_complete_op(BucketShard& bs, const rgw_obj& obj, RGWModifyOp op, string& tag,
12854 int64_t pool, uint64_t epoch,
12855 rgw_bucket_dir_entry& ent, RGWObjCategory category,
12856 list<rgw_obj_index_key> *remove_objs, uint16_t bilog_flags, rgw_zone_set *_zones_trace)
12857 {
12858 ObjectWriteOperation o;
12859 rgw_bucket_dir_entry_meta dir_meta;
12860 dir_meta = ent.meta;
12861 dir_meta.category = category;
12862
12863 rgw_bucket_entry_ver ver;
12864 ver.pool = pool;
12865 ver.epoch = epoch;
12866 cls_rgw_obj_key key(ent.key.name, ent.key.instance);
12867 cls_rgw_guard_bucket_resharding(o, -ERR_BUSY_RESHARDING);
12868 cls_rgw_bucket_complete_op(o, op, tag, ver, key, dir_meta, remove_objs,
12869 get_zone().log_data, bilog_flags, _zones_trace);
12870 complete_op_data *arg;
12871 index_completion_manager->create_completion(obj, op, tag, ver, key, dir_meta, remove_objs,
12872 get_zone().log_data, bilog_flags, _zones_trace, &arg);
12873 librados::AioCompletion *completion = arg->rados_completion;
12874 int ret = bs.index_ctx.aio_operate(bs.bucket_obj, arg->rados_completion, &o);
12875 completion->release(); /* can't reference arg here, as it might have already been released */
12876 return ret;
12877 }
12878
12879 int RGWRados::cls_obj_complete_add(BucketShard& bs, const rgw_obj& obj, string& tag,
12880 int64_t pool, uint64_t epoch,
12881 rgw_bucket_dir_entry& ent, RGWObjCategory category,
12882 list<rgw_obj_index_key> *remove_objs, uint16_t bilog_flags, rgw_zone_set *zones_trace)
12883 {
12884 return cls_obj_complete_op(bs, obj, CLS_RGW_OP_ADD, tag, pool, epoch, ent, category, remove_objs, bilog_flags, zones_trace);
12885 }
12886
12887 int RGWRados::cls_obj_complete_del(BucketShard& bs, string& tag,
12888 int64_t pool, uint64_t epoch,
12889 rgw_obj& obj,
12890 real_time& removed_mtime,
12891 list<rgw_obj_index_key> *remove_objs,
12892 uint16_t bilog_flags,
12893 rgw_zone_set *zones_trace)
12894 {
12895 rgw_bucket_dir_entry ent;
12896 ent.meta.mtime = removed_mtime;
12897 obj.key.get_index_key(&ent.key);
12898 return cls_obj_complete_op(bs, obj, CLS_RGW_OP_DEL, tag, pool, epoch, ent, RGW_OBJ_CATEGORY_NONE, remove_objs, bilog_flags, zones_trace);
12899 }
12900
12901 int RGWRados::cls_obj_complete_cancel(BucketShard& bs, string& tag, rgw_obj& obj, uint16_t bilog_flags, rgw_zone_set *zones_trace)
12902 {
12903 rgw_bucket_dir_entry ent;
12904 obj.key.get_index_key(&ent.key);
12905 return cls_obj_complete_op(bs, obj, CLS_RGW_OP_CANCEL, tag, -1 /* pool id */, 0, ent, RGW_OBJ_CATEGORY_NONE, NULL, bilog_flags, zones_trace);
12906 }
12907
12908 int RGWRados::cls_obj_set_bucket_tag_timeout(RGWBucketInfo& bucket_info, uint64_t timeout)
12909 {
12910 librados::IoCtx index_ctx;
12911 map<int, string> bucket_objs;
12912 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs);
12913 if (r < 0)
12914 return r;
12915
12916 return CLSRGWIssueSetTagTimeout(index_ctx, bucket_objs, cct->_conf->rgw_bucket_index_max_aio, timeout)();
12917 }
12918
12919 int RGWRados::cls_bucket_list(RGWBucketInfo& bucket_info, int shard_id, rgw_obj_index_key& start, const string& prefix,
12920 uint32_t num_entries, bool list_versions, map<string, rgw_bucket_dir_entry>& m,
12921 bool *is_truncated, rgw_obj_index_key *last_entry,
12922 bool (*force_check_filter)(const string& name))
12923 {
12924 ldout(cct, 10) << "cls_bucket_list " << bucket_info.bucket << " start " << start.name << "[" << start.instance << "] num_entries " << num_entries << dendl;
12925
12926 librados::IoCtx index_ctx;
12927 // key - oid (for different shards if there is any)
12928 // value - list result for the corresponding oid (shard), it is filled by the AIO callback
12929 map<int, string> oids;
12930 map<int, struct rgw_cls_list_ret> list_results;
12931 int r = open_bucket_index(bucket_info, index_ctx, oids, shard_id);
12932 if (r < 0)
12933 return r;
12934
12935 cls_rgw_obj_key start_key(start.name, start.instance);
12936 r = CLSRGWIssueBucketList(index_ctx, start_key, prefix, num_entries, list_versions,
12937 oids, list_results, cct->_conf->rgw_bucket_index_max_aio)();
12938 if (r < 0)
12939 return r;
12940
12941 // Create a list of iterators that are used to iterate each shard
12942 vector<map<string, struct rgw_bucket_dir_entry>::iterator> vcurrents(list_results.size());
12943 vector<map<string, struct rgw_bucket_dir_entry>::iterator> vends(list_results.size());
12944 vector<string> vnames(list_results.size());
12945 map<int, struct rgw_cls_list_ret>::iterator iter = list_results.begin();
12946 *is_truncated = false;
12947 for (; iter != list_results.end(); ++iter) {
12948 vcurrents.push_back(iter->second.dir.m.begin());
12949 vends.push_back(iter->second.dir.m.end());
12950 vnames.push_back(oids[iter->first]);
12951 *is_truncated = (*is_truncated || iter->second.is_truncated);
12952 }
12953
12954 // Create a map to track the next candidate entry from each shard, if the entry
12955 // from a specified shard is selected/erased, the next entry from that shard will
12956 // be inserted for next round selection
12957 map<string, size_t> candidates;
12958 for (size_t i = 0; i < vcurrents.size(); ++i) {
12959 if (vcurrents[i] != vends[i]) {
12960 candidates[vcurrents[i]->first] = i;
12961 }
12962 }
12963
12964 map<string, bufferlist> updates;
12965 uint32_t count = 0;
12966 while (count < num_entries && !candidates.empty()) {
12967 r = 0;
12968 // Select the next one
12969 int pos = candidates.begin()->second;
12970 const string& name = vcurrents[pos]->first;
12971 struct rgw_bucket_dir_entry& dirent = vcurrents[pos]->second;
12972
12973 bool force_check = force_check_filter &&
12974 force_check_filter(dirent.key.name);
12975 if ((!dirent.exists && !dirent.is_delete_marker()) ||
12976 !dirent.pending_map.empty() ||
12977 force_check) {
12978 /* there are uncommitted ops. We need to check the current state,
12979 * and if the tags are old we need to do cleanup as well. */
12980 librados::IoCtx sub_ctx;
12981 sub_ctx.dup(index_ctx);
12982 r = check_disk_state(sub_ctx, bucket_info, dirent, dirent, updates[vnames[pos]]);
12983 if (r < 0 && r != -ENOENT) {
12984 return r;
12985 }
12986 }
12987 if (r >= 0) {
12988 ldout(cct, 10) << "RGWRados::cls_bucket_list: got " << dirent.key.name << "[" << dirent.key.instance << "]" << dendl;
12989 m[name] = std::move(dirent);
12990 ++count;
12991 }
12992
12993 // Refresh the candidates map
12994 candidates.erase(candidates.begin());
12995 ++vcurrents[pos];
12996 if (vcurrents[pos] != vends[pos]) {
12997 candidates[vcurrents[pos]->first] = pos;
12998 }
12999 }
13000
13001 // Suggest updates if there is any
13002 map<string, bufferlist>::iterator miter = updates.begin();
13003 for (; miter != updates.end(); ++miter) {
13004 if (miter->second.length()) {
13005 ObjectWriteOperation o;
13006 cls_rgw_suggest_changes(o, miter->second);
13007 // we don't care if we lose suggested updates, send them off blindly
13008 AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL);
13009 index_ctx.aio_operate(miter->first, c, &o);
13010 c->release();
13011 }
13012 }
13013
13014 // Check if all the returned entries are consumed or not
13015 for (size_t i = 0; i < vcurrents.size(); ++i) {
13016 if (vcurrents[i] != vends[i])
13017 *is_truncated = true;
13018 }
13019 if (!m.empty())
13020 *last_entry = m.rbegin()->first;
13021
13022 return 0;
13023 }
13024
13025 int RGWRados::cls_obj_usage_log_add(const string& oid, rgw_usage_log_info& info)
13026 {
13027 rgw_raw_obj obj(get_zone_params().usage_log_pool, oid);
13028
13029 rgw_rados_ref ref;
13030 int r = get_raw_obj_ref(obj, &ref);
13031 if (r < 0) {
13032 return r;
13033 }
13034
13035 ObjectWriteOperation op;
13036 cls_rgw_usage_log_add(op, info);
13037
13038 r = ref.ioctx.operate(ref.oid, &op);
13039 return r;
13040 }
13041
13042 int RGWRados::cls_obj_usage_log_read(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries,
13043 string& read_iter, map<rgw_user_bucket, rgw_usage_log_entry>& usage, bool *is_truncated)
13044 {
13045 rgw_raw_obj obj(get_zone_params().usage_log_pool, oid);
13046
13047 rgw_rados_ref ref;
13048 int r = get_raw_obj_ref(obj, &ref);
13049 if (r < 0) {
13050 return r;
13051 }
13052
13053 *is_truncated = false;
13054
13055 r = cls_rgw_usage_log_read(ref.ioctx, ref.oid, user, start_epoch, end_epoch,
13056 max_entries, read_iter, usage, is_truncated);
13057
13058 return r;
13059 }
13060
13061 int RGWRados::cls_obj_usage_log_trim(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch)
13062 {
13063 rgw_raw_obj obj(get_zone_params().usage_log_pool, oid);
13064
13065 rgw_rados_ref ref;
13066 int r = get_raw_obj_ref(obj, &ref);
13067 if (r < 0) {
13068 return r;
13069 }
13070
13071 r = cls_rgw_usage_log_trim(ref.ioctx, ref.oid, user, start_epoch, end_epoch);
13072 return r;
13073 }
13074
13075 int RGWRados::remove_objs_from_index(RGWBucketInfo& bucket_info, list<rgw_obj_index_key>& oid_list)
13076 {
13077 librados::IoCtx index_ctx;
13078 string dir_oid;
13079
13080 uint8_t suggest_flag = (get_zone().log_data ? CEPH_RGW_DIR_SUGGEST_LOG_OP : 0);
13081
13082 int r = open_bucket_index(bucket_info, index_ctx, dir_oid);
13083 if (r < 0)
13084 return r;
13085
13086 bufferlist updates;
13087
13088 for (auto iter = oid_list.begin(); iter != oid_list.end(); ++iter) {
13089 rgw_bucket_dir_entry entry;
13090 entry.key = *iter;
13091 dout(2) << "RGWRados::remove_objs_from_index bucket=" << bucket_info.bucket << " obj=" << entry.key.name << ":" << entry.key.instance << dendl;
13092 entry.ver.epoch = (uint64_t)-1; // ULLONG_MAX, needed to that objclass doesn't skip out request
13093 updates.append(CEPH_RGW_REMOVE | suggest_flag);
13094 ::encode(entry, updates);
13095 }
13096
13097 bufferlist out;
13098
13099 r = index_ctx.exec(dir_oid, RGW_CLASS, RGW_DIR_SUGGEST_CHANGES, updates, out);
13100
13101 return r;
13102 }
13103
13104 int RGWRados::check_disk_state(librados::IoCtx io_ctx,
13105 const RGWBucketInfo& bucket_info,
13106 rgw_bucket_dir_entry& list_state,
13107 rgw_bucket_dir_entry& object,
13108 bufferlist& suggested_updates)
13109 {
13110 const rgw_bucket& bucket = bucket_info.bucket;
13111 uint8_t suggest_flag = (get_zone().log_data ? CEPH_RGW_DIR_SUGGEST_LOG_OP : 0);
13112
13113 std::string loc;
13114
13115 rgw_obj obj(bucket, list_state.key);
13116
13117 string oid;
13118 get_obj_bucket_and_oid_loc(obj, oid, loc);
13119
13120 if (loc != list_state.locator) {
13121 ldout(cct, 0) << "WARNING: generated locator (" << loc << ") is different from listed locator (" << list_state.locator << ")" << dendl;
13122 }
13123
13124 io_ctx.locator_set_key(list_state.locator);
13125
13126 RGWObjState *astate = NULL;
13127 RGWObjectCtx rctx(this);
13128 int r = get_obj_state(&rctx, bucket_info, obj, &astate, false);
13129 if (r < 0)
13130 return r;
13131
13132 list_state.pending_map.clear(); // we don't need this and it inflates size
13133 if (!astate->exists) {
13134 /* object doesn't exist right now -- hopefully because it's
13135 * marked as !exists and got deleted */
13136 if (list_state.exists) {
13137 /* FIXME: what should happen now? Work out if there are any
13138 * non-bad ways this could happen (there probably are, but annoying
13139 * to handle!) */
13140 }
13141 // encode a suggested removal of that key
13142 list_state.ver.epoch = io_ctx.get_last_version();
13143 list_state.ver.pool = io_ctx.get_id();
13144 cls_rgw_encode_suggestion(CEPH_RGW_REMOVE, list_state, suggested_updates);
13145 return -ENOENT;
13146 }
13147
13148 string etag;
13149 string content_type;
13150 ACLOwner owner;
13151
13152 object.meta.size = astate->size;
13153 object.meta.accounted_size = astate->accounted_size;
13154 object.meta.mtime = astate->mtime;
13155
13156 map<string, bufferlist>::iterator iter = astate->attrset.find(RGW_ATTR_ETAG);
13157 if (iter != astate->attrset.end()) {
13158 etag = iter->second.c_str();
13159 }
13160 iter = astate->attrset.find(RGW_ATTR_CONTENT_TYPE);
13161 if (iter != astate->attrset.end()) {
13162 content_type = iter->second.c_str();
13163 }
13164 iter = astate->attrset.find(RGW_ATTR_ACL);
13165 if (iter != astate->attrset.end()) {
13166 r = decode_policy(iter->second, &owner);
13167 if (r < 0) {
13168 dout(0) << "WARNING: could not decode policy for object: " << obj << dendl;
13169 }
13170 }
13171
13172 if (astate->has_manifest) {
13173 RGWObjManifest::obj_iterator miter;
13174 RGWObjManifest& manifest = astate->manifest;
13175 for (miter = manifest.obj_begin(); miter != manifest.obj_end(); ++miter) {
13176 const rgw_raw_obj& raw_loc = miter.get_location().get_raw_obj(this);
13177 rgw_obj loc;
13178 rgw_raw_obj_to_obj(manifest.get_obj().bucket, raw_loc, &loc);
13179
13180 if (loc.key.ns == RGW_OBJ_NS_MULTIPART) {
13181 dout(10) << "check_disk_state(): removing manifest part from index: " << loc << dendl;
13182 r = delete_obj_index(loc);
13183 if (r < 0) {
13184 dout(0) << "WARNING: delete_obj_index() returned r=" << r << dendl;
13185 }
13186 }
13187 }
13188 }
13189
13190 object.meta.etag = etag;
13191 object.meta.content_type = content_type;
13192 object.meta.owner = owner.get_id().to_str();
13193 object.meta.owner_display_name = owner.get_display_name();
13194
13195 // encode suggested updates
13196 list_state.ver.pool = io_ctx.get_id();
13197 list_state.ver.epoch = astate->epoch;
13198 list_state.meta.size = object.meta.size;
13199 list_state.meta.accounted_size = object.meta.accounted_size;
13200 list_state.meta.mtime = object.meta.mtime;
13201 list_state.meta.category = main_category;
13202 list_state.meta.etag = etag;
13203 list_state.meta.content_type = content_type;
13204 if (astate->obj_tag.length() > 0)
13205 list_state.tag = astate->obj_tag.c_str();
13206 list_state.meta.owner = owner.get_id().to_str();
13207 list_state.meta.owner_display_name = owner.get_display_name();
13208
13209 list_state.exists = true;
13210 cls_rgw_encode_suggestion(CEPH_RGW_UPDATE | suggest_flag, list_state, suggested_updates);
13211 return 0;
13212 }
13213
13214 int RGWRados::cls_bucket_head(const RGWBucketInfo& bucket_info, int shard_id, map<string, struct rgw_bucket_dir_header>& headers, map<int, string> *bucket_instance_ids)
13215 {
13216 librados::IoCtx index_ctx;
13217 map<int, string> oids;
13218 map<int, struct rgw_cls_list_ret> list_results;
13219 int r = open_bucket_index(bucket_info, index_ctx, oids, list_results, shard_id, bucket_instance_ids);
13220 if (r < 0)
13221 return r;
13222
13223 r = CLSRGWIssueGetDirHeader(index_ctx, oids, list_results, cct->_conf->rgw_bucket_index_max_aio)();
13224 if (r < 0)
13225 return r;
13226
13227 map<int, struct rgw_cls_list_ret>::iterator iter = list_results.begin();
13228 for(; iter != list_results.end(); ++iter) {
13229 headers[oids[iter->first]] = iter->second.dir.header;
13230 }
13231 return 0;
13232 }
13233
13234 int RGWRados::cls_bucket_head_async(const RGWBucketInfo& bucket_info, int shard_id, RGWGetDirHeader_CB *ctx, int *num_aio)
13235 {
13236 librados::IoCtx index_ctx;
13237 map<int, string> bucket_objs;
13238 int r = open_bucket_index(bucket_info, index_ctx, bucket_objs, shard_id);
13239 if (r < 0)
13240 return r;
13241
13242 map<int, string>::iterator iter = bucket_objs.begin();
13243 for (; iter != bucket_objs.end(); ++iter) {
13244 r = cls_rgw_get_dir_header_async(index_ctx, iter->second, static_cast<RGWGetDirHeader_CB*>(ctx->get()));
13245 if (r < 0) {
13246 ctx->put();
13247 break;
13248 } else {
13249 (*num_aio)++;
13250 }
13251 }
13252 return r;
13253 }
13254
13255 int RGWRados::cls_user_get_header(const string& user_id, cls_user_header *header)
13256 {
13257 string buckets_obj_id;
13258 rgw_get_buckets_obj(user_id, buckets_obj_id);
13259 rgw_raw_obj obj(get_zone_params().user_uid_pool, buckets_obj_id);
13260
13261 rgw_rados_ref ref;
13262 int r = get_raw_obj_ref(obj, &ref);
13263 if (r < 0) {
13264 return r;
13265 }
13266
13267 librados::ObjectReadOperation op;
13268 int rc;
13269 ::cls_user_get_header(op, header, &rc);
13270 bufferlist ibl;
13271 r = ref.ioctx.operate(ref.oid, &op, &ibl);
13272 if (r < 0)
13273 return r;
13274 if (rc < 0)
13275 return rc;
13276
13277 return 0;
13278 }
13279
13280 int RGWRados::cls_user_get_header_async(const string& user_id, RGWGetUserHeader_CB *ctx)
13281 {
13282 string buckets_obj_id;
13283 rgw_get_buckets_obj(user_id, buckets_obj_id);
13284 rgw_raw_obj obj(get_zone_params().user_uid_pool, buckets_obj_id);
13285
13286 rgw_rados_ref ref;
13287 int r = get_raw_obj_ref(obj, &ref);
13288 if (r < 0) {
13289 return r;
13290 }
13291
13292 r = ::cls_user_get_header_async(ref.ioctx, ref.oid, ctx);
13293 if (r < 0)
13294 return r;
13295
13296 return 0;
13297 }
13298
13299 int RGWRados::cls_user_sync_bucket_stats(rgw_raw_obj& user_obj, const RGWBucketInfo& bucket_info)
13300 {
13301 map<string, struct rgw_bucket_dir_header> headers;
13302 int r = cls_bucket_head(bucket_info, RGW_NO_SHARD, headers);
13303 if (r < 0) {
13304 ldout(cct, 20) << "cls_bucket_header() returned " << r << dendl;
13305 return r;
13306 }
13307
13308 cls_user_bucket_entry entry;
13309
13310 bucket_info.bucket.convert(&entry.bucket);
13311
13312 for (const auto& hiter : headers) {
13313 for (const auto& iter : hiter.second.stats) {
13314 const struct rgw_bucket_category_stats& header_stats = iter.second;
13315 entry.size += header_stats.total_size;
13316 entry.size_rounded += header_stats.total_size_rounded;
13317 entry.count += header_stats.num_entries;
13318 }
13319 }
13320
13321 list<cls_user_bucket_entry> entries;
13322 entries.push_back(entry);
13323
13324 r = cls_user_update_buckets(user_obj, entries, false);
13325 if (r < 0) {
13326 ldout(cct, 20) << "cls_user_update_buckets() returned " << r << dendl;
13327 return r;
13328 }
13329
13330 return 0;
13331 }
13332
13333 int RGWRados::cls_user_get_bucket_stats(const rgw_bucket& bucket, cls_user_bucket_entry& entry)
13334 {
13335 map<string, struct rgw_bucket_dir_header> headers;
13336 RGWBucketInfo bucket_info;
13337 RGWObjectCtx obj_ctx(this);
13338 int ret = get_bucket_instance_info(obj_ctx, bucket, bucket_info, NULL, NULL);
13339 if (ret < 0) {
13340 return ret;
13341 }
13342
13343 ret = cls_bucket_head(bucket_info, RGW_NO_SHARD, headers);
13344 if (ret < 0) {
13345 ldout(cct, 20) << "cls_bucket_header() returned " << ret << dendl;
13346 return ret;
13347 }
13348
13349 bucket.convert(&entry.bucket);
13350
13351 for (const auto& hiter : headers) {
13352 for (const auto& iter : hiter.second.stats) {
13353 const struct rgw_bucket_category_stats& header_stats = iter.second;
13354 entry.size += header_stats.total_size;
13355 entry.size_rounded += header_stats.total_size_rounded;
13356 entry.count += header_stats.num_entries;
13357 }
13358 }
13359
13360 return 0;
13361 }
13362
13363 int RGWRados::cls_user_list_buckets(rgw_raw_obj& obj,
13364 const string& in_marker,
13365 const string& end_marker,
13366 const int max_entries,
13367 list<cls_user_bucket_entry>& entries,
13368 string * const out_marker,
13369 bool * const truncated)
13370 {
13371 rgw_rados_ref ref;
13372 int r = get_raw_obj_ref(obj, &ref);
13373 if (r < 0) {
13374 return r;
13375 }
13376
13377 librados::ObjectReadOperation op;
13378 int rc;
13379
13380 cls_user_bucket_list(op, in_marker, end_marker, max_entries, entries, out_marker, truncated, &rc);
13381 bufferlist ibl;
13382 r = ref.ioctx.operate(ref.oid, &op, &ibl);
13383 if (r < 0)
13384 return r;
13385 if (rc < 0)
13386 return rc;
13387
13388 return 0;
13389 }
13390
13391 int RGWRados::cls_user_update_buckets(rgw_raw_obj& obj, list<cls_user_bucket_entry>& entries, bool add)
13392 {
13393 rgw_rados_ref ref;
13394 int r = get_raw_obj_ref(obj, &ref);
13395 if (r < 0) {
13396 return r;
13397 }
13398
13399 librados::ObjectWriteOperation op;
13400 cls_user_set_buckets(op, entries, add);
13401 r = ref.ioctx.operate(ref.oid, &op);
13402 if (r < 0)
13403 return r;
13404
13405 return 0;
13406 }
13407
13408 int RGWRados::complete_sync_user_stats(const rgw_user& user_id)
13409 {
13410 string buckets_obj_id;
13411 rgw_get_buckets_obj(user_id, buckets_obj_id);
13412 rgw_raw_obj obj(get_zone_params().user_uid_pool, buckets_obj_id);
13413 return cls_user_complete_stats_sync(obj);
13414 }
13415
13416 int RGWRados::cls_user_complete_stats_sync(rgw_raw_obj& obj)
13417 {
13418 rgw_rados_ref ref;
13419 int r = get_raw_obj_ref(obj, &ref);
13420 if (r < 0) {
13421 return r;
13422 }
13423
13424 librados::ObjectWriteOperation op;
13425 ::cls_user_complete_stats_sync(op);
13426 r = ref.ioctx.operate(ref.oid, &op);
13427 if (r < 0)
13428 return r;
13429
13430 return 0;
13431 }
13432
13433 int RGWRados::cls_user_add_bucket(rgw_raw_obj& obj, const cls_user_bucket_entry& entry)
13434 {
13435 list<cls_user_bucket_entry> l;
13436 l.push_back(entry);
13437
13438 return cls_user_update_buckets(obj, l, true);
13439 }
13440
13441 int RGWRados::cls_user_remove_bucket(rgw_raw_obj& obj, const cls_user_bucket& bucket)
13442 {
13443 rgw_rados_ref ref;
13444 int r = get_system_obj_ref(obj, &ref);
13445 if (r < 0) {
13446 return r;
13447 }
13448
13449 librados::ObjectWriteOperation op;
13450 ::cls_user_remove_bucket(op, bucket);
13451 r = ref.ioctx.operate(ref.oid, &op);
13452 if (r < 0)
13453 return r;
13454
13455 return 0;
13456 }
13457
13458 int RGWRados::check_bucket_shards(const RGWBucketInfo& bucket_info, const rgw_bucket& bucket,
13459 RGWQuotaInfo& bucket_quota)
13460 {
13461 if (!cct->_conf->rgw_dynamic_resharding) {
13462 return 0;
13463 }
13464
13465 bool need_resharding = false;
13466 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
13467 uint32_t suggested_num_shards;
13468
13469 int ret = quota_handler->check_bucket_shards((uint64_t)cct->_conf->rgw_max_objs_per_shard,
13470 num_source_shards, bucket_info.owner, bucket, bucket_quota,
13471 1, need_resharding, &suggested_num_shards);
13472 if (ret < 0) {
13473 return ret;
13474 }
13475
13476 if (need_resharding) {
13477 ldout(cct, 20) << __func__ << " bucket " << bucket.name << " need resharding " <<
13478 " old num shards " << bucket_info.num_shards << " new num shards " << suggested_num_shards <<
13479 dendl;
13480 return add_bucket_to_reshard(bucket_info, suggested_num_shards);
13481 }
13482
13483 return ret;
13484 }
13485
13486 int RGWRados::add_bucket_to_reshard(const RGWBucketInfo& bucket_info, uint32_t new_num_shards)
13487 {
13488 RGWReshard reshard(this);
13489
13490 uint32_t num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
13491
13492 new_num_shards = min(new_num_shards, get_max_bucket_shards());
13493 if (new_num_shards <= num_source_shards) {
13494 ldout(cct, 20) << "not resharding bucket name=" << bucket_info.bucket.name << ", orig_num=" << num_source_shards << ", new_num_shards=" << new_num_shards << dendl;
13495 return 0;
13496 }
13497
13498 cls_rgw_reshard_entry entry;
13499 entry.time = real_clock::now();
13500 entry.tenant = bucket_info.owner.tenant;
13501 entry.bucket_name = bucket_info.bucket.name;
13502 entry.bucket_id = bucket_info.bucket.bucket_id;
13503 entry.old_num_shards = num_source_shards;
13504 entry.new_num_shards = new_num_shards;
13505
13506 return reshard.add(entry);
13507 }
13508
13509 int RGWRados::check_quota(const rgw_user& bucket_owner, rgw_bucket& bucket,
13510 RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t obj_size)
13511 {
13512 return quota_handler->check_quota(bucket_owner, bucket, user_quota, bucket_quota, 1, obj_size);
13513 }
13514
13515 void RGWRados::get_bucket_index_objects(const string& bucket_oid_base,
13516 uint32_t num_shards, map<int, string>& bucket_objects, int shard_id)
13517 {
13518 if (!num_shards) {
13519 bucket_objects[0] = bucket_oid_base;
13520 } else {
13521 char buf[bucket_oid_base.size() + 32];
13522 if (shard_id < 0) {
13523 for (uint32_t i = 0; i < num_shards; ++i) {
13524 snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), i);
13525 bucket_objects[i] = buf;
13526 }
13527 } else {
13528 if ((uint32_t)shard_id > num_shards) {
13529 return;
13530 }
13531 snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), shard_id);
13532 bucket_objects[shard_id] = buf;
13533 }
13534 }
13535 }
13536
13537 void RGWRados::get_bucket_instance_ids(const RGWBucketInfo& bucket_info, int shard_id, map<int, string> *result)
13538 {
13539 const rgw_bucket& bucket = bucket_info.bucket;
13540 string plain_id = bucket.name + ":" + bucket.bucket_id;
13541 if (!bucket_info.num_shards) {
13542 (*result)[0] = plain_id;
13543 } else {
13544 char buf[16];
13545 if (shard_id < 0) {
13546 for (uint32_t i = 0; i < bucket_info.num_shards; ++i) {
13547 snprintf(buf, sizeof(buf), ":%d", i);
13548 (*result)[i] = plain_id + buf;
13549 }
13550 } else {
13551 if ((uint32_t)shard_id > bucket_info.num_shards) {
13552 return;
13553 }
13554 snprintf(buf, sizeof(buf), ":%d", shard_id);
13555 (*result)[shard_id] = plain_id + buf;
13556 }
13557 }
13558 }
13559
13560 int RGWRados::get_target_shard_id(const RGWBucketInfo& bucket_info, const string& obj_key,
13561 int *shard_id)
13562 {
13563 int r = 0;
13564 switch (bucket_info.bucket_index_shard_hash_type) {
13565 case RGWBucketInfo::MOD:
13566 if (!bucket_info.num_shards) {
13567 if (shard_id) {
13568 *shard_id = -1;
13569 }
13570 } else {
13571 uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
13572 uint32_t sid2 = sid ^ ((sid & 0xFF) << 24);
13573 sid = rgw_shards_mod(sid2, bucket_info.num_shards);
13574 if (shard_id) {
13575 *shard_id = (int)sid;
13576 }
13577 }
13578 break;
13579 default:
13580 r = -ENOTSUP;
13581 }
13582 return r;
13583 }
13584
13585 void RGWRados::get_bucket_index_object(const string& bucket_oid_base, uint32_t num_shards,
13586 int shard_id, string *bucket_obj)
13587 {
13588 if (!num_shards) {
13589 // By default with no sharding, we use the bucket oid as itself
13590 (*bucket_obj) = bucket_oid_base;
13591 } else {
13592 char buf[bucket_oid_base.size() + 32];
13593 snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), shard_id);
13594 (*bucket_obj) = buf;
13595 }
13596 }
13597
13598 int RGWRados::get_bucket_index_object(const string& bucket_oid_base, const string& obj_key,
13599 uint32_t num_shards, RGWBucketInfo::BIShardsHashType hash_type, string *bucket_obj, int *shard_id)
13600 {
13601 int r = 0;
13602 switch (hash_type) {
13603 case RGWBucketInfo::MOD:
13604 if (!num_shards) {
13605 // By default with no sharding, we use the bucket oid as itself
13606 (*bucket_obj) = bucket_oid_base;
13607 if (shard_id) {
13608 *shard_id = -1;
13609 }
13610 } else {
13611 uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
13612 uint32_t sid2 = sid ^ ((sid & 0xFF) << 24);
13613 sid = rgw_shards_mod(sid2, num_shards);
13614 char buf[bucket_oid_base.size() + 32];
13615 snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), sid);
13616 (*bucket_obj) = buf;
13617 if (shard_id) {
13618 *shard_id = (int)sid;
13619 }
13620 }
13621 break;
13622 default:
13623 r = -ENOTSUP;
13624 }
13625 return r;
13626 }
13627
13628 void RGWStateLog::oid_str(int shard, string& oid) {
13629 oid = RGW_STATELOG_OBJ_PREFIX + module_name + ".";
13630 char buf[16];
13631 snprintf(buf, sizeof(buf), "%d", shard);
13632 oid += buf;
13633 }
13634
13635 int RGWStateLog::get_shard_num(const string& object) {
13636 uint32_t val = ceph_str_hash_linux(object.c_str(), object.length());
13637 return val % num_shards;
13638 }
13639
13640 string RGWStateLog::get_oid(const string& object) {
13641 int shard = get_shard_num(object);
13642 string oid;
13643 oid_str(shard, oid);
13644 return oid;
13645 }
13646
13647 int RGWStateLog::open_ioctx(librados::IoCtx& ioctx) {
13648 rgw_pool pool;
13649 store->get_log_pool(pool);
13650 int r = rgw_init_ioctx(store->get_rados_handle(), pool, ioctx);
13651 if (r < 0) {
13652 lderr(store->ctx()) << "ERROR: could not open rados pool" << dendl;
13653 return r;
13654 }
13655 return 0;
13656 }
13657
13658 int RGWStateLog::store_entry(const string& client_id, const string& op_id, const string& object,
13659 uint32_t state, bufferlist *bl, uint32_t *check_state)
13660 {
13661 if (client_id.empty() ||
13662 op_id.empty() ||
13663 object.empty()) {
13664 ldout(store->ctx(), 0) << "client_id / op_id / object is empty" << dendl;
13665 }
13666
13667 librados::IoCtx ioctx;
13668 int r = open_ioctx(ioctx);
13669 if (r < 0)
13670 return r;
13671
13672 string oid = get_oid(object);
13673
13674 librados::ObjectWriteOperation op;
13675 if (check_state) {
13676 cls_statelog_check_state(op, client_id, op_id, object, *check_state);
13677 }
13678 utime_t ts = ceph_clock_now();
13679 bufferlist nobl;
13680 cls_statelog_add(op, client_id, op_id, object, ts, state, (bl ? *bl : nobl));
13681 r = ioctx.operate(oid, &op);
13682 if (r < 0) {
13683 return r;
13684 }
13685
13686 return 0;
13687 }
13688
13689 int RGWStateLog::remove_entry(const string& client_id, const string& op_id, const string& object)
13690 {
13691 if (client_id.empty() ||
13692 op_id.empty() ||
13693 object.empty()) {
13694 ldout(store->ctx(), 0) << "client_id / op_id / object is empty" << dendl;
13695 }
13696
13697 librados::IoCtx ioctx;
13698 int r = open_ioctx(ioctx);
13699 if (r < 0)
13700 return r;
13701
13702 string oid = get_oid(object);
13703
13704 librados::ObjectWriteOperation op;
13705 cls_statelog_remove_by_object(op, object, op_id);
13706 r = ioctx.operate(oid, &op);
13707 if (r < 0) {
13708 return r;
13709 }
13710
13711 return 0;
13712 }
13713
13714 void RGWStateLog::init_list_entries(const string& client_id, const string& op_id, const string& object,
13715 void **handle)
13716 {
13717 list_state *state = new list_state;
13718 state->client_id = client_id;
13719 state->op_id = op_id;
13720 state->object = object;
13721 if (object.empty()) {
13722 state->cur_shard = 0;
13723 state->max_shard = num_shards - 1;
13724 } else {
13725 state->cur_shard = state->max_shard = get_shard_num(object);
13726 }
13727 *handle = (void *)state;
13728 }
13729
13730 int RGWStateLog::list_entries(void *handle, int max_entries,
13731 list<cls_statelog_entry>& entries,
13732 bool *done)
13733 {
13734 list_state *state = static_cast<list_state *>(handle);
13735
13736 librados::IoCtx ioctx;
13737 int r = open_ioctx(ioctx);
13738 if (r < 0)
13739 return r;
13740
13741 entries.clear();
13742
13743 for (; state->cur_shard <= state->max_shard && max_entries > 0; ++state->cur_shard) {
13744 string oid;
13745 oid_str(state->cur_shard, oid);
13746
13747 librados::ObjectReadOperation op;
13748 list<cls_statelog_entry> ents;
13749 bool truncated;
13750 cls_statelog_list(op, state->client_id, state->op_id, state->object, state->marker,
13751 max_entries, ents, &state->marker, &truncated);
13752 bufferlist ibl;
13753 r = ioctx.operate(oid, &op, &ibl);
13754 if (r == -ENOENT) {
13755 truncated = false;
13756 r = 0;
13757 }
13758 if (r < 0) {
13759 ldout(store->ctx(), 0) << "cls_statelog_list returned " << r << dendl;
13760 return r;
13761 }
13762
13763 if (!truncated) {
13764 state->marker.clear();
13765 }
13766
13767 max_entries -= ents.size();
13768
13769 entries.splice(entries.end(), ents);
13770
13771 if (truncated)
13772 break;
13773 }
13774
13775 *done = (state->cur_shard > state->max_shard);
13776
13777 return 0;
13778 }
13779
13780 void RGWStateLog::finish_list_entries(void *handle)
13781 {
13782 list_state *state = static_cast<list_state *>(handle);
13783 delete state;
13784 }
13785
13786 void RGWStateLog::dump_entry(const cls_statelog_entry& entry, Formatter *f)
13787 {
13788 f->open_object_section("statelog_entry");
13789 f->dump_string("client_id", entry.client_id);
13790 f->dump_string("op_id", entry.op_id);
13791 f->dump_string("object", entry.object);
13792 entry.timestamp.gmtime_nsec(f->dump_stream("timestamp"));
13793 if (!dump_entry_internal(entry, f)) {
13794 f->dump_int("state", entry.state);
13795 }
13796 f->close_section();
13797 }
13798
13799 RGWOpState::RGWOpState(RGWRados *_store) : RGWStateLog(_store, _store->ctx()->_conf->rgw_num_zone_opstate_shards, string("obj_opstate"))
13800 {
13801 }
13802
13803 bool RGWOpState::dump_entry_internal(const cls_statelog_entry& entry, Formatter *f)
13804 {
13805 string s;
13806 switch ((OpState)entry.state) {
13807 case OPSTATE_UNKNOWN:
13808 s = "unknown";
13809 break;
13810 case OPSTATE_IN_PROGRESS:
13811 s = "in-progress";
13812 break;
13813 case OPSTATE_COMPLETE:
13814 s = "complete";
13815 break;
13816 case OPSTATE_ERROR:
13817 s = "error";
13818 break;
13819 case OPSTATE_ABORT:
13820 s = "abort";
13821 break;
13822 case OPSTATE_CANCELLED:
13823 s = "cancelled";
13824 break;
13825 default:
13826 s = "invalid";
13827 }
13828 f->dump_string("state", s);
13829 return true;
13830 }
13831
13832 int RGWOpState::state_from_str(const string& s, OpState *state)
13833 {
13834 if (s == "unknown") {
13835 *state = OPSTATE_UNKNOWN;
13836 } else if (s == "in-progress") {
13837 *state = OPSTATE_IN_PROGRESS;
13838 } else if (s == "complete") {
13839 *state = OPSTATE_COMPLETE;
13840 } else if (s == "error") {
13841 *state = OPSTATE_ERROR;
13842 } else if (s == "abort") {
13843 *state = OPSTATE_ABORT;
13844 } else if (s == "cancelled") {
13845 *state = OPSTATE_CANCELLED;
13846 } else {
13847 return -EINVAL;
13848 }
13849
13850 return 0;
13851 }
13852
13853 int RGWOpState::set_state(const string& client_id, const string& op_id, const string& object, OpState state)
13854 {
13855 uint32_t s = (uint32_t)state;
13856 return store_entry(client_id, op_id, object, s, NULL, NULL);
13857 }
13858
13859 int RGWOpState::renew_state(const string& client_id, const string& op_id, const string& object, OpState state)
13860 {
13861 uint32_t s = (uint32_t)state;
13862 return store_entry(client_id, op_id, object, s, NULL, &s);
13863 }
13864
13865 RGWOpStateSingleOp::RGWOpStateSingleOp(RGWRados *store, const string& cid, const string& oid,
13866 const string& obj) : os(store), client_id(cid), op_id(oid), object(obj)
13867 {
13868 cct = store->ctx();
13869 cur_state = RGWOpState::OPSTATE_UNKNOWN;
13870 }
13871
13872 int RGWOpStateSingleOp::set_state(RGWOpState::OpState state) {
13873 last_update = real_clock::now();
13874 cur_state = state;
13875 return os.set_state(client_id, op_id, object, state);
13876 }
13877
13878 int RGWOpStateSingleOp::renew_state() {
13879 real_time now = real_clock::now();
13880
13881 int rate_limit_sec = cct->_conf->rgw_opstate_ratelimit_sec;
13882
13883 if (rate_limit_sec && now - last_update < make_timespan(rate_limit_sec)) {
13884 return 0;
13885 }
13886
13887 last_update = now;
13888 return os.renew_state(client_id, op_id, object, cur_state);
13889 }
13890
13891
13892 uint64_t RGWRados::instance_id()
13893 {
13894 return get_rados_handle()->get_instance_id();
13895 }
13896
13897 uint64_t RGWRados::next_bucket_id()
13898 {
13899 Mutex::Locker l(bucket_id_lock);
13900 return ++max_bucket_id;
13901 }
13902
13903 RGWRados *RGWStoreManager::init_storage_provider(CephContext *cct, bool use_gc_thread, bool use_lc_thread, bool quota_threads, bool run_sync_thread, bool run_reshard_thread)
13904 {
13905 int use_cache = cct->_conf->rgw_cache_enabled;
13906 RGWRados *store = NULL;
13907 if (!use_cache) {
13908 store = new RGWRados;
13909 } else {
13910 store = new RGWCache<RGWRados>;
13911 }
13912
13913 if (store->initialize(cct, use_gc_thread, use_lc_thread, quota_threads, run_sync_thread, run_reshard_thread) < 0) {
13914 delete store;
13915 return NULL;
13916 }
13917
13918 return store;
13919 }
13920
13921 RGWRados *RGWStoreManager::init_raw_storage_provider(CephContext *cct)
13922 {
13923 RGWRados *store = NULL;
13924 store = new RGWRados;
13925
13926 store->set_context(cct);
13927
13928 if (store->init_rados() < 0) {
13929 delete store;
13930 return NULL;
13931 }
13932
13933 return store;
13934 }
13935
13936 void RGWStoreManager::close_storage(RGWRados *store)
13937 {
13938 if (!store)
13939 return;
13940
13941 store->finalize();
13942
13943 delete store;
13944 }
13945
13946 librados::Rados* RGWRados::get_rados_handle()
13947 {
13948 if (rados.size() == 1) {
13949 return &rados[0];
13950 } else {
13951 handle_lock.get_read();
13952 pthread_t id = pthread_self();
13953 std::map<pthread_t, int>:: iterator it = rados_map.find(id);
13954
13955 if (it != rados_map.end()) {
13956 handle_lock.put_read();
13957 return &rados[it->second];
13958 } else {
13959 handle_lock.put_read();
13960 handle_lock.get_write();
13961 const uint32_t handle = next_rados_handle;
13962 rados_map[id] = handle;
13963 if (++next_rados_handle == rados.size()) {
13964 next_rados_handle = 0;
13965 }
13966 handle_lock.put_write();
13967 return &rados[handle];
13968 }
13969 }
13970 }
13971
13972 int RGWRados::delete_raw_obj_aio(const rgw_raw_obj& obj, list<librados::AioCompletion *>& handles)
13973 {
13974 rgw_rados_ref ref;
13975 int ret = get_raw_obj_ref(obj, &ref);
13976 if (ret < 0) {
13977 lderr(cct) << "ERROR: failed to get obj ref with ret=" << ret << dendl;
13978 return ret;
13979 }
13980
13981 ObjectWriteOperation op;
13982 list<string> prefixes;
13983 cls_rgw_remove_obj(op, prefixes);
13984
13985 AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL);
13986 ret = ref.ioctx.aio_operate(ref.oid, c, &op);
13987 if (ret < 0) {
13988 lderr(cct) << "ERROR: AioOperate failed with ret=" << ret << dendl;
13989 c->release();
13990 return ret;
13991 }
13992
13993 handles.push_back(c);
13994
13995 return 0;
13996 }
13997
13998 int RGWRados::delete_obj_aio(const rgw_obj& obj,
13999 RGWBucketInfo& bucket_info, RGWObjState *astate,
14000 list<librados::AioCompletion *>& handles, bool keep_index_consistent)
14001 {
14002 rgw_rados_ref ref;
14003 int ret = get_obj_head_ref(bucket_info, obj, &ref);
14004 if (ret < 0) {
14005 lderr(cct) << "ERROR: failed to get obj ref with ret=" << ret << dendl;
14006 return ret;
14007 }
14008
14009 if (keep_index_consistent) {
14010 RGWRados::Bucket bop(this, bucket_info);
14011 RGWRados::Bucket::UpdateIndex index_op(&bop, obj);
14012
14013 ret = index_op.prepare(CLS_RGW_OP_DEL, &astate->write_tag);
14014 if (ret < 0) {
14015 lderr(cct) << "ERROR: failed to prepare index op with ret=" << ret << dendl;
14016 return ret;
14017 }
14018 }
14019
14020 ObjectWriteOperation op;
14021 list<string> prefixes;
14022 cls_rgw_remove_obj(op, prefixes);
14023
14024 AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL);
14025 ret = ref.ioctx.aio_operate(ref.oid, c, &op);
14026 if (ret < 0) {
14027 lderr(cct) << "ERROR: AioOperate failed with ret=" << ret << dendl;
14028 c->release();
14029 return ret;
14030 }
14031
14032 handles.push_back(c);
14033
14034 if (keep_index_consistent) {
14035 ret = delete_obj_index(obj);
14036 if (ret < 0) {
14037 lderr(cct) << "ERROR: failed to delete obj index with ret=" << ret << dendl;
14038 return ret;
14039 }
14040 }
14041 return ret;
14042 }
14043
14044 int rgw_compression_info_from_attrset(map<string, bufferlist>& attrs, bool& need_decompress, RGWCompressionInfo& cs_info) {
14045 map<string, bufferlist>::iterator value = attrs.find(RGW_ATTR_COMPRESSION);
14046 if (value != attrs.end()) {
14047 bufferlist::iterator bliter = value->second.begin();
14048 try {
14049 ::decode(cs_info, bliter);
14050 } catch (buffer::error& err) {
14051 return -EIO;
14052 }
14053 if (cs_info.blocks.size() == 0) {
14054 return -EIO;
14055 }
14056 if (cs_info.compression_type != "none")
14057 need_decompress = true;
14058 else
14059 need_decompress = false;
14060 return 0;
14061 } else {
14062 need_decompress = false;
14063 return 0;
14064 }
14065 }
14066
14067 bool RGWRados::call(std::string command, cmdmap_t& cmdmap, std::string format,
14068 bufferlist& out)
14069 {
14070 if (command == "cache list") {
14071 boost::optional<std::string> filter;
14072 auto i = cmdmap.find("filter");
14073 if (i != cmdmap.cend()) {
14074 filter = boost::get<std::string>(i->second);
14075 }
14076 std::unique_ptr<Formatter> f(ceph::Formatter::create(format, "table"));
14077 if (f) {
14078 f->open_array_section("cache_entries");
14079 call_list(filter, f.get());
14080 f->close_section();
14081 f->flush(out);
14082 return true;
14083 } else {
14084 out.append("Unable to create Formatter.\n");
14085 return false;
14086 }
14087 } else if (command == "cache inspect") {
14088 std::unique_ptr<Formatter> f(ceph::Formatter::create(format, "json-pretty"));
14089 if (f) {
14090 const auto& target = boost::get<std::string>(cmdmap["target"]);
14091 if (call_inspect(target, f.get())) {
14092 f->flush(out);
14093 return true;
14094 } else {
14095 out.append(string("Unable to find entry ") + target + string(".\n"));
14096 return false;
14097 }
14098 } else {
14099 out.append("Unable to create Formatter.\n");
14100 return false;
14101 }
14102 } else if (command == "cache erase") {
14103 const auto& target = boost::get<std::string>(cmdmap["target"]);
14104 if (call_erase(target)) {
14105 return true;
14106 } else {
14107 out.append(string("Unable to find entry ") + target + string(".\n"));
14108 return false;
14109 }
14110 } else if (command == "cache zap") {
14111 call_zap();
14112 return true;
14113 }
14114 return false;
14115 }
14116
14117 void RGWRados::call_list(const boost::optional<std::string>&,
14118 ceph::Formatter*)
14119 {
14120 return;
14121 }
14122
14123 bool RGWRados::call_inspect(const std::string&, Formatter*)
14124 {
14125 return false;
14126 }
14127
14128 bool RGWRados::call_erase(const std::string&) {
14129 return false;
14130 }
14131
14132 void RGWRados::call_zap() {
14133 return;
14134 }