]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/librgw_file_marker.cc
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) 2015 Red Hat, Inc.
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.
21 #include "include/rados/librgw.h"
22 #include "include/rados/rgw_file.h"
23 #include "rgw/rgw_file_int.h"
24 #include "rgw/rgw_lib_frontend.h" // direct requests
26 #include "gtest/gtest.h"
27 #include "common/ceph_argparse.h"
28 #include "common/debug.h"
29 #include "global/global_init.h"
30 #include "include/ceph_assert.h"
32 #define dout_subsys ceph_subsys_rgw
42 librgw_t rgw_h
= nullptr;
43 string
userid("testuser");
44 string
access_key("");
45 string
secret_key("");
46 struct rgw_fs
*fs
= nullptr;
47 CephContext
* cct
= nullptr;
49 uint32_t owner_uid
= 867;
50 uint32_t owner_gid
= 5309;
52 uint32_t create_mask
= RGW_SETATTR_UID
| RGW_SETATTR_GID
| RGW_SETATTR_MODE
;
54 string
bucket_name("dmarker");
60 struct rgw_file_handle
* fh
;
61 struct rgw_file_handle
* parent_fh
;
62 RGWFileHandle
* rgw_fh
; // alias into fh
66 state() : readdir(false) {}
69 obj_rec(string _name
, struct rgw_file_handle
* _fh
,
70 struct rgw_file_handle
* _parent_fh
, RGWFileHandle
* _rgw_fh
)
71 : name(std::move(_name
)), fh(_fh
), parent_fh(_parent_fh
),
81 rgw_fh
= get_rgwfh(fh
);
84 friend ostream
& operator<<(ostream
& os
, const obj_rec
& rec
);
88 ostream& operator<<(ostream& os, const obj_rec& rec)
90 RGWFileHandle* rgw_fh = rec.rgw_fh;
92 const char* type = rgw_fh->is_dir() ? "DIR " : "FILE ";
93 os << rec.rgw_fh->full_object_name()
94 << " (" << rec.rgw_fh->object_name() << "): "
101 std::stack
<obj_rec
> obj_stack
;
102 std::deque
<obj_rec
> cleanup_queue
;
104 typedef std::vector
<obj_rec
> obj_vec
;
105 typedef std::tuple
<obj_rec
, obj_vec
> dirs1_rec
;
106 typedef std::vector
<dirs1_rec
> dirs1_vec
;
113 const struct stat
& st
;
115 obj_rec_st(const obj_rec
& _obj
, const struct stat
& _st
)
116 : obj(_obj
), st(_st
) {}
120 ostream& operator<<(ostream& os, const obj_rec_st& rec)
122 RGWFileHandle* rgw_fh = rec.obj.rgw_fh;
124 const char* type = rgw_fh->is_dir() ? "DIR " : "FILE ";
125 os << rgw_fh->full_object_name()
126 << " (" << rgw_fh->object_name() << "): "
128 const struct stat& st = rec.st;
129 switch(uint8_t(rgw_fh->is_dir())) {
131 os << " mode: " << st.st_mode;
132 os << " nlinks: " << st.st_nlink;
136 os << " mode: " << st.st_mode;
137 os << " size: " << st.st_size;
146 bool do_marker1
= false;
147 bool do_marker2
= true;
148 bool do_create
= false;
149 bool do_delete
= false;
150 bool verbose
= false;
152 string
marker_dir("nfs_marker");
153 struct rgw_file_handle
*bucket_fh
= nullptr;
154 struct rgw_file_handle
*marker_fh
;
155 uint32_t marker_nobjs
= 2*1024;
156 std::deque
<obj_rec
> marker_objs
;
158 using dirent_t
= std::tuple
<std::string
, uint64_t>;
161 std::vector
<dirent_t
> obj_names
;
163 dirent_vec() : count(0) {}
173 typedef boost::variant
<uint64_t*, const char*> readdir_offset
;
176 std::string s1
{"blunderbuss"};
178 readdir_offset v1
{&i1
};
179 readdir_offset v2
{s1
.c_str()};
180 readdir_offset v3
{static_cast<const char*>(nullptr)};
182 uint64_t* pi1
= get
<uint64_t*>(v1
);
183 ASSERT_NE(pi1
, nullptr);
184 std::cout
<< "read i1: " << *pi1
<< std::endl
;
186 const char* ps1
= get
<const char*>(v2
);
187 ASSERT_NE(ps1
, nullptr);
188 std::cout
<< "read s1: " << ps1
<< std::endl
;
190 const char* ps3
= get
<const char*>(v3
);
191 ASSERT_EQ(ps3
, nullptr);
192 std::cout
<< "read s3: " << ps3
<< std::endl
;
196 int ret
= librgw_create(&rgw_h
, saved_args
.argc
, saved_args
.argv
);
198 ASSERT_NE(rgw_h
, nullptr);
201 TEST(LibRGW
, MOUNT
) {
202 int ret
= rgw_mount2(rgw_h
, userid
.c_str(), access_key
.c_str(),
203 secret_key
.c_str(), "/", &fs
, RGW_MOUNT_FLAG_NONE
);
205 ASSERT_NE(fs
, nullptr);
207 cct
= static_cast<RGWLibFS
*>(fs
->fs_private
)->get_context();
210 TEST(LibRGW
, MARKER1_SETUP_BUCKET
) {
211 /* "large" directory enumeration test. this one deals only with
216 st
.st_uid
= owner_uid
;
217 st
.st_gid
= owner_gid
;
220 (void) rgw_lookup(fs
, fs
->root_fh
, bucket_name
.c_str(), &bucket_fh
,
221 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
226 st
.st_uid
= owner_uid
;
227 st
.st_gid
= owner_gid
;
230 ret
= rgw_mkdir(fs
, fs
->root_fh
, bucket_name
.c_str(), &st
, create_mask
,
231 &bucket_fh
, RGW_MKDIR_FLAG_NONE
);
236 ASSERT_NE(bucket_fh
, nullptr);
238 (void) rgw_lookup(fs
, bucket_fh
, marker_dir
.c_str(), &marker_fh
,
239 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
242 ret
= rgw_mkdir(fs
, bucket_fh
, marker_dir
.c_str(), &st
, create_mask
,
243 &marker_fh
, RGW_MKDIR_FLAG_NONE
);
248 ASSERT_NE(marker_fh
, nullptr);
251 TEST(LibRGW
, MARKER1_SETUP_OBJECTS
)
253 /* "large" directory enumeration test. this one deals only with
259 for (uint32_t ix
= 0; ix
< marker_nobjs
; ++ix
) {
260 std::string
object_name("f_");
261 object_name
+= to_string(ix
);
262 obj_rec obj
{object_name
, nullptr, marker_fh
, nullptr};
263 // lookup object--all operations are by handle
264 ret
= rgw_lookup(fs
, marker_fh
, obj
.name
.c_str(), &obj
.fh
,
265 nullptr, 0, RGW_LOOKUP_FLAG_CREATE
);
267 obj
.rgw_fh
= get_rgwfh(obj
.fh
);
268 // open object--open transaction
269 ret
= rgw_open(fs
, obj
.fh
, 0 /* posix flags */, RGW_OPEN_FLAG_NONE
);
271 ASSERT_TRUE(obj
.rgw_fh
->is_open());
272 // unstable write data
274 string
data("data for ");
276 int ret
= rgw_write(fs
, obj
.fh
, 0, data
.length(), &nbytes
,
277 (void*) data
.c_str(), RGW_WRITE_FLAG_NONE
);
279 ASSERT_EQ(nbytes
, data
.length());
280 // commit transaction (write on close)
281 ret
= rgw_close(fs
, obj
.fh
, 0 /* flags */);
284 /* XXX std:cout fragged...did it get /0 in the stream
286 printf("created: %s:%s\n", bucket_name
.c_str(), obj
.name
.c_str());
289 marker_objs
.push_back(obj
);
295 static int r2_cb(const char* name
, void *arg
, uint64_t offset
,
296 struct stat
* st
, uint32_t st_mask
,
299 *(static_cast<dirent_vec
*>(arg
));
301 printf("%s bucket=%s dir=%s iv count=%d called back name=%s flags=%d\n",
309 string name_str
{name
};
310 if (! ((name_str
== ".") ||
311 (name_str
== ".."))) {
312 dvec
.obj_names
.push_back(dirent_t
{std::move(name_str
), offset
});
314 return true; /* XXX */
318 TEST(LibRGW
, MARKER1_READDIR
)
327 /* because RGWReaddirRequest::default_max is 1000 (XXX make
328 * configurable?) and marker_nobjs is 5*1024, the number
329 * of required rgw_readdir operations N should be
330 * marker_nobjs/1000 < N < marker_nobjs/1000+1, i.e., 6 when
331 * marker_nobjs==5*1024 */
332 uint32_t max_iterations
= marker_nobjs
/1000+1;
335 ASSERT_TRUE(dvec
.count
<= max_iterations
);
336 int ret
= rgw_readdir(fs
, marker_fh
, &offset
, r2_cb
, &dvec
, &eof
,
337 RGW_READDIR_FLAG_DOTDOT
);
339 ASSERT_GE(dvec
.obj_names
.size(), 0);
340 ASSERT_EQ(offset
, get
<1>(dvec
.obj_names
.back())); // cookie check
343 std::cout
<< "Read " << dvec
.obj_names
.size() << " objects in "
344 << marker_dir
.c_str() << std::endl
;
348 TEST(LibRGW
, MARKER2_READDIR
)
354 std::string marker
{""};
357 /* because RGWReaddirRequest::default_max is 1000 (XXX make
358 * configurable?) and marker_nobjs is 5*1024, the number
359 * of required rgw_readdir operations N should be
360 * marker_nobjs/1000 < N < marker_nobjs/1000+1, i.e., 6 when
361 * marker_nobjs==5*1024 */
362 uint32_t max_iterations
= marker_nobjs
/1000+1;
365 ASSERT_TRUE(dvec
.count
<= max_iterations
);
366 int ret
= rgw_readdir2(fs
, marker_fh
,
367 (marker
.length() > 0) ? marker
.c_str() : nullptr,
369 RGW_READDIR_FLAG_NONE
);
371 ASSERT_GE(dvec
.obj_names
.size(), 0);
372 marker
= get
<0>(dvec
.obj_names
.back());
374 } while((!eof
) && dvec
.count
< 4);
375 std::cout
<< "Read " << dvec
.obj_names
.size() << " objects in "
376 << marker_dir
.c_str() << std::endl
;
380 TEST(LibRGW
, MARKER1_OBJ_CLEANUP
)
383 for (auto& obj
: marker_objs
) {
387 std::cout
<< "unlinking: " << bucket_name
<< ":" << obj
.name
390 rc
= rgw_unlink(fs
, marker_fh
, obj
.name
.c_str(), RGW_UNLINK_FLAG_NONE
);
392 rc
= rgw_fh_rele(fs
, obj
.fh
, 0 /* flags */);
399 TEST(LibRGW
, CLEANUP
) {
403 cleanup_queue
.push_back(
404 obj_rec
{bucket_name
, bucket_fh
, fs
->root_fh
, get_rgwfh(fs
->root_fh
)});
407 for (auto& elt
: cleanup_queue
) {
409 rc
= rgw_fh_rele(fs
, elt
.fh
, 0 /* flags */);
413 cleanup_queue
.clear();
416 TEST(LibRGW
, UMOUNT
) {
420 int ret
= rgw_umount(fs
, RGW_UMOUNT_FLAG_NONE
);
424 TEST(LibRGW
, SHUTDOWN
) {
425 librgw_shutdown(rgw_h
);
428 int main(int argc
, char *argv
[])
430 auto args
= argv_to_vec(argc
, argv
);
433 char* v
= getenv("AWS_ACCESS_KEY_ID");
438 v
= getenv("AWS_SECRET_ACCESS_KEY");
444 for (auto arg_iter
= args
.begin(); arg_iter
!= args
.end();) {
445 if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--access",
448 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--secret",
451 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--userid",
454 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--bn",
457 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--uid",
459 owner_uid
= std::stoi(val
);
460 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--gid",
462 owner_gid
= std::stoi(val
);
463 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--nobjs",
465 marker_nobjs
= std::stoi(val
);
466 } else if (ceph_argparse_flag(args
, arg_iter
, "--marker1",
469 } else if (ceph_argparse_flag(args
, arg_iter
, "--create",
472 } else if (ceph_argparse_flag(args
, arg_iter
, "--delete",
475 } else if (ceph_argparse_flag(args
, arg_iter
, "--verbose",
483 /* don't accidentally run as anonymous */
484 if ((access_key
== "") ||
485 (secret_key
== "")) {
486 std::cout
<< argv
[0] << " no AWS credentials, exiting" << std::endl
;
490 saved_args
.argc
= argc
;
491 saved_args
.argv
= argv
;
493 ::testing::InitGoogleTest(&argc
, argv
);
494 return RUN_ALL_TESTS();