Improve test_recheck to check all possible combinations

This commit is contained in:
Vitaliy Filippov
2026-05-18 01:17:56 +03:00
parent 7b454bd16c
commit 912aca11a3
+181 -41
View File
@@ -76,6 +76,38 @@ void _test_big_write(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t
heap.complete_block_write(mblock);
}
void _test_big_intent(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t inode, uint64_t stripe, uint64_t version,
bool stable, uint32_t offset, uint32_t len, uint8_t *data, uint32_t expected_mblock = 0)
{
uint32_t mblock = 999999;
object_id oid = { .inode = INODE_WITH_POOL(1, inode), .stripe = stripe };
uint8_t ext_bitmap[dsk.clean_entry_bitmap_size];
memset(ext_bitmap, 0x8e, dsk.clean_entry_bitmap_size);
heap_entry_t *obj = heap.read_entry(oid);
int res = heap.add_big_intent(oid, &obj, version, offset, len, ext_bitmap, data, NULL, &mblock);
assert(res == 0);
assert(mblock == 0);
heap.start_block_write(mblock);
heap.complete_block_write(mblock);
heap.complete_lsn_write(obj->lsn);
}
void _test_redirect_intent(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t inode, uint64_t stripe, uint64_t version, uint64_t location,
bool stable, uint32_t offset, uint32_t len, uint8_t *data, uint32_t expected_mblock = 0)
{
heap.use_data(INODE_WITH_POOL(1, inode), location); // blocks are allocated before write and outside the heap_t
uint32_t mblock = 999999;
object_id oid = { .inode = INODE_WITH_POOL(1, inode), .stripe = stripe };
uint8_t ext_bitmap[dsk.clean_entry_bitmap_size];
memset(ext_bitmap, 0x8e, dsk.clean_entry_bitmap_size);
heap_entry_t *obj = heap.read_entry(oid);
int res = heap.add_redirect_intent(oid, &obj, version, offset, len, location, ext_bitmap, data, &mblock);
assert(res == 0);
assert(mblock == expected_mblock || expected_mblock == UINT32_MAX);
heap.start_block_write(mblock);
heap.complete_block_write(mblock);
}
int _test_do_small_write(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t inode, uint64_t stripe, uint64_t version,
uint32_t offset, uint32_t len, uint64_t location, bool stable, uint8_t *data, bool is_intent = false, uint32_t *mblock = NULL, heap_entry_t **obj = NULL)
{
@@ -979,8 +1011,10 @@ void test_modify_bitmap()
printf("OK test_modify_bitmap\n");
}
void test_recheck(bool async, bool csum, bool intent)
void test_recheck(bool async, bool csum)
{
printf("test_recheck %s %s\n", async ? "async" : "sync", csum ? "csum" : "no_csum");
blockstore_disk_t dsk;
_test_init(dsk, csum);
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
@@ -993,15 +1027,52 @@ void test_recheck(bool async, bool csum, bool intent)
blockstore_heap_t heap(&dsk, buffer_area.data());
heap.finish_recheck();
// object 1
_test_big_write(heap, dsk, 1, 0, 1, 0x20000, true, 0, 8192, buffer_area.data());
_test_small_write(heap, dsk, 1, 0, 2, 8*1024, 8*1024, 16*1024, true, buffer_area.data(), intent);
// object 1 - two intent writes, both valid
_test_big_write(heap, dsk, 1, 0, 1, 0, true, 0, 8192, buffer_area.data());
_test_small_write(heap, dsk, 1, 0, 2, 4*1024, 8*1024, 0, true, buffer_area.data(), true);
_test_small_write(heap, dsk, 1, 0, 3, 8*1024, 8*1024, 0, true, buffer_area.data(), true);
// object 2
_test_big_write(heap, dsk, 2, 0, 1, 0x40000, true, 0, 8192, buffer_area.data());
if (intent)
_test_small_write(heap, dsk, 2, 0, 2, 20*1024, 4*1024, 36*1024, true, buffer_area.data(), intent);
_test_small_write(heap, dsk, 2, 0, intent ? 3 : 2, 8*1024, 12*1024, 24*1024, true, buffer_area.data(), intent);
// object 2 - two intent writes, second invalid
_test_big_write(heap, dsk, 2, 0, 1, 0x20000, true, 0, 8192, buffer_area.data());
_test_small_write(heap, dsk, 2, 0, 2, 4*1024, 8*1024, 0, true, buffer_area.data(), true);
_test_small_write(heap, dsk, 2, 0, 3, 8*1024, 8*1024, 0, true, buffer_area.data(), true);
// object 3 - 2 valid small writes
_test_big_write(heap, dsk, 3, 0, 1, 0x40000, true, 0, 8192, buffer_area.data());
memset(buffer_area.data()+12*1024, 0xab, 8*1024);
_test_small_write(heap, dsk, 3, 0, 2, 4*1024, 8*1024, 12*1024, true, buffer_area.data());
memset(buffer_area.data()+20*1024, 0xab, 8*1024);
_test_small_write(heap, dsk, 3, 0, 3, 8*1024, 8*1024, 20*1024, true, buffer_area.data());
// object 4 - first valid and second invalid small write
_test_big_write(heap, dsk, 4, 0, 1, 0x60000, true, 0, 8192, buffer_area.data());
memset(buffer_area.data()+28*1024, 0xab, 8*1024);
_test_small_write(heap, dsk, 4, 0, 2, 4*1024, 8*1024, 28*1024, true, buffer_area.data());
memset(buffer_area.data()+36*1024, 0xab, 8*1024);
memset(buffer_area.data()+36*1024+4096+40, 0xcc, 40);
_test_small_write(heap, dsk, 4, 0, 3, 8*1024, 8*1024, 36*1024, true, buffer_area.data());
// object 5 - first invalid and second valid small write
_test_big_write(heap, dsk, 5, 0, 1, 0x80000, true, 0, 8192, buffer_area.data());
memset(buffer_area.data()+44*1024, 0xab, 8*1024);
memset(buffer_area.data()+44*1024+4096+40, 0xcc, 40);
_test_small_write(heap, dsk, 5, 0, 2, 4*1024, 8*1024, 44*1024, true, buffer_area.data());
memset(buffer_area.data()+52*1024, 0xab, 8*1024);
_test_small_write(heap, dsk, 5, 0, 3, 8*1024, 8*1024, 52*1024, true, buffer_area.data());
// object 6 - single big_intent write, valid
_test_redirect_intent(heap, dsk, 6, 0, 1, 0xA0000, true, 16384, 8192, buffer_area.data());
// object 7 - single big_intent write, invalid
_test_redirect_intent(heap, dsk, 7, 0, 1, 0xC0000, true, 16384, 8192, buffer_area.data());
// object 8 - big_write + big_intent write, valid
_test_big_write(heap, dsk, 8, 0, 1, 0xE0000, true, 0, 8192, buffer_area.data());
_test_big_intent(heap, dsk, 8, 0, 2, true, 16384, 8192, buffer_area.data());
// object 9 - big_write + big_intent write, invalid
_test_big_write(heap, dsk, 9, 0, 1, 0x100000, true, 0, 8192, buffer_area.data());
_test_big_intent(heap, dsk, 9, 0, 2, true, 16384, 8192, buffer_area.data());
// persist
assert(heap.get_meta_block_used_space(0) > 0);
@@ -1011,8 +1082,10 @@ void test_recheck(bool async, bool csum, bool intent)
// reload heap
{
memset(buffer_area.data()+16*1024, 0xab, 20*1024); // valid data
memset(buffer_area.data()+20*1024+64, 0xcc, 4); // invalid data in the second block of the first write
memset(buffer_area.data()+16*1024, 0xab, 8*1024); // valid data for object 1
memset(buffer_area.data()+24*1024, 0xab, 12*1024); // valid data for object 1 write 1
memset(buffer_area.data()+36*1024, 0xab, 4*1024); // valid data for object 1 write 2
memset(buffer_area.data()+36*1024+64, 0xcc, 4); // invalid data for object 1 write 2
blockstore_heap_t heap(&dsk, async ? NULL : buffer_area.data(), 10);
uint64_t entries_loaded;
@@ -1025,24 +1098,37 @@ void test_recheck(bool async, bool csum, bool intent)
calls++;
if (len)
{
if (!intent)
assert(len == 8*1024);
if (is_data)
{
assert(!is_data);
assert(offset == 16384 && len == 8192 || offset == 24*1024 && len == 12*1024);
memcpy(buf, buffer_area.data()+offset, len);
// intent writes
if (offset == 8*1024) // valid
memcpy(buf, buffer_area.data(), len);
else if (offset == 0x20000+8*1024) // invalid
memset(buf, 0xcc, len);
else if (offset == 0xA0000+16*1024) // valid
memcpy(buf, buffer_area.data(), len);
else if (offset == 0xC0000+16*1024) // invalid
memset(buf, 0xcc, len);
else if (offset == 0xE0000+16*1024) // valid
memcpy(buf, buffer_area.data(), len);
else if (offset == 0x100000+16*1024) // invalid
memset(buf, 0xcc, len);
else
assert(0);
}
else
{
assert(is_data);
assert(offset == 0x20000+8192 && len == 8192 || 0x40000+8192 && len == 12*1024);
memcpy(buf, buffer_area.data() + (offset == 0x20000+8192 ? 16*1024 : 24*1024), len);
assert(offset == 12*1024 || offset == 20*1024 || offset == 28*1024 || offset == 36*1024 ||
offset == 44*1024 || offset == 52*1024);
memcpy(buf, buffer_area.data()+offset, len);
}
assert(cb);
cb();
}
}, 1);
assert(done);
assert(calls == (async || intent ? 3 : 1));
assert(calls == (async ? 13 : 7));
heap.finish_recheck();
@@ -1050,30 +1136,88 @@ void test_recheck(bool async, bool csum, bool intent)
assert(mod.size() == 1);
assert(mod[0] == 0);
// read object 1 - big_write should be there but small_write should be rechecked and removed
// check objects
object_id oid = { .inode = INODE_WITH_POOL(1, 1), .stripe = 0 };
heap_entry_t *obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 1);
assert(obj->lsn == 1);
assert(obj->entry_type == BS_HEAP_BIG_WRITE|BS_HEAP_STABLE);
assert(obj->version == 1);
assert(obj->big_location(&heap) == 0x20000);
assert(count_writes(heap, obj) == 3);
assert(obj->lsn == 3);
assert(obj->entry_type == BS_HEAP_INTENT_WRITE|BS_HEAP_STABLE);
assert(obj->version == 3);
// read object 2 - both writes should be present
oid = { .inode = INODE_WITH_POOL(1, 2), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == (intent ? 3 : 2));
assert(obj->lsn == (intent ? 5 : 4));
assert(count_writes(heap, obj) == 2);
assert(obj->lsn == 5);
assert(obj->entry_type == BS_HEAP_INTENT_WRITE|BS_HEAP_STABLE);
assert(obj->version == 2);
oid = { .inode = INODE_WITH_POOL(1, 3), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 3);
assert(obj->lsn == 9);
assert(obj->entry_type == BS_HEAP_SMALL_WRITE|BS_HEAP_STABLE);
assert(obj->version == (intent ? 3 : 2));
assert(obj->small().offset == 8192);
assert(obj->small().len == 12*1024);
assert(obj->small().location == 24*1024);
assert(obj->version == 3);
assert(obj->small().offset == 8*1024);
assert(obj->small().len == 8*1024);
assert(obj->small().location == 20*1024);
oid = { .inode = INODE_WITH_POOL(1, 4), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 2);
assert(obj->lsn == 11);
assert(obj->entry_type == BS_HEAP_SMALL_WRITE|BS_HEAP_STABLE);
assert(obj->version == 2);
assert(obj->small().offset == 4*1024);
assert(obj->small().len == 8*1024);
assert(obj->small().location == 28*1024);
oid = { .inode = INODE_WITH_POOL(1, 5), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 1);
assert(obj->lsn == 13);
assert(obj->entry_type == BS_HEAP_BIG_WRITE|BS_HEAP_STABLE);
assert(obj->version == 1);
oid = { .inode = INODE_WITH_POOL(1, 6), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 1);
assert(obj->lsn == 16);
assert(obj->entry_type == BS_HEAP_BIG_INTENT|BS_HEAP_STABLE);
assert(obj->version == 1);
oid = { .inode = INODE_WITH_POOL(1, 7), .stripe = 0 };
obj = heap.read_entry(oid);
assert(!obj);
oid = { .inode = INODE_WITH_POOL(1, 8), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 1);
assert(obj->lsn == 19);
assert(obj->entry_type == BS_HEAP_BIG_INTENT|BS_HEAP_STABLE);
assert(obj->version == 2);
oid = { .inode = INODE_WITH_POOL(1, 9), .stripe = 0 };
obj = heap.read_entry(oid);
assert(obj);
assert(count_writes(heap, obj) == 1);
assert(obj->lsn == 21); // lsn 20 is inserted for compaction
assert(obj->entry_type == BS_HEAP_BIG_WRITE|BS_HEAP_STABLE);
assert(obj->version == 1);
// check space
assert(check_used_space(heap, dsk, 0));
}
printf("OK test_recheck %s %s %s\n", async ? "async" : "sync", csum ? "csum" : "no_csum", intent ? "intent" : "buffered");
printf("...OK\n");
}
void test_corruption()
@@ -2488,14 +2632,10 @@ int main(int narg, char *args[])
test_compact(false, false);
test_iterate_compaction();
test_modify_bitmap();
test_recheck(false, true, false);
test_recheck(false, false, false);
test_recheck(true, true, false);
test_recheck(true, false, false);
test_recheck(false, true, true);
test_recheck(false, false, true);
test_recheck(true, true, true);
test_recheck(true, false, true);
test_recheck(false, true);
test_recheck(false, false);
test_recheck(true, true);
test_recheck(true, false);
test_corruption();
test_full_overwrite(true);
test_full_overwrite(false);