bluestore自己管理裸盘的块设备,管理空闲空间的类是FreelistManager,所有的块组成一个bitmap,0为空闲,1为使用。
FreelistManager *FreelistManager::create(
CephContext* cct,
string type,
KeyValueDB *kvdb,
string prefix)
{
assert(prefix == "B");
if (type == "bitmap")
return new BitmapFreelistManager(cct, kvdb, "B", "b");
return NULL;
}
从FreelistManager 的create函数可以看出目前空闲list只能由BitmapFreelistManager 来管理,也就是说type只能是bitmap,否则会返回NULL
int BitmapFreelistManager::create(uint64_t new_size, uint64_t min_alloc_size,
KeyValueDB::Transaction txn)
{
bytes_per_block = std::max(cct->_conf->bdev_block_size,
(int64_t)min_alloc_size);
assert(ISP2(bytes_per_block));
size = P2ALIGN(new_size, bytes_per_block);
blocks_per_key = cct->_conf->bluestore_freelist_blocks_per_key;
_init_misc();
blocks = size / bytes_per_block;
if (blocks / blocks_per_key * blocks_per_key != blocks) {
blocks = (blocks / blocks_per_key + 1) * blocks_per_key;
dout(10) << __func__ << " rounding blocks up from 0x" << std::hex << size
<< " to 0x" << (blocks * bytes_per_block)
<< " (0x" << blocks << " blocks)" << std::dec << dendl;
// set past-eof blocks as allocated
_xor(size, blocks * bytes_per_block - size, txn);
}
dout(10) << __func__
<< " size 0x" << std::hex << size
<< " bytes_per_block 0x" << bytes_per_block
<< " blocks 0x" << blocks
<< " blocks_per_key 0x" << blocks_per_key
<< std::dec << dendl;
{
bufferlist bl;
::encode(bytes_per_block, bl);
txn->set(meta_prefix, "bytes_per_block", bl);
}
{
bufferlist bl;
::encode(blocks_per_key, bl);
txn->set(meta_prefix, "blocks_per_key", bl);
}
{
bufferlist bl;
::encode(blocks, bl);
txn->set(meta_prefix, "blocks", bl);
}
{
bufferlist bl;
::encode(size, bl);
txn->set(meta_prefix, "size", bl);
}
return 0;
}
从BitmapFreelistManager的create函数可以看出,块设备的元数据是用kv存储的,默认有四个key,分别是bytes_per_block/blocks_per_key
/blocks/size
BitmapFreelistManager 提供的申请块设备和释放块设备的函数分别如下:可以看到无论申请还是释放 都是通过xor来进行的
void BitmapFreelistManager::allocate(
uint64_t offset, uint64_t length,
KeyValueDB::Transaction txn)
{
dout(10) << __func__ << " 0x" << std::hex << offset << "~" << length
<< std::dec << dendl;
if (cct->_conf->bluestore_debug_freelist)
_verify_range(offset, length, 0);
_xor(offset, length, txn);
}
void BitmapFreelistManager::release(
uint64_t offset, uint64_t length,
KeyValueDB::Transaction txn)
{
dout(10) << __func__ << " 0x" << std::hex << offset << "~" << length
<< std::dec << dendl;
if (cct->_conf->bluestore_debug_freelist)
_verify_range(offset, length, 1);
_xor(offset, length, txn);
}
我们看看xor的实现
在xor中会针对申请的块设备的起始地址和size 来判断要申请的块设备属于哪个块设备组
我们这里以最简单的case为例,即要申请的块设备在同一个组内
void BitmapFreelistManager::_xor(
uint64_t offset, uint64_t length,
KeyValueDB::Transaction txn)
{
// must be block aligned
assert((offset & block_mask) == offset);
assert((length & block_mask) == length);
uint64_t first_key = offset & key_mask;
uint64_t last_key = (offset + length - 1) & key_mask;
dout(20) << __func__ << " first_key 0x" << std::hex << first_key
<< " last_key 0x" << last_key << std::dec << dendl;
#针对要申请的块设备在同一个组内
if (first_key == last_key) {
bufferptr p(blocks_per_key >> 3);
p.zero();
#起始block的编号
unsigned s = (offset & ~key_mask) / bytes_per_block;
#结束block的编号
unsigned e = ((offset + length - 1) & ~key_mask) / bytes_per_block;
#讲s和e之间的block 的bitmap置位为1,表示这段块设备已经被占用
for (unsigned i = s; i <= e; ++i) {
p[i >> 3] ^= 1ull << (i & 7);
}
string k;
make_offset_key(first_key, &k);
bufferlist bl;
bl.append(p);
dout(30) << __func__ << " 0x" << std::hex << first_key << std::dec << ": ";
bl.hexdump(*_dout, false);
*_dout << dendl;
#这里的merge操作也是xor操作,表示和目前的value 来xor操作
txn->merge(bitmap_prefix, k, bl);
} else {
}
从下面这个函数知道merge操作其实是调用XorMergeOperator 来进行的
void BitmapFreelistManager::setup_merge_operator(KeyValueDB *db, string prefix)
{
ceph::shared_ptr<XorMergeOperator> merge_op(new XorMergeOperator);
db->set_merge_operator(prefix, merge_op);
}
而XorMergeOperator 的merge操作如下:可以看到也是进行xor操作
struct XorMergeOperator : public KeyValueDB::MergeOperator {
void merge_nonexistent(
const char *rdata, size_t rlen, std::string *new_value) override {
*new_value = std::string(rdata, rlen);
}
void merge(
const char *ldata, size_t llen,
const char *rdata, size_t rlen,
std::string *new_value) override {
assert(llen == rlen);
*new_value = std::string(ldata, llen);
for (size_t i = 0; i < rlen; ++i) {
(*new_value)[i] ^= rdata[i];
}
}
}
bluestore的空闲块管理
最新推荐文章于 2024-05-09 16:11:14 发布