+TEST_P(StoreTestSpecificAUSize, ExcessiveFragmentation) {
+ if (string(GetParam()) != "bluestore")
+ return;
+
+ g_conf->set_val("bluestore_block_size",
+ stringify((uint64_t)2048 * 1024 * 1024));
+
+ ASSERT_EQ(g_conf->get_val<uint64_t>("bluefs_alloc_size"),
+ 1024 * 1024);
+
+ size_t block_size = 0x10000;
+ StartDeferred(block_size);
+
+ ObjectStore::Sequencer osr("test");
+ int r;
+ coll_t cid;
+ ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
+ ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
+
+ {
+ ObjectStore::Transaction t;
+ t.create_collection(cid, 0);
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ {
+ // create 2x400MB objects in a way that their pextents are interleaved
+ ObjectStore::Transaction t;
+ bufferlist bl;
+
+ bl.append(std::string(block_size * 4, 'a')); // 256KB
+ uint64_t offs = 0;
+ while(offs < (uint64_t)400 * 1024 * 1024) {
+ t.write(cid, hoid1, offs, bl.length(), bl, 0);
+ t.write(cid, hoid2, offs, bl.length(), bl, 0);
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ offs += bl.length();
+ if( (offs % (100 * 1024 * 1024)) == 0) {
+ std::cout<<"written " << offs << std::endl;
+ }
+ }
+ }
+ std::cout<<"written 800MB"<<std::endl;
+ {
+ // Partially overwrite objects with 100MB each leaving space
+ // fragmented and occuping still unfragmented space at the end
+ // So we'll have enough free space but it'll lack long enough (e.g. 1MB)
+ // contiguous pextents.
+ ObjectStore::Transaction t;
+ bufferlist bl;
+
+ bl.append(std::string(block_size * 4, 'a'));
+ uint64_t offs = 0;
+ while(offs < 112 * 1024 * 1024) {
+ t.write(cid, hoid1, offs, bl.length(), bl, 0);
+ t.write(cid, hoid2, offs, bl.length(), bl, 0);
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ // this will produce high fragmentation if original allocations
+ // were contiguous
+ offs += bl.length();
+ if( (offs % (10 * 1024 * 1024)) == 0) {
+ std::cout<<"written " << offs << std::endl;
+ }
+ }
+ }
+ {
+ // remove one of the object producing much free space
+ // and hence triggering bluefs rebalance.
+ // Which should fail as there is no long enough pextents.
+ ObjectStore::Transaction t;
+ t.remove(cid, hoid2);
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+
+ auto to_sleep = 5 *
+ (int)g_conf->get_val<double>("bluestore_bluefs_balance_interval");
+ std::cout<<"sleeping... " << std::endl;
+ sleep(to_sleep);
+
+ {
+ // touch another object to triggerrebalance
+ ObjectStore::Transaction t;
+ t.touch(cid, hoid1);
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ {
+ ObjectStore::Transaction t;
+ t.remove(cid, hoid1);
+ t.remove(cid, hoid2);
+ t.remove_collection(cid);
+ cerr << "Cleaning" << std::endl;
+ r = apply_transaction(store, &osr, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ g_conf->set_val("bluestore_block_size",
+ stringify(DEF_STORE_TEST_BLOCKDEV_SIZE));
+}
+