1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
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.
15 #include "global/global_init.h"
16 #include "common/ceph_argparse.h"
17 #include "rgw/rgw_common.h"
18 #include "rgw/rgw_rados.h"
19 #include "test_rgw_common.h"
20 #include <gtest/gtest.h>
24 auto cct
= new CephContext(CEPH_ENTITY_TYPE_CLIENT
);
25 const DoutPrefix
dp(cct
, 1, "test rgw manifest: ");
27 struct OldObjManifestPart
{
28 old_rgw_obj loc
; /* the object where the data is located */
29 uint64_t loc_ofs
; /* the offset at that object where the data is located */
30 uint64_t size
; /* the part size */
32 OldObjManifestPart() : loc_ofs(0), size(0) {}
34 void encode(bufferlist
& bl
) const {
35 ENCODE_START(2, 2, bl
);
42 void decode(bufferlist::const_iterator
& bl
) {
43 DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl
);
50 void dump(Formatter
*f
) const;
51 static void generate_test_instances(list
<OldObjManifestPart
*>& o
);
53 WRITE_CLASS_ENCODER(OldObjManifestPart
)
55 class OldObjManifest
{
57 map
<uint64_t, OldObjManifestPart
> objs
;
62 OldObjManifest() : obj_size(0) {}
63 OldObjManifest(const OldObjManifest
& rhs
) {
66 OldObjManifest
& operator=(const OldObjManifest
& rhs
) {
68 obj_size
= rhs
.obj_size
;
72 const map
<uint64_t, OldObjManifestPart
>& get_objs() {
76 void append(uint64_t ofs
, const OldObjManifestPart
& part
) {
78 obj_size
= std::max(obj_size
, ofs
+ part
.size
);
81 void encode(bufferlist
& bl
) const {
82 ENCODE_START(2, 2, bl
);
88 void decode(bufferlist::const_iterator
& bl
) {
89 DECODE_START_LEGACY_COMPAT_LEN_32(6, 2, 2, bl
);
99 WRITE_CLASS_ENCODER(OldObjManifest
)
101 void append_head(list
<rgw_obj
> *objs
, rgw_obj
& head
)
103 objs
->push_back(head
);
106 void append_stripes(list
<rgw_obj
> *objs
, RGWObjManifest
& manifest
, uint64_t obj_size
, uint64_t stripe_size
)
108 string prefix
= manifest
.get_prefix();
109 rgw_bucket bucket
= manifest
.get_obj().bucket
;
112 for (uint64_t ofs
= manifest
.get_max_head_size(); ofs
< obj_size
; ofs
+= stripe_size
) {
114 snprintf(buf
, sizeof(buf
), "%d", ++i
);
115 string oid
= prefix
+ buf
;
116 cout
<< "oid=" << oid
<< std::endl
;
118 obj
.init_ns(bucket
, oid
, "shadow");
119 objs
->push_back(obj
);
123 static void gen_obj(test_rgw_env
& env
, uint64_t obj_size
, uint64_t head_max_size
, uint64_t stripe_size
,
124 RGWObjManifest
*manifest
, const rgw_placement_rule
& placement_rule
, rgw_bucket
*bucket
, rgw_obj
*head
, RGWObjManifest::generator
*gen
,
125 list
<rgw_obj
> *test_objs
)
127 manifest
->set_trivial_rule(head_max_size
, stripe_size
);
129 test_rgw_init_bucket(bucket
, "buck");
131 *head
= rgw_obj(*bucket
, "oid");
132 gen
->create_begin(g_ceph_context
, manifest
, placement_rule
, nullptr, *bucket
, *head
);
134 append_head(test_objs
, *head
);
135 cout
<< "test_objs.size()=" << test_objs
->size() << std::endl
;
136 append_stripes(test_objs
, *manifest
, obj_size
, stripe_size
);
138 cout
<< "test_objs.size()=" << test_objs
->size() << std::endl
;
140 ASSERT_EQ((int)manifest
->get_obj_size(), 0);
141 ASSERT_EQ((int)manifest
->get_head_size(), 0);
142 ASSERT_EQ(manifest
->has_tail(), false);
145 list
<rgw_obj
>::iterator iter
= test_objs
->begin();
147 while (ofs
< obj_size
) {
148 rgw_raw_obj obj
= gen
->get_cur_obj(env
.zonegroup
, env
.zone_params
);
149 cout
<< "obj=" << obj
<< std::endl
;
150 rgw_raw_obj test_raw
= rgw_obj_select(*iter
).get_raw_obj(env
.zonegroup
, env
.zone_params
);
151 ASSERT_TRUE(obj
== test_raw
);
153 ofs
= std::min(ofs
+ gen
->cur_stripe_max_size(), obj_size
);
154 gen
->create_next(ofs
);
156 cout
<< "obj=" << obj
<< " *iter=" << *iter
<< std::endl
;
157 cout
<< "test_objs.size()=" << test_objs
->size() << std::endl
;
162 if (manifest
->has_tail()) {
163 rgw_raw_obj obj
= gen
->get_cur_obj(env
.zonegroup
, env
.zone_params
);
164 rgw_raw_obj test_raw
= rgw_obj_select(*iter
).get_raw_obj(env
.zonegroup
, env
.zone_params
);
165 ASSERT_TRUE(obj
== test_raw
);
168 ASSERT_TRUE(iter
== test_objs
->end());
169 ASSERT_EQ(manifest
->get_obj_size(), obj_size
);
170 ASSERT_EQ(manifest
->get_head_size(), std::min(obj_size
, head_max_size
));
171 ASSERT_EQ(manifest
->has_tail(), (obj_size
> head_max_size
));
174 static void gen_old_obj(test_rgw_env
& env
, uint64_t obj_size
, uint64_t head_max_size
, uint64_t stripe_size
,
175 OldObjManifest
*manifest
, old_rgw_bucket
*bucket
, old_rgw_obj
*head
,
176 list
<old_rgw_obj
> *test_objs
)
178 test_rgw_init_old_bucket(bucket
, "buck");
180 *head
= old_rgw_obj(*bucket
, "obj");
182 OldObjManifestPart part
;
184 part
.size
= head_max_size
;
187 manifest
->append(0, part
);
188 test_objs
->push_back(part
.loc
);
191 append_rand_alpha(g_ceph_context
, prefix
, prefix
, 16);
194 for (uint64_t ofs
= head_max_size
; ofs
< obj_size
; ofs
+= stripe_size
, i
++) {
196 snprintf(buf
, sizeof(buf
), "%s.%d", prefix
.c_str(), i
);
197 old_rgw_obj
loc(*bucket
, buf
);
198 loc
.set_ns("shadow");
199 OldObjManifestPart part
;
201 part
.size
= min(stripe_size
, obj_size
- ofs
);
204 manifest
->append(ofs
, part
);
206 test_objs
->push_back(loc
);
210 TEST(TestRGWManifest
, head_only_obj
) {
212 RGWObjManifest manifest
;
215 RGWObjManifest::generator gen
;
217 int obj_size
= 256 * 1024;
221 gen_obj(env
, obj_size
, 512 * 1024, 4 * 1024 * 1024, &manifest
, env
.zonegroup
.default_placement
, &bucket
, &head
, &gen
, &objs
);
223 cout
<< " manifest.get_obj_size()=" << manifest
.get_obj_size() << std::endl
;
224 cout
<< " manifest.get_head_size()=" << manifest
.get_head_size() << std::endl
;
225 list
<rgw_obj
>::iterator liter
;
227 RGWObjManifest::obj_iterator iter
;
228 for (iter
= manifest
.obj_begin(&dp
), liter
= objs
.begin();
229 iter
!= manifest
.obj_end(&dp
) && liter
!= objs
.end();
231 ASSERT_TRUE(env
.get_raw(*liter
) == env
.get_raw(iter
.get_location()));
234 ASSERT_TRUE(iter
== manifest
.obj_end(&dp
));
235 ASSERT_TRUE(liter
== objs
.end());
237 rgw_raw_obj raw_head
;
239 iter
= manifest
.obj_find(&dp
, 100 * 1024);
240 ASSERT_TRUE(env
.get_raw(iter
.get_location()) == env
.get_raw(head
));
241 ASSERT_EQ((int)iter
.get_stripe_size(), obj_size
);
244 TEST(TestRGWManifest
, obj_with_head_and_tail
) {
246 RGWObjManifest manifest
;
249 RGWObjManifest::generator gen
;
253 int obj_size
= 21 * 1024 * 1024 + 1000;
254 int stripe_size
= 4 * 1024 * 1024;
255 int head_size
= 512 * 1024;
257 gen_obj(env
, obj_size
, head_size
, stripe_size
, &manifest
, env
.zonegroup
.default_placement
, &bucket
, &head
, &gen
, &objs
);
259 list
<rgw_obj
>::iterator liter
;
261 rgw_obj_select last_obj
;
263 RGWObjManifest::obj_iterator iter
;
264 for (iter
= manifest
.obj_begin(&dp
), liter
= objs
.begin();
265 iter
!= manifest
.obj_end(&dp
) && liter
!= objs
.end();
267 cout
<< "*liter=" << *liter
<< " iter.get_location()=" << env
.get_raw(iter
.get_location()) << std::endl
;
268 ASSERT_TRUE(env
.get_raw(*liter
) == env
.get_raw(iter
.get_location()));
270 last_obj
= iter
.get_location();
273 ASSERT_TRUE(iter
== manifest
.obj_end(&dp
));
274 ASSERT_TRUE(liter
== objs
.end());
276 iter
= manifest
.obj_find(&dp
, 100 * 1024);
277 ASSERT_TRUE(env
.get_raw(iter
.get_location()) == env
.get_raw(head
));
278 ASSERT_EQ((int)iter
.get_stripe_size(), head_size
);
280 uint64_t ofs
= 20 * 1024 * 1024 + head_size
;
281 iter
= manifest
.obj_find(&dp
, ofs
+ 100);
283 ASSERT_TRUE(env
.get_raw(iter
.get_location()) == env
.get_raw(last_obj
));
284 ASSERT_EQ(iter
.get_stripe_ofs(), ofs
);
285 ASSERT_EQ(iter
.get_stripe_size(), obj_size
- ofs
);
288 TEST(TestRGWManifest
, multipart
) {
291 vector
<RGWObjManifest
> pm(num_parts
);
293 uint64_t part_size
= 10 * 1024 * 1024;
294 uint64_t stripe_size
= 4 * 1024 * 1024;
296 string upload_id
= "abc123";
298 for (int i
= 0; i
< num_parts
; ++i
) {
299 RGWObjManifest
& manifest
= pm
[i
];
300 RGWObjManifest::generator gen
;
301 manifest
.set_prefix(upload_id
);
303 manifest
.set_multipart_part_rule(stripe_size
, i
+ 1);
307 for (ofs
= 0; ofs
< part_size
; ofs
+= stripe_size
) {
309 rgw_placement_rule
rule(env
.zonegroup
.default_placement
.name
, RGW_STORAGE_CLASS_STANDARD
);
310 int r
= gen
.create_begin(g_ceph_context
, &manifest
, rule
, nullptr, bucket
, head
);
314 gen
.create_next(ofs
);
317 if (ofs
> part_size
) {
318 gen
.create_next(part_size
);
324 for (int i
= 0; i
< num_parts
; i
++) {
325 m
.append(&dp
, pm
[i
], env
.zonegroup
, env
.zone_params
);
327 RGWObjManifest::obj_iterator iter
;
328 for (iter
= m
.obj_begin(&dp
); iter
!= m
.obj_end(&dp
); ++iter
) {
329 RGWObjManifest::obj_iterator fiter
= m
.obj_find(&dp
, iter
.get_ofs());
330 ASSERT_TRUE(env
.get_raw(fiter
.get_location()) == env
.get_raw(iter
.get_location()));
333 ASSERT_EQ(m
.get_obj_size(), num_parts
* part_size
);
336 TEST(TestRGWManifest
, old_obj_manifest
) {
338 OldObjManifest old_manifest
;
339 old_rgw_bucket old_bucket
;
340 old_rgw_obj old_head
;
342 int obj_size
= 40 * 1024 * 1024;
343 uint64_t stripe_size
= 4 * 1024 * 1024;
344 uint64_t head_size
= 512 * 1024;
346 list
<old_rgw_obj
> old_objs
;
348 gen_old_obj(env
, obj_size
, head_size
, stripe_size
, &old_manifest
, &old_bucket
, &old_head
, &old_objs
);
350 ASSERT_EQ(old_objs
.size(), 11u);
354 encode(old_manifest
, bl
);
356 RGWObjManifest manifest
;
359 auto iter
= bl
.cbegin();
360 decode(manifest
, iter
);
361 } catch (buffer::error
& err
) {
365 rgw_raw_obj last_obj
;
367 RGWObjManifest::obj_iterator iter
;
368 auto liter
= old_objs
.begin();
369 for (iter
= manifest
.obj_begin(&dp
);
370 iter
!= manifest
.obj_end(&dp
) && liter
!= old_objs
.end();
372 rgw_pool
old_pool(liter
->bucket
.data_pool
);
374 prepend_old_bucket_marker(old_bucket
, liter
->get_object(), old_oid
);
375 rgw_raw_obj
raw_old(old_pool
, old_oid
);
376 cout
<< "*liter=" << raw_old
<< " iter.get_location()=" << env
.get_raw(iter
.get_location()) << std::endl
;
377 ASSERT_EQ(raw_old
, env
.get_raw(iter
.get_location()));
379 last_obj
= env
.get_raw(iter
.get_location());
382 ASSERT_TRUE(liter
== old_objs
.end());
383 ASSERT_TRUE(iter
== manifest
.obj_end(&dp
));
388 int main(int argc
, char **argv
) {
389 auto args
= argv_to_vec(argc
, argv
);
390 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
391 CODE_ENVIRONMENT_UTILITY
,
392 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
393 common_init_finish(g_ceph_context
);
394 ::testing::InitGoogleTest(&argc
, argv
);
395 return RUN_ALL_TESTS();