Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / objectstore / test_bluefs.cc
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
19 string 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
32 char* 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
41 void rm_temp_bdev(string f)
42 {
43   ::unlink(f.c_str());
44 }
45
46 TEST(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
57 TEST(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
72 TEST(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
104 TEST(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);
128       ASSERT_EQ(0, fs.fsync(h));
129     }
130     fs.close_writer(h);
131   }
132   fs.umount();
133   rm_temp_bdev(fn);
134 }
135
136 #define ALLOC_SIZE 4096
137
138 void 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
174 void 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
191 void 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
220 bool writes_done = false;
221
222 void 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
233 void do_join(std::thread& t)
234 {
235     t.join();
236 }
237
238 void 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
249 TEST(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
284 TEST(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
312 TEST(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
347 TEST(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
400 TEST(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
453 TEST(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
491 TEST(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
529 TEST(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?
565   ASSERT_EQ(0, fs.mount());
566   fs.umount();
567   rm_temp_bdev(fn);
568 }
569
570 int 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 }