]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: Adds an option to limit max allocation size. Useful primarily for testing 9604/head
authorIgor Fedotov <ifedotov@mirantis.com>
Wed, 8 Jun 2016 13:38:41 +0000 (16:38 +0300)
committerIgor Fedotov <ifedotov@mirantis.com>
Fri, 10 Jun 2016 14:49:46 +0000 (17:49 +0300)
Signed-off-by: Igor Fedotov <ifedotov@mirantis.com>
src/common/config_opts.h
src/os/bluestore/BlueStore.cc
src/os/bluestore/BlueStore.h
src/test/objectstore/store_test.cc

index fe8353d84665060144288f04ef5f0c418e46ea97..194f92c0548cbad7b1a523f2ce36cbd95dbba8be 100644 (file)
@@ -957,6 +957,7 @@ OPTION(bluestore_max_csum_block, OPT_U32, 64*1024)
 OPTION(bluestore_min_alloc_size, OPT_U32, 0)
 OPTION(bluestore_min_alloc_size_hdd, OPT_U32, 64*1024)
 OPTION(bluestore_min_alloc_size_ssd, OPT_U32, 4*1024)
+OPTION(bluestore_max_alloc_size, OPT_U32, 0)
 OPTION(bluestore_compression, OPT_STR, "none")  // force|aggressive|passive|none
 OPTION(bluestore_compression_algorithm, OPT_STR, "snappy")
 OPTION(bluestore_compression_min_blob_size, OPT_U32, 256*1024)
index 149635124c1a4c447e62f7b3e28aa3ad99172702..dbd3fedb4d880023e934adfe47506ff5f39488a4 100644 (file)
@@ -1008,6 +1008,7 @@ BlueStore::BlueStore(CephContext *cct, const string& path)
     logger(NULL),
     csum_type(bluestore_blob_t::CSUM_CRC32C),
     min_alloc_size(0),
+    max_alloc_size(0),
     sync_wal_apply(cct->_conf->bluestore_sync_wal_apply)
 {
   _init_logger();
@@ -1273,8 +1274,9 @@ int BlueStore::_check_or_set_bdev_label(
   return 0;
 }
 
-void BlueStore::_set_min_alloc(void)
+void BlueStore::_set_alloc_sizes(void)
 {
+  max_alloc_size = g_conf->bluestore_max_alloc_size;
   /*
    * Set device block size according to its media
    */
@@ -1290,6 +1292,7 @@ void BlueStore::_set_min_alloc(void)
   }
 
   dout(10) << __func__ << " min_alloc_size 0x" << std::hex << min_alloc_size
+          << " max_alloc_size 0x" << max_alloc_size
           << std::dec << dendl;
 }
 
@@ -1317,7 +1320,8 @@ int BlueStore::_open_bdev(bool create)
     ++block_size_order;
   }
 
-  _set_min_alloc();
+  _set_alloc_sizes();
+  max_alloc_size = g_conf->bluestore_max_alloc_size;
   return 0;
 
  fail_close:
@@ -5927,7 +5931,8 @@ int BlueStore::_do_alloc_write(
     while (final_length > 0) {
       bluestore_pextent_t e;
       uint32_t l;
-      int r = alloc->allocate(final_length, min_alloc_size, hint,
+      uint64_t want = max_alloc_size ? MIN(final_length, max_alloc_size) : final_length;
+      int r = alloc->allocate(want, min_alloc_size, hint,
                              &e.offset, &l);
       assert(r == 0);
       need -= l;
index d2bcfe046c1f3707f40af4d021e59b07faf65f62..c4ade3d69fc5774ba23833ad1f1254bae9da10c5 100644 (file)
@@ -908,6 +908,8 @@ private:
 
   uint64_t min_alloc_size; ///< minimum allocation unit (power of 2)
 
+  uint64_t max_alloc_size; ///< maximum allocation unit (power of 2)
+
   bool sync_wal_apply;   ///< see config option bluestore_sync_wal_apply
 
   // compression options
@@ -944,7 +946,7 @@ private:
   int _read_fsid(uuid_d *f);
   int _write_fsid();
   void _close_fsid();
-  void _set_min_alloc();
+  void _set_alloc_sizes();
   int _open_bdev(bool create);
   void _close_bdev();
   int _open_db(bool create);
index c0220d22db1c768e7f53773b75a5f83092bd5999..a32bd9df1f02866c1bdb096ffb6047b5eb7bc1be 100644 (file)
@@ -1295,6 +1295,203 @@ TEST_P(StoreTest, BluestoreStatFSTest) {
   g_ceph_context->_conf->apply_changes(NULL);
 }
 
+TEST_P(StoreTest, BluestoreFragmentedBlobTest) {
+  if(string(GetParam()) != "bluestore")
+    return;
+
+  ObjectStore::Sequencer osr("test");
+  int r;
+  coll_t cid;
+  ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
+  {
+    ObjectStore::Transaction t;
+    t.create_collection(cid, 0);
+    cerr << "Creating collection " << cid << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+  }
+  {
+    bool exists = store->exists(cid, hoid);
+    ASSERT_TRUE(!exists);
+
+    ObjectStore::Transaction t;
+    t.touch(cid, hoid);
+    cerr << "Creating object " << hoid << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    exists = store->exists(cid, hoid);
+    ASSERT_EQ(true, exists);
+  }
+  {
+    struct store_statfs_t statfs;
+    int r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ( 0u, statfs.allocated);
+    ASSERT_EQ( 0u, statfs.stored);
+    ASSERT_EQ(0x1000u, statfs.bsize);
+    ASSERT_EQ(g_conf->bluestore_block_size / 0x1000, statfs.blocks);
+    ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf->bluestore_block_size);
+  }
+  std::string data;
+  data.resize(0x10000 * 3);
+  {
+    ObjectStore::Transaction t;
+    for(size_t i = 0;i < data.size(); i++)
+      data[i] = i / 256 + 1;
+    bufferlist bl, newdata;
+    bl.append(data);
+    t.write(cid, hoid, 0, bl.length(), bl);
+    t.zero(cid, hoid, 0x10000, 0x10000);
+    cerr << "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    struct store_statfs_t statfs;
+    int r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(0x20000, statfs.stored);
+    ASSERT_EQ(0x20000, statfs.allocated);
+
+    r = store->read(cid, hoid, 0, data.size(), newdata);
+    ASSERT_EQ(r, (int)data.size());
+    {
+      bufferlist expected;
+      expected.append(data.substr(0, 0x10000));
+      expected.append(string(0x10000, 0));
+      expected.append(data.substr(0x20000, 0x10000));
+      ASSERT_TRUE(newdata.contents_equal(expected));
+    }
+    newdata.clear();
+
+    r = store->read(cid, hoid, 1, data.size()-2, newdata);
+    ASSERT_EQ(r, (int)data.size()-2);
+    {
+      bufferlist expected;
+      expected.append(data.substr(1, 0x10000-1));
+      expected.append(string(0x10000, 0));
+      expected.append(data.substr(0x20000, 0x10000 - 1));
+      ASSERT_TRUE(newdata.contents_equal(expected));
+    }
+    newdata.clear();
+  }
+  //force fsck
+  EXPECT_EQ(store->umount(), 0);
+  EXPECT_EQ(store->mount(), 0);
+
+  {
+    ObjectStore::Transaction t;
+    std::string data2(3, 'b');
+    bufferlist bl, newdata;
+    bl.append(data2);
+    t.write(cid, hoid, 0x20000, bl.length(), bl);
+    cerr << "Write 3 bytes after the hole" << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    struct store_statfs_t statfs;
+    int r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(0x20000, statfs.allocated);
+    ASSERT_EQ(0x20000, statfs.stored);
+
+    r = store->read(cid, hoid, 0x20000-1, 21, newdata);
+    ASSERT_EQ(r, (int)21);
+    {
+      bufferlist expected;
+      expected.append(string(0x1, 0));
+      expected.append(string(data2));
+      expected.append(data.substr(0x20003, 21-4));
+      ASSERT_TRUE(newdata.contents_equal(expected));
+    }
+    newdata.clear();
+  }
+  //force fsck
+  EXPECT_EQ(store->umount(), 0);
+  EXPECT_EQ(store->mount(), 0);
+
+  {
+    ObjectStore::Transaction t;
+    std::string data2(3, 'a');
+    bufferlist bl, newdata;
+    bl.append(data2);
+    t.write(cid, hoid, 0x10000+1, bl.length(), bl);
+    cerr << "Write 3 bytes to the hole" << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    struct store_statfs_t statfs;
+    int r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(0x30000, statfs.allocated);
+    ASSERT_EQ(0x20003, statfs.stored);
+
+    r = store->read(cid, hoid, 0x10000-1, 0x10000+22, newdata);
+    ASSERT_EQ(r, (int)0x10000+22);
+    {
+      bufferlist expected;
+      expected.append(data.substr(0x10000-1, 1));
+      expected.append(string(0x1, 0));
+      expected.append(data2);
+      expected.append(string(0x10000-4, 0));
+      expected.append(string(0x3, 'b'));
+      expected.append(data.substr(0x20004, 21-3));
+      ASSERT_TRUE(newdata.contents_equal(expected));
+    }
+    newdata.clear();
+  }
+  {
+    ObjectStore::Transaction t;
+    bufferlist bl, newdata;
+    bl.append(string(0x30000, 'c'));
+    t.write(cid, hoid, 0, 0x30000, bl);
+    t.zero(cid, hoid, 0, 0x10000);
+    t.zero(cid, hoid, 0x20000, 0x10000);
+    cerr << "Rewrite an object and create two holes at the begining and the end" << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    struct store_statfs_t statfs;
+    int r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(0x10000, statfs.allocated);
+    ASSERT_EQ(0x10000, statfs.stored);
+
+    r = store->read(cid, hoid, 0, 0x30000, newdata);
+    ASSERT_EQ(r, (int)0x30000);
+    {
+      bufferlist expected;
+      expected.append(string(0x10000, 0));
+      expected.append(string(0x10000, 'c'));
+      expected.append(string(0x10000, 0));
+      ASSERT_TRUE(newdata.contents_equal(expected));
+    }
+    newdata.clear();
+  }
+
+  //force fsck
+  EXPECT_EQ(store->umount(), 0);
+  EXPECT_EQ(store->mount(), 0);
+
+  {
+    ObjectStore::Transaction t;
+    t.remove(cid, hoid);
+    t.remove_collection(cid);
+    cerr << "Cleaning" << std::endl;
+    r = apply_transaction(store, &osr, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    struct store_statfs_t statfs;
+    r = store->statfs(&statfs);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ( 0u, statfs.allocated);
+    ASSERT_EQ( 0u, statfs.stored);
+    ASSERT_EQ( 0u, statfs.compressed_original);
+    ASSERT_EQ( 0u, statfs.compressed);
+    ASSERT_EQ( 0u, statfs.compressed_allocated);
+  }
+}
+
 TEST_P(StoreTest, ManySmallWrite) {
   ObjectStore::Sequencer osr("test");
   int r;
@@ -4522,6 +4719,7 @@ int main(int argc, char **argv) {
   g_ceph_context->_conf->set_val("bluestore_debug_small_allocations", "4");
   g_ceph_context->_conf->set_val("bluestore_debug_freelist", "true");
   g_ceph_context->_conf->set_val("bluestore_clone_cow", "true");
+  g_ceph_context->_conf->set_val("bluestore_max_alloc_size", "196608");
   g_ceph_context->_conf->set_val(
     "enable_experimental_unrecoverable_data_corrupting_features", "*");
   g_ceph_context->_conf->apply_changes(NULL);