1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
13 #include "global/global_init.h"
14 #include "common/ceph_argparse.h"
15 #include "include/stringify.h"
16 #include "include/scope_guard.h"
17 #include "common/errno.h"
18 #include <gtest/gtest.h>
20 #include "os/bluestore/BlueFS.h"
22 std::unique_ptr
<char[]> gen_buffer(uint64_t size
)
24 std::unique_ptr
<char[]> buffer
= std::make_unique
<char[]>(size
);
25 std::independent_bits_engine
<std::default_random_engine
, CHAR_BIT
, unsigned char> e
;
26 std::generate(buffer
.get(), buffer
.get()+size
, std::ref(e
));
32 TempBdev(uint64_t size
)
33 : path
{get_temp_bdev(size
)}
38 const std::string path
;
40 static string
get_temp_bdev(uint64_t size
)
43 string fn
= "ceph_test_bluefs.tmp.block." + stringify(getpid())
44 + "." + stringify(++n
);
45 int fd
= ::open(fn
.c_str(), O_CREAT
|O_RDWR
|O_TRUNC
, 0644);
47 int r
= ::ftruncate(fd
, size
);
52 static void rm_temp_bdev(string f
)
59 std::stack
<std::pair
<std::string
, std::string
>> saved_settings
;
62 ConfSaver(ConfigProxy
& conf
) : conf(conf
) {
63 conf
._clear_safe_to_start_threads();
66 conf
._clear_safe_to_start_threads();
67 while(saved_settings
.size() > 0) {
68 auto& e
= saved_settings
.top();
69 conf
.set_val_or_die(e
.first
, e
.second
);
72 conf
.set_safe_to_start_threads();
73 conf
.apply_changes(nullptr);
75 void SetVal(const char* key
, const char* val
) {
76 std::string
skey(key
);
78 conf
.get_val(skey
, &prev_val
);
79 conf
.set_val_or_die(skey
, val
);
80 saved_settings
.emplace(skey
, prev_val
);
83 conf
.set_safe_to_start_threads();
84 conf
.apply_changes(nullptr);
89 uint64_t size
= 1048576 * 128;
92 BlueFS
fs(g_ceph_context
);
93 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
94 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
95 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
98 TEST(BlueFS
, mkfs_mount
) {
99 uint64_t size
= 1048576 * 128;
101 BlueFS
fs(g_ceph_context
);
102 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
103 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
105 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
106 ASSERT_EQ(0, fs
.mount());
107 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
108 ASSERT_EQ(fs
.get_total(BlueFS::BDEV_DB
), size
- 1048576);
109 ASSERT_LT(fs
.get_free(BlueFS::BDEV_DB
), size
- 1048576);
113 TEST(BlueFS
, mkfs_mount_duplicate_gift
) {
114 uint64_t size
= 1048576 * 128;
115 TempBdev bdev
{ size
};
116 bluefs_extent_t dup_ext
;
118 BlueFS
fs(g_ceph_context
);
119 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
120 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
122 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
123 ASSERT_EQ(0, fs
.mount());
126 BlueFS::FileWriter
*h
;
127 ASSERT_EQ(0, fs
.mkdir("dir"));
128 ASSERT_EQ(0, fs
.open_for_write("dir", "file1", &h
, false));
133 ceph_assert(h
->file
->fnode
.extents
.size() > 0);
134 dup_ext
= h
->file
->fnode
.extents
[0];
135 ceph_assert(dup_ext
.bdev
== BlueFS::BDEV_DB
);
143 BlueFS
fs(g_ceph_context
);
144 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
145 ASSERT_EQ(0, fs
.mount());
146 // free allocation presumably allocated for file1
147 std::cout
<< "duplicate extent: " << std::hex
148 << dup_ext
.offset
<< "~" << dup_ext
.length
149 << std::dec
<< std::endl
;
150 fs
.debug_inject_duplicate_gift(BlueFS::BDEV_DB
, dup_ext
.offset
, dup_ext
.length
);
152 // overwrite file1 with file2
153 BlueFS::FileWriter
*h
;
154 ASSERT_EQ(0, fs
.open_for_write("dir", "file2", &h
, false));
164 g_ceph_context
->_conf
.set_val_or_die("bluefs_log_replay_check_allocations", "true");
165 g_ceph_context
->_conf
.apply_changes(nullptr);
169 BlueFS
fs(g_ceph_context
);
170 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
171 ASSERT_NE(0, fs
.mount());
175 TEST(BlueFS
, write_read
) {
176 uint64_t size
= 1048576 * 128;
178 BlueFS
fs(g_ceph_context
);
179 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
180 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
182 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
183 ASSERT_EQ(0, fs
.mount());
184 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
186 BlueFS::FileWriter
*h
;
187 ASSERT_EQ(0, fs
.mkdir("dir"));
188 ASSERT_EQ(0, fs
.open_for_write("dir", "file", &h
, false));
196 BlueFS::FileReader
*h
;
197 ASSERT_EQ(0, fs
.open_for_read("dir", "file", &h
));
199 BlueFS::FileReaderBuffer
buf(4096);
200 ASSERT_EQ(9, fs
.read(h
, &buf
, 0, 1024, &bl
, NULL
));
201 ASSERT_EQ(0, strncmp("foobarbaz", bl
.c_str(), 9));
207 TEST(BlueFS
, small_appends
) {
208 uint64_t size
= 1048576 * 128;
210 BlueFS
fs(g_ceph_context
);
211 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
212 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
214 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
215 ASSERT_EQ(0, fs
.mount());
216 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
218 BlueFS::FileWriter
*h
;
219 ASSERT_EQ(0, fs
.mkdir("dir"));
220 ASSERT_EQ(0, fs
.open_for_write("dir", "file", &h
, false));
221 for (unsigned i
= 0; i
< 10000; ++i
) {
222 h
->append("abcdeabcdeabcdeabcdeabcdeabc", 23);
228 BlueFS::FileWriter
*h
;
229 ASSERT_EQ(0, fs
.open_for_write("dir", "file_sync", &h
, false));
230 for (unsigned i
= 0; i
< 1000; ++i
) {
231 h
->append("abcdeabcdeabcdeabcdeabcdeabc", 23);
232 ASSERT_EQ(0, fs
.fsync(h
));
239 TEST(BlueFS
, very_large_write
) {
240 // we'll write a ~5G file, so allocate more than that for the whole fs
241 uint64_t size
= 1048576 * 1024 * 6ull;
243 BlueFS
fs(g_ceph_context
);
245 bool old
= g_ceph_context
->_conf
.get_val
<bool>("bluefs_buffered_io");
246 g_ceph_context
->_conf
.set_val("bluefs_buffered_io", "false");
247 uint64_t total_written
= 0;
249 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
250 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
252 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
253 ASSERT_EQ(0, fs
.mount());
254 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
255 char buf
[1048571]; // this is biggish, but intentionally not evenly aligned
256 for (unsigned i
= 0; i
< sizeof(buf
); ++i
) {
260 BlueFS::FileWriter
*h
;
261 ASSERT_EQ(0, fs
.mkdir("dir"));
262 ASSERT_EQ(0, fs
.open_for_write("dir", "bigfile", &h
, false));
263 for (unsigned i
= 0; i
< 3*1024*1048576ull / sizeof(buf
); ++i
) {
264 h
->append(buf
, sizeof(buf
));
265 total_written
+= sizeof(buf
);
268 for (unsigned i
= 0; i
< 2*1024*1048576ull / sizeof(buf
); ++i
) {
269 h
->append(buf
, sizeof(buf
));
270 total_written
+= sizeof(buf
);
276 BlueFS::FileReader
*h
;
277 ASSERT_EQ(0, fs
.open_for_read("dir", "bigfile", &h
));
279 BlueFS::FileReaderBuffer
readbuf(10485760);
280 ASSERT_EQ(h
->file
->fnode
.size
, total_written
);
281 for (unsigned i
= 0; i
< 3*1024*1048576ull / sizeof(buf
); ++i
) {
283 fs
.read(h
, &readbuf
, i
* sizeof(buf
), sizeof(buf
), &bl
, NULL
);
284 int r
= memcmp(buf
, bl
.c_str(), sizeof(buf
));
286 cerr
<< "read got mismatch at offset " << i
*sizeof(buf
) << " r " << r
291 for (unsigned i
= 0; i
< 2*1024*1048576ull / sizeof(buf
); ++i
) {
293 fs
.read(h
, &readbuf
, i
* sizeof(buf
), sizeof(buf
), &bl
, NULL
);
294 int r
= memcmp(buf
, bl
.c_str(), sizeof(buf
));
296 cerr
<< "read got mismatch at offset " << i
*sizeof(buf
) << " r " << r
302 ASSERT_EQ(0, fs
.open_for_read("dir", "bigfile", &h
));
303 ASSERT_EQ(h
->file
->fnode
.size
, total_written
);
304 unique_ptr
<char> huge_buf(new char[h
->file
->fnode
.size
]);
305 auto l
= h
->file
->fnode
.size
;
306 int64_t r
= fs
.read(h
, &readbuf
, 0, l
, NULL
, huge_buf
.get());
307 ASSERT_EQ(r
, (int64_t)l
);
312 g_ceph_context
->_conf
.set_val("bluefs_buffered_io", stringify((int)old
));
315 TEST(BlueFS
, very_large_write2
) {
316 // we'll write a ~5G file, so allocate more than that for the whole fs
317 uint64_t size_full
= 1048576 * 1024 * 6ull;
318 uint64_t size
= 1048576 * 1024 * 5ull;
319 TempBdev bdev
{ size_full
};
320 BlueFS
fs(g_ceph_context
);
322 bool old
= g_ceph_context
->_conf
.get_val
<bool>("bluefs_buffered_io");
323 g_ceph_context
->_conf
.set_val("bluefs_buffered_io", "false");
324 uint64_t total_written
= 0;
326 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false, 1048576));
327 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size_full
- 1048576);
329 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
330 ASSERT_EQ(0, fs
.mount());
331 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
333 char fill_arr
[1 << 20]; // 1M
334 for (size_t i
= 0; i
< sizeof(fill_arr
); ++i
) {
335 fill_arr
[i
] = (char)i
;
337 std::unique_ptr
<char[]> buf
;
338 buf
.reset(new char[size
]);
339 for (size_t i
= 0; i
< size
; i
+= sizeof(fill_arr
)) {
340 memcpy(buf
.get() + i
, fill_arr
, sizeof(fill_arr
));
343 BlueFS::FileWriter
* h
;
344 ASSERT_EQ(0, fs
.mkdir("dir"));
345 ASSERT_EQ(0, fs
.open_for_write("dir", "bigfile", &h
, false));
346 fs
.append_try_flush(h
, buf
.get(), size
);
347 total_written
= size
;
351 memset(buf
.get(), 0, size
);
353 BlueFS::FileReader
* h
;
354 ASSERT_EQ(0, fs
.open_for_read("dir", "bigfile", &h
));
355 ASSERT_EQ(h
->file
->fnode
.size
, total_written
);
356 auto l
= h
->file
->fnode
.size
;
357 BlueFS::FileReaderBuffer
readbuf(10485760);
358 int64_t r
= fs
.read(h
, &readbuf
, 0, l
, NULL
, buf
.get());
359 ASSERT_EQ(r
, (int64_t)l
);
360 for (size_t i
= 0; i
< size
; i
+= sizeof(fill_arr
)) {
361 ceph_assert(memcmp(buf
.get() + i
, fill_arr
, sizeof(fill_arr
)) == 0);
367 g_ceph_context
->_conf
.set_val("bluefs_buffered_io", stringify((int)old
));
370 #define ALLOC_SIZE 4096
372 void write_data(BlueFS
&fs
, uint64_t rationed_bytes
)
375 uint64_t written_bytes
= 0;
376 rationed_bytes
-= ALLOC_SIZE
;
379 ss
<< std::this_thread::get_id();
380 dir
.append(ss
.str());
382 dir
.append(to_string(j
));
383 ASSERT_EQ(0, fs
.mkdir(dir
));
385 string file
= "file.";
386 file
.append(to_string(j
));
387 BlueFS::FileWriter
*h
;
388 ASSERT_EQ(0, fs
.open_for_write(dir
, file
, &h
, false));
389 ASSERT_NE(nullptr, h
);
390 auto sg
= make_scope_guard([&fs
, h
] { fs
.close_writer(h
); });
392 std::unique_ptr
<char[]> buf
= gen_buffer(ALLOC_SIZE
);
393 bufferptr bp
= buffer::claim_char(ALLOC_SIZE
, buf
.get());
395 h
->append(bl
.c_str(), bl
.length());
400 written_bytes
+= g_conf()->bluefs_alloc_size
;
402 if ((rationed_bytes
- written_bytes
) <= g_conf()->bluefs_alloc_size
) {
408 void create_single_file(BlueFS
&fs
)
410 BlueFS::FileWriter
*h
;
412 string dir
= "dir.test";
413 ASSERT_EQ(0, fs
.mkdir(dir
));
414 string file
= "testfile";
415 ASSERT_EQ(0, fs
.open_for_write(dir
, file
, &h
, false));
417 std::unique_ptr
<char[]> buf
= gen_buffer(ALLOC_SIZE
);
418 bufferptr bp
= buffer::claim_char(ALLOC_SIZE
, buf
.get());
420 h
->append(bl
.c_str(), bl
.length());
425 void write_single_file(BlueFS
&fs
, uint64_t rationed_bytes
)
428 const string dir
= "dir.test";
429 const string file
= "testfile";
430 uint64_t written_bytes
= 0;
431 rationed_bytes
-= ALLOC_SIZE
;
433 BlueFS::FileWriter
*h
;
434 ASSERT_EQ(0, fs
.open_for_write(dir
, file
, &h
, false));
435 ASSERT_NE(nullptr, h
);
436 auto sg
= make_scope_guard([&fs
, h
] { fs
.close_writer(h
); });
438 std::unique_ptr
<char[]> buf
= gen_buffer(ALLOC_SIZE
);
439 bufferptr bp
= buffer::claim_char(ALLOC_SIZE
, buf
.get());
441 h
->append(bl
.c_str(), bl
.length());
446 written_bytes
+= g_conf()->bluefs_alloc_size
;
447 if ((rationed_bytes
- written_bytes
) <= g_conf()->bluefs_alloc_size
) {
453 bool writes_done
= false;
455 void sync_fs(BlueFS
&fs
)
458 if (writes_done
== true)
460 fs
.sync_metadata(false);
466 void do_join(std::thread
& t
)
471 void join_all(std::vector
<std::thread
>& v
)
473 std::for_each(v
.begin(),v
.end(),do_join
);
476 #define NUM_WRITERS 3
477 #define NUM_SYNC_THREADS 1
479 #define NUM_SINGLE_FILE_WRITERS 1
480 #define NUM_MULTIPLE_FILE_WRITERS 2
482 TEST(BlueFS
, test_flush_1
) {
483 uint64_t size
= 1048576 * 128;
485 g_ceph_context
->_conf
.set_val(
488 g_ceph_context
->_conf
.apply_changes(nullptr);
490 BlueFS
fs(g_ceph_context
);
491 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
492 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
494 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
495 ASSERT_EQ(0, fs
.mount());
496 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
498 std::vector
<std::thread
> write_thread_multiple
;
499 uint64_t effective_size
= size
- (32 * 1048576); // leaving the last 32 MB for log compaction
500 uint64_t per_thread_bytes
= (effective_size
/(NUM_MULTIPLE_FILE_WRITERS
+ NUM_SINGLE_FILE_WRITERS
));
501 for (int i
=0; i
<NUM_MULTIPLE_FILE_WRITERS
; i
++) {
502 write_thread_multiple
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
505 create_single_file(fs
);
506 std::vector
<std::thread
> write_thread_single
;
507 for (int i
=0; i
<NUM_SINGLE_FILE_WRITERS
; i
++) {
508 write_thread_single
.push_back(std::thread(write_single_file
, std::ref(fs
), per_thread_bytes
));
511 join_all(write_thread_single
);
512 join_all(write_thread_multiple
);
517 TEST(BlueFS
, test_flush_2
) {
518 uint64_t size
= 1048576 * 256;
520 g_ceph_context
->_conf
.set_val(
523 g_ceph_context
->_conf
.apply_changes(nullptr);
525 BlueFS
fs(g_ceph_context
);
526 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
527 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
529 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
530 ASSERT_EQ(0, fs
.mount());
531 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
533 uint64_t effective_size
= size
- (128 * 1048576); // leaving the last 32 MB for log compaction
534 uint64_t per_thread_bytes
= (effective_size
/(NUM_WRITERS
));
535 std::vector
<std::thread
> write_thread_multiple
;
536 for (int i
=0; i
<NUM_WRITERS
; i
++) {
537 write_thread_multiple
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
540 join_all(write_thread_multiple
);
545 TEST(BlueFS
, test_flush_3
) {
546 uint64_t size
= 1048576 * 256;
548 g_ceph_context
->_conf
.set_val(
551 g_ceph_context
->_conf
.apply_changes(nullptr);
553 BlueFS
fs(g_ceph_context
);
554 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
555 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
557 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
558 ASSERT_EQ(0, fs
.mount());
559 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
561 std::vector
<std::thread
> write_threads
;
562 uint64_t effective_size
= size
- (64 * 1048576); // leaving the last 11 MB for log compaction
563 uint64_t per_thread_bytes
= (effective_size
/(NUM_WRITERS
));
564 for (int i
=0; i
<NUM_WRITERS
; i
++) {
565 write_threads
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
568 std::vector
<std::thread
> sync_threads
;
569 for (int i
=0; i
<NUM_SYNC_THREADS
; i
++) {
570 sync_threads
.push_back(std::thread(sync_fs
, std::ref(fs
)));
573 join_all(write_threads
);
575 join_all(sync_threads
);
580 TEST(BlueFS
, test_simple_compaction_sync
) {
581 g_ceph_context
->_conf
.set_val(
582 "bluefs_compact_log_sync",
584 uint64_t size
= 1048576 * 128;
587 BlueFS
fs(g_ceph_context
);
588 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
589 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
591 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
592 ASSERT_EQ(0, fs
.mount());
593 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
595 for (int i
=0; i
<10; i
++) {
597 dir
.append(to_string(i
));
598 ASSERT_EQ(0, fs
.mkdir(dir
));
599 for (int j
=0; j
<10; j
++) {
600 string file
= "file.";
601 file
.append(to_string(j
));
602 BlueFS::FileWriter
*h
;
603 ASSERT_EQ(0, fs
.open_for_write(dir
, file
, &h
, false));
604 ASSERT_NE(nullptr, h
);
605 auto sg
= make_scope_guard([&fs
, h
] { fs
.close_writer(h
); });
607 std::unique_ptr
<char[]> buf
= gen_buffer(4096);
608 bufferptr bp
= buffer::claim_char(4096, buf
.get());
610 h
->append(bl
.c_str(), bl
.length());
616 for (int i
=0; i
<10; i
+=2) {
618 dir
.append(to_string(i
));
619 for (int j
=0; j
<10; j
++) {
620 string file
= "file.";
621 file
.append(to_string(j
));
622 fs
.unlink(dir
, file
);
623 fs
.sync_metadata(false);
625 ASSERT_EQ(0, fs
.rmdir(dir
));
626 fs
.sync_metadata(false);
633 TEST(BlueFS
, test_simple_compaction_async
) {
634 g_ceph_context
->_conf
.set_val(
635 "bluefs_compact_log_sync",
637 uint64_t size
= 1048576 * 128;
640 BlueFS
fs(g_ceph_context
);
641 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
642 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
644 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
645 ASSERT_EQ(0, fs
.mount());
646 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
648 for (int i
=0; i
<10; i
++) {
650 dir
.append(to_string(i
));
651 ASSERT_EQ(0, fs
.mkdir(dir
));
652 for (int j
=0; j
<10; j
++) {
653 string file
= "file.";
654 file
.append(to_string(j
));
655 BlueFS::FileWriter
*h
;
656 ASSERT_EQ(0, fs
.open_for_write(dir
, file
, &h
, false));
657 ASSERT_NE(nullptr, h
);
658 auto sg
= make_scope_guard([&fs
, h
] { fs
.close_writer(h
); });
660 std::unique_ptr
<char[]> buf
= gen_buffer(4096);
661 bufferptr bp
= buffer::claim_char(4096, buf
.get());
663 h
->append(bl
.c_str(), bl
.length());
669 for (int i
=0; i
<10; i
+=2) {
671 dir
.append(to_string(i
));
672 for (int j
=0; j
<10; j
++) {
673 string file
= "file.";
674 file
.append(to_string(j
));
675 fs
.unlink(dir
, file
);
676 fs
.sync_metadata(false);
678 ASSERT_EQ(0, fs
.rmdir(dir
));
679 fs
.sync_metadata(false);
686 TEST(BlueFS
, test_compaction_sync
) {
687 uint64_t size
= 1048576 * 128;
689 g_ceph_context
->_conf
.set_val(
692 g_ceph_context
->_conf
.set_val(
693 "bluefs_compact_log_sync",
696 BlueFS
fs(g_ceph_context
);
697 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
698 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
700 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
701 ASSERT_EQ(0, fs
.mount());
702 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
704 std::vector
<std::thread
> write_threads
;
705 uint64_t effective_size
= size
- (32 * 1048576); // leaving the last 32 MB for log compaction
706 uint64_t per_thread_bytes
= (effective_size
/(NUM_WRITERS
));
707 for (int i
=0; i
<NUM_WRITERS
; i
++) {
708 write_threads
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
711 std::vector
<std::thread
> sync_threads
;
712 for (int i
=0; i
<NUM_SYNC_THREADS
; i
++) {
713 sync_threads
.push_back(std::thread(sync_fs
, std::ref(fs
)));
716 join_all(write_threads
);
718 join_all(sync_threads
);
724 TEST(BlueFS
, test_compaction_async
) {
725 uint64_t size
= 1048576 * 128;
727 g_ceph_context
->_conf
.set_val(
730 g_ceph_context
->_conf
.set_val(
731 "bluefs_compact_log_sync",
734 BlueFS
fs(g_ceph_context
);
735 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
736 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
738 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
739 ASSERT_EQ(0, fs
.mount());
740 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
742 std::vector
<std::thread
> write_threads
;
743 uint64_t effective_size
= size
- (32 * 1048576); // leaving the last 32 MB for log compaction
744 uint64_t per_thread_bytes
= (effective_size
/(NUM_WRITERS
));
745 for (int i
=0; i
<NUM_WRITERS
; i
++) {
746 write_threads
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
749 std::vector
<std::thread
> sync_threads
;
750 for (int i
=0; i
<NUM_SYNC_THREADS
; i
++) {
751 sync_threads
.push_back(std::thread(sync_fs
, std::ref(fs
)));
754 join_all(write_threads
);
756 join_all(sync_threads
);
762 TEST(BlueFS
, test_replay
) {
763 uint64_t size
= 1048576 * 128;
765 g_ceph_context
->_conf
.set_val(
768 g_ceph_context
->_conf
.set_val(
769 "bluefs_compact_log_sync",
772 BlueFS
fs(g_ceph_context
);
773 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
774 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
776 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
777 ASSERT_EQ(0, fs
.mount());
778 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
780 std::vector
<std::thread
> write_threads
;
781 uint64_t effective_size
= size
- (32 * 1048576); // leaving the last 32 MB for log compaction
782 uint64_t per_thread_bytes
= (effective_size
/(NUM_WRITERS
));
783 for (int i
=0; i
<NUM_WRITERS
; i
++) {
784 write_threads
.push_back(std::thread(write_data
, std::ref(fs
), per_thread_bytes
));
787 std::vector
<std::thread
> sync_threads
;
788 for (int i
=0; i
<NUM_SYNC_THREADS
; i
++) {
789 sync_threads
.push_back(std::thread(sync_fs
, std::ref(fs
)));
792 join_all(write_threads
);
794 join_all(sync_threads
);
798 // remount and check log can replay safe?
799 ASSERT_EQ(0, fs
.mount());
800 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
804 TEST(BlueFS
, test_replay_growth
) {
805 uint64_t size
= 1048576LL * (2 * 1024 + 128);
808 ConfSaver
conf(g_ceph_context
->_conf
);
809 conf
.SetVal("bluefs_alloc_size", "4096");
810 conf
.SetVal("bluefs_shared_alloc_size", "4096");
811 conf
.SetVal("bluefs_compact_log_sync", "false");
812 conf
.SetVal("bluefs_min_log_runway", "32768");
813 conf
.SetVal("bluefs_max_log_runway", "65536");
814 conf
.SetVal("bluefs_allocator", "stupid");
815 conf
.SetVal("bluefs_sync_write", "true");
818 BlueFS
fs(g_ceph_context
);
819 ASSERT_EQ(0, fs
.add_block_device(BlueFS::BDEV_DB
, bdev
.path
, false));
820 fs
.add_block_extent(BlueFS::BDEV_DB
, 1048576, size
- 1048576);
822 ASSERT_EQ(0, fs
.mkfs(fsid
, { BlueFS::BDEV_DB
, false, false }));
823 ASSERT_EQ(0, fs
.mount());
824 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
825 ASSERT_EQ(0, fs
.mkdir("dir"));
828 BlueFS::FileWriter
*h
;
829 ASSERT_EQ(0, fs
.open_for_write("dir", "file", &h
, false));
830 for (size_t i
= 0; i
< 10000; i
++) {
831 h
->append(data
, 2000);
835 fs
.umount(true); //do not compact on exit!
837 // remount and check log can replay safe?
838 ASSERT_EQ(0, fs
.mount());
839 ASSERT_EQ(0, fs
.maybe_verify_layout({ BlueFS::BDEV_DB
, false, false }));
843 int main(int argc
, char **argv
) {
844 vector
<const char*> args
;
845 argv_to_vec(argc
, (const char **)argv
, args
);
847 map
<string
,string
> defaults
= {
848 { "debug_bluefs", "1/20" },
849 { "debug_bdev", "1/20" }
852 auto cct
= global_init(&defaults
, args
, CEPH_ENTITY_TYPE_CLIENT
,
853 CODE_ENVIRONMENT_UTILITY
,
854 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
855 common_init_finish(g_ceph_context
);
856 g_ceph_context
->_conf
.set_val(
857 "enable_experimental_unrecoverable_data_corrupting_features",
859 g_ceph_context
->_conf
.apply_changes(nullptr);
861 ::testing::InitGoogleTest(&argc
, argv
);
862 return RUN_ALL_TESTS();