WIP dump/load heap
This commit is contained in:
@@ -228,11 +228,11 @@ void blockstore_disk_t::calc_lengths()
|
||||
{
|
||||
// data
|
||||
data_len = data_device_size - data_offset;
|
||||
if (data_fd == meta_fd && data_offset < meta_offset)
|
||||
if (data_device == meta_device && data_offset < meta_offset)
|
||||
{
|
||||
data_len = meta_offset - data_offset;
|
||||
}
|
||||
if (data_fd == journal_fd && data_offset < journal_offset)
|
||||
if (data_device == journal_device && data_offset < journal_offset)
|
||||
{
|
||||
data_len = data_len < journal_offset-data_offset
|
||||
? data_len : journal_offset-data_offset;
|
||||
@@ -247,23 +247,23 @@ void blockstore_disk_t::calc_lengths()
|
||||
data_len = cfg_data_size;
|
||||
}
|
||||
// meta
|
||||
meta_area_size = (meta_fd == data_fd ? data_device_size : meta_device_size) - meta_offset;
|
||||
if (meta_fd == data_fd && meta_offset <= data_offset)
|
||||
meta_area_size = (meta_device == data_device ? data_device_size : meta_device_size) - meta_offset;
|
||||
if (meta_device == data_device && meta_offset <= data_offset)
|
||||
{
|
||||
meta_area_size = data_offset - meta_offset;
|
||||
}
|
||||
if (meta_fd == journal_fd && meta_offset <= journal_offset)
|
||||
if (meta_device == journal_device && meta_offset <= journal_offset)
|
||||
{
|
||||
meta_area_size = meta_area_size < journal_offset-meta_offset
|
||||
? meta_area_size : journal_offset-meta_offset;
|
||||
}
|
||||
// journal
|
||||
journal_len = (journal_fd == data_fd ? data_device_size : (journal_fd == meta_fd ? meta_device_size : journal_device_size)) - journal_offset;
|
||||
if (journal_fd == data_fd && journal_offset <= data_offset)
|
||||
journal_len = (journal_device == data_device ? data_device_size : (journal_device == meta_device ? meta_device_size : journal_device_size)) - journal_offset;
|
||||
if (journal_device == data_device && journal_offset <= data_offset)
|
||||
{
|
||||
journal_len = data_offset - journal_offset;
|
||||
}
|
||||
if (journal_fd == meta_fd && journal_offset <= meta_offset)
|
||||
if (journal_device == meta_device && journal_offset <= meta_offset)
|
||||
{
|
||||
journal_len = journal_len < meta_offset-journal_offset
|
||||
? journal_len : meta_offset-journal_offset;
|
||||
|
||||
@@ -1285,18 +1285,11 @@ void blockstore_heap_t::allocate_block(heap_block_info_t & inf)
|
||||
}
|
||||
}
|
||||
|
||||
int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block)
|
||||
int blockstore_heap_t::allocate_new_object(object_id oid, uint32_t full_object_size, uint32_t *modified_block, heap_object_t **new_obj)
|
||||
{
|
||||
// By now, initial small_writes are not allowed
|
||||
if (wr->type() != BS_HEAP_BIG_WRITE &&
|
||||
wr->type() != BS_HEAP_TOMBSTONE)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
const uint32_t wr_size = wr->get_size(this);
|
||||
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
|
||||
uint32_t block_num = 0;
|
||||
int res = get_block_for_new_object(block_num, sizeof(heap_object_t)+wr_size+max_write_entry_size);
|
||||
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
|
||||
int res = get_block_for_new_object(block_num, full_object_size+max_write_entry_size);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
@@ -1307,27 +1300,66 @@ int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *mod
|
||||
{
|
||||
*modified_block = block_num;
|
||||
}
|
||||
const uint32_t offset = find_block_space(block_num, sizeof(heap_object_t)+wr_size);
|
||||
const uint32_t offset = find_block_space(block_num, full_object_size);
|
||||
if (offset == UINT32_MAX)
|
||||
{
|
||||
return ENOSPC;
|
||||
}
|
||||
add_used_space(block_num, full_object_size);
|
||||
block_index[get_pg_id(oid.inode, oid.stripe)][oid.inode][oid.stripe] = (uint64_t)block_num*dsk->meta_block_size + offset;
|
||||
// and just append the object entry
|
||||
heap_object_t *new_entry = (heap_object_t *)(inf.data + offset);
|
||||
new_entry->write_pos = sizeof(heap_object_t);
|
||||
new_entry->inode = oid.inode;
|
||||
new_entry->stripe = oid.stripe;
|
||||
heap_write_t *new_wr = new_entry->get_writes();
|
||||
*new_obj = (heap_object_t *)(inf.data + offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block)
|
||||
{
|
||||
// By now, initial small_writes are not allowed
|
||||
if (wr->type() != BS_HEAP_BIG_WRITE &&
|
||||
wr->type() != BS_HEAP_TOMBSTONE)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
const uint32_t wr_size = wr->get_size(this);
|
||||
heap_object_t *new_obj = NULL;
|
||||
int res = allocate_new_object(oid, sizeof(heap_object_t)+wr_size, modified_block, &new_obj);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
// Fill the object entry
|
||||
new_obj->size = sizeof(heap_object_t);
|
||||
new_obj->write_pos = sizeof(heap_object_t);
|
||||
new_obj->inode = oid.inode;
|
||||
new_obj->stripe = oid.stripe;
|
||||
heap_write_t *new_wr = new_obj->get_writes();
|
||||
memcpy(new_wr, wr, wr_size);
|
||||
new_wr->next_pos = 0;
|
||||
new_wr->size = wr_size;
|
||||
new_wr->lsn = ++next_lsn;
|
||||
wr->lsn = new_wr->lsn;
|
||||
push_inflight_lsn(oid, new_wr->lsn, new_wr->needs_compact(this) ? HEAP_INFLIGHT_COMPACTABLE : 0);
|
||||
new_entry->size = sizeof(heap_object_t);
|
||||
new_entry->crc32c = new_entry->calc_crc32c();
|
||||
add_used_space(block_num, sizeof(heap_object_t) + wr_size);
|
||||
new_obj->crc32c = new_obj->calc_crc32c();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blockstore_heap_t::copy_object(heap_object_t *obj, uint32_t *modified_block)
|
||||
{
|
||||
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
|
||||
auto oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
||||
assert(!read_entry(oid, NULL));
|
||||
uint32_t full_object_size = obj->size;
|
||||
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
full_object_size += wr->size;
|
||||
}
|
||||
heap_object_t *new_obj = NULL;
|
||||
int res = allocate_new_object(oid, full_object_size, modified_block, &new_obj);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
copy_full_object((uint8_t*)new_obj, obj);
|
||||
new_obj->crc32c = new_obj->calc_crc32c();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +215,7 @@ class blockstore_heap_t
|
||||
bool mvcc_check_tracking(object_id oid);
|
||||
void free_mvcc(heap_mvcc_map_t::iterator mvcc_it);
|
||||
void allocate_block(heap_block_info_t & inf);
|
||||
int allocate_new_object(object_id oid, uint32_t full_object_size, uint32_t *modified_block, heap_object_t **new_obj);
|
||||
int add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block);
|
||||
void mark_overwritten(uint64_t over_lsn, uint64_t inode, heap_write_t *wr, heap_write_t *end_wr, bool tracking_active);
|
||||
int update_object(uint32_t block_num, heap_object_t *obj, heap_write_t *wr, uint32_t *modified_block, uint32_t *moved_from_block);
|
||||
@@ -268,6 +269,8 @@ public:
|
||||
bool calc_block_checksums(uint32_t *block_csums, uint8_t *bitmap,
|
||||
uint32_t start, uint32_t end, std::function<uint8_t*(uint32_t start, uint32_t & len)> next,
|
||||
bool set, std::function<void(uint32_t, uint32_t, uint32_t)> bad_block_cb);
|
||||
// copy an object as is
|
||||
int copy_object(heap_object_t *obj, uint32_t *modified_block);
|
||||
// auto-compacts the object, then adds a write entry to it and to the compaction queue
|
||||
// return 0 if OK, or maybe ENOSPC
|
||||
int post_write(object_id oid, heap_write_t *wr, uint32_t *modified_block, uint32_t *moved_from_block);
|
||||
|
||||
@@ -355,7 +355,8 @@ void blockstore_impl_t::dump_diagnostics()
|
||||
void blockstore_meta_header_v3_t::set_crc32c()
|
||||
{
|
||||
header_csum = 0;
|
||||
uint32_t calc = crc32c(0, this, sizeof(*this));
|
||||
uint32_t calc = crc32c(0, this, version == BLOCKSTORE_META_FORMAT_HEAP
|
||||
? sizeof(blockstore_meta_header_v3_t) : sizeof(blockstore_meta_header_v2_t));
|
||||
header_csum = calc;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ add_executable(vitastor-disk
|
||||
disk_tool.cpp disk_simple_offsets.cpp
|
||||
disk_tool_discard.cpp disk_tool_journal.cpp disk_tool_meta.cpp disk_tool_prepare.cpp disk_tool_resize.cpp
|
||||
disk_tool_resize_auto.cpp disk_tool_udev.cpp disk_tool_utils.cpp disk_tool_upgrade.cpp
|
||||
../util/crc32c.c ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp ../util/rw_blocking.cpp ../util/allocator.cpp ../util/ringloop.cpp ../blockstore/blockstore_disk.cpp
|
||||
../util/crc32c.c ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp ../util/rw_blocking.cpp ../util/allocator.cpp ../util/ringloop.cpp
|
||||
../blockstore/blockstore_disk.cpp ../blockstore/blockstore_heap.cpp ../blockstore/multilist.cpp
|
||||
)
|
||||
target_link_libraries(vitastor-disk
|
||||
tcmalloc_minimal
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "blockstore.h"
|
||||
#include "blockstore_disk.h"
|
||||
#include "blockstore_heap.h"
|
||||
#include "ondisk_formats.h"
|
||||
|
||||
// Calculate offsets for a block device and print OSD command line parameters
|
||||
void disk_tool_simple_offsets(json11::Json cfg, bool json_output)
|
||||
|
||||
+34
-18
@@ -192,12 +192,12 @@ static const char *help_text =
|
||||
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
|
||||
"\n"
|
||||
"vitastor-disk dump-meta <osd_device>\n"
|
||||
"vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>\n"
|
||||
"vitastor-disk dump-meta [osd_options...]\n"
|
||||
" Dump metadata in JSON format.\n"
|
||||
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
|
||||
"\n"
|
||||
"vitastor-disk write-meta <osd_device>\n"
|
||||
"vitastor-disk write-meta <meta_file> <offset> <size>\n"
|
||||
"vitastor-disk write-meta [osd_options...]\n"
|
||||
" Write metadata from JSON taken from standard input in the same format as produced by `dump-meta`.\n"
|
||||
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
|
||||
"\n"
|
||||
@@ -364,48 +364,64 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else if (!strcmp(cmd[0], "dump-meta"))
|
||||
{
|
||||
if (cmd.size() != 2 && cmd.size() < 5)
|
||||
{
|
||||
print_help(help_text, "vitastor-disk", cmd[0], false);
|
||||
return 1;
|
||||
}
|
||||
self.dsk.meta_device = cmd[1];
|
||||
if (cmd.size() > 2)
|
||||
if (cmd.size() == 5)
|
||||
{
|
||||
// Old format
|
||||
self.dsk.meta_device = cmd[1];
|
||||
self.dsk.meta_block_size = strtoul(cmd[2], NULL, 10);
|
||||
self.dsk.meta_offset = strtoull(cmd[3], NULL, 10);
|
||||
self.dsk.meta_area_size = strtoull(cmd[4], NULL, 10);
|
||||
}
|
||||
else
|
||||
else if (cmd.size() == 2)
|
||||
{
|
||||
// First argument is an OSD device - take metadata layout parameters from it
|
||||
self.dsk.meta_device = cmd[1];
|
||||
if (self.dump_load_check_superblock(self.dsk.meta_device))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse all OSD options from cmdline
|
||||
self.dsk.parse_config(self.options);
|
||||
if (self.options["io"] != "")
|
||||
self.dsk.data_io = self.dsk.meta_io = self.dsk.journal_io = self.options["io"];
|
||||
// FIXME: This is a really repeated pattern, move it somewhere
|
||||
self.dsk.open_data();
|
||||
self.dsk.open_meta();
|
||||
self.dsk.open_journal();
|
||||
self.dsk.calc_lengths();
|
||||
self.dsk.close_all();
|
||||
}
|
||||
return self.dump_meta();
|
||||
}
|
||||
else if (!strcmp(cmd[0], "write-meta"))
|
||||
{
|
||||
if (cmd.size() != 2 && cmd.size() < 4)
|
||||
{
|
||||
print_help(help_text, "vitastor-disk", cmd[0], false);
|
||||
return 1;
|
||||
}
|
||||
self.new_meta_device = cmd[1];
|
||||
if (cmd.size() > 2)
|
||||
if (cmd.size() == 4)
|
||||
{
|
||||
self.new_meta_device = cmd[1];
|
||||
self.new_meta_offset = strtoull(cmd[2], NULL, 10);
|
||||
self.new_meta_len = strtoull(cmd[3], NULL, 10);
|
||||
}
|
||||
else
|
||||
else if (cmd.size() == 2)
|
||||
{
|
||||
// First argument is an OSD device - take metadata layout parameters from it
|
||||
self.new_meta_device = cmd[1];
|
||||
if (self.dump_load_check_superblock(self.new_meta_device))
|
||||
return 1;
|
||||
self.new_meta_device = self.dsk.meta_device;
|
||||
self.new_meta_offset = self.dsk.meta_offset;
|
||||
self.new_meta_len = self.dsk.meta_area_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse all OSD options from cmdline
|
||||
self.dsk.parse_config(self.options);
|
||||
self.dsk.open_data();
|
||||
self.dsk.open_meta();
|
||||
self.dsk.open_journal();
|
||||
self.dsk.calc_lengths();
|
||||
self.dsk.close_all();
|
||||
}
|
||||
std::string json_err;
|
||||
json11::Json meta = json11::Json::parse(read_all_fd(0), json_err);
|
||||
if (json_err != "")
|
||||
|
||||
+32
-13
@@ -16,6 +16,7 @@
|
||||
#include "json11/json11.hpp"
|
||||
#include "blockstore_disk.h"
|
||||
#include "blockstore.h"
|
||||
#include "blockstore_heap.h"
|
||||
#include "ondisk_formats.h"
|
||||
#include "crc32c.h"
|
||||
#include "allocator.h"
|
||||
@@ -46,7 +47,9 @@ struct disk_tool_t
|
||||
std::map<std::string, std::string> options;
|
||||
bool test_mode = false;
|
||||
bool all = false, json = false, now = false;
|
||||
bool dump_with_blocks, dump_with_data;
|
||||
bool dump_with_blocks = false, dump_with_data = false;
|
||||
bool dump_as_old = false;
|
||||
int log_level = 1;
|
||||
blockstore_disk_t dsk;
|
||||
|
||||
// resize data and/or move metadata and journal
|
||||
@@ -61,25 +64,30 @@ struct disk_tool_t
|
||||
uint64_t meta_pos;
|
||||
uint64_t journal_pos, journal_calc_data_pos;
|
||||
|
||||
uint8_t *buffer_area = NULL;
|
||||
bool first_block, first_entry;
|
||||
|
||||
allocator_t *data_alloc;
|
||||
allocator_t *data_alloc = NULL;
|
||||
std::map<uint64_t, uint64_t> data_remap;
|
||||
std::map<uint64_t, uint64_t>::iterator remap_it;
|
||||
ring_loop_t *ringloop;
|
||||
ring_loop_t *ringloop = NULL;
|
||||
ring_consumer_t ring_consumer;
|
||||
int remap_active;
|
||||
journal_entry_start je_start;
|
||||
uint8_t *new_journal_buf, *new_meta_buf, *new_journal_ptr, *new_journal_data;
|
||||
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;
|
||||
blockstore_disk_t new_dsk;
|
||||
blockstore_heap_t *new_heap = 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;
|
||||
int new_journal_fd, new_meta_fd;
|
||||
resizer_data_moving_t *moving_blocks;
|
||||
uint32_t new_meta_format = 0;
|
||||
int new_journal_fd = -1, new_meta_fd = -1;
|
||||
resizer_data_moving_t *moving_blocks = NULL;
|
||||
|
||||
bool started;
|
||||
void *small_write_data;
|
||||
void *small_write_data = NULL;
|
||||
uint32_t data_crc32;
|
||||
bool data_csum_valid;
|
||||
uint32_t crc32_last;
|
||||
@@ -91,17 +99,24 @@ struct disk_tool_t
|
||||
void dump_journal_entry(int num, journal_entry *je, bool json);
|
||||
int process_journal(std::function<int(void*)> block_fn, bool do_open = true);
|
||||
int process_journal_block(void *buf, std::function<void(int, journal_entry*)> iter_fn);
|
||||
int process_meta(std::function<void(blockstore_meta_header_v2_t *)> hdr_fn,
|
||||
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn, bool do_open = true);
|
||||
int process_meta(std::function<void(blockstore_meta_header_v3_t *)> hdr_fn,
|
||||
std::function<void(blockstore_heap_t *heap, heap_object_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,
|
||||
bool with_data, bool do_open);
|
||||
|
||||
int dump_meta();
|
||||
void dump_meta_header(blockstore_meta_header_v2_t *hdr);
|
||||
void dump_meta_header(blockstore_meta_header_v3_t *hdr);
|
||||
void dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap);
|
||||
void dump_heap_entry_as_old(blockstore_heap_t *heap, heap_object_t *obj);
|
||||
void dump_heap_entry(blockstore_heap_t *heap, heap_object_t *obj);
|
||||
|
||||
int dump_load_check_superblock(const std::string & device);
|
||||
|
||||
int write_json_journal(json11::Json entries);
|
||||
int write_json_meta(json11::Json meta);
|
||||
int write_json_heap(json11::Json meta, json11::Json journal);
|
||||
int index_journal_by_object(json11::Json journal,
|
||||
std::map<object_id, std::vector<json11::Json::object>> & journal_by_object);
|
||||
|
||||
int resize_data(std::string device);
|
||||
int resize_parse_move_journal(std::map<std::string, std::string> & move_options, bool dry_run);
|
||||
@@ -109,13 +124,17 @@ struct disk_tool_t
|
||||
|
||||
int raw_resize();
|
||||
int resize_parse_params();
|
||||
void resize_init(blockstore_meta_header_v2_t *hdr);
|
||||
void resize_init(blockstore_meta_header_v3_t *hdr);
|
||||
int resize_remap_blocks();
|
||||
int resize_copy_data();
|
||||
int resize_rewrite_journal();
|
||||
void resize_alloc_journal();
|
||||
void build_journal_start();
|
||||
void choose_journal_block(uint32_t je_size);
|
||||
int resize_rebuild_journal();
|
||||
int resize_write_new_journal();
|
||||
int resize_rewrite_meta();
|
||||
int resize_rebuild_meta();
|
||||
int resize_write_new_meta();
|
||||
void free_new_meta();
|
||||
|
||||
int udev_import(std::string device);
|
||||
int read_sb(std::string device);
|
||||
|
||||
@@ -54,12 +54,22 @@ int disk_tool_t::trim_data(std::string device)
|
||||
fprintf(stderr, "Reading metadata\n");
|
||||
data_alloc = new allocator_t(dsk.block_count);
|
||||
r = process_meta(
|
||||
[this](blockstore_meta_header_v2_t *hdr) {},
|
||||
[this](blockstore_meta_header_v3_t *hdr) {},
|
||||
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
|
||||
{
|
||||
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
|
||||
{
|
||||
data_alloc->set(wr->location / dsk.data_block_size, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
data_alloc->set(block_num, true);
|
||||
},
|
||||
false
|
||||
false, false
|
||||
);
|
||||
if (r != 0)
|
||||
{
|
||||
|
||||
@@ -7,37 +7,116 @@
|
||||
#include "json_util.h"
|
||||
#include "malloc_or_die.h"
|
||||
|
||||
int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)> hdr_fn,
|
||||
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn, bool do_open)
|
||||
#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_object_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,
|
||||
bool with_data, bool do_open)
|
||||
{
|
||||
int r = 0;
|
||||
if (dsk.meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
{
|
||||
fprintf(stderr, "Invalid metadata block size: is not a multiple of %d\n", DIRECT_IO_ALIGNMENT);
|
||||
return 1;
|
||||
}
|
||||
int buf_size = 1024*1024;
|
||||
if (buf_size % dsk.meta_block_size)
|
||||
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;
|
||||
if (do_open)
|
||||
{
|
||||
if (dsk.meta_fd >= 0)
|
||||
{
|
||||
fprintf(stderr, "Bug: Metadata device is already opened\n");
|
||||
return 1;
|
||||
close_error:
|
||||
r = 1;
|
||||
goto close_free;
|
||||
}
|
||||
dsk.meta_fd = open(dsk.meta_device.c_str(), (options["io"] == "cached" ? 0 : O_DIRECT) | O_RDONLY);
|
||||
if (dsk.meta_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open metadata device %s: %s\n", dsk.meta_device.c_str(), strerror(errno));
|
||||
return 1;
|
||||
goto close_error;
|
||||
}
|
||||
}
|
||||
int buf_size = 1024*1024;
|
||||
if (buf_size % dsk.meta_block_size)
|
||||
buf_size = 8*dsk.meta_block_size;
|
||||
void *data = memalign_or_die(MEM_ALIGNMENT, buf_size);
|
||||
else if (dsk.meta_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Bug: Metadata device is not opened\n");
|
||||
goto close_error;
|
||||
}
|
||||
// Check superblock
|
||||
blockstore_meta_header_v2_t *hdr = (blockstore_meta_header_v2_t *)data;
|
||||
lseek64(dsk.meta_fd, dsk.meta_offset, 0);
|
||||
read_blocking(dsk.meta_fd, hdr, dsk.meta_block_size);
|
||||
if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1)
|
||||
if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1 && hdr->version == BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
if (hdr->data_csum_type != 0 &&
|
||||
hdr->data_csum_type != BLOCKSTORE_CSUM_CRC32C)
|
||||
{
|
||||
goto csum_unknown;
|
||||
}
|
||||
if (!dsk.journal_len && !with_data)
|
||||
{
|
||||
fprintf(stderr, "Buffer area (former journal) location must be specified to dump \"heap\" with data\n");
|
||||
goto close_error;
|
||||
}
|
||||
// Load buffer_area
|
||||
if (with_data)
|
||||
{
|
||||
buffer_area = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, dsk.journal_len);
|
||||
if (dsk.journal_device == dsk.meta_device || dsk.journal_device == "")
|
||||
{
|
||||
dsk.journal_fd = dsk.meta_fd;
|
||||
}
|
||||
else if (do_open)
|
||||
{
|
||||
if (dsk.journal_fd >= 0)
|
||||
{
|
||||
fprintf(stderr, "Bug: Metadata device is already opened\n");
|
||||
goto close_error;
|
||||
}
|
||||
dsk.journal_fd = open(dsk.journal_device.c_str(), (options["io"] == "cached" ? 0 : O_DIRECT) | O_RDONLY);
|
||||
if (dsk.journal_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open journal device %s: %s\n", dsk.journal_device.c_str(), strerror(errno));
|
||||
goto close_error;
|
||||
}
|
||||
}
|
||||
else if (dsk.journal_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Bug: journal device is not opened\n");
|
||||
goto close_error;
|
||||
}
|
||||
uint64_t journal_pos = 0;
|
||||
lseek64(dsk.journal_fd, dsk.journal_offset+journal_pos, 0);
|
||||
while (journal_pos < dsk.journal_len)
|
||||
{
|
||||
uint64_t read_len = buf_size < dsk.journal_len-journal_pos ? buf_size : dsk.journal_len-journal_pos;
|
||||
read_blocking(dsk.journal_fd, buffer_area+journal_pos, read_len);
|
||||
journal_pos += read_len;
|
||||
}
|
||||
}
|
||||
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;
|
||||
meta_pos = dsk.meta_block_size;
|
||||
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
|
||||
while (meta_pos < dsk.meta_area_size)
|
||||
{
|
||||
uint64_t read_len = buf_size < dsk.meta_area_size-meta_pos ? buf_size : dsk.meta_area_size-meta_pos;
|
||||
read_blocking(dsk.meta_fd, data, read_len);
|
||||
heap->read_blocks(meta_pos-dsk.meta_block_size, read_len, data, [&](heap_object_t *obj)
|
||||
{
|
||||
obj_fn(heap, obj, ((uint8_t*)obj-data+meta_pos)/dsk.meta_block_size);
|
||||
}, [](uint32_t, uint32_t, uint8_t*){});
|
||||
meta_pos += read_len;
|
||||
}
|
||||
delete heap;
|
||||
}
|
||||
else if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1)
|
||||
{
|
||||
dsk.meta_format = hdr->version;
|
||||
dsk.calc_lengths();
|
||||
@@ -55,27 +134,16 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
|
||||
if (hdr->data_csum_type != 0 &&
|
||||
hdr->data_csum_type != BLOCKSTORE_CSUM_CRC32C)
|
||||
{
|
||||
csum_unknown:
|
||||
fprintf(stderr, "I don't know checksum format %u, the only supported format is crc32c = %u.\n", hdr->data_csum_type, BLOCKSTORE_CSUM_CRC32C);
|
||||
free(data);
|
||||
if (do_open)
|
||||
{
|
||||
close(dsk.meta_fd);
|
||||
dsk.meta_fd = -1;
|
||||
}
|
||||
return 1;
|
||||
goto close_error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unsupported version
|
||||
fprintf(stderr, "Metadata format is too new for me (stored version is %ju, max supported %u).\n", hdr->version, BLOCKSTORE_META_FORMAT_V2);
|
||||
free(data);
|
||||
if (do_open)
|
||||
{
|
||||
close(dsk.meta_fd);
|
||||
dsk.meta_fd = -1;
|
||||
}
|
||||
return 1;
|
||||
goto close_error;
|
||||
}
|
||||
if (hdr->meta_block_size != dsk.meta_block_size)
|
||||
{
|
||||
@@ -100,9 +168,9 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
|
||||
hdr = NULL;
|
||||
meta_pos = dsk.meta_block_size;
|
||||
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
|
||||
while (meta_pos < dsk.meta_area_size)
|
||||
while (meta_pos < dsk.min_meta_len)
|
||||
{
|
||||
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 < dsk.min_meta_len-meta_pos ? buf_size : dsk.min_meta_len-meta_pos;
|
||||
read_blocking(dsk.meta_fd, data, read_len);
|
||||
meta_pos += read_len;
|
||||
for (uint64_t blk = 0; blk < read_len; blk += dsk.meta_block_size)
|
||||
@@ -117,7 +185,7 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
|
||||
uint32_t *entry_csum = (uint32_t*)((uint8_t*)entry + dsk.clean_entry_size - 4);
|
||||
if (*entry_csum != crc32c(0, entry, dsk.clean_entry_size - 4))
|
||||
{
|
||||
fprintf(stderr, "Metadata entry %ju is corrupt (checksum mismatch), skipping\n", block_num);
|
||||
fprintf(stderr, "Metadata entry %lu is corrupt (checksum mismatch), skipping\n", block_num);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -153,13 +221,25 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
|
||||
}
|
||||
}
|
||||
}
|
||||
close_free:
|
||||
free(data);
|
||||
if (buffer_area)
|
||||
{
|
||||
free(buffer_area);
|
||||
buffer_area = NULL;
|
||||
}
|
||||
if (do_open)
|
||||
{
|
||||
close(dsk.meta_fd);
|
||||
dsk.meta_fd = -1;
|
||||
if (dsk.journal_fd >= 0)
|
||||
{
|
||||
if (dsk.journal_fd != dsk.meta_fd)
|
||||
close(dsk.journal_fd);
|
||||
dsk.journal_fd = -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int disk_tool_t::dump_load_check_superblock(const std::string & device)
|
||||
@@ -190,15 +270,33 @@ int disk_tool_t::dump_load_check_superblock(const std::string & device)
|
||||
int disk_tool_t::dump_meta()
|
||||
{
|
||||
int r = process_meta(
|
||||
[this](blockstore_meta_header_v2_t *hdr) { dump_meta_header(hdr); },
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap) { dump_meta_entry(block_num, entry, bitmap); }
|
||||
[this](blockstore_meta_header_v3_t *hdr)
|
||||
{
|
||||
if (dump_as_old)
|
||||
{
|
||||
hdr->version = BLOCKSTORE_META_FORMAT_V2;
|
||||
hdr->compacted_lsn = 0;
|
||||
hdr->header_csum = 0;
|
||||
hdr->header_csum = crc32c(0, hdr, sizeof(blockstore_meta_header_v2_t));
|
||||
}
|
||||
dump_meta_header(hdr);
|
||||
},
|
||||
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
|
||||
{
|
||||
if (dump_as_old)
|
||||
dump_heap_entry_as_old(heap, obj);
|
||||
else
|
||||
dump_heap_entry(heap, obj);
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap) { dump_meta_entry(block_num, entry, bitmap); },
|
||||
true, true
|
||||
);
|
||||
if (r == 0)
|
||||
printf("\n]}\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
|
||||
void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr)
|
||||
{
|
||||
if (hdr)
|
||||
{
|
||||
@@ -219,6 +317,15 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
|
||||
csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size
|
||||
);
|
||||
}
|
||||
else if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
printf(
|
||||
"{\"version\":\"3.0\",\"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
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,6 +334,125 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
|
||||
first_entry = true;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_heap_entry_as_old(blockstore_heap_t *heap, heap_object_t *obj)
|
||||
{
|
||||
heap_write_t *wr = NULL;
|
||||
for (wr = obj->get_writes(); wr && wr->flags != (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE) &&
|
||||
wr->flags != (BS_HEAP_TOMBSTONE|BS_HEAP_STABLE); wr = wr->next())
|
||||
{
|
||||
}
|
||||
if (!wr || wr->flags != (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%ju,\"pool\":%u,\"inode\":\"0x%jx\",\"stripe\":\"0x%jx\",\"version\":%ju"
|
||||
(first_entry ? ENTRY_FMT : (",\n" ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
wr->location/dsk.data_block_size, INODE_POOL(obj->inode), INODE_NO_POOL(obj->inode),
|
||||
obj->stripe, wr->version
|
||||
);
|
||||
printf(",\"bitmap\":\"");
|
||||
uint8_t* bitmap = wr->get_int_bitmap(heap);
|
||||
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", bitmap[i]);
|
||||
}
|
||||
bitmap = wr->get_ext_bitmap(heap);
|
||||
printf("\",\"ext_bitmap\":\"");
|
||||
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", bitmap[i]);
|
||||
}
|
||||
uint8_t *csums = wr->get_checksums(heap);
|
||||
uint32_t csum_size = wr->get_csum_size(heap);
|
||||
if (csums)
|
||||
{
|
||||
printf("\",\"block_csums\":\"");
|
||||
for (uint32_t i = 0; i < csum_size; i++)
|
||||
{
|
||||
printf("%02x", csums[i]);
|
||||
}
|
||||
}
|
||||
if (wr->get_checksum(heap))
|
||||
{
|
||||
printf("\",\"crc32c\":\"%08x", *wr->get_checksum(heap));
|
||||
}
|
||||
printf("\"}");
|
||||
first_entry = false;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_heap_entry(blockstore_heap_t *heap, heap_object_t *obj)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"pool\":%u,\"inode\":\"0x%jx\",\"stripe\":\"0x%jx\",\"writes\":["
|
||||
(first_entry ? ENTRY_FMT : (",\n" ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
INODE_POOL(obj->inode), INODE_NO_POOL(obj->inode), obj->stripe
|
||||
);
|
||||
heap_write_t *wr = NULL;
|
||||
bool first_wr = true;
|
||||
for (wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"lsn\":%ju,\"version\":%ju,\"type\":\"%s\",\"stable\":%s,\"offset\":%u,\"len\":%u"
|
||||
(first_wr ? ENTRY_FMT : ("," ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
wr->lsn, wr->version, (wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? "small" : (
|
||||
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE ? "big" : (
|
||||
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_INTENT_WRITE ? "intent" : (
|
||||
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_TOMBSTONE ? "tombstone" : "unknown"))),
|
||||
(wr->flags & BS_HEAP_STABLE) ? "true" : "false",
|
||||
wr->offset, wr->len
|
||||
);
|
||||
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE ||
|
||||
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE && !dump_with_data)
|
||||
{
|
||||
printf(",\"location\":%ju", wr->location);
|
||||
}
|
||||
else if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE && dump_with_data)
|
||||
{
|
||||
printf(",\"data\":\"");
|
||||
for (uint32_t i = 0; i < wr->len; i++)
|
||||
printf("%02x", buffer_area[wr->location + i]);
|
||||
printf("\"");
|
||||
}
|
||||
uint8_t* bitmap = wr->get_int_bitmap(heap);
|
||||
if (bitmap)
|
||||
{
|
||||
printf(",\"bitmap\":\"");
|
||||
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
|
||||
printf("%02x", bitmap[i]);
|
||||
printf("\"");
|
||||
}
|
||||
bitmap = wr->get_ext_bitmap(heap);
|
||||
if (bitmap)
|
||||
{
|
||||
printf(",\"ext_bitmap\":\"");
|
||||
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
|
||||
printf("%02x", bitmap[i]);
|
||||
printf("\"");
|
||||
}
|
||||
uint8_t *csums = wr->get_checksums(heap);
|
||||
if (csums)
|
||||
{
|
||||
printf(",\"block_csums\":\"");
|
||||
uint32_t csum_size = wr->get_csum_size(heap);
|
||||
for (uint32_t i = 0; i < csum_size; i++)
|
||||
printf("%02x", csums[i]);
|
||||
printf("\"");
|
||||
}
|
||||
if (wr->get_checksum(heap))
|
||||
{
|
||||
printf(",\"data_crc32c\":\"%08x\"", *wr->get_checksum(heap));
|
||||
}
|
||||
printf("}");
|
||||
first_wr = false;
|
||||
}
|
||||
printf("]}");
|
||||
first_entry = false;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
printf(
|
||||
@@ -289,7 +515,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
|
||||
? BLOCKSTORE_CSUM_CRC32C
|
||||
: BLOCKSTORE_CSUM_NONE);
|
||||
new_hdr->csum_block_size = meta["csum_block_size"].uint64_value();
|
||||
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(*new_hdr));
|
||||
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(blockstore_meta_header_v2_t));
|
||||
}
|
||||
uint32_t new_clean_entry_header_size = (new_hdr->version == BLOCKSTORE_META_FORMAT_V1
|
||||
? sizeof(clean_disk_entry) : sizeof(clean_disk_entry) + 4 /*entry_csum*/);
|
||||
@@ -299,6 +525,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
|
||||
: 0);
|
||||
new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size;
|
||||
new_entries_per_block = new_hdr->meta_block_size / new_clean_entry_size;
|
||||
// FIXME: Use a streaming json parser
|
||||
for (const auto & e: meta["entries"].array_items())
|
||||
{
|
||||
uint64_t data_block = e["block"].uint64_value();
|
||||
@@ -332,7 +559,366 @@ int disk_tool_t::write_json_meta(json11::Json meta)
|
||||
}
|
||||
}
|
||||
int r = resize_write_new_meta();
|
||||
free(new_meta_buf);
|
||||
new_meta_buf = NULL;
|
||||
free_new_meta();
|
||||
return r;
|
||||
}
|
||||
|
||||
int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
|
||||
{
|
||||
new_meta_hdr->zero = 0;
|
||||
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||
new_meta_hdr->version = BLOCKSTORE_META_FORMAT_HEAP;
|
||||
new_meta_hdr->meta_block_size = meta["meta_block_size"].uint64_value()
|
||||
? meta["meta_block_size"].uint64_value() : 4096;
|
||||
new_meta_hdr->data_block_size = meta["data_block_size"].uint64_value()
|
||||
? meta["data_block_size"].uint64_value() : 131072;
|
||||
new_meta_hdr->bitmap_granularity = meta["bitmap_granularity"].uint64_value()
|
||||
? meta["bitmap_granularity"].uint64_value() : 4096;
|
||||
new_meta_hdr->data_csum_type = meta["data_csum_type"].is_number()
|
||||
? meta["data_csum_type"].uint64_value()
|
||||
: (meta["data_csum_type"].string_value() == "crc32c"
|
||||
? BLOCKSTORE_CSUM_CRC32C
|
||||
: 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_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;
|
||||
if (new_journal_len)
|
||||
{
|
||||
memset(new_journal_buf, 0, new_journal_len);
|
||||
}
|
||||
uint64_t total_used_space = 0;
|
||||
uint32_t used_space = 0;
|
||||
// FIXME: Use a streaming json parser
|
||||
if (meta["version"] == "3.0")
|
||||
{
|
||||
// New format
|
||||
std::vector<uint8_t> object_buf;
|
||||
new_heap = new blockstore_heap_t(&dsk, new_journal_buf, 0);
|
||||
for (const auto & meta_entry: meta["entries"].array_items())
|
||||
{
|
||||
bool invalid = false;
|
||||
object_id oid = {
|
||||
.inode = (sscanf_json(NULL, meta_entry["pool"]) << (64-POOL_ID_BITS)) | sscanf_json(NULL, meta_entry["inode"]),
|
||||
.stripe = sscanf_json(NULL, meta_entry["stripe"]),
|
||||
};
|
||||
object_buf.clear();
|
||||
object_buf.resize(sizeof(heap_object_t));
|
||||
heap_object_t *obj = (heap_object_t*)object_buf.data();
|
||||
obj->size = sizeof(heap_object_t);
|
||||
obj->write_pos = meta_entry["writes"].array_items().size() ? sizeof(heap_object_t) : 0;
|
||||
obj->inode = oid.inode;
|
||||
obj->stripe = oid.stripe;
|
||||
size_t pos = sizeof(heap_object_t);
|
||||
heap_write_t *last_wr = NULL;
|
||||
for (auto & write_entry: meta_entry["writes"].array_items())
|
||||
{
|
||||
object_buf.resize(object_buf.size() + new_heap->get_max_write_entry_size());
|
||||
heap_write_t *wr = (heap_write_t*)(object_buf.data() + pos);
|
||||
last_wr = wr;
|
||||
uint8_t wr_type = 0;
|
||||
if (write_entry["type"] == "small")
|
||||
wr_type = BS_HEAP_SMALL_WRITE;
|
||||
else if (write_entry["type"] == "intent")
|
||||
wr_type = BS_HEAP_INTENT_WRITE;
|
||||
else if (write_entry["type"] == "big")
|
||||
wr_type = BS_HEAP_BIG_WRITE;
|
||||
else if (write_entry["type"] == "tombstone")
|
||||
wr_type = BS_HEAP_TOMBSTONE;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Write entry in %s has invalid type: %s, skipping object\n", meta_entry.dump().c_str(), write_entry["type"].dump().c_str());
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
wr->flags = wr_type | (write_entry["stable"].bool_value() ? BS_HEAP_STABLE : 0);
|
||||
wr->lsn = write_entry["lsn"].uint64_value();
|
||||
wr->version = write_entry["version"].uint64_value();
|
||||
wr->offset = write_entry["offset"].uint64_value();
|
||||
wr->len = write_entry["len"].uint64_value();
|
||||
wr->location = write_entry["location"].uint64_value();
|
||||
wr->size = wr->get_size(new_heap);
|
||||
wr->next_pos = wr->size;
|
||||
if (wr_type == BS_HEAP_SMALL_WRITE && write_entry["data"].is_string() && wr->len > 0)
|
||||
{
|
||||
if (!new_journal_buf)
|
||||
{
|
||||
fprintf(stderr, "Loading small write data requires overwriting buffer area\n");
|
||||
free_new_meta();
|
||||
return 1;
|
||||
}
|
||||
wr->location = new_heap->find_free_buffer_area(wr->len);
|
||||
fromhexstr(write_entry["data"].string_value(), wr->len, new_journal_buf + wr->location);
|
||||
}
|
||||
if (write_entry["bitmap"].is_string() && wr->get_int_bitmap(new_heap))
|
||||
{
|
||||
fromhexstr(write_entry["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_int_bitmap(new_heap));
|
||||
}
|
||||
if (write_entry["ext_bitmap"].is_string() && wr->get_ext_bitmap(new_heap))
|
||||
{
|
||||
fromhexstr(write_entry["ext_bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(new_heap));
|
||||
}
|
||||
if (write_entry["block_csums"].is_string() && wr->get_checksums(new_heap))
|
||||
{
|
||||
fromhexstr(write_entry["block_csums"].string_value(), wr->get_csum_size(new_heap), wr->get_ext_bitmap(new_heap));
|
||||
}
|
||||
if (write_entry["data_crc32c"].is_string() && wr->get_checksum(new_heap))
|
||||
{
|
||||
*wr->get_checksum(new_heap) = sscanf_json("%jx", write_entry["data_crc32c"]);
|
||||
}
|
||||
}
|
||||
if (invalid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
last_wr->next_pos = 0;
|
||||
new_heap->copy_object(obj, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!journal.is_array())
|
||||
{
|
||||
fprintf(stderr, "Metadata should include journal in you want to convert it to the \"heap\" format\n");
|
||||
close_err:
|
||||
free(new_meta_buf);
|
||||
new_meta_buf = NULL;
|
||||
return 1;
|
||||
}
|
||||
std::map<object_id, std::vector<json11::Json::object>> journal_by_object;
|
||||
if (index_journal_by_object(journal, journal_by_object) != 0)
|
||||
{
|
||||
goto close_err;
|
||||
}
|
||||
journal = json11::Json();
|
||||
// Convert old format to the new format
|
||||
uint64_t next_lsn = 0;
|
||||
uint64_t meta_offset = 0;
|
||||
const uint32_t space_per_object = sizeof(heap_object_t) + sizeof(heap_write_t) +
|
||||
new_clean_entry_bitmap_size*2 + new_data_csum_size;
|
||||
uint64_t buffer_pos = 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;
|
||||
dsk.meta_block_target_free_space = 800;
|
||||
blockstore_heap_t heap(&dsk, NULL, 0);
|
||||
for (const auto & meta_entry: meta["entries"].array_items())
|
||||
{
|
||||
object_id oid = {
|
||||
.inode = (sscanf_json(NULL, meta_entry["pool"]) << (64-POOL_ID_BITS)) | sscanf_json(NULL, meta_entry["inode"]),
|
||||
.stripe = sscanf_json(NULL, meta_entry["stripe"]),
|
||||
};
|
||||
uint32_t space_for_this = space_per_object;
|
||||
auto j_it = journal_by_object.find(oid);
|
||||
if (j_it != journal_by_object.end())
|
||||
{
|
||||
for (auto & rec: j_it->second)
|
||||
{
|
||||
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
|
||||
{
|
||||
uint64_t off = rec["offset"].uint64_value();
|
||||
uint64_t len = rec["len"].uint64_value();
|
||||
if (off+len > new_meta_hdr->data_block_size)
|
||||
{
|
||||
fprintf(stderr, "Journal entry has too large offset or length: %s\n", json11::Json(rec).dump().c_str());
|
||||
goto close_err;
|
||||
}
|
||||
space_for_this += sizeof(heap_write_t) + new_clean_entry_bitmap_size +
|
||||
((off+len+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size - off/new_meta_hdr->csum_block_size) * (new_meta_hdr->data_csum_type & 0xFF);
|
||||
}
|
||||
else /*if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")*/
|
||||
{
|
||||
space_for_this += sizeof(heap_write_t) + 2*new_clean_entry_bitmap_size + new_data_csum_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (space_for_this > new_meta_hdr->meta_block_size)
|
||||
{
|
||||
fprintf(stderr, "Object doesn't fit in a single metadata block. Object meta: %s, object journal: %s\n",
|
||||
meta_entry.dump().c_str(), json11::Json(j_it->second).dump().c_str());
|
||||
goto close_err;
|
||||
}
|
||||
if (used_space + space_for_this > new_meta_hdr->meta_block_size-dsk.meta_block_target_free_space)
|
||||
{
|
||||
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);
|
||||
}
|
||||
meta_offset += new_meta_hdr->meta_block_size;
|
||||
used_space = 0;
|
||||
if (meta_offset >= new_meta_len)
|
||||
{
|
||||
fprintf(stderr, "Metadata doesn't fit into the new area (total used space: %ju, minimum free space in block: %u/%u)\n",
|
||||
total_used_space, dsk.meta_block_target_free_space, new_meta_hdr->meta_block_size);
|
||||
goto close_err;
|
||||
}
|
||||
}
|
||||
heap_object_t *obj = (heap_object_t*)(new_meta_buf + meta_offset + used_space);
|
||||
obj->size = sizeof(heap_object_t);
|
||||
obj->write_pos = sizeof(heap_object_t);
|
||||
obj->inode = oid.inode;
|
||||
obj->stripe = oid.stripe;
|
||||
heap_write_t *wr = obj->get_writes();
|
||||
wr->next_pos = 0;
|
||||
wr->flags = BS_HEAP_BIG_WRITE|BS_HEAP_STABLE;
|
||||
wr->lsn = ++next_lsn;
|
||||
wr->version = sscanf_json(NULL, meta_entry["version"]);
|
||||
wr->offset = 0;
|
||||
wr->len = new_meta_hdr->data_block_size;
|
||||
wr->location = meta_entry["block"].uint64_value() * new_meta_hdr->data_block_size;
|
||||
wr->size = wr->get_size(&heap);
|
||||
fromhexstr(meta_entry["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_int_bitmap(&heap));
|
||||
fromhexstr(meta_entry["ext_bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
|
||||
if (new_meta_hdr->data_csum_type != 0)
|
||||
fromhexstr(meta_entry["data_csum"].string_value(), new_data_csum_size, wr->get_checksums(&heap));
|
||||
if (j_it != journal_by_object.end())
|
||||
{
|
||||
for (auto & rec: j_it->second)
|
||||
{
|
||||
wr->next_pos = wr->get_size(&heap);
|
||||
wr = wr->next();
|
||||
wr->next_pos = 0;
|
||||
wr->lsn = ++next_lsn;
|
||||
wr->version = rec["ver"].uint64_value();
|
||||
wr->offset = rec["offset"].uint64_value();
|
||||
wr->len = rec["len"].uint64_value();
|
||||
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
|
||||
{
|
||||
if (wr->len > 0 && !rec["data"].is_string())
|
||||
{
|
||||
fprintf(stderr, "Error: entry data is missing, please generate the dump with --json --format data\n");
|
||||
goto close_err;
|
||||
}
|
||||
wr->flags = BS_HEAP_SMALL_WRITE | (rec["type"] == "small_write_instant" ? BS_HEAP_STABLE : 0);
|
||||
fromhexstr(rec["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
|
||||
fromhexstr(rec["data"].string_value(), wr->len, new_journal_buf+buffer_pos);
|
||||
if (wr->len > 0)
|
||||
{
|
||||
if (!new_meta_hdr->data_csum_type)
|
||||
*wr->get_checksum(&heap) = crc32c(0, new_journal_buf+buffer_pos, wr->len);
|
||||
else
|
||||
heap.calc_block_checksums((uint32_t*)wr->get_checksums(&heap), new_journal_buf+buffer_pos, NULL, wr->offset, wr->offset+wr->len, true, NULL);
|
||||
}
|
||||
buffer_pos += wr->len;
|
||||
}
|
||||
else if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")
|
||||
{
|
||||
wr->flags = BS_HEAP_BIG_WRITE | (rec["type"] == "big_write_instant" ? BS_HEAP_STABLE : 0);
|
||||
wr->location = sscanf_json(NULL, rec["loc"]);
|
||||
bitmap_set(wr->get_int_bitmap(&heap), wr->offset, wr->len, new_meta_hdr->bitmap_granularity);
|
||||
fromhexstr(rec["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
|
||||
if (new_meta_hdr->data_csum_type != 0)
|
||||
{
|
||||
if ((wr->offset % new_meta_hdr->csum_block_size) || (wr->len % new_meta_hdr->csum_block_size))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Error: big_write journal entries not aligned to csum_block_size can't be converted between v0.9 and v3.0 metadata\n"
|
||||
"Stop writes and flush the journal or convert OSDs one by one without the journal if you still want to do it.\n");
|
||||
goto close_err;
|
||||
}
|
||||
fromhexstr(rec["block_csums"].string_value(),
|
||||
((wr->offset+wr->len+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size
|
||||
- wr->offset/new_meta_hdr->csum_block_size) * (new_meta_hdr->data_csum_type & 0xFF),
|
||||
wr->get_checksums(&heap));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
wr->size = wr->get_size(&heap);
|
||||
}
|
||||
}
|
||||
obj->crc32c = obj->calc_crc32c();
|
||||
assert(((uint8_t*)wr + wr->size - (uint8_t*)obj) == space_for_this);
|
||||
used_space += space_for_this;
|
||||
total_used_space += space_for_this;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
int r = resize_write_new_meta();
|
||||
if (r == 0)
|
||||
{
|
||||
r = resize_write_new_journal();
|
||||
}
|
||||
free_new_meta();
|
||||
return r;
|
||||
}
|
||||
|
||||
int disk_tool_t::index_journal_by_object(json11::Json journal,
|
||||
std::map<object_id, std::vector<json11::Json::object>> & journal_by_object)
|
||||
{
|
||||
for (const auto & rec: journal.array_items())
|
||||
{
|
||||
object_id oid = {
|
||||
.inode = sscanf_json(NULL, rec["inode"]),
|
||||
.stripe = sscanf_json(NULL, rec["stripe"]),
|
||||
};
|
||||
auto & jbo = journal_by_object[oid];
|
||||
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
|
||||
{
|
||||
jbo.push_back(rec.object_items());
|
||||
}
|
||||
else if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")
|
||||
{
|
||||
if (rec["type"] == "big_write_instant")
|
||||
jbo.clear();
|
||||
jbo.push_back(rec.object_items());
|
||||
}
|
||||
else if (rec["type"] == "delete")
|
||||
{
|
||||
jbo.clear();
|
||||
}
|
||||
else if (rec["type"] == "stable")
|
||||
{
|
||||
uint64_t commit_to = rec["version"].uint64_value();
|
||||
for (size_t i = 0; i < jbo.size(); i++)
|
||||
{
|
||||
if (jbo[i]["version"].uint64_value() <= commit_to)
|
||||
{
|
||||
if (jbo[i]["type"] == "big_write")
|
||||
{
|
||||
jbo.erase(jbo.begin(), jbo.begin()+i);
|
||||
i = 0;
|
||||
jbo[i]["type"] = "big_write_instant";
|
||||
}
|
||||
else if (jbo[i]["type"] == "small_write")
|
||||
{
|
||||
jbo[i]["type"] = "small_write_instant";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rec["type"] == "rollback")
|
||||
{
|
||||
uint64_t rollback_to = rec["version"].uint64_value();
|
||||
for (size_t i = jbo.size()-1; i >= 0; i--)
|
||||
{
|
||||
if (jbo[i]["version"].uint64_value() > rollback_to)
|
||||
jbo.erase(jbo.begin()+i, jbo.begin()+i+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown journal entry type: %s\n", rec.dump().c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
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[] = {
|
||||
"meta_format",
|
||||
"data_csum_type",
|
||||
"csum_block_size",
|
||||
"autosync_writes",
|
||||
@@ -128,7 +129,8 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_
|
||||
dsk.open_meta();
|
||||
dsk.open_journal();
|
||||
dsk.calc_lengths();
|
||||
dsk.data_offset += (new_meta_len ? 0 : (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len));
|
||||
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);
|
||||
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"] },
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
#include <limits.h>
|
||||
|
||||
#include "disk_tool.h"
|
||||
#include "rw_blocking.h"
|
||||
#include "str_util.h"
|
||||
@@ -25,65 +28,87 @@ int disk_tool_t::raw_resize()
|
||||
// Parse parameters
|
||||
r = resize_parse_params();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
// Fill allocator
|
||||
fprintf(stderr, "Reading metadata\n");
|
||||
data_alloc = new allocator_t((new_data_len < dsk.data_len ? dsk.data_len : new_data_len) / dsk.data_block_size);
|
||||
r = process_meta(
|
||||
[this](blockstore_meta_header_v2_t *hdr)
|
||||
[this](blockstore_meta_header_v3_t *hdr)
|
||||
{
|
||||
resize_init(hdr);
|
||||
},
|
||||
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
|
||||
{
|
||||
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
|
||||
{
|
||||
data_alloc->set(wr->location / dsk.data_block_size, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
data_alloc->set(block_num, true);
|
||||
}
|
||||
},
|
||||
true, true
|
||||
);
|
||||
if (r != 0)
|
||||
return r;
|
||||
fprintf(stderr, "Reading journal\n");
|
||||
r = process_journal([this](void *buf)
|
||||
goto ret;
|
||||
if (dsk.meta_format != BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
return process_journal_block(buf, [this](int num, journal_entry *je)
|
||||
fprintf(stderr, "Reading journal\n");
|
||||
r = process_journal([this](void *buf)
|
||||
{
|
||||
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
return process_journal_block(buf, [this](int num, journal_entry *je)
|
||||
{
|
||||
data_alloc->set(je->big_write.location / dsk.data_block_size, true);
|
||||
}
|
||||
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
{
|
||||
data_alloc->set(je->big_write.location / dsk.data_block_size, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (r != 0)
|
||||
goto ret;
|
||||
}
|
||||
// Remap blocks
|
||||
r = resize_remap_blocks();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
// Copy data blocks into new places
|
||||
fprintf(stderr, "Moving data blocks\n");
|
||||
r = resize_copy_data();
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Rewrite journal
|
||||
fprintf(stderr, "Rebuilding journal\n");
|
||||
r = resize_rewrite_journal();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
// Rewrite metadata
|
||||
resize_alloc_journal();
|
||||
fprintf(stderr, "Rebuilding metadata\n");
|
||||
r = resize_rewrite_meta();
|
||||
r = resize_rebuild_meta();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
if (new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
// Rewrite journal
|
||||
fprintf(stderr, "Rebuilding journal\n");
|
||||
r = resize_rebuild_journal();
|
||||
if (r != 0)
|
||||
goto ret;
|
||||
fprintf(stderr, "Writing new journal\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Writing new buffer area\n");
|
||||
// Write new journal
|
||||
fprintf(stderr, "Writing new journal\n");
|
||||
r = resize_write_new_journal();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
// Write new metadata
|
||||
fprintf(stderr, "Writing new metadata\n");
|
||||
r = resize_write_new_meta();
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto ret;
|
||||
fprintf(stderr, "Done\n");
|
||||
ret:
|
||||
free_new_meta();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,6 +152,8 @@ int disk_tool_t::resize_parse_params()
|
||||
? parse_size(options["new_journal_offset"]) : dsk.journal_offset;
|
||||
new_journal_len = options.find("new_journal_len") != options.end()
|
||||
? parse_size(options["new_journal_len"]) : dsk.journal_len;
|
||||
new_meta_format = options.find("new_meta_format") != options.end()
|
||||
? stoull_full(options["new_meta_format"]) : 0;
|
||||
if (new_data_len+new_data_offset > dsk.data_device_size)
|
||||
new_data_len = dsk.data_device_size-new_data_offset;
|
||||
if (new_meta_device == dsk.data_device && new_data_offset < new_meta_offset &&
|
||||
@@ -152,7 +179,7 @@ int disk_tool_t::resize_parse_params()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void disk_tool_t::resize_init(blockstore_meta_header_v2_t *hdr)
|
||||
void disk_tool_t::resize_init(blockstore_meta_header_v3_t *hdr)
|
||||
{
|
||||
if (hdr && dsk.data_block_size != hdr->data_block_size)
|
||||
{
|
||||
@@ -171,6 +198,15 @@ void disk_tool_t::resize_init(blockstore_meta_header_v2_t *hdr)
|
||||
dsk.data_csum_type = hdr->data_csum_type;
|
||||
dsk.csum_block_size = hdr->csum_block_size;
|
||||
}
|
||||
if (hdr && dsk.meta_format != hdr->version)
|
||||
{
|
||||
dsk.meta_format = hdr->version;
|
||||
}
|
||||
if (new_meta_format == 0)
|
||||
{
|
||||
new_meta_format = hdr && hdr->version == BLOCKSTORE_META_FORMAT_HEAP ? BLOCKSTORE_META_FORMAT_HEAP : BLOCKSTORE_META_FORMAT_V2;
|
||||
}
|
||||
dsk.calc_lengths();
|
||||
if (((new_data_offset-dsk.data_offset) % dsk.data_block_size))
|
||||
{
|
||||
fprintf(stderr, "Data alignment mismatch: old data offset is 0x%jx, new is 0x%jx, but alignment on %x should be equal\n",
|
||||
@@ -360,15 +396,57 @@ int disk_tool_t::resize_copy_data()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_rewrite_journal()
|
||||
void disk_tool_t::resize_alloc_journal()
|
||||
{
|
||||
// Simply overwriting on the fly may be impossible because old and new areas may overlap
|
||||
// For now, just build new journal data in memory
|
||||
new_journal_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_journal_len);
|
||||
memset(new_journal_buf, 0, new_journal_len);
|
||||
new_journal_ptr = new_journal_buf;
|
||||
new_journal_data = new_journal_ptr + dsk.journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
memset(new_journal_buf, 0, new_journal_len);
|
||||
}
|
||||
|
||||
void disk_tool_t::build_journal_start()
|
||||
{
|
||||
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
||||
*((journal_entry_start*)ne) = (journal_entry_start){
|
||||
.magic = JOURNAL_MAGIC,
|
||||
.type = JE_START,
|
||||
.size = sizeof(journal_entry_start),
|
||||
.journal_start = dsk.journal_block_size,
|
||||
.version = JOURNAL_VERSION_V2,
|
||||
.data_csum_type = dsk.data_csum_type,
|
||||
.csum_block_size = dsk.csum_block_size,
|
||||
};
|
||||
ne->crc32 = je_crc32(ne);
|
||||
new_journal_ptr += dsk.journal_block_size;
|
||||
new_journal_data = new_journal_ptr+dsk.journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
}
|
||||
|
||||
void disk_tool_t::choose_journal_block(uint32_t je_size)
|
||||
{
|
||||
if (dsk.journal_block_size < new_journal_in_pos+je_size)
|
||||
{
|
||||
new_journal_ptr = new_journal_data;
|
||||
if (new_journal_ptr-new_journal_buf >= new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
||||
exit(1);
|
||||
}
|
||||
new_journal_data = new_journal_ptr+dsk.journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
if (dsk.journal_block_size < je_size)
|
||||
{
|
||||
fprintf(stderr, "Error: journal entry too large (%u bytes)\n", je_size);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_rebuild_journal()
|
||||
{
|
||||
// Simply overwriting on the fly may be impossible because old and new areas may overlap
|
||||
// For now, just build new journal data in memory
|
||||
process_journal([this](void *buf)
|
||||
{
|
||||
return process_journal_block(buf, [this](int num, journal_entry *je)
|
||||
@@ -385,39 +463,11 @@ int disk_tool_t::resize_rewrite_journal()
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
||||
*((journal_entry_start*)ne) = (journal_entry_start){
|
||||
.magic = JOURNAL_MAGIC,
|
||||
.type = JE_START,
|
||||
.size = sizeof(journal_entry_start),
|
||||
.journal_start = dsk.journal_block_size,
|
||||
.version = JOURNAL_VERSION_V2,
|
||||
.data_csum_type = dsk.data_csum_type,
|
||||
.csum_block_size = dsk.csum_block_size,
|
||||
};
|
||||
ne->crc32 = je_crc32(ne);
|
||||
new_journal_ptr += dsk.journal_block_size;
|
||||
new_journal_data = new_journal_ptr+dsk.journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
build_journal_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dsk.journal_block_size < new_journal_in_pos+je->size)
|
||||
{
|
||||
new_journal_ptr = new_journal_data;
|
||||
if (new_journal_ptr-new_journal_buf >= new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
||||
exit(1);
|
||||
}
|
||||
new_journal_data = new_journal_ptr+dsk.journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
if (dsk.journal_block_size < je->size)
|
||||
{
|
||||
fprintf(stderr, "Error: journal entry too large (%u bytes)\n", je->size);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
choose_journal_block(je->size);
|
||||
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
||||
memcpy(ne, je, je->size);
|
||||
ne->crc32_prev = new_crc32_prev;
|
||||
@@ -464,30 +514,173 @@ int disk_tool_t::resize_write_new_journal()
|
||||
fsync(new_journal_fd);
|
||||
close(new_journal_fd);
|
||||
new_journal_fd = -1;
|
||||
free(new_journal_buf);
|
||||
new_journal_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_rewrite_meta()
|
||||
int disk_tool_t::resize_rebuild_meta()
|
||||
{
|
||||
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
||||
memset(new_meta_buf, 0, new_meta_len);
|
||||
if (new_meta_format == BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
new_dsk = dsk;
|
||||
new_dsk.data_offset = new_data_offset;
|
||||
new_dsk.data_len = new_data_len;
|
||||
new_dsk.block_count = new_data_len / dsk.data_block_size;
|
||||
new_dsk.journal_device = new_journal_device;
|
||||
new_dsk.journal_offset = new_journal_offset;
|
||||
new_dsk.journal_len = new_journal_len;
|
||||
new_dsk.meta_device = new_meta_device;
|
||||
new_dsk.meta_offset = new_meta_offset;
|
||||
new_dsk.meta_area_size = new_meta_len;
|
||||
new_dsk.meta_format = new_meta_format;
|
||||
new_heap = new blockstore_heap_t(&new_dsk, NULL, 0);
|
||||
new_meta_hdr = (blockstore_meta_header_v3_t *)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size);
|
||||
memset(new_meta_hdr, 0, dsk.meta_block_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
std::vector<heap_write_t*> writes;
|
||||
int r = process_meta(
|
||||
[this](blockstore_meta_header_v2_t *hdr)
|
||||
[&](blockstore_meta_header_v3_t *hdr)
|
||||
{
|
||||
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 = BLOCKSTORE_META_FORMAT_V2;
|
||||
new_hdr->meta_block_size = dsk.meta_block_size;
|
||||
new_hdr->data_block_size = dsk.data_block_size;
|
||||
new_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
|
||||
new_hdr->data_csum_type = dsk.data_csum_type;
|
||||
new_hdr->csum_block_size = dsk.csum_block_size;
|
||||
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(*new_hdr));
|
||||
new_meta_hdr->zero = 0;
|
||||
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||
new_meta_hdr->version = new_meta_format == 0 ? BLOCKSTORE_META_FORMAT_HEAP : new_meta_format;
|
||||
new_meta_hdr->meta_block_size = dsk.meta_block_size;
|
||||
new_meta_hdr->data_block_size = dsk.data_block_size;
|
||||
new_meta_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
|
||||
new_meta_hdr->data_csum_type = dsk.data_csum_type;
|
||||
new_meta_hdr->csum_block_size = dsk.csum_block_size;
|
||||
new_meta_hdr->compacted_lsn = hdr->compacted_lsn;
|
||||
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));
|
||||
if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP && new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
|
||||
{
|
||||
build_journal_start();
|
||||
}
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
[&](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
|
||||
{
|
||||
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
|
||||
{
|
||||
if (wr->next() && new_meta_hdr->data_csum_type != 0 &&
|
||||
((wr->offset % new_meta_hdr->csum_block_size) || (wr->len % new_meta_hdr->csum_block_size)))
|
||||
{
|
||||
fprintf(stderr, "Error: big_write journal entries not aligned to csum_block_size can't be converted between v0.9 and v3.0 metadata\n");
|
||||
exit(1);
|
||||
}
|
||||
auto block_num = wr->location / dsk.data_block_size;
|
||||
auto remap_it = data_remap.find(block_num);
|
||||
if (remap_it != data_remap.end())
|
||||
block_num = remap_it->second;
|
||||
if (block_num < free_first || block_num >= total_blocks-free_last)
|
||||
{
|
||||
fprintf(stderr, "BUG: remapped block %ju not in range %ju..%ju\n", block_num, free_first, total_blocks-free_last);
|
||||
exit(1);
|
||||
}
|
||||
block_num += data_idx_diff;
|
||||
wr->location = block_num * dsk.data_block_size;
|
||||
}
|
||||
else if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE)
|
||||
{
|
||||
if (new_heap && wr->len > 0)
|
||||
{
|
||||
if (new_journal_ptr-new_journal_buf+wr->len > new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Small write data doesn't fit into the new buffer area\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(new_journal_ptr, buffer_area+wr->location, wr->len);
|
||||
wr->location = new_journal_ptr-new_journal_buf;
|
||||
new_journal_ptr += wr->len;
|
||||
}
|
||||
}
|
||||
else if (!new_heap)
|
||||
{
|
||||
fprintf(stderr, "Object %jx:%jx can't be converted to the old format because it contains %s\n",
|
||||
obj->inode, obj->stripe, (wr->flags & BS_HEAP_TYPE) == BS_HEAP_TOMBSTONE
|
||||
? "a tombstone" : ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_INTENT_WRITE ? "an intent_write entry" : "an unknown entry"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (new_heap)
|
||||
{
|
||||
// New -> New
|
||||
new_heap->copy_object(obj, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill journal
|
||||
writes.clear();
|
||||
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||
{
|
||||
writes.push_back(wr);
|
||||
}
|
||||
for (ssize_t i = writes.size()-2; i >= 0; i--)
|
||||
{
|
||||
auto wr = writes[i];
|
||||
assert((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE || wr->flags == BS_HEAP_BIG_WRITE);
|
||||
uint32_t je_size = dsk.dirty_dyn_size(wr->offset, wr->len) +
|
||||
((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? sizeof(journal_entry_small_write) : sizeof(journal_entry_big_write));
|
||||
choose_journal_block(je_size);
|
||||
journal_entry *je = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
||||
je->magic = JOURNAL_MAGIC;
|
||||
je->type = (wr->flags & BS_HEAP_STABLE) ? JE_SMALL_WRITE_INSTANT : JE_SMALL_WRITE;
|
||||
je->size = je_size;
|
||||
je->crc32_prev = new_crc32_prev;
|
||||
je->small_write.oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
||||
je->small_write.version = wr->version;
|
||||
je->small_write.offset = wr->offset;
|
||||
je->small_write.len = wr->len;
|
||||
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE)
|
||||
{
|
||||
je->small_write.data_offset = new_journal_data-new_journal_buf;
|
||||
if (je->small_write.data_offset + je->small_write.len > new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(new_journal_data, buffer_area+wr->location, je->small_write.len);
|
||||
new_journal_data += je->small_write.len;
|
||||
if (dsk.data_csum_type == 0 && wr->get_checksum(heap))
|
||||
je->small_write.crc32_data = *wr->get_checksum(heap);
|
||||
}
|
||||
else
|
||||
{
|
||||
je->big_write.location = wr->location;
|
||||
}
|
||||
memcpy((uint8_t*)je + je->size, wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
|
||||
if (dsk.data_csum_type != 0 && wr->get_checksums(heap))
|
||||
memcpy((uint8_t*)je + je->size + new_clean_entry_bitmap_size, wr->get_checksums(heap), new_data_csum_size);
|
||||
je->crc32 = je_crc32(je);
|
||||
new_journal_in_pos += je->size;
|
||||
new_crc32_prev = je->crc32;
|
||||
}
|
||||
// New -> Old
|
||||
if (writes[writes.size()-1]->flags == BS_HEAP_BIG_WRITE|BS_HEAP_STABLE)
|
||||
{
|
||||
auto big_wr = writes[writes.size()-1];
|
||||
uint64_t block_num = big_wr->location / dsk.data_block_size;
|
||||
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
|
||||
dsk.meta_block_size*(block_num / new_entries_per_block) +
|
||||
new_clean_entry_size*(block_num % new_entries_per_block));
|
||||
new_entry->oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
||||
new_entry->version = big_wr->version;
|
||||
memcpy(new_entry->bitmap, big_wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
|
||||
memcpy(new_entry->bitmap + new_clean_entry_bitmap_size, big_wr->get_int_bitmap(heap), new_clean_entry_bitmap_size);
|
||||
memcpy(new_entry->bitmap + 2*new_clean_entry_bitmap_size, big_wr->get_checksums(heap), new_data_csum_size);
|
||||
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
|
||||
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
auto remap_it = data_remap.find(block_num);
|
||||
if (remap_it != data_remap.end())
|
||||
@@ -498,26 +691,44 @@ int disk_tool_t::resize_rewrite_meta()
|
||||
exit(1);
|
||||
}
|
||||
block_num += data_idx_diff;
|
||||
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
|
||||
dsk.meta_block_size*(block_num / new_entries_per_block) +
|
||||
new_clean_entry_size*(block_num % new_entries_per_block));
|
||||
new_entry->oid = entry->oid;
|
||||
new_entry->version = entry->version;
|
||||
if (bitmap)
|
||||
memcpy(new_entry->bitmap, bitmap, 2*new_clean_entry_bitmap_size + new_data_csum_size);
|
||||
if (new_heap)
|
||||
{
|
||||
// Old -> New
|
||||
uint8_t wr_buf[new_heap->get_max_write_entry_size()];
|
||||
heap_write_t *wr = (heap_write_t*)wr_buf;
|
||||
wr->flags = BS_HEAP_BIG_WRITE|BS_HEAP_STABLE;
|
||||
wr->location = block_num * dsk.data_block_size;
|
||||
wr->next_pos = 0;
|
||||
wr->offset = 0;
|
||||
wr->len = 0;
|
||||
wr->size = wr->get_size(new_heap);
|
||||
if (bitmap)
|
||||
{
|
||||
memcpy(wr->get_ext_bitmap(new_heap), bitmap, new_clean_entry_bitmap_size);
|
||||
memcpy(wr->get_int_bitmap(new_heap), bitmap+new_clean_entry_bitmap_size, new_clean_entry_bitmap_size);
|
||||
memcpy(wr->get_checksums(new_heap), bitmap+2*new_clean_entry_bitmap_size, new_data_csum_size);
|
||||
}
|
||||
new_heap->post_write(entry->oid, wr, NULL, NULL);
|
||||
}
|
||||
else
|
||||
memset(new_entry->bitmap, 0xff, 2*new_clean_entry_bitmap_size);
|
||||
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
|
||||
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
|
||||
}
|
||||
{
|
||||
// Old -> Old
|
||||
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
|
||||
dsk.meta_block_size*(block_num / new_entries_per_block) +
|
||||
new_clean_entry_size*(block_num % new_entries_per_block));
|
||||
new_entry->oid = entry->oid;
|
||||
new_entry->version = entry->version;
|
||||
if (bitmap)
|
||||
memcpy(new_entry->bitmap, bitmap, 2*new_clean_entry_bitmap_size + new_data_csum_size);
|
||||
else
|
||||
memset(new_entry->bitmap, 0xff, 2*new_clean_entry_bitmap_size);
|
||||
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
|
||||
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
|
||||
}
|
||||
},
|
||||
true, true
|
||||
);
|
||||
if (r != 0)
|
||||
{
|
||||
free(new_meta_buf);
|
||||
new_meta_buf = NULL;
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_write_new_meta()
|
||||
@@ -529,11 +740,60 @@ int disk_tool_t::resize_write_new_meta()
|
||||
return 1;
|
||||
}
|
||||
lseek64(new_meta_fd, new_meta_offset, 0);
|
||||
write_blocking(new_meta_fd, new_meta_buf, new_meta_len);
|
||||
if (new_meta_buf)
|
||||
{
|
||||
write_blocking(new_meta_fd, new_meta_buf, new_meta_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(new_heap);
|
||||
uint32_t new_meta_blocks = new_meta_len / dsk.meta_block_size - 1;
|
||||
uint8_t *zero_block = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size);
|
||||
memset(zero_block, 0, dsk.meta_block_size);
|
||||
std::vector<iovec> iov;
|
||||
iov.reserve(IOV_MAX);
|
||||
iov.push_back((iovec){ .iov_base = new_meta_hdr, .iov_len = dsk.meta_block_size });
|
||||
for (uint32_t i = 0; i < new_meta_blocks; i++)
|
||||
{
|
||||
uint8_t *data = new_heap->get_meta_block(i);
|
||||
iov.push_back((iovec){ .iov_base = data ? data : zero_block, .iov_len = dsk.meta_block_size });
|
||||
if (iov.size() >= IOV_MAX)
|
||||
{
|
||||
writev_blocking(new_meta_fd, iov.data(), iov.size());
|
||||
iov.clear();
|
||||
}
|
||||
}
|
||||
if (iov.size() > 0)
|
||||
writev_blocking(new_meta_fd, iov.data(), iov.size());
|
||||
free(zero_block);
|
||||
zero_block = NULL;
|
||||
}
|
||||
fsync(new_meta_fd);
|
||||
close(new_meta_fd);
|
||||
new_meta_fd = -1;
|
||||
free(new_meta_buf);
|
||||
new_meta_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void disk_tool_t::free_new_meta()
|
||||
{
|
||||
if (new_heap)
|
||||
{
|
||||
delete new_heap;
|
||||
new_heap = NULL;
|
||||
}
|
||||
if ((uint8_t*)new_meta_hdr != new_meta_buf)
|
||||
{
|
||||
free(new_meta_hdr);
|
||||
new_meta_hdr = NULL;
|
||||
}
|
||||
if (new_meta_buf)
|
||||
{
|
||||
free(new_meta_buf);
|
||||
new_meta_buf = NULL;
|
||||
}
|
||||
if (new_journal_buf)
|
||||
{
|
||||
free(new_journal_buf);
|
||||
new_journal_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,10 @@ int disk_tool_t::resize_data(std::string device)
|
||||
auto new_meta_device = move_options.find("new_meta_device") != move_options.end()
|
||||
? 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_data_offset = 4096 + (new_journal_device == dsk.data_device ? new_journal_len : 0) +
|
||||
(new_meta_device == dsk.data_device ? dsk.meta_area_size : 0);
|
||||
(new_meta_device == dsk.data_device ? new_meta_len : 0);
|
||||
new_data_offset += ((dsk.data_offset-new_data_offset) % dsk.data_block_size);
|
||||
if (new_data_offset != dsk.data_offset)
|
||||
move_options["new_data_offset"] = std::to_string(new_data_offset);
|
||||
@@ -236,7 +238,7 @@ int disk_tool_t::resize_parse_move_meta(std::map<std::string, std::string> & mov
|
||||
auto new_journal_device = move_options.find("new_journal_device") != move_options.end()
|
||||
? move_options["new_journal_device"] : dsk.journal_device;
|
||||
move_options["new_meta_device"] = dsk.data_device;
|
||||
move_options["new_meta_len"] = std::to_string(dsk.meta_area_size);
|
||||
move_options["new_meta_len"] = std::to_string(new_meta_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -246,7 +248,6 @@ int disk_tool_t::resize_parse_move_meta(std::map<std::string, std::string> & mov
|
||||
std::string parent_dev = get_parent_device(real_dev);
|
||||
if (parent_dev == "")
|
||||
return 1;
|
||||
uint64_t new_meta_len = 0;
|
||||
if (parent_dev == real_dev)
|
||||
{
|
||||
// whole disk - create partition
|
||||
|
||||
+10
-6
@@ -145,6 +145,9 @@ void _test_init(blockstore_disk_t & dsk, bool csum)
|
||||
if (csum)
|
||||
config["data_csum_type"] = "crc32c";
|
||||
dsk.parse_config(config);
|
||||
dsk.data_device = "data";
|
||||
dsk.meta_device = "meta";
|
||||
dsk.journal_device = "journal";
|
||||
dsk.data_device_size = 1*1024*1024*1024;
|
||||
dsk.meta_device_size = 4*1024*1024;
|
||||
dsk.journal_device_size = 4*1024*1024;
|
||||
@@ -1236,6 +1239,7 @@ void test_alloc_buffer()
|
||||
heap.use_buffer_area(1, pos, 64*1024);
|
||||
assert(heap.get_buffer_area_used_space() == (i+1)*64*1024);
|
||||
assert(!heap.is_buffer_area_free(i*64*1024+4096, 4096));
|
||||
assert(heap.is_buffer_area_free(i*64*1024+4096, 0)); // zero length is always free
|
||||
if (i < 4096/64-1)
|
||||
assert(heap.is_buffer_area_free((i+1)*64*1024, 64*1024));
|
||||
}
|
||||
@@ -1280,9 +1284,9 @@ void test_full_alloc()
|
||||
dsk.data_device_size = 8*1024*1024;
|
||||
dsk.meta_device_size = 5*4096;
|
||||
dsk.journal_device_size = 4*1024*1024;
|
||||
dsk.data_fd = 0;
|
||||
dsk.meta_fd = 1;
|
||||
dsk.journal_fd = 2;
|
||||
dsk.data_device = "data";
|
||||
dsk.meta_device = "meta";
|
||||
dsk.journal_device = "journal";
|
||||
dsk.calc_lengths();
|
||||
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
|
||||
|
||||
@@ -1581,9 +1585,9 @@ void test_move()
|
||||
dsk.data_device_size = 8*1024*1024;
|
||||
dsk.meta_device_size = 5*4096;
|
||||
dsk.journal_device_size = 4*1024*1024;
|
||||
dsk.data_fd = 0;
|
||||
dsk.meta_fd = 1;
|
||||
dsk.journal_fd = 2;
|
||||
dsk.data_device = "data";
|
||||
dsk.meta_device = "meta";
|
||||
dsk.journal_device = "journal";
|
||||
dsk.calc_lengths();
|
||||
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
|
||||
|
||||
|
||||
+19
-12
@@ -25,27 +25,34 @@ done
|
||||
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
offsets=$(build/src/disk_tool/vitastor-disk simple-offsets --format json ./testdata/bin/test_osd$i.bin)
|
||||
opts=$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin)
|
||||
meta_format=$(echo $offsets | jq -r .meta_format)
|
||||
meta_offset=$(echo $offsets | jq -r .meta_offset)
|
||||
data_offset=$(echo $offsets | jq -r .data_offset)
|
||||
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 0 $meta_offset >./testdata/journal_before_resize.json
|
||||
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta_before_resize.json
|
||||
#build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 0 $meta_offset >./testdata/journal_before_resize.json
|
||||
#build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta_before_resize.json
|
||||
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts >./testdata/meta_before_resize.json
|
||||
new_data_offset=$((128*1024*1024+data_offset%131072))
|
||||
build/src/disk_tool/vitastor-disk raw-resize --io cached \
|
||||
$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin 2>/dev/null) \
|
||||
$opts \
|
||||
--new_meta_offset 0 \
|
||||
--new_meta_len $((1024*1024)) \
|
||||
--new_journal_offset $((1024*1024)) \
|
||||
--new_data_offset $((128*1024*1024+32768))
|
||||
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 $((1024*1024)) $((127*1024*1024)) >./testdata/journal_after_resize.json
|
||||
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 0 $((1024*1024)) >./testdata/meta_after_resize.json
|
||||
--new_data_offset $new_data_offset
|
||||
#build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 $((1024*1024)) $((127*1024*1024)) >./testdata/journal_after_resize.json
|
||||
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts \
|
||||
--meta_offset 0 \
|
||||
--meta_len $((1024*1024)) \
|
||||
--journal_offset $((1024*1024)) \
|
||||
--data_offset $new_data_offset >./testdata/meta_after_resize.json
|
||||
if ! (cat ./testdata/meta_before_resize.json ./testdata/meta_after_resize.json | \
|
||||
jq -e -s 'map([ .entries[] | del(.block) ] | sort_by(.pool, .inode, .stripe)) | .[0] == .[1] and (.[0] | length) > 1000'); then
|
||||
jq -e -s 'map([ .entries[] | del(.block, .writes[].location) ] | sort_by(.pool, .inode, .stripe)) | .[0] == .[1] and (.[0] | length) > 1000'); then
|
||||
format_error "OSD $i metadata corrupted after resizing"
|
||||
fi
|
||||
if ! (cat ./testdata/journal_before_resize.json ./testdata/journal_after_resize.json | \
|
||||
jq -e -s 'map([ .[] | del(.crc32, .crc32_prev, .valid, .loc, .start) ]) | .[0] == .[1] and (.[0] | length) > 1'); then
|
||||
format_error "OSD $i journal corrupted after resizing"
|
||||
fi
|
||||
#if ! (cat ./testdata/journal_before_resize.json ./testdata/journal_after_resize.json | \
|
||||
# jq -e -s 'map([ .[] | del(.crc32, .crc32_prev, .valid, .loc, .start) ]) | .[0] == .[1] and (.[0] | length) > 1'); then
|
||||
# format_error "OSD $i journal corrupted after resizing"
|
||||
#fi
|
||||
done
|
||||
|
||||
$ETCDCTL del --prefix /vitastor/osd/state/
|
||||
@@ -56,7 +63,7 @@ for i in $(seq 1 $OSD_COUNT); do
|
||||
--data_device ./testdata/bin/test_osd$i.bin \
|
||||
--meta_offset 0 \
|
||||
--journal_offset $((1024*1024)) \
|
||||
--data_offset $((128*1024*1024+32768)) >>./testdata/osd$i.log 2>&1 &
|
||||
--data_offset $new_data_offset >>./testdata/osd$i.log 2>&1 &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ trap "kill -9 $(jobs -p) || true; sudo losetup -d $LOOP1 $LOOP2"' || true' EXIT
|
||||
# also test prepare --hybrid :)
|
||||
# non-vitastor random type UUID to prevent udev activation
|
||||
mount | grep '/dev type devtmpfs' || sudo mount udev /dev/ -t devtmpfs
|
||||
sudo build/src/disk_tool/vitastor-disk-test prepare --no_init 1 --meta_reserve 1x,1M \
|
||||
sudo build/src/disk_tool/vitastor-disk-test prepare --meta_format 2 --no_init 1 --meta_reserve 1x,1M \
|
||||
--block_size 131072 --osd_num 987654 --part_type_uuid 0df42ae0-3695-4395-a957-7d5ff3645c56 \
|
||||
--hybrid --fast-devices $LOOP2 $LOOP1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user