Add a regression test for the last 2 fixed bugs
This commit is contained in:
@@ -72,7 +72,7 @@ int ring_loop_mock_t::register_eventfd()
|
|||||||
|
|
||||||
io_uring_sqe* ring_loop_mock_t::get_sqe()
|
io_uring_sqe* ring_loop_mock_t::get_sqe()
|
||||||
{
|
{
|
||||||
if (free_ring_datas.size() == 0)
|
if (free_ring_datas.size() == 0 || is_full && is_full())
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -399,3 +399,8 @@ bool disk_mock_t::submit(io_uring_sqe *sqe)
|
|||||||
// 3) when fsync is enabled, write cache should be sometimes lost during a simulated power outage
|
// 3) when fsync is enabled, write cache should be sometimes lost during a simulated power outage
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ring_loop_mock_t::set_fake_full(std::function<bool()> is_full)
|
||||||
|
{
|
||||||
|
this->is_full = is_full;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ class ring_loop_mock_t: public ring_loop_i
|
|||||||
std::vector<ring_data_t *> submit_ring_datas;
|
std::vector<ring_data_t *> submit_ring_datas;
|
||||||
std::vector<ring_data_t *> completed_ring_datas;
|
std::vector<ring_data_t *> completed_ring_datas;
|
||||||
std::function<void(io_uring_sqe *)> submit_cb;
|
std::function<void(io_uring_sqe *)> submit_cb;
|
||||||
bool in_loop;
|
bool fake_full = false;
|
||||||
bool loop_again;
|
bool in_loop = false;
|
||||||
|
bool loop_again = false;
|
||||||
bool support_zc = false;
|
bool support_zc = false;
|
||||||
|
std::function<bool()> is_full;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ring_loop_mock_t(int qd, std::function<void(io_uring_sqe *)> submit_cb);
|
ring_loop_mock_t(int qd, std::function<void(io_uring_sqe *)> submit_cb);
|
||||||
@@ -40,6 +42,7 @@ public:
|
|||||||
void restore(unsigned sqe_tail);
|
void restore(unsigned sqe_tail);
|
||||||
|
|
||||||
void mark_completed(ring_data_t *data);
|
void mark_completed(ring_data_t *data);
|
||||||
|
void set_fake_full(std::function<bool()> is_full);
|
||||||
};
|
};
|
||||||
|
|
||||||
class disk_mock_t
|
class disk_mock_t
|
||||||
|
|||||||
@@ -376,9 +376,89 @@ static void test_validate_padded_journal()
|
|||||||
free(read_op.buf);
|
free(read_op.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that read is retried and temporary read buffers are freed correctly (LSAN)
|
||||||
|
// TODO: Check retries in other configuration
|
||||||
|
static void test_read_retry_on_ring_full_1M_csum4k_clean()
|
||||||
|
{
|
||||||
|
printf("\n-- test_read_retry_on_ring_full_1M_csum4k_clean\n");
|
||||||
|
|
||||||
|
bs_test_t test;
|
||||||
|
test.default_cfg();
|
||||||
|
test.config["inmemory_metadata"] = "0";
|
||||||
|
test.config["block_size"] = "1048576";
|
||||||
|
test.config["data_csum_type"] = "crc32c";
|
||||||
|
test.config["csum_block_size"] = "4096";
|
||||||
|
test.init();
|
||||||
|
printf("blockstore initialized\n");
|
||||||
|
|
||||||
|
// Big_write without external bitmap(!) - also checks if journaled big_writes
|
||||||
|
// are handled correctly (they don't have an external bitmap)
|
||||||
|
printf("write v1 0+1M\n");
|
||||||
|
blockstore_op_t op;
|
||||||
|
op.opcode = BS_OP_WRITE_STABLE;
|
||||||
|
op.oid = { .inode = 1, .stripe = 0 };
|
||||||
|
op.version = 1;
|
||||||
|
op.offset = 0;
|
||||||
|
op.len = 1024*1024;
|
||||||
|
op.buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, op.len);
|
||||||
|
memset(op.buf, 0xAA, op.len);
|
||||||
|
test.exec_op(&op);
|
||||||
|
assert(op.retval == op.len);
|
||||||
|
|
||||||
|
// Wait for flushing
|
||||||
|
printf("triggering compaction\n");
|
||||||
|
test.flusher()->request_trim();
|
||||||
|
while (test.flusher()->get_queue_size())
|
||||||
|
test.ringloop->loop();
|
||||||
|
while (test.flusher()->is_active())
|
||||||
|
test.ringloop->loop();
|
||||||
|
test.flusher()->release_trim();
|
||||||
|
assert(!test.flusher()->get_queue_size());
|
||||||
|
printf("compaction complete\n");
|
||||||
|
|
||||||
|
// Read with retry
|
||||||
|
printf("read with ring-full-retries\n");
|
||||||
|
blockstore_op_t read_op;
|
||||||
|
read_op.opcode = BS_OP_READ;
|
||||||
|
read_op.oid = { .inode = 1, .stripe = 0 };
|
||||||
|
read_op.version = 2;
|
||||||
|
read_op.offset = 0;
|
||||||
|
read_op.len = 1024*1024;
|
||||||
|
read_op.buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, read_op.len);
|
||||||
|
int req_count = 0;
|
||||||
|
int retry_on = 0;
|
||||||
|
bool done = false;
|
||||||
|
read_op.callback = [&](blockstore_op_t *op)
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
};
|
||||||
|
// Force a retry after each sqe
|
||||||
|
test.ringloop->set_fake_full([&]
|
||||||
|
{
|
||||||
|
if (req_count == retry_on)
|
||||||
|
{
|
||||||
|
printf("hit retry on sqe %d\n", req_count);
|
||||||
|
req_count = 0;
|
||||||
|
retry_on++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
req_count++;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
test.bs->enqueue_op(&read_op);
|
||||||
|
while (!done)
|
||||||
|
test.ringloop->loop();
|
||||||
|
read_op.callback = nullptr;
|
||||||
|
assert(read_op.retval == read_op.len);
|
||||||
|
|
||||||
|
free(op.buf);
|
||||||
|
free(read_op.buf);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int narg, char *args[])
|
int main(int narg, char *args[])
|
||||||
{
|
{
|
||||||
test_preserve_corruption();
|
test_preserve_corruption();
|
||||||
test_validate_padded_journal();
|
test_validate_padded_journal();
|
||||||
|
test_read_retry_on_ring_full_1M_csum4k_clean();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user