Add a dump|load test, fix multiple bugs in both new&old dump/load utils

Details:
- New store dump/write-meta didn't use actual metadata parameters from the header
- New store write-meta calculated small entry sizes incorrectly
- Old store write-journal imported entries with checksums incorrectly
- Old store write-meta didn't import block_csums at all (it was using a wrong json key)
This commit is contained in:
Vitaliy Filippov
2026-06-17 01:19:12 +03:00
parent c491db699c
commit 430d3cfb6f
5 changed files with 145 additions and 17 deletions
+72
View File
@@ -306,6 +306,78 @@ jobs:
echo ""
done
test_dump_load:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_dump_load.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_dump_load_32k:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: TEST_NAME=32k OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" /root/vitastor/tests/test_dump_load.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_old_dump_load:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: OLD=1 /root/vitastor/tests/test_dump_load.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_dump_load_old_32k:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: TEST_NAME=old_32k OLD=1 OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" /root/vitastor/tests/test_dump_load.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_old_interrupted_rebalance:
runs-on: ubuntu-latest
needs: build
+12 -14
View File
@@ -477,11 +477,15 @@ int disk_tool_t::write_json_journal(json11::Json entries)
uint16_t type = t_it->second;
if (type == JE_START)
continue;
uint32_t offset = (uint32_t)rec["offset"].uint64_value();
uint32_t len = (uint32_t)rec["len"].uint64_value();
uint32_t data_csum_blocks = !dsk.data_csum_type || !len ? 0 :
(((offset + len - 1)/dsk.csum_block_size - offset/dsk.csum_block_size + 1));
uint32_t data_csum_size = data_csum_blocks*(dsk.data_csum_type & 0xFF);
uint32_t entry_size = (type == JE_START
? sizeof(journal_entry_start)
: (type == JE_SMALL_WRITE || type == JE_SMALL_WRITE_INSTANT
? sizeof(journal_entry_small_write) + dsk.clean_entry_bitmap_size +
(dsk.data_csum_type ? rec["len"].uint64_value()/dsk.csum_block_size*(dsk.data_csum_type & 0xFF) : 0)
? sizeof(journal_entry_small_write) + dsk.clean_entry_bitmap_size + data_csum_size
: (type == JE_BIG_WRITE || type == JE_BIG_WRITE_INSTANT
? sizeof(journal_entry_big_write) + dsk.clean_entry_bitmap_size +
(dsk.data_csum_type ? rec["len"].uint64_value()/dsk.csum_block_size*(dsk.data_csum_type & 0xFF) : 0)
@@ -523,15 +527,12 @@ int disk_tool_t::write_json_journal(json11::Json entries)
.stripe = sscanf_json(NULL, rec["stripe"]),
},
.version = rec["ver"].uint64_value(),
.offset = (uint32_t)rec["offset"].uint64_value(),
.len = (uint32_t)rec["len"].uint64_value(),
.offset = offset,
.len = len,
.data_offset = (uint64_t)(new_journal_data-new_journal_buf),
.crc32_data = !dsk.data_csum_type ? 0 : (uint32_t)sscanf_json("%x", rec["data_crc32"]),
};
uint32_t data_csum_blocks = !dsk.data_csum_type ? 0 :
(((ne->small_write.offset+ne->small_write.len)/dsk.csum_block_size - ne->small_write.len/dsk.csum_block_size));
uint32_t data_csum_size = data_csum_blocks*(dsk.data_csum_type & 0xFF);
fromhexstr(rec["bitmap"].string_value(), dsk.clean_entry_bitmap_size, ((uint8_t*)ne) + sizeof(journal_entry_small_write) + data_csum_size);
fromhexstr(rec["bitmap"].string_value(), dsk.clean_entry_bitmap_size, ((uint8_t*)ne) + sizeof(journal_entry_small_write));
fromhexstr(rec["data"].string_value(), ne->small_write.len, new_journal_data);
if (ne->small_write.len > 0 && !rec["data"].is_string())
{
@@ -545,7 +546,7 @@ int disk_tool_t::write_json_journal(json11::Json entries)
ne->small_write.crc32_data = crc32c(0, new_journal_data, ne->small_write.len);
else if (dsk.data_csum_type == BLOCKSTORE_CSUM_CRC32C)
{
uint32_t *block_csums = (uint32_t*)(((uint8_t*)ne) + sizeof(journal_entry_small_write));
uint32_t *block_csums = (uint32_t*)(((uint8_t*)ne) + sizeof(journal_entry_small_write) + dsk.clean_entry_bitmap_size);
for (uint32_t i = 0; i < data_csum_blocks; i++)
{
uint32_t block_begin = (ne->small_write.offset/dsk.csum_block_size + i) * dsk.csum_block_size;
@@ -574,12 +575,9 @@ int disk_tool_t::write_json_journal(json11::Json entries)
.len = (uint32_t)rec["len"].uint64_value(),
.location = sscanf_json(NULL, rec["loc"]),
};
uint32_t data_csum_blocks = !dsk.data_csum_type ? 0 :
(((ne->small_write.offset+ne->small_write.len)/dsk.csum_block_size - ne->small_write.len/dsk.csum_block_size));
uint32_t data_csum_size = data_csum_blocks*(dsk.data_csum_type & 0xFF);
fromhexstr(rec["bitmap"].string_value(), dsk.clean_entry_bitmap_size, ((uint8_t*)ne) + sizeof(journal_entry_big_write) + data_csum_size);
fromhexstr(rec["bitmap"].string_value(), dsk.clean_entry_bitmap_size, ((uint8_t*)ne) + sizeof(journal_entry_big_write));
if (dsk.data_csum_type)
fromhexstr(rec["block_csums"].string_value(), data_csum_size, ((uint8_t*)ne) + sizeof(journal_entry_big_write));
fromhexstr(rec["block_csums"].string_value(), data_csum_size, ((uint8_t*)ne) + sizeof(journal_entry_big_write) + dsk.clean_entry_bitmap_size);
}
else if (type == JE_STABLE || type == JE_ROLLBACK || type == JE_DELETE)
{
+16 -3
View File
@@ -95,6 +95,12 @@ close_error:
journal_pos += read_len;
}
}
dsk.meta_format = hdr->version;
dsk.data_block_size = hdr->data_block_size;
dsk.csum_block_size = hdr->csum_block_size;
dsk.data_csum_type = hdr->data_csum_type;
dsk.bitmap_granularity = hdr->bitmap_granularity;
dsk.clean_entry_bitmap_size = (hdr->data_block_size / hdr->bitmap_granularity + 7) / 8;
blockstore_heap_t *heap = new blockstore_heap_t(&dsk, buffer_area, log_level);
// Load heap and just iterate it in memory
hdr_fn(hdr);
@@ -575,7 +581,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
{
if (new_data_csum_size)
{
fromhexstr(e["data_csum"].string_value(), new_data_csum_size,
fromhexstr(e["block_csums"].string_value(), new_data_csum_size,
((uint8_t*)new_entry) + sizeof(clean_disk_entry) + 2*new_clean_entry_bitmap_size);
}
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
@@ -616,6 +622,12 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
new_data_csum_size = (new_meta_hdr->csum_block_size
? ((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);
dsk.meta_format = new_meta_hdr->version;
dsk.data_block_size = new_meta_hdr->data_block_size;
dsk.csum_block_size = new_meta_hdr->csum_block_size;
dsk.data_csum_type = new_meta_hdr->data_csum_type;
dsk.bitmap_granularity = new_meta_hdr->bitmap_granularity;
dsk.clean_entry_bitmap_size = (new_meta_hdr->data_block_size / new_meta_hdr->bitmap_granularity + 7) / 8;
new_journal_buf = NULL;
if (new_journal_len)
{
@@ -696,7 +708,7 @@ close_err0:
wr->entry_type = 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->size = wr->get_size(&heap);
wr->size = wr_size;
if (wr_type == BS_HEAP_SMALL_WRITE || wr_type == BS_HEAP_INTENT_WRITE)
{
wr->small().offset = wr_offset;
@@ -736,6 +748,7 @@ close_err0:
bi.offset = wr_offset;
bi.len = wr_len;
}
wr->size = wr->get_size(&heap);
if (write_entry["bitmap"].is_string() && wr->get_int_bitmap(&heap))
{
fromhexstr(write_entry["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_int_bitmap(&heap));
@@ -794,7 +807,7 @@ close_err:
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_data_csum_size)
fromhexstr(meta_entry["data_csum"].string_value(), new_data_csum_size, wr->get_checksums(&heap));
fromhexstr(meta_entry["block_csums"].string_value(), new_data_csum_size, wr->get_checksums(&heap));
wr->crc32c = wr->calc_crc32c();
assert((uint8_t*)wr + wr->size == new_meta_buf + meta_offset + used_space);
auto j_it = journal_by_object.find(oid);
+5
View File
@@ -24,6 +24,11 @@ IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
SCHEME=ec ./test_interrupted_rebalance.sh
SCHEME=ec IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
./test_dump_load.sh
TEST_NAME=32k OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" ./test_dump_load.sh
OLD=1 ./test_dump_load.sh
TEST_NAME=old_32k OLD=1 OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" ./test_dump_load.sh
OLD=1 ./test_interrupted_rebalance.sh
OLD=1 IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
OLD=1 SCHEME=ec ./test_interrupted_rebalance.sh
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash -ex
PG_COUNT=${PG_COUNT:-32}
. `dirname $0`/run_3osds.sh
$VITASTOR_FIO -bs=4M -direct=1 -iodepth=4 \
-rw=write -end_fsync=1 -pool=1 -inode=1 -size=256M -runtime=10
$VITASTOR_FIO -bs=4k -direct=1 -iodepth=32 \
-rw=randwrite -end_fsync=1 -pool=1 -inode=1 -size=256M -runtime=10 -number_ios=1024
for i in $(seq 1 $OSD_COUNT); do
pid=OSD${i}_PID
pid=${!pid}
kill -9 $pid
done
offsets=$(build/src/disk_tool/vitastor-disk simple-offsets --format json ./testdata/bin/test_osd1.bin $OFFSET_ARGS)
opts=$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd1.bin $OFFSET_ARGS)
meta_format=$(echo $offsets | jq -r .meta_format)
journal_offset=$(echo $offsets | jq -r .journal_offset)
meta_offset=$(echo $offsets | jq -r .meta_offset)
data_offset=$(echo $offsets | jq -r .data_offset)
if [[ "$meta_format" = "3" ]]; then
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts | jq '. + { "entries": .entries | sort_by(.stripe) }' >./testdata/meta.json
build/src/disk_tool/vitastor-disk write-meta --io cached $opts <./testdata/meta.json
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts | jq '. + { "entries": .entries | sort_by(.stripe) }' >./testdata/meta2.json
else
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd1.bin 4096 $journal_offset $((meta_offset-journal_offset)) | jq 'map(del(.crc32, .crc32_prev)) | map(if .type == "small_write" or .type == "small_write_instant" then del(.loc) elif .type == "start" then del(.start) else . end)' >./testdata/journal.json
build/src/disk_tool/vitastor-disk write-journal --io cached --json ./testdata/bin/test_osd1.bin 4096 4 $journal_offset $((meta_offset-journal_offset)) <./testdata/journal.json
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd1.bin 4096 $journal_offset $((meta_offset-journal_offset)) | jq 'map(del(.crc32, .crc32_prev)) | map(if .type == "small_write" or .type == "small_write_instant" then del(.loc) elif .type == "start" then del(.start) else . end)' >./testdata/journal2.json
diff ./testdata/journal.json ./testdata/journal2.json
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd1.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta.json
build/src/disk_tool/vitastor-disk write-meta --io cached $opts <./testdata/meta.json
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd1.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta2.json
fi
diff ./testdata/meta.json ./testdata/meta2.json
format_green OK