]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/librgw_file_marker.cc
2475423fd468322b68a0b95eee0dcc340f255c59
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.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
40 librgw_t rgw_h
= nullptr;
41 string
userid("testuser");
42 string
access_key("");
43 string
secret_key("");
44 struct rgw_fs
*fs
= nullptr;
45 CephContext
* cct
= nullptr;
47 uint32_t owner_uid
= 867;
48 uint32_t owner_gid
= 5309;
50 uint32_t create_mask
= RGW_SETATTR_UID
| RGW_SETATTR_GID
| RGW_SETATTR_MODE
;
52 string
bucket_name("dmarker");
58 struct rgw_file_handle
* fh
;
59 struct rgw_file_handle
* parent_fh
;
60 RGWFileHandle
* rgw_fh
; // alias into fh
64 state() : readdir(false) {}
67 obj_rec(string _name
, struct rgw_file_handle
* _fh
,
68 struct rgw_file_handle
* _parent_fh
, RGWFileHandle
* _rgw_fh
)
69 : name(std::move(_name
)), fh(_fh
), parent_fh(_parent_fh
),
79 rgw_fh
= get_rgwfh(fh
);
82 friend ostream
& operator<<(ostream
& os
, const obj_rec
& rec
);
86 ostream& operator<<(ostream& os, const obj_rec& rec)
88 RGWFileHandle* rgw_fh = rec.rgw_fh;
90 const char* type = rgw_fh->is_dir() ? "DIR " : "FILE ";
91 os << rec.rgw_fh->full_object_name()
92 << " (" << rec.rgw_fh->object_name() << "): "
99 std::stack
<obj_rec
> obj_stack
;
100 std::deque
<obj_rec
> cleanup_queue
;
102 typedef std::vector
<obj_rec
> obj_vec
;
103 typedef std::tuple
<obj_rec
, obj_vec
> dirs1_rec
;
104 typedef std::vector
<dirs1_rec
> dirs1_vec
;
111 const struct stat
& st
;
113 obj_rec_st(const obj_rec
& _obj
, const struct stat
& _st
)
114 : obj(_obj
), st(_st
) {}
118 ostream& operator<<(ostream& os, const obj_rec_st& rec)
120 RGWFileHandle* rgw_fh = rec.obj.rgw_fh;
122 const char* type = rgw_fh->is_dir() ? "DIR " : "FILE ";
123 os << rgw_fh->full_object_name()
124 << " (" << rgw_fh->object_name() << "): "
126 const struct stat& st = rec.st;
127 switch(uint8_t(rgw_fh->is_dir())) {
129 os << " mode: " << st.st_mode;
130 os << " nlinks: " << st.st_nlink;
134 os << " mode: " << st.st_mode;
135 os << " size: " << st.st_size;
144 bool do_marker1
= false;
145 bool do_marker2
= true;
146 bool do_create
= false;
147 bool do_delete
= false;
148 bool verbose
= false;
150 string
marker_dir("nfs_marker");
151 struct rgw_file_handle
*bucket_fh
= nullptr;
152 struct rgw_file_handle
*marker_fh
;
153 uint32_t marker_nobjs
= 2*1024;
154 std::deque
<obj_rec
> marker_objs
;
156 using dirent_t
= std::tuple
<std::string
, uint64_t>;
159 std::vector
<dirent_t
> obj_names
;
161 dirent_vec() : count(0) {}
171 typedef boost::variant
<uint64_t*, const char*> readdir_offset
;
174 std::string s1
{"blunderbuss"};
176 readdir_offset v1
{&i1
};
177 readdir_offset v2
{s1
.c_str()};
178 readdir_offset v3
{static_cast<const char*>(nullptr)};
180 uint64_t* pi1
= get
<uint64_t*>(v1
);
181 ASSERT_NE(pi1
, nullptr);
182 std::cout
<< "read i1: " << *pi1
<< std::endl
;
184 const char* ps1
= get
<const char*>(v2
);
185 ASSERT_NE(ps1
, nullptr);
186 std::cout
<< "read s1: " << ps1
<< std::endl
;
188 const char* ps3
= get
<const char*>(v3
);
189 ASSERT_EQ(ps3
, nullptr);
190 std::cout
<< "read s3: " << ps3
<< std::endl
;
194 int ret
= librgw_create(&rgw_h
, saved_args
.argc
, saved_args
.argv
);
196 ASSERT_NE(rgw_h
, nullptr);
199 TEST(LibRGW
, MOUNT
) {
200 int ret
= rgw_mount2(rgw_h
, userid
.c_str(), access_key
.c_str(),
201 secret_key
.c_str(), "/", &fs
, RGW_MOUNT_FLAG_NONE
);
203 ASSERT_NE(fs
, nullptr);
205 cct
= static_cast<RGWLibFS
*>(fs
->fs_private
)->get_context();
208 TEST(LibRGW
, MARKER1_SETUP_BUCKET
) {
209 /* "large" directory enumeration test. this one deals only with
214 st
.st_uid
= owner_uid
;
215 st
.st_gid
= owner_gid
;
218 (void) rgw_lookup(fs
, fs
->root_fh
, bucket_name
.c_str(), &bucket_fh
,
219 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
224 st
.st_uid
= owner_uid
;
225 st
.st_gid
= owner_gid
;
228 ret
= rgw_mkdir(fs
, fs
->root_fh
, bucket_name
.c_str(), &st
, create_mask
,
229 &bucket_fh
, RGW_MKDIR_FLAG_NONE
);
234 ASSERT_NE(bucket_fh
, nullptr);
236 (void) rgw_lookup(fs
, bucket_fh
, marker_dir
.c_str(), &marker_fh
,
237 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
240 ret
= rgw_mkdir(fs
, bucket_fh
, marker_dir
.c_str(), &st
, create_mask
,
241 &marker_fh
, RGW_MKDIR_FLAG_NONE
);
246 ASSERT_NE(marker_fh
, nullptr);
249 TEST(LibRGW
, MARKER1_SETUP_OBJECTS
)
251 /* "large" directory enumeration test. this one deals only with
257 for (uint32_t ix
= 0; ix
< marker_nobjs
; ++ix
) {
258 std::string
object_name("f_");
259 object_name
+= to_string(ix
);
260 obj_rec obj
{object_name
, nullptr, marker_fh
, nullptr};
261 // lookup object--all operations are by handle
262 ret
= rgw_lookup(fs
, marker_fh
, obj
.name
.c_str(), &obj
.fh
,
263 nullptr, 0, RGW_LOOKUP_FLAG_CREATE
);
265 obj
.rgw_fh
= get_rgwfh(obj
.fh
);
266 // open object--open transaction
267 ret
= rgw_open(fs
, obj
.fh
, 0 /* posix flags */, RGW_OPEN_FLAG_NONE
);
269 ASSERT_TRUE(obj
.rgw_fh
->is_open());
270 // unstable write data
272 string
data("data for ");
274 int ret
= rgw_write(fs
, obj
.fh
, 0, data
.length(), &nbytes
,
275 (void*) data
.c_str(), RGW_WRITE_FLAG_NONE
);
277 ASSERT_EQ(nbytes
, data
.length());
278 // commit transaction (write on close)
279 ret
= rgw_close(fs
, obj
.fh
, 0 /* flags */);
282 /* XXX std:cout fragged...did it get /0 in the stream
284 printf("created: %s:%s\n", bucket_name
.c_str(), obj
.name
.c_str());
287 marker_objs
.push_back(obj
);
293 static bool r2_cb(const char* name
, void *arg
, uint64_t offset
,
294 struct stat
* st
, uint32_t st_mask
,
297 *(static_cast<dirent_vec
*>(arg
));
299 printf("%s bucket=%s dir=%s iv count=%d called back name=%s flags=%d\n",
307 string name_str
{name
};
308 if (! ((name_str
== ".") ||
309 (name_str
== ".."))) {
310 dvec
.obj_names
.push_back(dirent_t
{std::move(name_str
), offset
});
312 return true; /* XXX */
316 TEST(LibRGW
, MARKER1_READDIR
)
325 /* because RGWReaddirRequest::default_max is 1000 (XXX make
326 * configurable?) and marker_nobjs is 5*1024, the number
327 * of required rgw_readdir operations N should be
328 * marker_nobjs/1000 < N < marker_nobjs/1000+1, i.e., 6 when
329 * marker_nobjs==5*1024 */
330 uint32_t max_iterations
= marker_nobjs
/1000+1;
333 ASSERT_TRUE(dvec
.count
<= max_iterations
);
334 int ret
= rgw_readdir(fs
, marker_fh
, &offset
, r2_cb
, &dvec
, &eof
,
335 RGW_READDIR_FLAG_DOTDOT
);
337 ASSERT_GE(dvec
.obj_names
.size(), 0);
338 ASSERT_EQ(offset
, get
<1>(dvec
.obj_names
.back())); // cookie check
341 std::cout
<< "Read " << dvec
.obj_names
.size() << " objects in "
342 << marker_dir
.c_str() << std::endl
;
346 TEST(LibRGW
, MARKER2_READDIR
)
352 std::string marker
{""};
355 /* because RGWReaddirRequest::default_max is 1000 (XXX make
356 * configurable?) and marker_nobjs is 5*1024, the number
357 * of required rgw_readdir operations N should be
358 * marker_nobjs/1000 < N < marker_nobjs/1000+1, i.e., 6 when
359 * marker_nobjs==5*1024 */
360 uint32_t max_iterations
= marker_nobjs
/1000+1;
363 ASSERT_TRUE(dvec
.count
<= max_iterations
);
364 int ret
= rgw_readdir2(fs
, marker_fh
,
365 (marker
.length() > 0) ? marker
.c_str() : nullptr,
367 RGW_READDIR_FLAG_NONE
);
369 ASSERT_GE(dvec
.obj_names
.size(), 0);
370 marker
= get
<0>(dvec
.obj_names
.back());
372 } while((!eof
) && dvec
.count
< 4);
373 std::cout
<< "Read " << dvec
.obj_names
.size() << " objects in "
374 << marker_dir
.c_str() << std::endl
;
378 TEST(LibRGW
, MARKER1_OBJ_CLEANUP
)
381 for (auto& obj
: marker_objs
) {
385 std::cout
<< "unlinking: " << bucket_name
<< ":" << obj
.name
388 rc
= rgw_unlink(fs
, marker_fh
, obj
.name
.c_str(), RGW_UNLINK_FLAG_NONE
);
390 rc
= rgw_fh_rele(fs
, obj
.fh
, 0 /* flags */);
397 TEST(LibRGW
, CLEANUP
) {
401 cleanup_queue
.push_back(
402 obj_rec
{bucket_name
, bucket_fh
, fs
->root_fh
, get_rgwfh(fs
->root_fh
)});
405 for (auto& elt
: cleanup_queue
) {
407 rc
= rgw_fh_rele(fs
, elt
.fh
, 0 /* flags */);
411 cleanup_queue
.clear();
414 TEST(LibRGW
, UMOUNT
) {
418 int ret
= rgw_umount(fs
, RGW_UMOUNT_FLAG_NONE
);
422 TEST(LibRGW
, SHUTDOWN
) {
423 librgw_shutdown(rgw_h
);
426 int main(int argc
, char *argv
[])
430 vector
<const char*> args
;
432 argv_to_vec(argc
, const_cast<const char**>(argv
), args
);
435 v
= getenv("AWS_ACCESS_KEY_ID");
440 v
= getenv("AWS_SECRET_ACCESS_KEY");
445 for (auto arg_iter
= args
.begin(); arg_iter
!= args
.end();) {
446 if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--access",
449 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--secret",
452 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--userid",
455 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--bn",
458 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--uid",
460 owner_uid
= std::stoi(val
);
461 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--gid",
463 owner_gid
= std::stoi(val
);
464 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--nobjs",
466 marker_nobjs
= std::stoi(val
);
467 } else if (ceph_argparse_flag(args
, arg_iter
, "--marker1",
470 } else if (ceph_argparse_flag(args
, arg_iter
, "--create",
473 } else if (ceph_argparse_flag(args
, arg_iter
, "--delete",
476 } else if (ceph_argparse_flag(args
, arg_iter
, "--verbose",
484 /* don't accidentally run as anonymous */
485 if ((access_key
== "") ||
486 (secret_key
== "")) {
487 std::cout
<< argv
[0] << " no AWS credentials, exiting" << std::endl
;
491 saved_args
.argc
= argc
;
492 saved_args
.argv
= argv
;
494 ::testing::InitGoogleTest(&argc
, argv
);
495 return RUN_ALL_TESTS();