Implement test_resize_auto for the new (lsm/heap) store

This commit is contained in:
Vitaliy Filippov
2025-12-02 01:52:42 +03:00
parent 2fb7022c78
commit 8ffdb93ed3
8 changed files with 195 additions and 106 deletions
+20 -14
View File
@@ -27,6 +27,9 @@
#define VITASTOR_PART_TYPE "e7009fac-a5a1-4d72-af72-53de13059903"
#define DEFAULT_HYBRID_JOURNAL "1G"
#define DEFAULT_HYBRID_SSD_JOURNAL "128M"
#define VITASTOR_META_FORMAT_NAME_V1 "0.6"
#define VITASTOR_META_FORMAT_NAME_V2 "0.9"
#define VITASTOR_META_FORMAT_NAME_HEAP "3.0"
struct resizer_data_moving_t;
@@ -51,18 +54,20 @@ struct disk_tool_t
bool dump_as_old = false;
bool skip_obsolete = false;
int log_level = 1;
double meta_reserve_multiple = 2;
uint64_t meta_reserve_min_size = (uint64_t)1024*1024*1024;
blockstore_disk_t dsk;
// resize data and/or move metadata and journal
int iodepth;
std::string new_meta_device, new_journal_device;
uint64_t new_data_offset, new_data_len;
uint64_t new_journal_offset, new_journal_len;
uint64_t new_meta_offset, new_meta_len;
uint64_t new_data_offset = 0, new_data_len = 0;
uint64_t new_journal_offset = 0, new_journal_len = 0;
uint64_t new_meta_offset = 0, new_meta_len = 0;
/**** State ****/
uint64_t journal_pos, journal_calc_data_pos;
uint64_t journal_pos = 0, journal_calc_data_pos = 0;
uint8_t *buffer_area = NULL;
bool first_block, first_entry;
@@ -72,24 +77,24 @@ struct disk_tool_t
std::map<uint64_t, uint64_t>::iterator remap_it;
ring_loop_t *ringloop = NULL;
ring_consumer_t ring_consumer;
int remap_active;
int remap_active = 0;
journal_entry_start je_start;
uint8_t *new_journal_buf = NULL, *new_meta_buf = NULL, *new_journal_ptr = NULL, *new_journal_data = NULL;
blockstore_meta_header_v3_t *new_meta_hdr = NULL;
uint64_t new_journal_in_pos;
int64_t data_idx_diff;
uint64_t total_blocks, free_first, free_last;
uint64_t new_clean_entry_bitmap_size, new_data_csum_size, new_clean_entry_size, new_entries_per_block;
uint64_t new_journal_in_pos = 0;
int64_t data_idx_diff = 0;
uint64_t total_blocks = 0, free_first = 0, free_last = 0;
uint64_t new_clean_entry_bitmap_size = 0, new_data_csum_size = 0, new_clean_entry_size = 0, new_entries_per_block = 0;
uint32_t new_meta_format = 0;
int new_journal_fd = -1, new_meta_fd = -1;
resizer_data_moving_t *moving_blocks = NULL;
bool started;
bool started = false;
void *small_write_data = NULL;
uint32_t data_crc32;
bool data_csum_valid;
uint32_t crc32_last;
uint32_t new_crc32_prev;
uint32_t data_crc32 = 0;
bool data_csum_valid = false;
uint32_t crc32_last = 0;
uint32_t new_crc32_prev = 0;
~disk_tool_t();
@@ -152,6 +157,7 @@ struct disk_tool_t
json11::Json read_osd_superblock(std::string device, bool expect_exist = true, bool ignore_nonref = false);
uint32_t write_osd_superblock(std::string device, json11::Json params);
void parse_meta_reserve();
int prepare_one(std::map<std::string, std::string> options, int is_hdd, json11::Json::object & result);
int check_existing_partition(std::string & dev_by_uuid);
int fix_partition_type(std::string & dev_by_uuid);
+37 -37
View File
@@ -7,8 +7,6 @@
#include "json_util.h"
#include "malloc_or_die.h"
#define FREE_SPACE_BIT 0x8000
int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v3_t *)> hdr_fn,
std::function<void(blockstore_heap_t *heap, heap_entry_t *obj, uint32_t meta_block_num)> obj_fn,
std::function<void(uint64_t block_num, clean_disk_entry *entry_v1, uint8_t *bitmap)> record_fn,
@@ -25,7 +23,7 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v3_t *)>
buf_size = 8*dsk.meta_block_size;
uint8_t *data = NULL;
data = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, buf_size);
blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)data;
blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size);
if (do_open)
{
if (dsk.meta_fd >= 0)
@@ -101,13 +99,12 @@ close_error:
blockstore_heap_t *heap = new blockstore_heap_t(&dsk, buffer_area, log_level);
// Load heap and just iterate it in memory
hdr_fn(hdr);
hdr = NULL;
uint64_t meta_pos = dsk.meta_block_size;
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
uint64_t entries_loaded = 0;
while (meta_pos < dsk.meta_area_size)
while (meta_pos < hdr->meta_area_size)
{
uint64_t read_len = buf_size < dsk.meta_area_size-meta_pos ? buf_size : dsk.meta_area_size-meta_pos;
uint64_t read_len = buf_size < hdr->meta_area_size-meta_pos ? buf_size : hdr->meta_area_size-meta_pos;
read_blocking(dsk.meta_fd, data, read_len);
r = heap->load_blocks(meta_pos-dsk.meta_block_size, read_len, data, true, entries_loaded);
meta_pos += read_len;
@@ -165,7 +162,6 @@ csum_unknown:
// Read
uint64_t block_num = 0;
hdr_fn(hdr);
hdr = NULL;
uint64_t meta_pos = dsk.meta_block_size;
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
while (meta_pos < dsk.min_meta_len)
@@ -224,6 +220,7 @@ csum_unknown:
}
close_free:
free(data);
free(hdr);
if (buffer_area)
{
free(buffer_area);
@@ -308,7 +305,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr)
if (hdr->version == BLOCKSTORE_META_FORMAT_V1)
{
printf(
"{\"version\":\"0.6\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"{\"version\":\"" VITASTOR_META_FORMAT_NAME_V1 "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"\"entries\":[\n",
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity
);
@@ -316,7 +313,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr)
else if (hdr->version == BLOCKSTORE_META_FORMAT_V2)
{
printf(
"{\"version\":\"0.9\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"{\"version\":\"" VITASTOR_META_FORMAT_NAME_V2 "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"\"data_csum_type\":\"%s\",\"csum_block_size\":%u,\"entries\":[\n",
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity,
csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size
@@ -325,7 +322,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr)
else if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP)
{
printf(
"{\"version\":\"3.0\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"{\"version\":\"" VITASTOR_META_FORMAT_NAME_HEAP "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,"
"\"data_csum_type\":\"%s\",\"csum_block_size\":%u,\"entries\":[\n",
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity,
csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size
@@ -517,12 +514,16 @@ void disk_tool_t::dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, u
int disk_tool_t::write_json_meta(json11::Json meta)
{
if (meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_HEAP)
{
return write_json_heap(meta, meta["journal"]);
}
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
memset(new_meta_buf, 0, new_meta_len);
blockstore_meta_header_v2_t *new_hdr = (blockstore_meta_header_v2_t *)new_meta_buf;
new_hdr->zero = 0;
new_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
new_hdr->version = meta["version"].uint64_value() == BLOCKSTORE_META_FORMAT_V1
new_hdr->version = meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_V1
? BLOCKSTORE_META_FORMAT_V1 : BLOCKSTORE_META_FORMAT_V2;
new_hdr->meta_block_size = meta["meta_block_size"].uint64_value()
? meta["meta_block_size"].uint64_value() : 4096;
@@ -588,6 +589,9 @@ int disk_tool_t::write_json_meta(json11::Json meta)
int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
{
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
memset(new_meta_buf, 0, new_meta_len);
new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf;
new_meta_hdr->zero = 0;
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
new_meta_hdr->version = BLOCKSTORE_META_FORMAT_HEAP;
@@ -604,41 +608,29 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
: BLOCKSTORE_CSUM_NONE);
new_meta_hdr->csum_block_size = meta["csum_block_size"].uint64_value();
new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, sizeof(blockstore_meta_header_v3_t));
new_meta_hdr->meta_area_size = new_meta_len;
new_clean_entry_bitmap_size = (new_meta_hdr->data_block_size / new_meta_hdr->bitmap_granularity + 7) / 8;
new_clean_entry_size = 0;
new_entries_per_block = 0;
new_data_csum_size = (new_meta_hdr->data_csum_type
? ((new_meta_hdr->data_block_size+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size*(new_meta_hdr->data_csum_type & 0xFF))
: 0);
new_journal_buf = new_journal_len ? (uint8_t*)memalign(MEM_ALIGNMENT, new_journal_len) : NULL;
new_journal_buf = NULL;
if (new_journal_len)
{
new_journal_buf = (uint8_t*)memalign(MEM_ALIGNMENT, new_journal_len);
memset(new_journal_buf, 0, new_journal_len);
}
uint64_t total_used_space = 0;
uint32_t used_space = 0;
uint64_t meta_offset = 0;
// FIXME: Rather ugly. Remove the dependency on dsk from heap?
blockstore_disk_t dsk;
dsk.bitmap_granularity = new_meta_hdr->bitmap_granularity;
dsk.block_count = 16;
dsk.data_block_size = new_meta_hdr->data_block_size;
dsk.clean_entry_bitmap_size = new_clean_entry_bitmap_size;
dsk.csum_block_size = new_meta_hdr->csum_block_size;
dsk.data_csum_type = new_meta_hdr->data_csum_type;
dsk.journal_len = 4096;
dsk.meta_area_size = new_meta_len;
dsk.meta_block_size = new_meta_hdr->meta_block_size;
uint64_t meta_offset = dsk.meta_block_size;
blockstore_heap_t heap(&dsk, NULL, 0);
heap_entry_t *wr = NULL;
auto get_wr = [&](uint32_t entry_size)
{
if (used_space > new_meta_hdr->meta_block_size-entry_size)
{
if (used_space < new_meta_hdr->meta_block_size-2)
{
*((uint16_t*)(new_meta_buf + meta_offset + used_space)) = FREE_SPACE_BIT | (uint16_t)(new_meta_hdr->meta_block_size-used_space);
}
heap.fill_block_empty_space(new_meta_buf + meta_offset, used_space);
meta_offset += new_meta_hdr->meta_block_size;
used_space = 0;
if (meta_offset >= new_meta_len)
@@ -652,7 +644,7 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
return wr;
};
// FIXME: Use a streaming json parser
if (meta["version"] == "3.0")
if (meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_HEAP)
{
// New format
for (const auto & meta_entry: meta["entries"].array_items())
@@ -680,7 +672,8 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
wr_type = BS_HEAP_ROLLBACK;
else
{
fprintf(stderr, "Write entry in %s has invalid type: %s, skipping\n", write_entry.dump().c_str(), write_entry["type"].dump().c_str());
fprintf(stderr, "Write entry %s has invalid type: %s, aborting\n",
write_entry.dump().c_str(), write_entry["type"].dump().c_str());
close_err0:
free(new_meta_buf);
new_meta_buf = NULL;
@@ -723,8 +716,13 @@ close_err0:
else if (wr_type == BS_HEAP_BIG_WRITE)
{
uint64_t loc = write_entry["location"].uint64_value();
assert(!(loc % dsk.data_block_size));
assert((loc / dsk.data_block_size) < 0xFFFF0000);
if ((loc % dsk.data_block_size) || (loc / dsk.data_block_size) >= 0xFFFF0000)
{
fprintf(stderr, "Write entry %s has invalid location: 0x%jx, aborting\n",
write_entry.dump().c_str(), loc);
free_new_meta();
return 1;
}
wr->set_big_location(&heap, loc);
}
else if (wr_type == BS_HEAP_BIG_INTENT)
@@ -867,13 +865,15 @@ close_err:
}
}
}
if (used_space > 0 && used_space < new_meta_hdr->meta_block_size-2)
{
*((uint16_t*)(new_meta_buf + meta_offset + used_space)) = FREE_SPACE_BIT | (uint16_t)(new_meta_hdr->meta_block_size-used_space);
}
}
while (meta_offset < new_meta_len)
{
heap.fill_block_empty_space(new_meta_buf + meta_offset, used_space);
meta_offset += dsk.meta_block_size;
used_space = 0;
}
int r = resize_write_new_meta();
if (r == 0)
if (new_journal_buf && r == 0)
{
r = resize_write_new_journal();
}
+33 -17
View File
@@ -6,6 +6,25 @@
#include "json_util.h"
#include "osd_id.h"
void disk_tool_t::parse_meta_reserve()
{
meta_reserve_multiple = 2;
meta_reserve_min_size = (uint64_t)1024*1024*1024;
if (options.find("meta_reserve") != options.end())
{
int p1 = options["meta_reserve"].find("x"), p2 = options["meta_reserve"].find(",");
if (p1 >= 0 && p2 >= 0)
{
sscanf(options["meta_reserve"].c_str()+(p1 < p2 ? 0 : p2), "%lf", &meta_reserve_multiple);
meta_reserve_min_size = parse_size(options["meta_reserve"].substr(p1 < p2 ? p2 : 0, p1 < p2 ? options["meta_reserve"].size()-p2 : p2));
}
else if (p1 >= 0)
sscanf(options["meta_reserve"].c_str(), "%lf", &meta_reserve_multiple);
else
meta_reserve_min_size = parse_size(options["meta_reserve"]);
}
}
int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_hdd, json11::Json::object & result)
{
static const char *allow_additional_params[] = {
@@ -144,7 +163,17 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_
dsk.open_journal();
dsk.calc_lengths();
if (dsk.data_device == dsk.meta_device && !new_meta_len)
dsk.data_offset += (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len);
{
uint64_t new_meta_len = dsk.min_meta_len;
if (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP)
{
new_meta_len = dsk.min_meta_len*meta_reserve_multiple;
if (new_meta_len < meta_reserve_min_size)
new_meta_len = meta_reserve_min_size;
new_meta_len = (new_meta_len + dsk.meta_block_size-1) & ~((uint64_t)dsk.meta_block_size-1);
}
dsk.data_offset += new_meta_len;
}
dsk.meta_area_size = (dsk.data_device == dsk.meta_device ? dsk.data_offset : dsk.meta_device_size) - dsk.meta_offset;
sb = json11::Json::object {
{ "meta_format", options["meta_format"] },
@@ -562,24 +591,10 @@ int disk_tool_t::get_meta_partition(std::vector<vitastor_dev_info_t> & ssds, std
return 1;
}
// Leave some extra space for future metadata formats and round metadata area size to multiples of 1 MB
uint64_t meta_reserve_multiple = 2, min_meta_size = (uint64_t)1024*1024*1024;
if (options.find("meta_reserve") != options.end())
{
int p1 = options["meta_reserve"].find("x"), p2 = options["meta_reserve"].find(",");
if (p1 >= 0 && p2 >= 0)
{
meta_reserve_multiple = stoull_full(options["meta_reserve"].substr(p1 < p2 ? 0 : p2, p1 - (p1 < p2 ? 0 : p2)));
min_meta_size = parse_size(options["meta_reserve"].substr(p1 < p2 ? p2 : 0, p1 < p2 ? options["meta_reserve"].size()-p2 : p2));
}
else if (p1 >= 0)
meta_reserve_multiple = stoull_full(options["meta_reserve"].substr(0, p1));
else
min_meta_size = parse_size(options["meta_reserve"]);
}
meta_size = ((meta_size+1024*1024-1)/1024/1024)*1024*1024;
meta_size *= meta_reserve_multiple;
if (meta_size < min_meta_size)
meta_size = min_meta_size;
if (meta_size < meta_reserve_min_size)
meta_size = meta_reserve_min_size;
// Pick an SSD for journal&meta, balancing the number of serviced OSDs across SSDs
int sel = -1;
for (int i = 0; i < ssds.size(); i++)
@@ -610,6 +625,7 @@ int disk_tool_t::get_meta_partition(std::vector<vitastor_dev_info_t> & ssds, std
int disk_tool_t::prepare(std::vector<std::string> devices)
{
parse_meta_reserve();
if (options.find("data_device") != options.end() && options["data_device"] != "")
{
if (options.find("hybrid") != options.end() ||
+21 -8
View File
@@ -25,6 +25,7 @@ struct resizer_data_moving_t
int disk_tool_t::raw_resize()
{
int r;
parse_meta_reserve();
// Parse parameters
r = resize_parse_params();
if (r != 0)
@@ -225,17 +226,28 @@ void disk_tool_t::resize_init(blockstore_meta_header_v3_t *hdr)
new_data_csum_size = (dsk.data_csum_type
? ((dsk.data_block_size+dsk.csum_block_size-1)/dsk.csum_block_size*(dsk.data_csum_type & 0xFF))
: 0);
new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size;
new_entries_per_block = dsk.meta_block_size/new_clean_entry_size;
uint64_t new_meta_blocks = 1 + (new_data_len/dsk.data_block_size + new_entries_per_block-1) / new_entries_per_block;
if (!new_meta_len)
if (new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
{
new_meta_len = dsk.meta_block_size*new_meta_blocks;
new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size;
new_entries_per_block = dsk.meta_block_size/new_clean_entry_size;
uint64_t new_meta_blocks = 1 + (new_data_len/dsk.data_block_size + new_entries_per_block-1) / new_entries_per_block;
if (!new_meta_len)
{
new_meta_len = dsk.meta_block_size*new_meta_blocks;
}
if (new_meta_len < dsk.meta_block_size*new_meta_blocks)
{
fprintf(stderr, "New metadata area size is too small, should be at least %ju bytes\n", dsk.meta_block_size*new_meta_blocks);
exit(1);
}
}
if (new_meta_len < dsk.meta_block_size*new_meta_blocks)
else
{
fprintf(stderr, "New metadata area size is too small, should be at least %ju bytes\n", dsk.meta_block_size*new_meta_blocks);
exit(1);
new_clean_entry_size = new_entries_per_block = 0;
if (!new_meta_len)
{
new_meta_len = dsk.meta_area_size;
}
}
// Check that new metadata, journal and data areas don't overlap
if (new_meta_device == dsk.data_device && new_meta_offset < new_data_offset+new_data_len &&
@@ -631,6 +643,7 @@ int disk_tool_t::resize_rebuild_meta()
new_meta_hdr->data_csum_type = dsk.data_csum_type;
new_meta_hdr->csum_block_size = dsk.csum_block_size;
new_meta_hdr->completed_lsn = hdr->completed_lsn;
new_meta_hdr->meta_area_size = new_meta_len;
new_meta_hdr->header_csum = 0;
new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, new_meta_hdr->version == BLOCKSTORE_META_FORMAT_HEAP
? sizeof(blockstore_meta_header_v3_t) : sizeof(blockstore_meta_header_v2_t));
+3 -1
View File
@@ -8,6 +8,7 @@
int disk_tool_t::resize_data(std::string device)
{
parse_meta_reserve();
if (options.find("move_journal") == options.end() &&
options.find("move_data") == options.end() &&
options.find("journal_size") == options.end() &&
@@ -83,7 +84,8 @@ int disk_tool_t::resize_data(std::string device)
? move_options["new_meta_device"] : dsk.meta_device;
// Calculate new data & meta offsets
if (!new_meta_len)
new_meta_len = (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len);
new_meta_len = (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.meta_area_size : dsk.min_meta_len);
move_options["new_meta_len"] = std::to_string(new_meta_len);
new_data_offset = 4096 + (new_journal_device == dsk.data_device ? new_journal_len : 0) +
(new_meta_device == dsk.data_device ? new_meta_len : 0);
new_data_offset += ((dsk.data_offset-new_data_offset) % dsk.data_block_size);