Fix read_fulfill, use vector

blocking-uring-test
Vitaliy Filippov 2019-12-03 12:09:30 +03:00
parent a2ed38fb6b
commit aaea3e1f99
5 changed files with 77 additions and 74 deletions

View File

@ -202,6 +202,11 @@ public:
// Suspend operation until there is some free space on the data device
#define WAIT_FREE 5
struct fulfill_read_t
{
uint64_t offset, len;
};
struct blockstore_operation
{
// flags contain operation type and possibly other flags
@ -231,7 +236,7 @@ private:
int pending_ops;
// Read
std::map<uint64_t, struct iovec> read_vec;
std::vector<fulfill_read_t> read_vec;
// Sync, write
uint64_t min_used_journal_sector, max_used_journal_sector;
@ -312,8 +317,8 @@ class blockstore
int dequeue_read(blockstore_operation *read_op);
int fulfill_read(blockstore_operation *read_op, uint64_t &fulfilled, uint32_t item_start, uint32_t item_end,
uint32_t item_state, uint64_t item_version, uint64_t item_location);
int fulfill_read_push(blockstore_operation *read_op, uint64_t &fulfilled, uint32_t item_start,
uint32_t item_state, uint64_t item_version, uint64_t item_location, uint32_t cur_start, uint32_t cur_end);
int fulfill_read_push(blockstore_operation *op, void *buf, uint64_t offset, uint64_t len,
uint32_t item_state, uint64_t item_version);
void handle_read_event(ring_data_t *data, blockstore_operation *op);
// Write

View File

@ -200,7 +200,7 @@ bool journal_flusher_co::loop()
{
// First we submit all reads
offset = dirty_it->second.offset;
len = dirty_it->second.len;
end_offset = dirty_it->second.offset + dirty_it->second.len;
it = v.begin();
while (1)
{
@ -210,7 +210,7 @@ bool journal_flusher_co::loop()
if (it == v.end() || it->offset > offset)
{
submit_offset = dirty_it->second.location + offset - dirty_it->second.offset;
submit_len = it == v.end() || it->offset >= offset+len ? len : it->offset-offset;
submit_len = it == v.end() || it->offset >= end_offset ? end_offset-offset : it->offset-offset;
it = v.insert(it, (copy_buffer_t){ .offset = offset, .len = submit_len, .buf = memalign(512, submit_len) });
copy_count++;
if (bs->journal.inmemory)
@ -230,12 +230,11 @@ bool journal_flusher_co::loop()
wait_count++;
}
}
if (it == v.end() || it->offset+it->len >= offset+len)
{
offset = it->offset+it->len;
if (it == v.end() || offset >= end_offset)
break;
}
}
}
else if (dirty_it->second.state == ST_D_STABLE && !skip_copy)
{
// There is an unflushed big write. Copy small writes in its position

View File

@ -43,7 +43,7 @@ class journal_flusher_co
std::vector<copy_buffer_t> v;
std::vector<copy_buffer_t>::iterator it;
int copy_count;
uint64_t offset, len, submit_offset, submit_len, clean_loc, old_clean_loc, old_clean_ver;
uint64_t offset, end_offset, submit_offset, submit_len, clean_loc, old_clean_loc, old_clean_ver;
flusher_meta_write_t meta_old, meta_new;
std::map<object_id, uint64_t>::iterator repeat_it;
std::function<void(ring_data_t*)> simple_callback_r, simple_callback_w;

View File

@ -1,9 +1,7 @@
#include "blockstore.h"
int blockstore::fulfill_read_push(blockstore_operation *op, uint64_t &fulfilled, uint32_t item_start,
uint32_t item_state, uint64_t item_version, uint64_t item_location, uint32_t cur_start, uint32_t cur_end)
{
if (cur_end > cur_start)
int blockstore::fulfill_read_push(blockstore_operation *op, void *buf, uint64_t offset, uint64_t len,
uint32_t item_state, uint64_t item_version)
{
if (IS_IN_FLIGHT(item_state))
{
@ -15,36 +13,24 @@ int blockstore::fulfill_read_push(blockstore_operation *op, uint64_t &fulfilled,
else if (IS_DELETE(item_state))
{
// item is unallocated - return zeroes
memset((uint8_t*)op->buf + cur_start - op->offset, 0, cur_end - cur_start);
memset(buf, 0, len);
return 1;
}
if (journal.inmemory && IS_JOURNAL(item_state))
{
iovec v = {
(uint8_t*)op->buf + cur_start - op->offset,
cur_end - cur_start
};
op->read_vec[cur_start] = v;
memcpy(v.iov_base, journal.buffer + item_location + cur_start - item_start, v.iov_len);
memcpy(buf, journal.buffer + offset, len);
return 1;
}
BS_SUBMIT_GET_SQE(sqe, data);
data->iov = (struct iovec){
(uint8_t*)op->buf + cur_start - op->offset,
cur_end - cur_start
};
// FIXME: use simple std::vector instead of map for read_vec
op->read_vec[cur_start] = data->iov;
data->iov = (struct iovec){ buf, len };
op->pending_ops++;
my_uring_prep_readv(
sqe,
IS_JOURNAL(item_state) ? journal.fd : data_fd,
&data->iov, 1,
(IS_JOURNAL(item_state) ? journal.offset : data_offset) + item_location + cur_start - item_start
(IS_JOURNAL(item_state) ? journal.offset : data_offset) + offset
);
data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); };
fulfilled += cur_end-cur_start;
}
return 1;
}
@ -56,27 +42,28 @@ int blockstore::fulfill_read(blockstore_operation *read_op, uint64_t &fulfilled,
{
cur_start = cur_start < read_op->offset ? read_op->offset : cur_start;
item_end = item_end > read_op->offset + read_op->len ? read_op->offset + read_op->len : item_end;
auto fulfill_near = read_op->read_vec.lower_bound(cur_start);
if (fulfill_near != read_op->read_vec.begin())
auto it = read_op->read_vec.begin();
while (1)
{
fulfill_near--;
if (fulfill_near->first + fulfill_near->second.iov_len <= cur_start)
for (; it != read_op->read_vec.end(); it++)
if (it->offset >= cur_start)
break;
if (it == read_op->read_vec.end() || it->offset > cur_start)
{
fulfill_near++;
}
}
while (fulfill_near != read_op->read_vec.end() && fulfill_near->first < item_end)
{
if (!fulfill_read_push(read_op, fulfilled, item_start, item_state, item_version, item_location, cur_start, fulfill_near->first))
fulfill_read_t el = {
.offset = cur_start,
.len = it == read_op->read_vec.end() || it->offset >= item_end ? item_end-cur_start : it->offset-cur_start,
};
it = read_op->read_vec.insert(it, el);
fulfilled += el.len;
if (!fulfill_read_push(read_op, read_op->buf + el.offset - read_op->offset, item_location + el.offset - item_start, el.len, item_state, item_version))
{
return 0;
}
cur_start = fulfill_near->first + fulfill_near->second.iov_len;
fulfill_near++;
}
if (!fulfill_read_push(read_op, fulfilled, item_start, item_state, item_version, item_location, cur_start, item_end))
{
return 0;
cur_start = it->offset + it->len;
if (it == read_op->read_vec.end() || cur_start >= item_end)
break;
}
}
return 1;
@ -141,10 +128,18 @@ int blockstore::dequeue_read(blockstore_operation *read_op)
return 0;
}
}
if (!read_op->pending_ops)
{
// everything is fulfilled from memory
if (!read_op->read_vec.size())
{
// region is not allocated - return zeroes
memset(read_op->buf, 0, read_op->len);
}
if (fulfilled != read_op->len)
{
printf("BUG: fulfilled %lu < %d read bytes\n", fulfilled, read_op->len);
}
read_op->retval = read_op->len;
read_op->callback(read_op);
return 1;

View File

@ -194,11 +194,15 @@ static enum fio_q_status bs_queue(struct thread_data *td, struct io_u *io)
};
op->offset = io->offset % bsd->bs->block_size;
op->len = io->xfer_buflen;
op->callback = [io](blockstore_operation *op)
op->callback = [io, n](blockstore_operation *op)
{
io->error = op->retval < 0 ? -op->retval : 0;
bs_data *bsd = (bs_data*)io->engine_data;
bsd->inflight--;
bsd->completed.push_back(io);
#ifdef BLOCKSTORE_DEBUG
printf("--- OP_READ %llx n=%d retval=%d\n", io, n, op->retval);
#endif
delete op;
};
break;
@ -276,7 +280,7 @@ static enum fio_q_status bs_queue(struct thread_data *td, struct io_u *io)
}
#ifdef BLOCKSTORE_DEBUG
printf("+++ %s %llx\n", op->flags == OP_WRITE ? "OP_WRITE" : "OP_SYNC", io);
printf("+++ %s %llx n=%d\n", op->flags == OP_READ ? "OP_READ" : (op->flags == OP_WRITE ? "OP_WRITE" : "OP_SYNC"), io, n);
#endif
io->error = 0;
bsd->inflight++;