]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_multi.cc
220cc5071948827195a497e15db47ac6cc8052e4
[ceph.git] / ceph / src / rgw / rgw_multi.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 <string.h>
5
6 #include <iostream>
7 #include <map>
8
9 #include "include/types.h"
10
11 #include "rgw_xml.h"
12 #include "rgw_multi.h"
13
14 #define dout_subsys ceph_subsys_rgw
15
16 using namespace std;
17
18
19 bool RGWMultiPart::xml_end(const char *el)
20 {
21 RGWMultiPartNumber *num_obj = static_cast<RGWMultiPartNumber *>(find_first("PartNumber"));
22 RGWMultiETag *etag_obj = static_cast<RGWMultiETag *>(find_first("ETag"));
23
24 if (!num_obj || !etag_obj)
25 return false;
26
27 string s = num_obj->get_data();
28 if (s.empty())
29 return false;
30
31 num = atoi(s.c_str());
32
33 s = etag_obj->get_data();
34 etag = s;
35
36 return true;
37 }
38
39 bool RGWMultiCompleteUpload::xml_end(const char *el) {
40 XMLObjIter iter = find("Part");
41 RGWMultiPart *part = static_cast<RGWMultiPart *>(iter.get_next());
42 while (part) {
43 int num = part->get_num();
44 string etag = part->get_etag();
45 parts[num] = etag;
46 part = static_cast<RGWMultiPart *>(iter.get_next());
47 }
48 return true;
49 }
50
51
52 XMLObj *RGWMultiXMLParser::alloc_obj(const char *el) {
53 XMLObj *obj = NULL;
54 if (strcmp(el, "CompleteMultipartUpload") == 0 ||
55 strcmp(el, "MultipartUpload") == 0) {
56 obj = new RGWMultiCompleteUpload();
57 } else if (strcmp(el, "Part") == 0) {
58 obj = new RGWMultiPart();
59 } else if (strcmp(el, "PartNumber") == 0) {
60 obj = new RGWMultiPartNumber();
61 } else if (strcmp(el, "ETag") == 0) {
62 obj = new RGWMultiETag();
63 }
64
65 return obj;
66 }
67
68 bool is_v2_upload_id(const string& upload_id)
69 {
70 const char *uid = upload_id.c_str();
71
72 return (strncmp(uid, MULTIPART_UPLOAD_ID_PREFIX, sizeof(MULTIPART_UPLOAD_ID_PREFIX) - 1) == 0) ||
73 (strncmp(uid, MULTIPART_UPLOAD_ID_PREFIX_LEGACY, sizeof(MULTIPART_UPLOAD_ID_PREFIX_LEGACY) - 1) == 0);
74 }
75
76 int list_multipart_parts(RGWRados *store, RGWBucketInfo& bucket_info, CephContext *cct,
77 const string& upload_id,
78 string& meta_oid, int num_parts,
79 int marker, map<uint32_t, RGWUploadPartInfo>& parts,
80 int *next_marker, bool *truncated,
81 bool assume_unsorted)
82 {
83 map<string, bufferlist> parts_map;
84 map<string, bufferlist>::iterator iter;
85 bufferlist header;
86
87 rgw_obj obj;
88 obj.init_ns(bucket_info.bucket, meta_oid, RGW_OBJ_NS_MULTIPART);
89 obj.set_in_extra_data(true);
90
91 rgw_raw_obj raw_obj;
92 store->obj_to_raw(bucket_info.placement_rule, obj, &raw_obj);
93
94 bool sorted_omap = is_v2_upload_id(upload_id) && !assume_unsorted;
95
96 int ret;
97
98 parts.clear();
99
100 if (sorted_omap) {
101 string p;
102 p = "part.";
103 char buf[32];
104
105 snprintf(buf, sizeof(buf), "%08d", marker);
106 p.append(buf);
107
108 ret = store->omap_get_vals(raw_obj, header, p, num_parts + 1, parts_map);
109 } else {
110 ret = store->omap_get_all(raw_obj, header, parts_map);
111 }
112 if (ret < 0)
113 return ret;
114
115 int i;
116 int last_num = 0;
117
118 uint32_t expected_next = marker + 1;
119
120 for (i = 0, iter = parts_map.begin(); (i < num_parts || !sorted_omap) && iter != parts_map.end(); ++iter, ++i) {
121 bufferlist& bl = iter->second;
122 bufferlist::iterator bli = bl.begin();
123 RGWUploadPartInfo info;
124 try {
125 ::decode(info, bli);
126 } catch (buffer::error& err) {
127 ldout(cct, 0) << "ERROR: could not part info, caught buffer::error" << dendl;
128 return -EIO;
129 }
130 if (sorted_omap) {
131 if (info.num != expected_next) {
132 /* ouch, we expected a specific part num here, but we got a different one. Either
133 * a part is missing, or it could be a case of mixed rgw versions working on the same
134 * upload, where one gateway doesn't support correctly sorted omap keys for multipart
135 * upload just assume data is unsorted.
136 */
137 return list_multipart_parts(store, bucket_info, cct, upload_id, meta_oid, num_parts, marker, parts, next_marker, truncated, true);
138 }
139 expected_next++;
140 }
141 if (sorted_omap ||
142 (int)info.num > marker) {
143 parts[info.num] = info;
144 last_num = info.num;
145 }
146 }
147
148 if (sorted_omap) {
149 if (truncated)
150 *truncated = (iter != parts_map.end());
151 } else {
152 /* rebuild a map with only num_parts entries */
153
154 map<uint32_t, RGWUploadPartInfo> new_parts;
155 map<uint32_t, RGWUploadPartInfo>::iterator piter;
156
157 for (i = 0, piter = parts.begin(); i < num_parts && piter != parts.end(); ++i, ++piter) {
158 new_parts[piter->first] = piter->second;
159 last_num = piter->first;
160 }
161
162 if (truncated)
163 *truncated = (piter != parts.end());
164
165 parts.swap(new_parts);
166 }
167
168 if (next_marker) {
169 *next_marker = last_num;
170 }
171
172 return 0;
173 }
174
175 int list_multipart_parts(RGWRados *store, struct req_state *s,
176 const string& upload_id,
177 string& meta_oid, int num_parts,
178 int marker, map<uint32_t, RGWUploadPartInfo>& parts,
179 int *next_marker, bool *truncated,
180 bool assume_unsorted)
181 {
182 return list_multipart_parts(store, s->bucket_info, s->cct, upload_id, meta_oid, num_parts, marker, parts, next_marker, truncated, assume_unsorted);
183 }
184
185 int abort_multipart_upload(RGWRados *store, CephContext *cct, RGWObjectCtx *obj_ctx, RGWBucketInfo& bucket_info, RGWMPObj& mp_obj)
186 {
187 rgw_obj meta_obj;
188 meta_obj.init_ns(bucket_info.bucket, mp_obj.get_meta(), RGW_OBJ_NS_MULTIPART);
189 meta_obj.set_in_extra_data(true);
190 meta_obj.index_hash_source = mp_obj.get_key();
191 cls_rgw_obj_chain chain;
192 list<rgw_obj_index_key> remove_objs;
193 map<uint32_t, RGWUploadPartInfo> obj_parts;
194 bool truncated;
195 int marker = 0;
196 int ret;
197
198 do {
199 ret = list_multipart_parts(store, bucket_info, cct, mp_obj.get_upload_id(), mp_obj.get_meta(), 1000,
200 marker, obj_parts, &marker, &truncated);
201 if (ret < 0)
202 return ret;
203 for (auto obj_iter = obj_parts.begin(); obj_iter != obj_parts.end(); ++obj_iter) {
204 RGWUploadPartInfo& obj_part = obj_iter->second;
205 rgw_obj obj;
206 if (obj_part.manifest.empty()) {
207 string oid = mp_obj.get_part(obj_iter->second.num);
208 obj.init_ns(bucket_info.bucket, oid, RGW_OBJ_NS_MULTIPART);
209 obj.index_hash_source = mp_obj.get_key();
210 ret = store->delete_obj(*obj_ctx, bucket_info, obj, 0);
211 if (ret < 0 && ret != -ENOENT)
212 return ret;
213 } else {
214 store->update_gc_chain(meta_obj, obj_part.manifest, &chain);
215 RGWObjManifest::obj_iterator oiter = obj_part.manifest.obj_begin();
216 if (oiter != obj_part.manifest.obj_end()) {
217 rgw_obj head;
218 rgw_raw_obj raw_head = oiter.get_location().get_raw_obj(store);
219 rgw_raw_obj_to_obj(bucket_info.bucket, raw_head, &head);
220
221 rgw_obj_index_key key;
222 head.key.get_index_key(&key);
223 remove_objs.push_back(key);
224 }
225 }
226 }
227 } while (truncated);
228 /* use upload id as tag */
229 ret = store->send_chain_to_gc(chain, mp_obj.get_upload_id() , false); // do it async
230 if (ret < 0) {
231 ldout(cct, 5) << "gc->send_chain() returned " << ret << dendl;
232 return ret;
233 }
234 RGWRados::Object del_target(store, bucket_info, *obj_ctx, meta_obj);
235 RGWRados::Object::Delete del_op(&del_target);
236
237 del_op.params.bucket_owner = bucket_info.owner;
238 del_op.params.versioning_status = 0;
239 if (!remove_objs.empty()) {
240 del_op.params.remove_objs = &remove_objs;
241 }
242
243 // and also remove the metadata obj
244 ret = del_op.delete_obj();
245 return ret == -ENOENT?-ERR_NO_SUCH_UPLOAD:ret;
246 }
247