From 2a7aceddda7f8e304816780cd04ca7f5e98b0c4c Mon Sep 17 00:00:00 2001 From: Adam Kupczyk Date: Wed, 23 Oct 2024 11:57:01 +0000 Subject: [PATCH] os/bluestore: Add unittest for BlueFS::truncate() Add unittest for some truncate scenarios. Fixes: https://tracker.ceph.com/issues/68385 (addendum) Signed-off-by: Adam Kupczyk (cherry picked from commit 612f24b41fb44e478d6c1cc867dfa0720197793f) --- src/test/objectstore/test_bluefs.cc | 210 +++++++++------------------- 1 file changed, 65 insertions(+), 145 deletions(-) diff --git a/src/test/objectstore/test_bluefs.cc b/src/test/objectstore/test_bluefs.cc index 6d3ff1218a4..9c9921d02e3 100644 --- a/src/test/objectstore/test_bluefs.cc +++ b/src/test/objectstore/test_bluefs.cc @@ -1401,161 +1401,81 @@ TEST(BlueFS, test_concurrent_dir_link_and_compact_log_56210) { } } -TEST(BlueFS, test_log_runway) { - uint64_t max_log_runway = 65536; - ConfSaver conf(g_ceph_context->_conf); - conf.SetVal("bluefs_compact_log_sync", "false"); - conf.SetVal("bluefs_min_log_runway", "32768"); - conf.SetVal("bluefs_max_log_runway", std::to_string(max_log_runway).c_str()); - conf.ApplyChanges(); - - uint64_t size = 1048576 * 128; - TempBdev bdev{size}; - BlueFS fs(g_ceph_context); - ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev.path, false, 1048576)); +TEST(BlueFS, truncate_drops_allocations) { + constexpr uint64_t K = 1024; + constexpr uint64_t M = 1024 * K; uuid_d fsid; - ASSERT_EQ(0, fs.mkfs(fsid, { BlueFS::BDEV_DB, false, false })); - ASSERT_EQ(0, fs.mount()); - ASSERT_EQ(0, fs.maybe_verify_layout({ BlueFS::BDEV_DB, false, false })); - // longer transaction than current runway - std::string longdir(max_log_runway, 'a'); - fs.mkdir(longdir); - { - BlueFS::FileWriter *h; - ASSERT_EQ(0, fs.mkdir("dir")); - ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false)); - h->append("foo", 3); - h->append("bar", 3); - h->append("baz", 3); - fs.fsync(h); - fs.close_writer(h); - } - fs.umount(true); - fs.mount(); + const char* DIR_NAME="dir"; + const char* FILE_NAME="file1"; + struct { + uint64_t preallocated_size; + uint64_t write_size; + uint64_t truncate_to; + uint64_t allocated_after_truncate; + uint64_t slow_size = 0; + uint64_t slow_alloc_size = 64*K; + uint64_t db_size = 128*M; + uint64_t db_alloc_size = 1*M; + } scenarios [] = { + // on DB(which is SLOW) : 1 => 1, 64K remains + { 1*M, 1, 1, 64*K }, + // on DB(which is SLOW), alloc 4K : 1 => 1, 4K remains + { 1*M, 1, 1, 4*K, 0, 4*K }, + // on DB(which is SLOW), truncation on AU boundary : 128K => 128K, 128K remains + { 1*M, 128*K, 128*K, 128*K }, + // on DB(which is SLOW), no prealloc, truncation to 0 : 1666K => 0, 0 remains + { 0, 1666*K, 0, 0 }, + // on DB, truncate to 123K, expect 1M occupied + { 1234*K, 123*K, 123*K, 1*M, 128*M, 64*K, 10*M, 1*M }, + // on DB, truncate to 0, expect 0 occupied + { 1234*K, 345*K, 0, 0, 128*M, 64*K, 10*M, 1*M }, + // on DB, truncate to AU boundary, expect exactly 1M occupied + { 1234*K, 1123*K, 1*M, 1*M, 128*M, 64*K, 10*M, 1*M }, + // on DB and SLOW, truncate only data on SLOW + { 0, 10*M+1, 10*M+1, 10*M+64*K, 128*M, 64*K, 10*M, 1*M }, + // on DB and SLOW, preallocate and truncate only data on SLOW + { 6*M, 12*M, 10*M+1, 10*M+64*K, 128*M, 64*K, 10*M, 1*M }, + // on DB and SLOW, preallocate and truncate all in SLOW and some on DB + // note! prealloc 6M is important, one allocation for 12M will fallback to SLOW + // in 6M + 6M we can be sure that 6M is on DB and 6M is on SLOW + { 6*M, 12*M, 3*M+1, 4*M, 128*M, 64*K, 11*M, 1*M }, + }; + for (auto& s : scenarios) { + ConfSaver conf(g_ceph_context->_conf); + conf.SetVal("bluefs_shared_alloc_size", stringify(s.slow_alloc_size).c_str()); + conf.SetVal("bluefs_alloc_size", stringify(s.db_alloc_size).c_str()); - std::vector ls; - fs.readdir("dir", &ls); - ASSERT_EQ(ls.front(), "file"); - uint64_t file_size = 0; - utime_t mtime; - fs.stat("dir", "file", &file_size, &mtime); - ASSERT_EQ(file_size, 9); -} + g_ceph_context->_conf.set_val("bluefs_shared_alloc_size", stringify(s.slow_alloc_size)); + g_ceph_context->_conf.set_val("bluefs_alloc_size", stringify(s.db_alloc_size)); + TempBdev bdev_db{s.db_size}; + TempBdev bdev_slow{s.slow_size}; -TEST(BlueFS, test_log_runway_2) { - uint64_t max_log_runway = 65536; - ConfSaver conf(g_ceph_context->_conf); - conf.SetVal("bluefs_compact_log_sync", "false"); - conf.SetVal("bluefs_min_log_runway", "32768"); - conf.SetVal("bluefs_max_log_runway", std::to_string(max_log_runway).c_str()); - conf.ApplyChanges(); + BlueFS fs(g_ceph_context); + if (s.db_size != 0) { + ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev_db.path, false, 0)); + } + if (s.slow_size != 0) { + ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_SLOW, bdev_slow.path, false, 0)); + } - uint64_t size = 1048576 * 128; - TempBdev bdev{size}; - BlueFS fs(g_ceph_context); - ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev.path, false, 1048576)); - uuid_d fsid; - ASSERT_EQ(0, fs.mkfs(fsid, { BlueFS::BDEV_DB, false, false })); - ASSERT_EQ(0, fs.mount()); - ASSERT_EQ(0, fs.maybe_verify_layout({ BlueFS::BDEV_DB, false, false })); - // longer transaction than current runway - size_t name_length = max_log_runway * 2; - std::string longdir(name_length, 'a'); - std::string longfile(name_length, 'b'); - { - BlueFS::FileWriter *h; - ASSERT_EQ(0, fs.mkdir(longdir)); - ASSERT_EQ(0, fs.open_for_write(longdir, longfile, &h, false)); - h->append("canary", 6); - fs.fsync(h); - fs.close_writer(h); - fs.sync_metadata(true); - } - { + ASSERT_EQ(0, fs.mkfs(fsid, {BlueFS::BDEV_DB, false, false})); + ASSERT_EQ(0, fs.mount()); + ASSERT_EQ(0, fs.maybe_verify_layout({BlueFS::BDEV_DB, false, false})); BlueFS::FileWriter *h; ASSERT_EQ(0, fs.mkdir("dir")); - ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false)); - h->append("foo", 3); - h->append("bar", 3); - h->append("baz", 3); + ASSERT_EQ(0, fs.open_for_write(DIR_NAME, FILE_NAME, &h, false)); + uint64_t pre = fs.get_used(); + ASSERT_EQ(0, fs.preallocate(h->file, 0, s.preallocated_size)); + const std::string content(s.write_size, 'x'); + h->append(content.c_str(), content.length()); fs.fsync(h); - fs.close_writer(h); - } - fs.umount(true); - fs.mount(); - - std::vector ls; - fs.readdir("dir", &ls); - ASSERT_EQ(ls.front(), "file"); - uint64_t file_size = 0; - utime_t mtime; - fs.stat("dir", "file", &file_size, &mtime); - ASSERT_EQ(file_size, 9); - fs.stat(longdir, longfile, &file_size, &mtime); - ASSERT_EQ(file_size, 6); - - std::vector ls_longdir; - fs.readdir(longdir, &ls_longdir); - ASSERT_EQ(ls_longdir.front(), longfile); -} - -TEST(BlueFS, test_log_runway_3) { - uint64_t max_log_runway = 65536; - ConfSaver conf(g_ceph_context->_conf); - conf.SetVal("bluefs_alloc_size", "4096"); - conf.SetVal("bluefs_shared_alloc_size", "4096"); - conf.SetVal("bluefs_compact_log_sync", "false"); - conf.SetVal("bluefs_min_log_runway", "32768"); - conf.SetVal("bluefs_max_log_runway", std::to_string(max_log_runway).c_str()); - conf.ApplyChanges(); - - uint64_t size = 1048576 * 128; - TempBdev bdev{size}; - BlueFS fs(g_ceph_context); - ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev.path, false, 1048576)); - uuid_d fsid; - ASSERT_EQ(0, fs.mkfs(fsid, { BlueFS::BDEV_DB, false, false })); - ASSERT_EQ(0, fs.mount()); - ASSERT_EQ(0, fs.maybe_verify_layout({ BlueFS::BDEV_DB, false, false })); - // longer transaction than current runway - for (size_t m = 0; m < 40; m++) { - std::string longdir(max_log_runway + m, 'A' + m); - std::string longfile(max_log_runway + m, 'A' + m); - BlueFS::FileWriter *h; - ASSERT_EQ(0, fs.mkdir(longdir)); - ASSERT_EQ(0, fs.open_for_write(longdir, longfile, &h, false)); - h->append("canary", 6); - fs.fsync(h); - fs.close_writer(h); - fs.sync_metadata(true); - } - { - BlueFS::FileWriter *h; - ASSERT_EQ(0, fs.mkdir("dir")); - ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false)); - h->append("foo", 3); - h->append("bar", 3); - h->append("baz", 3); + ASSERT_EQ(0, fs.truncate(h, s.truncate_to)); fs.fsync(h); + uint64_t post = fs.get_used(); fs.close_writer(h); - } - fs.umount(true); - fs.mount(); + EXPECT_EQ(pre, post - s.allocated_after_truncate); - std::vector ls; - fs.readdir("dir", &ls); - ASSERT_EQ(ls.front(), "file"); - uint64_t file_size = 0; - utime_t mtime; - fs.stat("dir", "file", &file_size, &mtime); - ASSERT_EQ(file_size, 9); - for (size_t m = 0; m < 40; m++) { - uint64_t file_size = 0; - utime_t mtime; - std::string longdir(max_log_runway + m, 'A' + m); - std::string longfile(max_log_runway + m, 'A' + m); - fs.stat(longdir, longfile, &file_size, &mtime); - ASSERT_EQ(file_size, 6); + fs.umount(); } } -- 2.39.5