]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2013 eNovance SAS <licensing@enovance.com> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | #include <iostream> | |
15 | #include "common/ceph_json.h" | |
16 | #include "common/Formatter.h" | |
17 | #include "rgw/rgw_common.h" | |
18 | #include "rgw/rgw_rados.h" | |
11fdf7f2 | 19 | #include "rgw/rgw_zone.h" |
7c673cae FG |
20 | |
21 | #ifndef CEPH_TEST_RGW_COMMON_H | |
22 | #define CEPH_TEST_RGW_COMMON_H | |
23 | ||
24 | struct old_rgw_bucket { | |
25 | std::string tenant; | |
26 | std::string name; | |
27 | std::string data_pool; | |
28 | std::string data_extra_pool; /* if not set, then we should use data_pool instead */ | |
29 | std::string index_pool; | |
30 | std::string marker; | |
31 | std::string bucket_id; | |
32 | ||
33 | std::string oid; /* | |
34 | * runtime in-memory only info. If not empty, points to the bucket instance object | |
35 | */ | |
36 | ||
37 | old_rgw_bucket() { } | |
38 | // cppcheck-suppress noExplicitConstructor | |
39 | old_rgw_bucket(const std::string& s) : name(s) { | |
40 | data_pool = index_pool = s; | |
41 | marker = ""; | |
42 | } | |
11fdf7f2 | 43 | explicit old_rgw_bucket(const char *n) : name(n) { |
7c673cae FG |
44 | data_pool = index_pool = n; |
45 | marker = ""; | |
46 | } | |
47 | old_rgw_bucket(const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id, const char *h) : | |
48 | tenant(t), name(n), data_pool(dp), index_pool(ip), marker(m), bucket_id(id) {} | |
49 | ||
50 | void encode(bufferlist& bl) const { | |
51 | ENCODE_START(8, 3, bl); | |
11fdf7f2 TL |
52 | encode(name, bl); |
53 | encode(data_pool, bl); | |
54 | encode(marker, bl); | |
55 | encode(bucket_id, bl); | |
56 | encode(index_pool, bl); | |
57 | encode(data_extra_pool, bl); | |
58 | encode(tenant, bl); | |
7c673cae FG |
59 | ENCODE_FINISH(bl); |
60 | } | |
11fdf7f2 | 61 | void decode(bufferlist::const_iterator& bl) { |
7c673cae | 62 | DECODE_START_LEGACY_COMPAT_LEN(8, 3, 3, bl); |
11fdf7f2 TL |
63 | decode(name, bl); |
64 | decode(data_pool, bl); | |
7c673cae | 65 | if (struct_v >= 2) { |
11fdf7f2 | 66 | decode(marker, bl); |
7c673cae FG |
67 | if (struct_v <= 3) { |
68 | uint64_t id; | |
11fdf7f2 | 69 | decode(id, bl); |
7c673cae FG |
70 | char buf[16]; |
71 | snprintf(buf, sizeof(buf), "%llu", (long long)id); | |
72 | bucket_id = buf; | |
73 | } else { | |
11fdf7f2 | 74 | decode(bucket_id, bl); |
7c673cae FG |
75 | } |
76 | } | |
77 | if (struct_v >= 5) { | |
11fdf7f2 | 78 | decode(index_pool, bl); |
7c673cae FG |
79 | } else { |
80 | index_pool = data_pool; | |
81 | } | |
82 | if (struct_v >= 7) { | |
11fdf7f2 | 83 | decode(data_extra_pool, bl); |
7c673cae FG |
84 | } |
85 | if (struct_v >= 8) { | |
11fdf7f2 | 86 | decode(tenant, bl); |
7c673cae FG |
87 | } |
88 | DECODE_FINISH(bl); | |
89 | } | |
90 | ||
91 | // format a key for the bucket/instance. pass delim=0 to skip a field | |
92 | std::string get_key(char tenant_delim = '/', | |
93 | char id_delim = ':') const; | |
94 | ||
95 | const std::string& get_data_extra_pool() { | |
96 | if (data_extra_pool.empty()) { | |
97 | return data_pool; | |
98 | } | |
99 | return data_extra_pool; | |
100 | } | |
101 | ||
102 | void dump(Formatter *f) const; | |
103 | void decode_json(JSONObj *obj); | |
20effc67 | 104 | static void generate_test_instances(std::list<old_rgw_bucket*>& o); |
7c673cae FG |
105 | |
106 | bool operator<(const old_rgw_bucket& b) const { | |
107 | return name.compare(b.name) < 0; | |
108 | } | |
109 | }; | |
110 | WRITE_CLASS_ENCODER(old_rgw_bucket) | |
111 | ||
112 | class old_rgw_obj { | |
113 | std::string orig_obj; | |
114 | std::string loc; | |
115 | std::string object; | |
116 | std::string instance; | |
117 | public: | |
118 | const std::string& get_object() const { return object; } | |
119 | const std::string& get_orig_obj() const { return orig_obj; } | |
120 | const std::string& get_loc() const { return loc; } | |
121 | const std::string& get_instance() const { return instance; } | |
122 | old_rgw_bucket bucket; | |
123 | std::string ns; | |
124 | ||
125 | bool in_extra_data; /* in-memory only member, does not serialize */ | |
126 | ||
127 | // Represents the hash index source for this object once it is set (non-empty) | |
128 | std::string index_hash_source; | |
129 | ||
130 | old_rgw_obj() : in_extra_data(false) {} | |
131 | old_rgw_obj(old_rgw_bucket& b, const std::string& o) : in_extra_data(false) { | |
132 | init(b, o); | |
133 | } | |
134 | old_rgw_obj(old_rgw_bucket& b, const rgw_obj_key& k) : in_extra_data(false) { | |
135 | from_index_key(b, k); | |
136 | } | |
137 | void init(old_rgw_bucket& b, const std::string& o) { | |
138 | bucket = b; | |
139 | set_obj(o); | |
140 | reset_loc(); | |
141 | } | |
142 | void init_ns(old_rgw_bucket& b, const std::string& o, const std::string& n) { | |
143 | bucket = b; | |
144 | set_ns(n); | |
145 | set_obj(o); | |
146 | reset_loc(); | |
147 | } | |
148 | int set_ns(const char *n) { | |
149 | if (!n) | |
150 | return -EINVAL; | |
151 | std::string ns_str(n); | |
152 | return set_ns(ns_str); | |
153 | } | |
154 | int set_ns(const std::string& n) { | |
155 | if (n[0] == '_') | |
156 | return -EINVAL; | |
157 | ns = n; | |
158 | set_obj(orig_obj); | |
159 | return 0; | |
160 | } | |
161 | int set_instance(const std::string& i) { | |
162 | if (i[0] == '_') | |
163 | return -EINVAL; | |
164 | instance = i; | |
165 | set_obj(orig_obj); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | int clear_instance() { | |
20effc67 | 170 | return set_instance(std::string()); |
7c673cae FG |
171 | } |
172 | ||
173 | void set_loc(const std::string& k) { | |
174 | loc = k; | |
175 | } | |
176 | ||
177 | void reset_loc() { | |
178 | loc.clear(); | |
179 | /* | |
180 | * For backward compatibility. Older versions used to have object locator on all objects, | |
181 | * however, the orig_obj was the effective object locator. This had the same effect as not | |
182 | * having object locator at all for most objects but the ones that started with underscore as | |
183 | * these were escaped. | |
184 | */ | |
185 | if (orig_obj[0] == '_' && ns.empty()) { | |
186 | loc = orig_obj; | |
187 | } | |
188 | } | |
189 | ||
190 | bool have_null_instance() { | |
191 | return instance == "null"; | |
192 | } | |
193 | ||
194 | bool have_instance() { | |
195 | return !instance.empty(); | |
196 | } | |
197 | ||
198 | bool need_to_encode_instance() { | |
199 | return have_instance() && !have_null_instance(); | |
200 | } | |
201 | ||
202 | void set_obj(const std::string& o) { | |
203 | object.reserve(128); | |
204 | ||
205 | orig_obj = o; | |
206 | if (ns.empty() && !need_to_encode_instance()) { | |
207 | if (o.empty()) { | |
208 | return; | |
209 | } | |
210 | if (o.size() < 1 || o[0] != '_') { | |
211 | object = o; | |
212 | return; | |
213 | } | |
214 | object = "_"; | |
215 | object.append(o); | |
216 | } else { | |
217 | object = "_"; | |
218 | object.append(ns); | |
219 | if (need_to_encode_instance()) { | |
20effc67 | 220 | object.append(std::string(":") + instance); |
7c673cae FG |
221 | } |
222 | object.append("_"); | |
223 | object.append(o); | |
224 | } | |
225 | reset_loc(); | |
226 | } | |
227 | ||
228 | /* | |
229 | * get the object's key name as being referred to by the bucket index. | |
230 | */ | |
231 | std::string get_index_key_name() const { | |
232 | if (ns.empty()) { | |
233 | if (orig_obj.size() < 1 || orig_obj[0] != '_') { | |
234 | return orig_obj; | |
235 | } | |
236 | return std::string("_") + orig_obj; | |
237 | }; | |
238 | ||
239 | char buf[ns.size() + 16]; | |
240 | snprintf(buf, sizeof(buf), "_%s_", ns.c_str()); | |
241 | return std::string(buf) + orig_obj; | |
242 | }; | |
243 | ||
244 | void from_index_key(old_rgw_bucket& b, const rgw_obj_key& key) { | |
245 | if (key.name[0] != '_') { | |
246 | init(b, key.name); | |
247 | set_instance(key.instance); | |
248 | return; | |
249 | } | |
250 | if (key.name[1] == '_') { | |
251 | init(b, key.name.substr(1)); | |
252 | set_instance(key.instance); | |
253 | return; | |
254 | } | |
255 | ssize_t pos = key.name.find('_', 1); | |
256 | if (pos < 0) { | |
257 | /* shouldn't happen, just use key */ | |
258 | init(b, key.name); | |
259 | set_instance(key.instance); | |
260 | return; | |
261 | } | |
262 | ||
263 | init_ns(b, key.name.substr(pos + 1), key.name.substr(1, pos -1)); | |
264 | set_instance(key.instance); | |
265 | } | |
266 | ||
267 | void get_index_key(rgw_obj_key *key) const { | |
268 | key->name = get_index_key_name(); | |
269 | key->instance = instance; | |
270 | } | |
271 | ||
20effc67 | 272 | static void parse_ns_field(std::string& ns, std::string& instance) { |
7c673cae FG |
273 | int pos = ns.find(':'); |
274 | if (pos >= 0) { | |
275 | instance = ns.substr(pos + 1); | |
276 | ns = ns.substr(0, pos); | |
277 | } else { | |
278 | instance.clear(); | |
279 | } | |
280 | } | |
281 | ||
282 | std::string& get_hash_object() { | |
283 | return index_hash_source.empty() ? orig_obj : index_hash_source; | |
284 | } | |
285 | /** | |
286 | * Translate a namespace-mangled object name to the user-facing name | |
287 | * existing in the given namespace. | |
288 | * | |
289 | * If the object is part of the given namespace, it returns true | |
290 | * and cuts down the name to the unmangled version. If it is not | |
291 | * part of the given namespace, it returns false. | |
292 | */ | |
20effc67 | 293 | static bool translate_raw_obj_to_obj_in_ns(std::string& obj, std::string& instance, std::string& ns) { |
7c673cae FG |
294 | if (obj[0] != '_') { |
295 | if (ns.empty()) { | |
296 | return true; | |
297 | } | |
298 | return false; | |
299 | } | |
300 | ||
301 | std::string obj_ns; | |
302 | bool ret = parse_raw_oid(obj, &obj, &instance, &obj_ns); | |
303 | if (!ret) { | |
304 | return ret; | |
305 | } | |
306 | ||
307 | return (ns == obj_ns); | |
308 | } | |
309 | ||
310 | static bool parse_raw_oid(const std::string& oid, std::string *obj_name, std::string *obj_instance, std::string *obj_ns) { | |
311 | obj_instance->clear(); | |
312 | obj_ns->clear(); | |
313 | if (oid[0] != '_') { | |
314 | *obj_name = oid; | |
315 | return true; | |
316 | } | |
317 | ||
318 | if (oid.size() >= 2 && oid[1] == '_') { | |
319 | *obj_name = oid.substr(1); | |
320 | return true; | |
321 | } | |
322 | ||
323 | if (oid[0] != '_' || oid.size() < 3) // for namespace, min size would be 3: _x_ | |
324 | return false; | |
325 | ||
326 | int pos = oid.find('_', 1); | |
327 | if (pos <= 1) // if it starts with __, it's not in our namespace | |
328 | return false; | |
329 | ||
330 | *obj_ns = oid.substr(1, pos - 1); | |
331 | parse_ns_field(*obj_ns, *obj_instance); | |
332 | ||
333 | *obj_name = oid.substr(pos + 1); | |
334 | return true; | |
335 | } | |
336 | ||
337 | /** | |
338 | * Given a mangled object name and an empty namespace string, this | |
339 | * function extracts the namespace into the string and sets the object | |
340 | * name to be the unmangled version. | |
341 | * | |
342 | * It returns true after successfully doing so, or | |
343 | * false if it fails. | |
344 | */ | |
20effc67 | 345 | static bool strip_namespace_from_object(std::string& obj, std::string& ns, std::string& instance) { |
7c673cae FG |
346 | ns.clear(); |
347 | instance.clear(); | |
348 | if (obj[0] != '_') { | |
349 | return true; | |
350 | } | |
351 | ||
352 | size_t pos = obj.find('_', 1); | |
353 | if (pos == std::string::npos) { | |
354 | return false; | |
355 | } | |
356 | ||
357 | if (obj[1] == '_') { | |
358 | obj = obj.substr(1); | |
359 | return true; | |
360 | } | |
361 | ||
362 | size_t period_pos = obj.find('.'); | |
363 | if (period_pos < pos) { | |
364 | return false; | |
365 | } | |
366 | ||
367 | ns = obj.substr(1, pos-1); | |
368 | obj = obj.substr(pos+1, std::string::npos); | |
369 | ||
370 | parse_ns_field(ns, instance); | |
371 | return true; | |
372 | } | |
373 | ||
374 | void set_in_extra_data(bool val) { | |
375 | in_extra_data = val; | |
376 | } | |
377 | ||
378 | bool is_in_extra_data() const { | |
379 | return in_extra_data; | |
380 | } | |
381 | ||
382 | void encode(bufferlist& bl) const { | |
383 | ENCODE_START(5, 3, bl); | |
11fdf7f2 TL |
384 | encode(bucket.name, bl); |
385 | encode(loc, bl); | |
386 | encode(ns, bl); | |
387 | encode(object, bl); | |
388 | encode(bucket, bl); | |
389 | encode(instance, bl); | |
7c673cae | 390 | if (!ns.empty() || !instance.empty()) { |
11fdf7f2 | 391 | encode(orig_obj, bl); |
7c673cae FG |
392 | } |
393 | ENCODE_FINISH(bl); | |
394 | } | |
11fdf7f2 | 395 | void decode(bufferlist::const_iterator& bl) { |
7c673cae | 396 | DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); |
11fdf7f2 TL |
397 | decode(bucket.name, bl); |
398 | decode(loc, bl); | |
399 | decode(ns, bl); | |
400 | decode(object, bl); | |
7c673cae | 401 | if (struct_v >= 2) |
11fdf7f2 | 402 | decode(bucket, bl); |
7c673cae | 403 | if (struct_v >= 4) |
11fdf7f2 | 404 | decode(instance, bl); |
7c673cae FG |
405 | if (ns.empty() && instance.empty()) { |
406 | if (object[0] != '_') { | |
407 | orig_obj = object; | |
408 | } else { | |
409 | orig_obj = object.substr(1); | |
410 | } | |
411 | } else { | |
412 | if (struct_v >= 5) { | |
11fdf7f2 | 413 | decode(orig_obj, bl); |
7c673cae FG |
414 | } else { |
415 | ssize_t pos = object.find('_', 1); | |
416 | if (pos < 0) { | |
f67539c2 | 417 | throw buffer::malformed_input(); |
7c673cae FG |
418 | } |
419 | orig_obj = object.substr(pos); | |
420 | } | |
421 | } | |
422 | DECODE_FINISH(bl); | |
423 | } | |
424 | ||
425 | bool operator==(const old_rgw_obj& o) const { | |
426 | return (object.compare(o.object) == 0) && | |
427 | (bucket.name.compare(o.bucket.name) == 0) && | |
428 | (ns.compare(o.ns) == 0) && | |
429 | (instance.compare(o.instance) == 0); | |
430 | } | |
431 | bool operator<(const old_rgw_obj& o) const { | |
432 | int r = bucket.name.compare(o.bucket.name); | |
433 | if (r == 0) { | |
434 | r = bucket.bucket_id.compare(o.bucket.bucket_id); | |
435 | if (r == 0) { | |
436 | r = object.compare(o.object); | |
437 | if (r == 0) { | |
438 | r = ns.compare(o.ns); | |
439 | if (r == 0) { | |
440 | r = instance.compare(o.instance); | |
441 | } | |
442 | } | |
443 | } | |
444 | } | |
445 | ||
446 | return (r < 0); | |
447 | } | |
448 | }; | |
449 | WRITE_CLASS_ENCODER(old_rgw_obj) | |
450 | ||
20effc67 | 451 | static inline void prepend_old_bucket_marker(const old_rgw_bucket& bucket, const std::string& orig_oid, std::string& oid) |
7c673cae FG |
452 | { |
453 | if (bucket.marker.empty() || orig_oid.empty()) { | |
454 | oid = orig_oid; | |
455 | } else { | |
456 | oid = bucket.marker; | |
457 | oid.append("_"); | |
458 | oid.append(orig_oid); | |
459 | } | |
460 | } | |
461 | ||
462 | void test_rgw_init_env(RGWZoneGroup *zonegroup, RGWZoneParams *zone_params); | |
463 | ||
464 | struct test_rgw_env { | |
465 | RGWZoneGroup zonegroup; | |
466 | RGWZoneParams zone_params; | |
467 | rgw_data_placement_target default_placement; | |
468 | ||
469 | test_rgw_env() { | |
470 | test_rgw_init_env(&zonegroup, &zone_params); | |
11fdf7f2 TL |
471 | default_placement.data_pool = rgw_pool(zone_params.placement_pools[zonegroup.default_placement.name].get_standard_data_pool()); |
472 | default_placement.data_extra_pool = rgw_pool(zone_params.placement_pools[zonegroup.default_placement.name].data_extra_pool); | |
7c673cae FG |
473 | } |
474 | ||
475 | rgw_data_placement_target get_placement(const std::string& placement_id) { | |
476 | const RGWZonePlacementInfo& pi = zone_params.placement_pools[placement_id]; | |
477 | rgw_data_placement_target pt; | |
478 | pt.index_pool = pi.index_pool; | |
11fdf7f2 | 479 | pt.data_pool = pi.get_standard_data_pool(); |
7c673cae FG |
480 | pt.data_extra_pool = pi.data_extra_pool; |
481 | return pt; | |
482 | } | |
483 | ||
484 | rgw_raw_obj get_raw(const rgw_obj& obj) { | |
485 | rgw_obj_select s(obj); | |
486 | return s.get_raw_obj(zonegroup, zone_params); | |
487 | } | |
488 | ||
489 | rgw_raw_obj get_raw(const rgw_obj_select& os) { | |
490 | return os.get_raw_obj(zonegroup, zone_params); | |
491 | } | |
492 | }; | |
493 | ||
494 | void test_rgw_add_placement(RGWZoneGroup *zonegroup, RGWZoneParams *zone_params, const std::string& name, bool is_default); | |
495 | void test_rgw_populate_explicit_placement_bucket(rgw_bucket *b, const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id); | |
496 | void test_rgw_populate_old_bucket(old_rgw_bucket *b, const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id); | |
497 | ||
498 | std::string test_rgw_get_obj_oid(const rgw_obj& obj); | |
499 | void test_rgw_init_explicit_placement_bucket(rgw_bucket *bucket, const char *name); | |
500 | void test_rgw_init_old_bucket(old_rgw_bucket *bucket, const char *name); | |
501 | void test_rgw_populate_bucket(rgw_bucket *b, const char *t, const char *n, const char *m, const char *id); | |
502 | void test_rgw_init_bucket(rgw_bucket *bucket, const char *name); | |
503 | rgw_obj test_rgw_create_obj(const rgw_bucket& bucket, const std::string& name, const std::string& instance, const std::string& ns); | |
504 | ||
505 | #endif | |
506 |