public:
virtual ~Allocator() {}
- virtual int reserve(uint64_t need) = 0;
- virtual void unreserve(uint64_t unused) = 0;
-
/*
* Allocate required number of blocks in n number of extents.
* Min and Max number of extents are limited by:
len / m_block_size);
}
-int BitMapAllocator::reserve(uint64_t need)
-{
- int nblks = need / m_block_size; // apply floor
- assert(!(need % m_block_size));
- dout(10) << __func__ << " instance " << (uint64_t) this
- << " num_used " << m_bit_alloc->get_used_blocks()
- << " total " << m_bit_alloc->total_blocks()
- << dendl;
-
- if (!m_bit_alloc->reserve_blocks(nblks)) {
- return -ENOSPC;
- }
- return 0;
-}
-
-void BitMapAllocator::unreserve(uint64_t unused)
-{
- int nblks = unused / m_block_size;
- assert(!(unused % m_block_size));
-
- dout(10) << __func__ << " instance " << (uint64_t) this
- << " unused " << nblks
- << " num used " << m_bit_alloc->get_used_blocks()
- << " total " << m_bit_alloc->total_blocks()
- << dendl;
-
- m_bit_alloc->unreserve_blocks(nblks);
-}
-
int64_t BitMapAllocator::allocate(
uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
int64_t hint, PExtentVector *extents)
assert(!max_alloc_size || max_alloc_size >= alloc_unit);
+ //FIXME: reproduce reserve/unreserve
+
dout(10) << __func__ <<" instance "<< (uint64_t) this
<< " want_size " << want_size
<< " alloc_unit " << alloc_unit
BitMapAllocator(CephContext* cct, int64_t device_size, int64_t block_size);
~BitMapAllocator() override;
- int reserve(uint64_t need) override;
- void unreserve(uint64_t unused) override;
-
int64_t allocate(
uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
int64_t hint, PExtentVector *extents) override;
<< " want 0x" << std::hex << want << std::dec << dendl;
assert(id < alloc.size());
assert(alloc[id]);
- int r = alloc[id]->reserve(want);
- assert(r == 0); // caller shouldn't ask for more than they can get
+
int64_t got = alloc[id]->allocate(want, cct->_conf->bluefs_alloc_size, 0,
extents);
- if (got < (int64_t)want) {
- alloc[id]->unreserve(want - MAX(0, got));
- }
- if (got <= 0) {
+ if (got < 0) {
derr << __func__ << " failed to allocate space to return to bluestore"
- << dendl;
+ << dendl;
alloc[id]->dump();
return got;
}
}
flush_bdev();
- r = _flush_and_sync_log(l);
+ int r = _flush_and_sync_log(l);
assert(r == 0);
if (logger)
uint64_t min_alloc_size = cct->_conf->bluefs_alloc_size;
uint64_t left = ROUND_UP_TO(len, min_alloc_size);
- int r = -ENOSPC;
int64_t alloc_len = 0;
PExtentVector extents;
if (alloc[id]) {
- r = alloc[id]->reserve(left);
- }
-
- if (r == 0) {
uint64_t hint = 0;
if (!node->extents.empty() && node->extents.back().bdev == id) {
hint = node->extents.back().end();
extents.reserve(4); // 4 should be (more than) enough for most allocations
alloc_len = alloc[id]->allocate(left, min_alloc_size, hint, &extents);
}
- if (r < 0 || (alloc_len < (int64_t)left)) {
- if (r == 0) {
- alloc[id]->unreserve(left - alloc_len);
+ if (alloc_len < (int64_t)left) {
+ if (alloc_len != 0) {
interval_set<uint64_t> to_release;
for (auto& p : extents) {
to_release.insert(p.offset, p.length);
dout(10) << __func__ << " gifting " << gift
<< " (" << byte_u_t(gift) << ")" << dendl;
- // fixme: just do one allocation to start...
- int r = alloc->reserve(gift);
- assert(r == 0);
-
int64_t alloc_len = alloc->allocate(gift, cct->_conf->bluefs_alloc_size,
0, 0, extents);
if (alloc_len <= 0) {
dout(0) << __func__ << " no allocate on 0x" << std::hex << gift
<< " min_alloc_size 0x" << min_alloc_size << std::dec << dendl;
- alloc->unreserve(gift);
_dump_alloc_on_rebalance_failure();
return 0;
} else if (alloc_len < (int64_t)gift) {
<< " min_alloc_size 0x" << min_alloc_size
<< " allocated 0x" << alloc_len
<< std::dec << dendl;
- alloc->unreserve(gift - alloc_len);
_dump_alloc_on_rebalance_failure();
}
for (auto& e : *extents) {
need += wi.blob_length;
}
}
- int r = alloc->reserve(need);
- if (r < 0) {
- derr << __func__ << " failed to reserve 0x" << std::hex << need << std::dec
- << dendl;
- return r;
- }
PExtentVector prealloc;
prealloc.reserve(2 * wctx->writes.size());;
int prealloc_left = 0;
prealloc_left = alloc->allocate(
need, min_alloc_size, need,
0, &prealloc);
+ if (prealloc_left < 0) {
+ derr << __func__ << " failed to allocate 0x" << std::hex << need << std::dec
+ << dendl;
+ return -ENOSPC;
+ }
assert(prealloc_left == (int64_t)need);
+
dout(20) << __func__ << " prealloc " << prealloc << dendl;
auto prealloc_pos = prealloc.begin();
StupidAllocator::StupidAllocator(CephContext* cct)
: cct(cct), num_free(0),
- num_reserved(0),
free(10),
last_alloc(0)
{
}
}
-int StupidAllocator::reserve(uint64_t need)
-{
- std::lock_guard<std::mutex> l(lock);
- dout(10) << __func__ << " need 0x" << std::hex << need
- << " num_free 0x" << num_free
- << " num_reserved 0x" << num_reserved << std::dec << dendl;
- if ((int64_t)need > num_free - num_reserved)
- return -ENOSPC;
- num_reserved += need;
- return 0;
-}
-
-void StupidAllocator::unreserve(uint64_t unused)
-{
- std::lock_guard<std::mutex> l(lock);
- dout(10) << __func__ << " unused 0x" << std::hex << unused
- << " num_free 0x" << num_free
- << " num_reserved 0x" << num_reserved << std::dec << dendl;
- assert(num_reserved >= (int64_t)unused);
- num_reserved -= unused;
-}
-
/// return the effective length of the extent if we align to alloc_unit
uint64_t StupidAllocator::_aligned_len(
StupidAllocator::interval_set_t::iterator p,
}
num_free -= *length;
- num_reserved -= *length;
assert(num_free >= 0);
- assert(num_reserved >= 0);
last_alloc = *offset + *length;
return 0;
}
std::mutex lock;
int64_t num_free; ///< total bytes in freelist
- int64_t num_reserved; ///< reserved bytes
typedef mempool::bluestore_alloc::pool_allocator<
pair<const uint64_t,uint64_t>> allocator_t;
StupidAllocator(CephContext* cct);
~StupidAllocator() override;
- int reserve(uint64_t need) override;
- void unreserve(uint64_t unused) override;
-
int64_t allocate(
uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
int64_t hint, PExtentVector *extents) override;
{
init_alloc(blocks, block_size);
alloc->init_add_free(block_size, block_size);
- EXPECT_EQ(alloc->reserve(block_size), 0);
PExtentVector extents;
EXPECT_EQ(block_size, alloc->allocate(block_size, block_size,
0, (int64_t) 0, &extents));
*/
{
alloc->init_add_free(0, block_size * 4);
- EXPECT_EQ(alloc->reserve(block_size * 4), 0);
PExtentVector extents;
EXPECT_EQ(4*block_size,
alloc->allocate(4 * (uint64_t)block_size, (uint64_t) block_size,
{
alloc->init_add_free(0, block_size * 2);
alloc->init_add_free(3 * block_size, block_size * 2);
- EXPECT_EQ(alloc->reserve(block_size * 4), 0);
PExtentVector extents;
EXPECT_EQ(4*block_size,
*/
{
alloc->init_add_free(0, block_size * 4);
- EXPECT_EQ(alloc->reserve(block_size * 4), 0);
PExtentVector extents;
EXPECT_EQ(4*block_size,
alloc->allocate(4 * (uint64_t)block_size, (uint64_t) block_size,
*/
{
alloc->init_add_free(0, block_size * 4);
- EXPECT_EQ(alloc->reserve(block_size * 4), 0);
PExtentVector extents;
EXPECT_EQ(4*block_size,
alloc->allocate(4 * (uint64_t)block_size, (uint64_t) block_size,
*/
{
alloc->init_add_free(0, block_size * 1024);
- EXPECT_EQ(alloc->reserve(block_size * 1024), 0);
PExtentVector extents;
EXPECT_EQ(1024 * block_size,
alloc->allocate(1024 * (uint64_t)block_size,
*/
{
alloc->init_add_free(0, block_size * 16);
- EXPECT_EQ(alloc->reserve(block_size * 16), 0);
PExtentVector extents;
EXPECT_EQ(16 * block_size,
alloc->allocate(16 * (uint64_t)block_size, (uint64_t) block_size,
alloc->init_add_free(0, block_size * 256);
alloc->init_add_free(block_size * 512, block_size * 256);
- EXPECT_EQ(alloc->reserve(block_size * 512), 0);
PExtentVector extents;
EXPECT_EQ(512 * block_size,
alloc->allocate(512 * (uint64_t)block_size,
alloc->init_add_free(0, block_size * 256);
alloc->init_add_free(block_size * 512, block_size * 256);
extents.clear();
- EXPECT_EQ(alloc->reserve(block_size * 512), 0);
EXPECT_EQ(-ENOSPC,
alloc->allocate(512 * (uint64_t)block_size,
(uint64_t) block_size * 512,
alloc->init_add_free(2*block_size, (blocks-2)*block_size);
for (int64_t big = mas; big < 1048576*128; big*=2) {
cout << big << std::endl;
- EXPECT_EQ(alloc->reserve(big), 0);
PExtentVector extents;
EXPECT_EQ(big,
alloc->allocate(big, mas, 0, &extents));
alloc->init_add_free(0, blocks);
PExtentVector extents;
- alloc->reserve(blocks);
allocated = alloc->allocate(1, 1, 1, zone_size, &extents);
ASSERT_EQ(1, allocated);
alloc->init_add_free(2097152, 1064960);
alloc->init_add_free(3670016, 2097152);
- EXPECT_EQ(0, alloc->reserve(want_size));
PExtentVector extents;
EXPECT_EQ(want_size, alloc->allocate(want_size, alloc_unit, 0, &extents));
}
for (size_t i = 0; i < capacity / alloc_unit; ++i)
{
tmp.clear();
- EXPECT_EQ(0, alloc->reserve(want_size));
EXPECT_EQ(want_size, alloc->allocate(want_size, alloc_unit, 0, 0, &tmp));
allocated.insert(allocated.end(), tmp.begin(), tmp.end());
EXPECT_EQ(0.0, alloc->get_fragmentation(alloc_unit));
}
- EXPECT_EQ(-ENOSPC, alloc->reserve(want_size));
+ EXPECT_EQ(-ENOSPC, alloc->allocate(want_size, alloc_unit, 0, 0, &tmp));
for (size_t i = 0; i < allocated.size(); i += 2)
{