]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/objectstore/test_bluefs.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / objectstore / test_bluefs.cc
CommitLineData
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#include <stdio.h>
5#include <string.h>
6#include <iostream>
7#include <time.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <thread>
11#include "global/global_init.h"
12#include "common/ceph_argparse.h"
13#include "include/stringify.h"
14#include "common/errno.h"
15#include <gtest/gtest.h>
16
17#include "os/bluestore/BlueFS.h"
18
19string get_temp_bdev(uint64_t size)
20{
21 static int n = 0;
22 string fn = "ceph_test_bluefs.tmp.block." + stringify(getpid())
23 + "." + stringify(++n);
24 int fd = ::open(fn.c_str(), O_CREAT|O_RDWR|O_TRUNC, 0644);
25 assert(fd >= 0);
26 int r = ::ftruncate(fd, size);
27 assert(r >= 0);
28 ::close(fd);
29 return fn;
30}
31
32char* gen_buffer(uint64_t size)
33{
34 char *buffer = new char[size];
35 boost::random::random_device rand;
36 rand.generate(buffer, buffer + size);
37 return buffer;
38}
39
40
41void rm_temp_bdev(string f)
42{
43 ::unlink(f.c_str());
44}
45
46TEST(BlueFS, mkfs) {
47 uint64_t size = 1048576 * 128;
48 string fn = get_temp_bdev(size);
49 uuid_d fsid;
50 BlueFS fs(g_ceph_context);
51 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
52 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
53 ASSERT_EQ(0, fs.mkfs(fsid));
54 rm_temp_bdev(fn);
55}
56
57TEST(BlueFS, mkfs_mount) {
58 uint64_t size = 1048576 * 128;
59 string fn = get_temp_bdev(size);
60 BlueFS fs(g_ceph_context);
61 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
62 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
63 uuid_d fsid;
64 ASSERT_EQ(0, fs.mkfs(fsid));
65 ASSERT_EQ(0, fs.mount());
66 ASSERT_EQ(fs.get_total(BlueFS::BDEV_DB), size - 1048576);
67 ASSERT_LT(fs.get_free(BlueFS::BDEV_DB), size - 1048576);
68 fs.umount();
69 rm_temp_bdev(fn);
70}
71
72TEST(BlueFS, write_read) {
73 uint64_t size = 1048576 * 128;
74 string fn = get_temp_bdev(size);
75 BlueFS fs(g_ceph_context);
76 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
77 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
78 uuid_d fsid;
79 ASSERT_EQ(0, fs.mkfs(fsid));
80 ASSERT_EQ(0, fs.mount());
81 {
82 BlueFS::FileWriter *h;
83 ASSERT_EQ(0, fs.mkdir("dir"));
84 ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false));
85 h->append("foo", 3);
86 h->append("bar", 3);
87 h->append("baz", 3);
88 fs.fsync(h);
89 fs.close_writer(h);
90 }
91 {
92 BlueFS::FileReader *h;
93 ASSERT_EQ(0, fs.open_for_read("dir", "file", &h));
94 bufferlist bl;
95 BlueFS::FileReaderBuffer buf(4096);
96 ASSERT_EQ(9, fs.read(h, &buf, 0, 1024, &bl, NULL));
97 ASSERT_EQ(0, strncmp("foobarbaz", bl.c_str(), 9));
98 delete h;
99 }
100 fs.umount();
101 rm_temp_bdev(fn);
102}
103
104TEST(BlueFS, small_appends) {
105 uint64_t size = 1048576 * 128;
106 string fn = get_temp_bdev(size);
107 BlueFS fs(g_ceph_context);
108 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
109 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
110 uuid_d fsid;
111 ASSERT_EQ(0, fs.mkfs(fsid));
112 ASSERT_EQ(0, fs.mount());
113 {
114 BlueFS::FileWriter *h;
115 ASSERT_EQ(0, fs.mkdir("dir"));
116 ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false));
117 for (unsigned i = 0; i < 10000; ++i) {
118 h->append("abcdeabcdeabcdeabcdeabcdeabc", 23);
119 }
120 fs.fsync(h);
121 fs.close_writer(h);
122 }
123 {
124 BlueFS::FileWriter *h;
125 ASSERT_EQ(0, fs.open_for_write("dir", "file_sync", &h, false));
126 for (unsigned i = 0; i < 1000; ++i) {
127 h->append("abcdeabcdeabcdeabcdeabcdeabc", 23);
31f18b77 128 ASSERT_EQ(0, fs.fsync(h));
7c673cae
FG
129 }
130 fs.close_writer(h);
131 }
132 fs.umount();
133 rm_temp_bdev(fn);
134}
135
136#define ALLOC_SIZE 4096
137
138void write_data(BlueFS &fs, uint64_t rationed_bytes)
139{
140 BlueFS::FileWriter *h;
141 int j=0, r=0;
142 uint64_t written_bytes = 0;
143 rationed_bytes -= ALLOC_SIZE;
144 stringstream ss;
145 string dir = "dir.";
146 ss << std::this_thread::get_id();
147 dir.append(ss.str());
148 dir.append(".");
149 dir.append(to_string(j));
150 ASSERT_EQ(0, fs.mkdir(dir));
151 while (1) {
152 string file = "file.";
153 file.append(to_string(j));
154 ASSERT_EQ(0, fs.open_for_write(dir, file, &h, false));
155 bufferlist bl;
156 char *buf = gen_buffer(ALLOC_SIZE);
157 bufferptr bp = buffer::claim_char(ALLOC_SIZE, buf);
158 bl.push_back(bp);
159 h->append(bl.c_str(), bl.length());
160 r = fs.fsync(h);
161 if (r < 0) {
162 fs.close_writer(h);
163 break;
164 }
165 written_bytes += g_conf->bluefs_alloc_size;
166 fs.close_writer(h);
167 j++;
168 if ((rationed_bytes - written_bytes) <= g_conf->bluefs_alloc_size) {
169 break;
170 }
171 }
172}
173
174void create_single_file(BlueFS &fs)
175{
176 BlueFS::FileWriter *h;
177 stringstream ss;
178 string dir = "dir.test";
179 ASSERT_EQ(0, fs.mkdir(dir));
180 string file = "testfile";
181 ASSERT_EQ(0, fs.open_for_write(dir, file, &h, false));
182 bufferlist bl;
183 char *buf = gen_buffer(ALLOC_SIZE);
184 bufferptr bp = buffer::claim_char(ALLOC_SIZE, buf);
185 bl.push_back(bp);
186 h->append(bl.c_str(), bl.length());
187 fs.fsync(h);
188 fs.close_writer(h);
189}
190
191void write_single_file(BlueFS &fs, uint64_t rationed_bytes)
192{
193 BlueFS::FileWriter *h;
194 stringstream ss;
195 string dir = "dir.test";
196 string file = "testfile";
197 int r=0;
198 uint64_t written_bytes = 0;
199 rationed_bytes -= ALLOC_SIZE;
200 while (1) {
201 ASSERT_EQ(0, fs.open_for_write(dir, file, &h, false));
202 bufferlist bl;
203 char *buf = gen_buffer(ALLOC_SIZE);
204 bufferptr bp = buffer::claim_char(ALLOC_SIZE, buf);
205 bl.push_back(bp);
206 h->append(bl.c_str(), bl.length());
207 r = fs.fsync(h);
208 if (r < 0) {
209 fs.close_writer(h);
210 break;
211 }
212 written_bytes += g_conf->bluefs_alloc_size;
213 fs.close_writer(h);
214 if ((rationed_bytes - written_bytes) <= g_conf->bluefs_alloc_size) {
215 break;
216 }
217 }
218}
219
220bool writes_done = false;
221
222void sync_fs(BlueFS &fs)
223{
224 while (1) {
225 if (writes_done == true)
226 break;
227 fs.sync_metadata();
228 sleep(1);
229 }
230}
231
232
233void do_join(std::thread& t)
234{
235 t.join();
236}
237
238void join_all(std::vector<std::thread>& v)
239{
240 std::for_each(v.begin(),v.end(),do_join);
241}
242
243#define NUM_WRITERS 3
244#define NUM_SYNC_THREADS 1
245
246#define NUM_SINGLE_FILE_WRITERS 1
247#define NUM_MULTIPLE_FILE_WRITERS 2
248
249TEST(BlueFS, test_flush_1) {
250 uint64_t size = 1048576 * 128;
251 string fn = get_temp_bdev(size);
252 g_ceph_context->_conf->set_val(
253 "bluefs_alloc_size",
254 "65536");
255 g_ceph_context->_conf->apply_changes(NULL);
256
257 BlueFS fs(g_ceph_context);
258 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
259 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
260 uuid_d fsid;
261 ASSERT_EQ(0, fs.mkfs(fsid));
262 ASSERT_EQ(0, fs.mount());
263 {
264 std::vector<std::thread> write_thread_multiple;
265 uint64_t effective_size = size - (32 * 1048576); // leaving the last 32 MB for log compaction
266 uint64_t per_thread_bytes = (effective_size/(NUM_MULTIPLE_FILE_WRITERS + NUM_SINGLE_FILE_WRITERS));
267 for (int i=0; i<NUM_MULTIPLE_FILE_WRITERS ; i++) {
268 write_thread_multiple.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
269 }
270
271 create_single_file(fs);
272 std::vector<std::thread> write_thread_single;
273 for (int i=0; i<NUM_SINGLE_FILE_WRITERS; i++) {
274 write_thread_single.push_back(std::thread(write_single_file, std::ref(fs), per_thread_bytes));
275 }
276
277 join_all(write_thread_single);
278 join_all(write_thread_multiple);
279 }
280 fs.umount();
281 rm_temp_bdev(fn);
282}
283
284TEST(BlueFS, test_flush_2) {
285 uint64_t size = 1048576 * 256;
286 string fn = get_temp_bdev(size);
287 g_ceph_context->_conf->set_val(
288 "bluefs_alloc_size",
289 "65536");
290 g_ceph_context->_conf->apply_changes(NULL);
291
292 BlueFS fs(g_ceph_context);
293 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
294 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
295 uuid_d fsid;
296 ASSERT_EQ(0, fs.mkfs(fsid));
297 ASSERT_EQ(0, fs.mount());
298 {
299 uint64_t effective_size = size - (128 * 1048576); // leaving the last 32 MB for log compaction
300 uint64_t per_thread_bytes = (effective_size/(NUM_WRITERS));
301 std::vector<std::thread> write_thread_multiple;
302 for (int i=0; i<NUM_WRITERS; i++) {
303 write_thread_multiple.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
304 }
305
306 join_all(write_thread_multiple);
307 }
308 fs.umount();
309 rm_temp_bdev(fn);
310}
311
312TEST(BlueFS, test_flush_3) {
313 uint64_t size = 1048576 * 256;
314 string fn = get_temp_bdev(size);
315 g_ceph_context->_conf->set_val(
316 "bluefs_alloc_size",
317 "65536");
318 g_ceph_context->_conf->apply_changes(NULL);
319
320 BlueFS fs(g_ceph_context);
321 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
322 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
323 uuid_d fsid;
324 ASSERT_EQ(0, fs.mkfs(fsid));
325 ASSERT_EQ(0, fs.mount());
326 {
327 std::vector<std::thread> write_threads;
328 uint64_t effective_size = size - (64 * 1048576); // leaving the last 11 MB for log compaction
329 uint64_t per_thread_bytes = (effective_size/(NUM_WRITERS));
330 for (int i=0; i<NUM_WRITERS; i++) {
331 write_threads.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
332 }
333
334 std::vector<std::thread> sync_threads;
335 for (int i=0; i<NUM_SYNC_THREADS; i++) {
336 sync_threads.push_back(std::thread(sync_fs, std::ref(fs)));
337 }
338
339 join_all(write_threads);
340 writes_done = true;
341 join_all(sync_threads);
342 }
343 fs.umount();
344 rm_temp_bdev(fn);
345}
346
347TEST(BlueFS, test_simple_compaction_sync) {
348 g_ceph_context->_conf->set_val(
349 "bluefs_compact_log_sync",
350 "true");
351 uint64_t size = 1048576 * 128;
352 string fn = get_temp_bdev(size);
353
354 BlueFS fs(g_ceph_context);
355 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
356 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
357 uuid_d fsid;
358 ASSERT_EQ(0, fs.mkfs(fsid));
359 ASSERT_EQ(0, fs.mount());
360 {
361 BlueFS::FileWriter *h;
362 for (int i=0; i<10; i++) {
363 string dir = "dir.";
364 dir.append(to_string(i));
365 ASSERT_EQ(0, fs.mkdir(dir));
366 for (int j=0; j<10; j++) {
367 string file = "file.";
368 file.append(to_string(j));
369 ASSERT_EQ(0, fs.open_for_write(dir, file, &h, false));
370 bufferlist bl;
371 char *buf = gen_buffer(4096);
372 bufferptr bp = buffer::claim_char(4096, buf);
373 bl.push_back(bp);
374 h->append(bl.c_str(), bl.length());
375 fs.fsync(h);
376 fs.close_writer(h);
377 }
378 }
379 }
380 // Don't remove all
381 {
382 for (int i=0; i<10; i+=2) {
383 string dir = "dir.";
384 dir.append(to_string(i));
385 for (int j=0; j<10; j+=2) {
386 string file = "file.";
387 file.append(to_string(j));
388 fs.unlink(dir, file);
389 fs.flush_log();
390 }
391 fs.rmdir(dir);
392 fs.flush_log();
393 }
394 }
395 fs.compact_log();
396 fs.umount();
397 rm_temp_bdev(fn);
398}
399
400TEST(BlueFS, test_simple_compaction_async) {
401 g_ceph_context->_conf->set_val(
402 "bluefs_compact_log_sync",
403 "false");
404 uint64_t size = 1048576 * 128;
405 string fn = get_temp_bdev(size);
406
407 BlueFS fs(g_ceph_context);
408 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
409 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
410 uuid_d fsid;
411 ASSERT_EQ(0, fs.mkfs(fsid));
412 ASSERT_EQ(0, fs.mount());
413 {
414 BlueFS::FileWriter *h;
415 for (int i=0; i<10; i++) {
416 string dir = "dir.";
417 dir.append(to_string(i));
418 ASSERT_EQ(0, fs.mkdir(dir));
419 for (int j=0; j<10; j++) {
420 string file = "file.";
421 file.append(to_string(j));
422 ASSERT_EQ(0, fs.open_for_write(dir, file, &h, false));
423 bufferlist bl;
424 char *buf = gen_buffer(4096);
425 bufferptr bp = buffer::claim_char(4096, buf);
426 bl.push_back(bp);
427 h->append(bl.c_str(), bl.length());
428 fs.fsync(h);
429 fs.close_writer(h);
430 }
431 }
432 }
433 // Don't remove all
434 {
435 for (int i=0; i<10; i+=2) {
436 string dir = "dir.";
437 dir.append(to_string(i));
438 for (int j=0; j<10; j+=2) {
439 string file = "file.";
440 file.append(to_string(j));
441 fs.unlink(dir, file);
442 fs.flush_log();
443 }
444 fs.rmdir(dir);
445 fs.flush_log();
446 }
447 }
448 fs.compact_log();
449 fs.umount();
450 rm_temp_bdev(fn);
451}
452
453TEST(BlueFS, test_compaction_sync) {
454 uint64_t size = 1048576 * 128;
455 string fn = get_temp_bdev(size);
456 g_ceph_context->_conf->set_val(
457 "bluefs_alloc_size",
458 "65536");
459 g_ceph_context->_conf->set_val(
460 "bluefs_compact_log_sync",
461 "true");
462
463 BlueFS fs(g_ceph_context);
464 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
465 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
466 uuid_d fsid;
467 ASSERT_EQ(0, fs.mkfs(fsid));
468 ASSERT_EQ(0, fs.mount());
469 {
470 std::vector<std::thread> write_threads;
471 uint64_t effective_size = size - (32 * 1048576); // leaving the last 32 MB for log compaction
472 uint64_t per_thread_bytes = (effective_size/(NUM_WRITERS));
473 for (int i=0; i<NUM_WRITERS; i++) {
474 write_threads.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
475 }
476
477 std::vector<std::thread> sync_threads;
478 for (int i=0; i<NUM_SYNC_THREADS; i++) {
479 sync_threads.push_back(std::thread(sync_fs, std::ref(fs)));
480 }
481
482 join_all(write_threads);
483 writes_done = true;
484 join_all(sync_threads);
485 fs.compact_log();
486 }
487 fs.umount();
488 rm_temp_bdev(fn);
489}
490
491TEST(BlueFS, test_compaction_async) {
492 uint64_t size = 1048576 * 128;
493 string fn = get_temp_bdev(size);
494 g_ceph_context->_conf->set_val(
495 "bluefs_alloc_size",
496 "65536");
497 g_ceph_context->_conf->set_val(
498 "bluefs_compact_log_sync",
499 "false");
500
501 BlueFS fs(g_ceph_context);
502 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
503 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
504 uuid_d fsid;
505 ASSERT_EQ(0, fs.mkfs(fsid));
506 ASSERT_EQ(0, fs.mount());
507 {
508 std::vector<std::thread> write_threads;
509 uint64_t effective_size = size - (32 * 1048576); // leaving the last 32 MB for log compaction
510 uint64_t per_thread_bytes = (effective_size/(NUM_WRITERS));
511 for (int i=0; i<NUM_WRITERS; i++) {
512 write_threads.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
513 }
514
515 std::vector<std::thread> sync_threads;
516 for (int i=0; i<NUM_SYNC_THREADS; i++) {
517 sync_threads.push_back(std::thread(sync_fs, std::ref(fs)));
518 }
519
520 join_all(write_threads);
521 writes_done = true;
522 join_all(sync_threads);
523 fs.compact_log();
524 }
525 fs.umount();
526 rm_temp_bdev(fn);
527}
528
529TEST(BlueFS, test_replay) {
530 uint64_t size = 1048576 * 128;
531 string fn = get_temp_bdev(size);
532 g_ceph_context->_conf->set_val(
533 "bluefs_alloc_size",
534 "65536");
535 g_ceph_context->_conf->set_val(
536 "bluefs_compact_log_sync",
537 "false");
538
539 BlueFS fs(g_ceph_context);
540 ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, fn));
541 fs.add_block_extent(BlueFS::BDEV_DB, 1048576, size - 1048576);
542 uuid_d fsid;
543 ASSERT_EQ(0, fs.mkfs(fsid));
544 ASSERT_EQ(0, fs.mount());
545 {
546 std::vector<std::thread> write_threads;
547 uint64_t effective_size = size - (32 * 1048576); // leaving the last 32 MB for log compaction
548 uint64_t per_thread_bytes = (effective_size/(NUM_WRITERS));
549 for (int i=0; i<NUM_WRITERS; i++) {
550 write_threads.push_back(std::thread(write_data, std::ref(fs), per_thread_bytes));
551 }
552
553 std::vector<std::thread> sync_threads;
554 for (int i=0; i<NUM_SYNC_THREADS; i++) {
555 sync_threads.push_back(std::thread(sync_fs, std::ref(fs)));
556 }
557
558 join_all(write_threads);
559 writes_done = true;
560 join_all(sync_threads);
561 fs.compact_log();
562 }
563 fs.umount();
564 // remount and check log can replay safe?
31f18b77 565 ASSERT_EQ(0, fs.mount());
7c673cae
FG
566 fs.umount();
567 rm_temp_bdev(fn);
568}
569
570int main(int argc, char **argv) {
571 vector<const char*> args;
572 argv_to_vec(argc, (const char **)argv, args);
573 env_to_vec(args);
574
575 vector<const char *> def_args;
576 def_args.push_back("--debug-bluefs=1/20");
577 def_args.push_back("--debug-bdev=1/20");
578
579 auto cct = global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT,
580 CODE_ENVIRONMENT_UTILITY,
581 0);
582 common_init_finish(g_ceph_context);
583 g_ceph_context->_conf->set_val(
584 "enable_experimental_unrecoverable_data_corrupting_features",
585 "*");
586 g_ceph_context->_conf->apply_changes(NULL);
587
588 ::testing::InitGoogleTest(&argc, argv);
589 return RUN_ALL_TESTS();
590}