Use linked list heap in blockstore code
WIP, still slower than the old version :-E
This commit is contained in:
@@ -62,6 +62,16 @@ journal_flusher_co::~journal_flusher_co()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int journal_flusher_t::get_active()
|
||||||
|
{
|
||||||
|
return active_flushers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t journal_flusher_t::get_counter()
|
||||||
|
{
|
||||||
|
return compact_counter;
|
||||||
|
}
|
||||||
|
|
||||||
bool journal_flusher_t::is_active()
|
bool journal_flusher_t::is_active()
|
||||||
{
|
{
|
||||||
return active_flushers > 0 || bs->heap->get_compact_queue_size() > (force_start > 0 ? 0 : bs->flusher_start_threshold);
|
return active_flushers > 0 || bs->heap->get_compact_queue_size() > (force_start > 0 ? 0 : bs->flusher_start_threshold);
|
||||||
@@ -107,8 +117,11 @@ void journal_flusher_t::loop()
|
|||||||
cur_flusher_count--;
|
cur_flusher_count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int prev_active = active_flushers;
|
||||||
for (int i = 0; is_active() && i < cur_flusher_count; i++)
|
for (int i = 0; is_active() && i < cur_flusher_count; i++)
|
||||||
co[i].loop();
|
co[i].loop();
|
||||||
|
if (prev_active && !active_flushers && force_start > 0)
|
||||||
|
bs->ringloop->wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define await_sqe(label) \
|
#define await_sqe(label) \
|
||||||
@@ -168,7 +181,7 @@ resume_1:
|
|||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
compact_lsn = begin_wr->lsn;
|
compact_lsn = begin_wr->lsn;
|
||||||
assert(end_wr < (heap_write_t*)cur_obj->next() && end_wr->flags == (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE));
|
assert(!end_wr->next() && end_wr->flags == (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE));
|
||||||
clean_loc = end_wr->location;
|
clean_loc = end_wr->location;
|
||||||
// "Lock" object for flushing
|
// "Lock" object for flushing
|
||||||
repeat_it = flusher->sync_to_repeat.find(cur_oid);
|
repeat_it = flusher->sync_to_repeat.find(cur_oid);
|
||||||
@@ -194,7 +207,7 @@ resume_1:
|
|||||||
flusher->active_flushers++;
|
flusher->active_flushers++;
|
||||||
// Scan versions to flush
|
// Scan versions to flush
|
||||||
read_vec.clear();
|
read_vec.clear();
|
||||||
for (auto wr = begin_wr; wr != end_wr; wr = wr->next(bs->heap))
|
for (auto wr = begin_wr; wr != end_wr; wr = wr->next())
|
||||||
{
|
{
|
||||||
min_compact_lsn = wr->lsn;
|
min_compact_lsn = wr->lsn;
|
||||||
bs->prepare_read(read_vec, cur_obj, wr, 0, bs->dsk.data_block_size);
|
bs->prepare_read(read_vec, cur_obj, wr, 0, bs->dsk.data_block_size);
|
||||||
@@ -206,8 +219,7 @@ resume_1:
|
|||||||
overwrite_end = read_vec[read_vec.size()-1].offset + read_vec[read_vec.size()-1].len;
|
overwrite_end = read_vec[read_vec.size()-1].offset + read_vec[read_vec.size()-1].len;
|
||||||
}
|
}
|
||||||
read_to_fill_incomplete = false;
|
read_to_fill_incomplete = false;
|
||||||
if (bs->dsk.csum_block_size > bs->dsk.bitmap_granularity &&
|
if (bs->dsk.csum_block_size > bs->dsk.bitmap_granularity && end_wr->next())
|
||||||
end_wr < (heap_write_t*)cur_obj->next())
|
|
||||||
{
|
{
|
||||||
// Read original checksum blocks to calculate padded checksums if required
|
// Read original checksum blocks to calculate padded checksums if required
|
||||||
fill_partial_checksum_blocks();
|
fill_partial_checksum_blocks();
|
||||||
@@ -271,13 +283,12 @@ resume_12:
|
|||||||
resume_13:
|
resume_13:
|
||||||
if (copy_count && !fsync_batch(false, 11))
|
if (copy_count && !fsync_batch(false, 11))
|
||||||
return false;
|
return false;
|
||||||
|
bs->heap->unlock_entry(cur_oid, cur_lsn);
|
||||||
// Modify the metadata entry; don't write anything. Metadata block will be written on the next write
|
// Modify the metadata entry; don't write anything. Metadata block will be written on the next write
|
||||||
calc_block_checksums();
|
calc_block_checksums();
|
||||||
bs->heap->compact_object(cur_oid, cur_lsn, new_data_csums);
|
bs->heap->compact_object(cur_oid, cur_lsn, new_data_csums);
|
||||||
// Done, free all buffers
|
// Done, free all buffers
|
||||||
free_buffers();
|
free_buffers();
|
||||||
// Unlock entry and free referenced block only after fsync
|
|
||||||
bs->heap->unlock_entry(cur_oid, cur_lsn);
|
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
printf("Compacted %jx:%jx v%ju (%d writes)\n", cur_oid.inode, cur_oid.stripe, cur_version, copy_count);
|
printf("Compacted %jx:%jx v%ju (%d writes)\n", cur_oid.inode, cur_oid.stripe, cur_version, copy_count);
|
||||||
#endif
|
#endif
|
||||||
@@ -296,16 +307,16 @@ release_oid:
|
|||||||
repeat_it = flusher->sync_to_repeat.find(cur_oid);
|
repeat_it = flusher->sync_to_repeat.find(cur_oid);
|
||||||
do_repeat = (repeat_it != flusher->sync_to_repeat.end() && repeat_it->second > cur_version);
|
do_repeat = (repeat_it != flusher->sync_to_repeat.end() && repeat_it->second > cur_version);
|
||||||
flusher->sync_to_repeat.erase(repeat_it);
|
flusher->sync_to_repeat.erase(repeat_it);
|
||||||
|
flusher->active_flushers--;
|
||||||
if (do_repeat)
|
if (do_repeat)
|
||||||
{
|
{
|
||||||
// Flush the same object again
|
// Flush the same object again
|
||||||
goto resume_1;
|
goto resume_1;
|
||||||
}
|
}
|
||||||
// All done
|
// All done
|
||||||
flusher->active_flushers--;
|
flusher->compact_counter++;
|
||||||
wait_state = 0;
|
wait_state = 0;
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void journal_flusher_co::iterate_partial_overwrites(std::function<int(int, uint32_t, uint32_t)> cb)
|
void journal_flusher_co::iterate_partial_overwrites(std::function<int(int, uint32_t, uint32_t)> cb)
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class journal_flusher_t
|
|||||||
friend class journal_flusher_co;
|
friend class journal_flusher_co;
|
||||||
|
|
||||||
int advance_lsn_counter = 0;
|
int advance_lsn_counter = 0;
|
||||||
|
uint64_t compact_counter = 0;
|
||||||
|
|
||||||
int active_flushers = 0;
|
int active_flushers = 0;
|
||||||
int syncing_flushers = 0;
|
int syncing_flushers = 0;
|
||||||
@@ -105,6 +106,8 @@ public:
|
|||||||
journal_flusher_t(blockstore_impl_t *bs);
|
journal_flusher_t(blockstore_impl_t *bs);
|
||||||
~journal_flusher_t();
|
~journal_flusher_t();
|
||||||
void loop();
|
void loop();
|
||||||
|
int get_active();
|
||||||
|
uint64_t get_counter();
|
||||||
bool is_active();
|
bool is_active();
|
||||||
void request_trim();
|
void request_trim();
|
||||||
void release_trim();
|
void release_trim();
|
||||||
|
|||||||
@@ -244,11 +244,11 @@ void blockstore_impl_t::check_wait(blockstore_op_t *op)
|
|||||||
}
|
}
|
||||||
else if (PRIV(op)->wait_for == WAIT_COMPACTION)
|
else if (PRIV(op)->wait_for == WAIT_COMPACTION)
|
||||||
{
|
{
|
||||||
if (heap->get_compact_queue_size() >= PRIV(op)->wait_detail)
|
if (flusher->get_counter() <= PRIV(op)->wait_detail)
|
||||||
{
|
{
|
||||||
// do not submit
|
// do not submit
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
printf("Still waiting to reduce compaction queue size below %ju\n", PRIV(op)->wait_detail);
|
printf("Still waiting for more flushes\n");
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *op)
|
|||||||
PRIV(op)->pending_ops = 0;
|
PRIV(op)->pending_ops = 0;
|
||||||
auto & rv = PRIV(op)->read_vec;
|
auto & rv = PRIV(op)->read_vec;
|
||||||
uint64_t result_version = 0;
|
uint64_t result_version = 0;
|
||||||
for (heap_write_t *wr = obj->get_writes(); wr < (heap_write_t*)obj->next(); wr = wr->next(heap))
|
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||||
{
|
{
|
||||||
if (op->version < wr->version)
|
if (op->version < wr->version)
|
||||||
{
|
{
|
||||||
@@ -362,7 +362,7 @@ int blockstore_impl_t::read_bitmap(object_id oid, uint64_t target_version, void
|
|||||||
heap_object_t *obj = heap->read_entry(oid, NULL);
|
heap_object_t *obj = heap->read_entry(oid, NULL);
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
for (heap_write_t *wr = obj->get_writes(); wr < (heap_write_t*)obj->next(); wr = wr->next(heap))
|
for (auto wr = obj->get_writes(); wr; wr = wr->next())
|
||||||
{
|
{
|
||||||
if (target_version < wr->version)
|
if (target_version < wr->version)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ void blockstore_impl_t::cancel_all_writes(blockstore_op_t *op, int retval)
|
|||||||
(other_op->opcode == BS_OP_WRITE || other_op->opcode == BS_OP_WRITE_STABLE))
|
(other_op->opcode == BS_OP_WRITE || other_op->opcode == BS_OP_WRITE_STABLE))
|
||||||
{
|
{
|
||||||
// Mark operations to cancel them
|
// Mark operations to cancel them
|
||||||
|
if (PRIV(other_op)->op_state != 0 && PRIV(other_op)->op_state != 100)
|
||||||
|
write_iodepth--;
|
||||||
PRIV(other_op)->op_state = 100;
|
PRIV(other_op)->op_state = 100;
|
||||||
other_op->retval = retval;
|
other_op->retval = retval;
|
||||||
}
|
}
|
||||||
@@ -85,6 +87,7 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
prepare_meta_block_write(op, modified_block);
|
prepare_meta_block_write(op, modified_block);
|
||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
PRIV(op)->op_state = 5;
|
PRIV(op)->op_state = 5;
|
||||||
|
write_iodepth++;
|
||||||
}
|
}
|
||||||
// FIXME: Allow to do initial writes as buffered, not redirected
|
// FIXME: Allow to do initial writes as buffered, not redirected
|
||||||
// FIXME: Allow to do direct writes over holes
|
// FIXME: Allow to do direct writes over holes
|
||||||
@@ -97,20 +100,18 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
if (loc == UINT64_MAX ||
|
if (loc == UINT64_MAX ||
|
||||||
!obj && heap->get_block_for_new_object(tmp_block) != 0)
|
!obj && heap->get_block_for_new_object(tmp_block) != 0)
|
||||||
{
|
{
|
||||||
auto queue_size = heap->get_compact_queue_size();
|
if (!heap->get_compact_queue_size() && !flusher->get_active())
|
||||||
if (!queue_size)
|
|
||||||
{
|
{
|
||||||
// no space
|
// no space
|
||||||
cancel_all_writes(op, -ENOSPC);
|
cancel_all_writes(op, -ENOSPC);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
PRIV(op)->wait_for = WAIT_COMPACTION;
|
PRIV(op)->wait_for = WAIT_COMPACTION;
|
||||||
PRIV(op)->wait_detail = queue_size;
|
PRIV(op)->wait_detail = flusher->get_counter();
|
||||||
flusher->request_trim();
|
flusher->request_trim();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
BS_SUBMIT_GET_SQE(sqe, data);
|
BS_SUBMIT_GET_SQE(sqe, data);
|
||||||
write_iodepth++;
|
|
||||||
PRIV(op)->location = loc;
|
PRIV(op)->location = loc;
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
printf(
|
printf(
|
||||||
@@ -141,6 +142,7 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
PRIV(op)->pending_ops = 1;
|
PRIV(op)->pending_ops = 1;
|
||||||
unsynced_big_write_count++;
|
unsynced_big_write_count++;
|
||||||
PRIV(op)->op_state = 1;
|
PRIV(op)->op_state = 1;
|
||||||
|
write_iodepth++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -150,13 +152,12 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
if (loc == UINT64_MAX)
|
if (loc == UINT64_MAX)
|
||||||
{
|
{
|
||||||
PRIV(op)->wait_for = WAIT_COMPACTION;
|
PRIV(op)->wait_for = WAIT_COMPACTION;
|
||||||
PRIV(op)->wait_detail = heap->get_compact_queue_size();
|
PRIV(op)->wait_detail = flusher->get_counter();
|
||||||
flusher->request_trim();
|
flusher->request_trim();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// There is sufficient space. Check SQE(s)
|
// There is sufficient space. Check SQE(s)
|
||||||
BS_SUBMIT_CHECK_SQES(1 + (op->len > 0 ? 1 : 0));
|
BS_SUBMIT_CHECK_SQES(1 + (op->len > 0 ? 1 : 0));
|
||||||
write_iodepth++;
|
|
||||||
uint8_t wr_buf[heap->get_max_write_entry_size()];
|
uint8_t wr_buf[heap->get_max_write_entry_size()];
|
||||||
heap_write_t *wr = (heap_write_t*)wr_buf;
|
heap_write_t *wr = (heap_write_t*)wr_buf;
|
||||||
wr->version = op->version;
|
wr->version = op->version;
|
||||||
@@ -173,12 +174,15 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
int res = heap->post_write(op->oid, wr, &modified_block);
|
int res = heap->post_write(op->oid, wr, &modified_block);
|
||||||
if (res == ENOSPC)
|
if (res == ENOSPC)
|
||||||
{
|
{
|
||||||
cancel_all_writes(op, -ENOSPC);
|
if (!heap->get_compact_queue_size() && !flusher->get_active())
|
||||||
return 2;
|
{
|
||||||
}
|
// no space
|
||||||
else if (res == EAGAIN)
|
cancel_all_writes(op, -ENOSPC);
|
||||||
{
|
return 2;
|
||||||
// Pause submission, wait for compaction
|
}
|
||||||
|
PRIV(op)->wait_for = WAIT_COMPACTION;
|
||||||
|
PRIV(op)->wait_detail = flusher->get_counter();
|
||||||
|
flusher->request_trim();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
@@ -202,11 +206,13 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
if (!PRIV(op)->pending_ops)
|
if (!PRIV(op)->pending_ops)
|
||||||
{
|
{
|
||||||
PRIV(op)->op_state = 6;
|
PRIV(op)->op_state = 6;
|
||||||
|
write_iodepth++;
|
||||||
return continue_write(op);
|
return continue_write(op);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PRIV(op)->op_state = 5;
|
PRIV(op)->op_state = 5;
|
||||||
|
write_iodepth++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -260,7 +266,8 @@ resume_4:
|
|||||||
int res = heap->post_write(op->oid, wr, &modified_block);
|
int res = heap->post_write(op->oid, wr, &modified_block);
|
||||||
if (res == ENOSPC)
|
if (res == ENOSPC)
|
||||||
{
|
{
|
||||||
// wait for compaction
|
PRIV(op)->wait_for = WAIT_COMPACTION;
|
||||||
|
PRIV(op)->wait_detail = flusher->get_counter();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user