#include "BitmapFreelistManager.h"
#include "kv/KeyValueDB.h"
#include "os/kv.h"
+#include "include/stringify.h"
#include "common/debug.h"
_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;
+ blocks = size_2_block_count(size);
+ if (blocks * bytes_per_block > size) {
dout(10) << __func__ << " rounding blocks up from 0x" << std::hex << size
<< " to 0x" << (blocks * bytes_per_block)
<< " (0x" << blocks << " blocks)" << std::dec << dendl;
return 0;
}
-int BitmapFreelistManager::expand(uint64_t new_size, KeyValueDB::Transaction txn)
+int BitmapFreelistManager::_expand(uint64_t old_size, KeyValueDB* db)
{
- assert(new_size > size);
+ assert(old_size < size);
ceph_assert(isp2(bytes_per_block));
- uint64_t blocks0 = size / bytes_per_block;
- if (blocks0 / blocks_per_key * blocks_per_key != blocks0) {
- blocks0 = (blocks / blocks_per_key + 1) * blocks_per_key;
- dout(10) << __func__ << " rounding blocks up from 0x" << std::hex << size
- << " to 0x" << (blocks0 * bytes_per_block)
+ KeyValueDB::Transaction txn;
+ txn = db->get_transaction();
+
+ auto blocks0 = size_2_block_count(old_size);
+ if (blocks0 * bytes_per_block > old_size) {
+ dout(10) << __func__ << " rounding1 blocks up from 0x" << std::hex
+ << old_size << " to 0x" << (blocks0 * bytes_per_block)
<< " (0x" << blocks0 << " blocks)" << std::dec << dendl;
// reset past-eof blocks to unallocated
- _xor(size, blocks0 * bytes_per_block - size, txn);
+ _xor(old_size, blocks0 * bytes_per_block - old_size, txn);
}
- size = p2align(new_size, bytes_per_block);
- blocks = size / bytes_per_block;
+ size = p2align(size, bytes_per_block);
+ blocks = size_2_block_count(size);
- 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)
+ if (blocks * bytes_per_block > size) {
+ dout(10) << __func__ << " rounding2 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);
encode(size, bl);
txn->set(meta_prefix, "size", bl);
}
+ db->submit_transaction_sync(txn);
+
return 0;
}
-int BitmapFreelistManager::init(KeyValueDB *kvdb)
+int BitmapFreelistManager::read_size_meta_from_db(KeyValueDB* kvdb,
+ uint64_t* res)
{
- dout(1) << __func__ << dendl;
+ bufferlist v;
+ int r = kvdb->get(meta_prefix, "size", &v);
+ if (r < 0) {
+ derr << __func__ << " missing size meta in DB" << dendl;
+ return ENOENT;
+ } else {
+ auto p = v.cbegin();
+ decode(*res, p);
+ r = 0;
+ }
+ return r;
+}
+void BitmapFreelistManager::_load_from_db(KeyValueDB* kvdb)
+{
KeyValueDB::Iterator it = kvdb->get_iterator(meta_prefix);
it->lower_bound(string());
auto p = bl.cbegin();
decode(bytes_per_block, p);
dout(10) << __func__ << " bytes_per_block 0x" << std::hex
- << bytes_per_block << std::dec << dendl;
+ << bytes_per_block << std::dec << dendl;
} else if (k == "blocks") {
bufferlist bl = it->value();
auto p = bl.cbegin();
decode(blocks, p);
dout(10) << __func__ << " blocks 0x" << std::hex << blocks << std::dec
- << dendl;
+ << dendl;
} else if (k == "size") {
bufferlist bl = it->value();
auto p = bl.cbegin();
decode(size, p);
dout(10) << __func__ << " size 0x" << std::hex << size << std::dec
- << dendl;
+ << dendl;
} else if (k == "blocks_per_key") {
bufferlist bl = it->value();
auto p = bl.cbegin();
decode(blocks_per_key, p);
dout(10) << __func__ << " blocks_per_key 0x" << std::hex << blocks_per_key
- << std::dec << dendl;
+ << std::dec << dendl;
} else {
derr << __func__ << " unrecognized meta " << k << dendl;
- return -EIO;
}
it->next();
}
+}
+
+
+int BitmapFreelistManager::init(const bluestore_bdev_label_t& label,
+ KeyValueDB *kvdb,
+ bool db_in_read_only)
+{
+ dout(1) << __func__ << dendl;
+ int r = _init_from_label(label);
+ if (r != 0) {
+ dout(1) << __func__ << " fall back to legacy meta repo" << dendl;
+ _load_from_db(kvdb);
+ }
+ _sync(kvdb, db_in_read_only);
dout(10) << __func__ << std::hex
<< " size 0x" << size
return 0;
}
+int BitmapFreelistManager::_init_from_label(const bluestore_bdev_label_t& label)
+{
+ dout(1) << __func__ << dendl;
+
+ int r = ENOENT;
+ string err;
+
+ auto it = label.meta.find("bfm_size");
+ auto end = label.meta.end();
+ if (it != end) {
+ size = strict_iecstrtoll(it->second.c_str(), &err);
+ if (!err.empty()) {
+ derr << __func__ << " Failed to parse - "
+ << it->first << ":" << it->second
+ << ", error: " << err << dendl;
+ return r;
+ }
+ } else {
+ // this is expected for legacy deployed OSDs
+ dout(0) << __func__ << " bfm_size not found in bdev meta" << dendl;
+ return r;
+ }
+
+ it = label.meta.find("bfm_blocks");
+ if (it != end) {
+ blocks = strict_iecstrtoll(it->second.c_str(), &err);
+ if (!err.empty()) {
+ derr << __func__ << " Failed to parse - "
+ << it->first << ":" << it->second
+ << ", error: " << err << dendl;
+ return r;
+ }
+ } else {
+ derr << __func__ << " bfm_blocks not found in bdev meta" << dendl;
+ return r;
+ }
+
+ it = label.meta.find("bfm_bytes_per_block");
+ if (it != end) {
+ bytes_per_block = strict_iecstrtoll(it->second.c_str(), &err);
+ if (!err.empty()) {
+ derr << __func__ << " Failed to parse - "
+ << it->first << ":" << it->second
+ << ", error: " << err << dendl;
+ return r;
+ }
+ } else {
+ derr << __func__ << " bfm_bytes_per_block not found in bdev meta" << dendl;
+ return r;
+ }
+ it = label.meta.find("bfm_blocks_per_key");
+ if (it != end) {
+ blocks_per_key = strict_iecstrtoll(it->second.c_str(), &err);
+ if (!err.empty()) {
+ derr << __func__ << " Failed to parse - "
+ << it->first << ":" << it->second
+ << ", error: " << err << dendl;
+ return r;
+ }
+ } else {
+ derr << __func__ << " bfm_blocks_per_key not found in bdev meta" << dendl;
+ return r;
+ }
+ r = 0;
+ return 0;
+}
+
void BitmapFreelistManager::_init_misc()
{
bufferptr z(blocks_per_key >> 3);
<< dendl;
}
+void BitmapFreelistManager::sync(KeyValueDB* kvdb)
+{
+ _sync(kvdb, true);
+}
+
+void BitmapFreelistManager::_sync(KeyValueDB* kvdb, bool read_only)
+{
+ dout(10) << __func__ << " checks if size sync is needed" << dendl;
+ uint64_t size_db = 0;
+ int r = read_size_meta_from_db(kvdb, &size_db);
+ ceph_assert(r >= 0);
+ if (!read_only && size_db < size) {
+ dout(1) << __func__ << " committing new size 0x" << std::hex << size
+ << std::dec << dendl;
+ r = _expand(size_db, kvdb);
+ ceph_assert(r == 0);
+ } else if (size_db > size) {
+ // this might hapen when OSD passed the following sequence:
+ // upgrade -> downgrade -> expand -> upgrade
+ // One needs to run expand once again to syncup
+ dout(1) << __func__ << " fall back to legacy meta repo" << dendl;
+ _load_from_db(kvdb);
+ }
+}
+
void BitmapFreelistManager::shutdown()
{
dout(1) << __func__ << dendl;
}
}
}
+
+uint64_t BitmapFreelistManager::size_2_block_count(uint64_t target_size) const
+{
+ auto target_blocks = target_size / bytes_per_block;
+ if (target_blocks / blocks_per_key * blocks_per_key != target_blocks) {
+ target_blocks = (target_blocks / blocks_per_key + 1) * blocks_per_key;
+ }
+ return target_blocks;
+}
+
+void BitmapFreelistManager::get_meta(
+ uint64_t target_size,
+ std::vector<std::pair<string, string>>* res) const
+{
+ if (target_size == 0) {
+ res->emplace_back("bfm_blocks", stringify(blocks));
+ res->emplace_back("bfm_size", stringify(size));
+ } else {
+ target_size = p2align(target_size, bytes_per_block);
+ auto target_blocks = size_2_block_count(target_size);
+
+ res->emplace_back("bfm_blocks", stringify(target_blocks));
+ res->emplace_back("bfm_size", stringify(target_size));
+ }
+ res->emplace_back("bfm_bytes_per_block", stringify(bytes_per_block));
+ res->emplace_back("bfm_blocks_per_key", stringify(blocks_per_key));
+}