Fix GC and loading

This commit is contained in:
Vitaliy Filippov
2025-12-02 01:52:12 +03:00
parent d80c12ced2
commit 7b40561141
2 changed files with 79 additions and 57 deletions
+78 -56
View File
@@ -213,6 +213,13 @@ blockstore_heap_t::blockstore_heap_t(blockstore_disk_t *dsk, uint8_t *buffer_are
blockstore_heap_t::~blockstore_heap_t() blockstore_heap_t::~blockstore_heap_t()
{ {
for (auto & inflight: inflight_lsn)
{
if (inflight.flags & HEAP_INFLIGHT_GC)
{
free(list_item(inflight.wr));
}
}
for (auto & inf: block_info) for (auto & inf: block_info)
{ {
for (auto & entry: inf.entries) for (auto & entry: inf.entries)
@@ -295,7 +302,6 @@ int blockstore_heap_t::read_blocks(uint64_t disk_offset, uint64_t disk_size, uin
int blockstore_heap_t::load_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf, uint64_t &entries_loaded) int blockstore_heap_t::load_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf, uint64_t &entries_loaded)
{ {
entries_loaded = 0; entries_loaded = 0;
uint32_t used_space = 0;
return read_blocks(disk_offset, size, buf, [&](uint32_t block_num, heap_entry_t *wr_orig) return read_blocks(disk_offset, size, buf, [&](uint32_t block_num, heap_entry_t *wr_orig)
{ {
heap_list_item_t *li = (heap_list_item_t*)malloc_or_die(wr_orig->size + sizeof(heap_list_item_t) - sizeof(heap_entry_t)); heap_list_item_t *li = (heap_list_item_t*)malloc_or_die(wr_orig->size + sizeof(heap_list_item_t) - sizeof(heap_entry_t));
@@ -315,34 +321,32 @@ int blockstore_heap_t::load_blocks(uint64_t disk_offset, uint64_t size, uint8_t
{ {
// Mark <wr> as garbage // Mark <wr> as garbage
wr->set_garbage(); wr->set_garbage();
block_info[li->block_num].has_garbage = true;
} }
else if (wr->is_overwrite()) else if (wr->is_overwrite())
{ {
// Mark all previous entries as garbage // Mark all previous entries as garbage
for (auto prev_li = li->prev; prev_li; prev_li = prev_li->prev) for (auto prev_li = li->prev; prev_li && !prev_li->entry.is_garbage(); prev_li = prev_li->prev)
{ {
prev_li->entry.set_garbage(); prev_li->entry.set_garbage();
block_info[prev_li->block_num].has_garbage = true; // FIXME modify_alloc modify_alloc(prev_li->block_num, [&](heap_block_info_t & inf)
{
inf.has_garbage = true;
inf.used_space -= prev_li->entry.size;
});
} }
} }
if (!wr->is_garbage())
{
used_space += wr->size;
}
auto & inf = block_info[li->block_num];
if (!inf.entries.size())
{
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
}
inf.entries.push_back(li);
}, [&](uint32_t block_num, uint32_t last_offset, uint8_t *buf)
{
modify_alloc(block_num, [&](heap_block_info_t & inf) modify_alloc(block_num, [&](heap_block_info_t & inf)
{ {
inf.used_space = used_space; if (!inf.entries.size())
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
inf.entries.push_back(li);
if (!wr->is_garbage())
inf.used_space += wr->size;
else
inf.has_garbage = true;
}); });
used_space = 0; }, [&](uint32_t block_num, uint32_t last_offset, uint8_t *buf)
{
}); });
} }
@@ -385,9 +389,19 @@ void blockstore_heap_t::mark_used_blocks()
for (auto & op: ip.second) for (auto & op: ip.second)
{ {
bool added = false; bool added = false;
auto wr = &op.second.ptr->entry; auto li = op.second.ptr;
auto wr = &li->entry;
if (wr->entry_type == (BS_HEAP_DELETE|BS_HEAP_STABLE) && !li->prev)
{
mark_garbage(li->block_num, wr, UINT32_MAX);
wr = NULL;
}
while (wr) while (wr)
{ {
if (wr->is_garbage())
{
break;
}
if (wr->type() == BS_HEAP_SMALL_WRITE) if (wr->type() == BS_HEAP_SMALL_WRITE)
{ {
use_buffer_area(wr->inode, wr->small().location, wr->small().len); use_buffer_area(wr->inode, wr->small().location, wr->small().len);
@@ -410,48 +424,50 @@ void blockstore_heap_t::mark_used_blocks()
void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf) void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
{ {
if (cwr->size & FREE_SPACE_BIT) // FIXME auto free_entry = [&](heap_list_item_t *li)
{ {
// Already freed uint32_t block_num = li->block_num;
return; auto wr_size = li->entry.size;
free(li);
modify_alloc(block_num, [&](heap_block_info_t & inf)
{
inf.used_space -= wr_size;
for (auto it = inf.entries.begin(); it != inf.entries.end(); it++)
{
if (*it == li)
{
inf.entries.erase(it);
break;
}
}
});
recheck_modified_blocks.insert(block_num);
};
if (cwr->is_garbage())
{
// already freed after rechecking one of the previous small_write entries
free_entry(list_item(cwr));
} }
if (!calc_checksums(cwr, buf, false)) else if (!calc_checksums(cwr, buf, false))
{ {
// write entry is invalid, erase it and all newer entries // write entry is invalid, erase it and mark newer entries with FREE_SPACE_BIT
auto & inode_idx = block_index[get_pg_id(cwr->inode, cwr->stripe)][cwr->inode]; auto & inode_idx = block_index[get_pg_id(cwr->inode, cwr->stripe)][cwr->inode];
auto li = inode_idx[cwr->stripe].ptr; auto li = inode_idx[cwr->stripe].ptr;
int rolled_back = 0; int rolled_back = 1;
auto free_entry = [&]()
{
uint32_t block_num = li->block_num;
auto prev = li->prev;
auto wr_size = li->entry.size;
free(li);
modify_alloc(block_num, [&](heap_block_info_t & inf)
{
inf.used_space -= wr_size;
for (auto it = inf.entries.begin(); it != inf.entries.end(); it++)
{
if (*it == li)
{
inf.entries.erase(it);
break;
}
}
});
recheck_modified_blocks.insert(block_num);
li = prev;
rolled_back++;
};
while (li && cwr != &li->entry) while (li && cwr != &li->entry)
{ {
free_entry(); assert(li->entry.entry_type == cwr->entry_type);
auto prev = li->prev;
li->next = li->prev = NULL;
li->entry.set_garbage();
li = prev;
rolled_back++;
} }
assert(li); assert(li);
if (li->prev) if (li->prev)
{ {
fprintf(stderr, "Notice: %u unfinished writes to %jx:%jx v%jx since lsn %ju, rolling back\n", fprintf(stderr, "Notice: %u unfinished writes to %jx:%jx v%jx since lsn %ju, rolling back\n",
rolled_back+1, cwr->inode, cwr->stripe, prev(cwr)->version, prev(cwr)->lsn); rolled_back, cwr->inode, cwr->stripe, li->prev->entry.version, li->prev->entry.lsn);
inode_idx[cwr->stripe].ptr = li->prev; inode_idx[cwr->stripe].ptr = li->prev;
li->prev->next = NULL; li->prev->next = NULL;
} }
@@ -461,7 +477,7 @@ void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
cwr->inode, cwr->stripe); cwr->inode, cwr->stripe);
inode_idx.erase(cwr->stripe); inode_idx.erase(cwr->stripe);
} }
free_entry(); free_entry(li);
} }
} }
@@ -475,6 +491,7 @@ bool blockstore_heap_t::recheck_small_writes(std::function<void(bool is_data, ui
if (!recheck_queue_filled) if (!recheck_queue_filled)
{ {
fill_recheck_queue(); fill_recheck_queue();
recheck_queue_filled = true;
} }
if (read_buffer) if (read_buffer)
{ {
@@ -860,9 +877,11 @@ int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num,
inf.mod_lsn_to = gc_lsn; inf.mod_lsn_to = gc_lsn;
push_inflight_lsn(gc_lsn, &inf.entries[i]->entry, HEAP_INFLIGHT_GC); push_inflight_lsn(gc_lsn, &inf.entries[i]->entry, HEAP_INFLIGHT_GC);
} }
else if (j != i) else
{ {
inf.entries[j++] = inf.entries[i]; if (j != i)
inf.entries[j] = inf.entries[i];
j++;
} }
} }
inf.entries.resize(j); inf.entries.resize(j);
@@ -884,17 +903,19 @@ void blockstore_heap_t::insert_list_item(heap_idx_t & idx, heap_list_item_t *li)
// BIG_WRITE may be inserted into the middle of the sequence during compaction // BIG_WRITE may be inserted into the middle of the sequence during compaction
// and it overrides SMALL_WRITEs and COMMITs with the same LSN // and it overrides SMALL_WRITEs and COMMITs with the same LSN
// However, all entries of other types (say DELETE) override previous ones // However, all entries of other types (say DELETE) override previous ones
auto next_li = old_head;
auto prev_li = old_head->prev; auto prev_li = old_head->prev;
while (prev_li && !prev_li->entry.is_before(&li->entry)) while (prev_li && !prev_li->entry.is_before(&li->entry))
{ {
next_li = prev_li;
prev_li = prev_li->prev; prev_li = prev_li->prev;
} }
// Insert <li> between <old_head> and <prev_li> // Insert <li> between <next_li> and <prev_li>
li->prev = prev_li; li->prev = prev_li;
if (prev_li) if (prev_li)
prev_li->next = li; prev_li->next = li;
old_head->prev = li; next_li->prev = li;
li->next = old_head; li->next = next_li;
} }
else else
{ {
@@ -1351,7 +1372,7 @@ void blockstore_heap_t::mark_garbage_up_to(heap_entry_t *wr)
mvcc.garbage_entry = !mvcc.garbage_entry || mvcc.garbage_entry->lsn < wr->lsn ? wr : mvcc.garbage_entry; mvcc.garbage_entry = !mvcc.garbage_entry || mvcc.garbage_entry->lsn < wr->lsn ? wr : mvcc.garbage_entry;
return; return;
} }
assert((wr->type() == BS_HEAP_BIG_WRITE || wr->type() == BS_HEAP_DELETE) && (wr->entry_type & BS_HEAP_STABLE)); assert(wr->is_overwrite());
uint32_t used_big = (wr->type() == BS_HEAP_BIG_WRITE ? wr->big().block_num : UINT32_MAX); uint32_t used_big = (wr->type() == BS_HEAP_BIG_WRITE ? wr->big().block_num : UINT32_MAX);
wr = prev(wr); wr = prev(wr);
while (wr && !wr->is_garbage()) while (wr && !wr->is_garbage())
@@ -1820,6 +1841,7 @@ void blockstore_heap_t::apply_inflight(heap_inflight_lsn_t & inflight)
} }
if (!next) if (!next)
{ {
assert(!prev);
block_index[get_pg_id(wr->inode, wr->stripe)][wr->inode].erase(wr->stripe); block_index[get_pg_id(wr->inode, wr->stripe)][wr->inode].erase(wr->stripe);
} }
else else
+1 -1
View File
@@ -202,7 +202,7 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
{ {
wr = heap->prev(wr); wr = heap->prev(wr);
} }
assert(wr->type() == BS_HEAP_BIG_WRITE); assert(wr && wr->type() == BS_HEAP_BIG_WRITE);
PRIV(op)->location = wr->big_location(heap); PRIV(op)->location = wr->big_location(heap);
int res = heap->add_small_write(op->oid, obj, (BS_HEAP_INTENT_WRITE | (op->opcode == BS_OP_WRITE_STABLE ? BS_HEAP_STABLE : 0)), int res = heap->add_small_write(op->oid, obj, (BS_HEAP_INTENT_WRITE | (op->opcode == BS_OP_WRITE_STABLE ? BS_HEAP_STABLE : 0)),
op->version, op->offset, op->len, 0, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block); op->version, op->offset, op->len, 0, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);