Do full metadata GC on start (new store)
This commit is contained in:
@@ -94,6 +94,8 @@ void blockstore_disk_t::parse_config(std::map<std::string, std::string> & config
|
||||
csum_block_size = parse_size(config["csum_block_size"]);
|
||||
discard_on_start = config.find("discard_on_start") != config.end() &&
|
||||
(config["discard_on_start"] == "true" || config["discard_on_start"] == "1" || config["discard_on_start"] == "yes");
|
||||
gc_on_start = config.find("gc_on_start") == config.end() ||
|
||||
(config["gc_on_start"] == "true" || config["gc_on_start"] == "1" || config["gc_on_start"] == "yes");
|
||||
min_discard_size = parse_size(config["min_discard_size"]);
|
||||
if (!min_discard_size)
|
||||
min_discard_size = 1024*1024;
|
||||
|
||||
@@ -57,6 +57,8 @@ struct blockstore_disk_t
|
||||
bool inmemory_journal = true;
|
||||
// Data discard granularity and minimum size (for the sake of performance)
|
||||
bool discard_on_start = false;
|
||||
// GC on start (new store)
|
||||
bool gc_on_start = true;
|
||||
uint64_t min_discard_size = 1024*1024;
|
||||
uint64_t discard_granularity = 0;
|
||||
|
||||
|
||||
@@ -673,9 +673,53 @@ int blockstore_heap_t::mark_used_blocks()
|
||||
});
|
||||
}
|
||||
}
|
||||
if (dsk->gc_on_start)
|
||||
{
|
||||
recheck_full_gc();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void blockstore_heap_t::recheck_full_gc()
|
||||
{
|
||||
uint32_t block_num = 0;
|
||||
for (auto & inf: block_info)
|
||||
{
|
||||
// Instantly collect all garbage on restart
|
||||
if (inf.garbage_space > 0)
|
||||
{
|
||||
if (log_level > 5)
|
||||
{
|
||||
fprintf(stderr, "Clearing %u out of %u garbage bytes in block %u\n", inf.garbage_space, inf.used_space, block_num);
|
||||
}
|
||||
uint32_t collected_garbage = 0;
|
||||
size_t i = 0, j = 0;
|
||||
for (; i < inf.entries.size(); i++)
|
||||
{
|
||||
if (inf.entries[i]->entry.is_garbage())
|
||||
{
|
||||
collected_garbage += inf.entries[i]->entry.size;
|
||||
remove_list_item(inf.entries[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j != i)
|
||||
inf.entries[j] = inf.entries[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
inf.entries.resize(j);
|
||||
modify_alloc(block_num, [&](heap_block_info_t & inf)
|
||||
{
|
||||
inf.used_space -= collected_garbage;
|
||||
inf.garbage_space -= collected_garbage;
|
||||
});
|
||||
recheck_modified_blocks.insert(block_num);
|
||||
}
|
||||
block_num++;
|
||||
}
|
||||
}
|
||||
|
||||
void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
|
||||
{
|
||||
auto free_entry = [&](heap_list_item_t *li)
|
||||
@@ -2336,44 +2380,50 @@ void blockstore_heap_t::apply_inflight(heap_inflight_lsn_t & inflight)
|
||||
{
|
||||
// Remove entry
|
||||
auto li = list_item(wr);
|
||||
auto prev = li->prev;
|
||||
auto next = li->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
if (!next)
|
||||
{
|
||||
// The last freed entry must be a deletion
|
||||
assert(!prev);
|
||||
assert(wr->entry_type == BS_HEAP_DELETE|BS_HEAP_STABLE);
|
||||
auto & pg_idx = block_index[get_pg_id(wr->inode, wr->stripe)];
|
||||
auto & inode_idx = pg_idx[wr->inode];
|
||||
heap_inode_map_t::iterator li_it;
|
||||
heap_list_item_t *old_li = NULL;
|
||||
inode_map_get(inode_idx, li_it, old_li, wr->stripe);
|
||||
inode_map_erase(pg_idx, inode_idx, li_it, old_li);
|
||||
}
|
||||
else
|
||||
{
|
||||
next->prev = prev;
|
||||
if (!prev && next->entry.entry_type == (BS_HEAP_DELETE|BS_HEAP_STABLE))
|
||||
{
|
||||
// free BS_HEAP_DELETEs when all previous entries are also freed
|
||||
mark_garbage(next->block_num, &next->entry, UINT32_MAX);
|
||||
}
|
||||
}
|
||||
if (li->entry.is_garbage())
|
||||
{
|
||||
garbage_entries--;
|
||||
garbage_memory -= list_item_overhead(li->entry.size);
|
||||
}
|
||||
live_entries--;
|
||||
live_memory -= list_item_overhead(li->entry.size);
|
||||
free(li);
|
||||
remove_list_item(li);
|
||||
}
|
||||
}
|
||||
|
||||
void blockstore_heap_t::remove_list_item(heap_list_item_t *li)
|
||||
{
|
||||
auto prev = li->prev;
|
||||
auto next = li->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
if (!next)
|
||||
{
|
||||
// The last freed entry must be a deletion
|
||||
assert(!prev);
|
||||
auto wr = &li->entry;
|
||||
assert(wr->entry_type == BS_HEAP_DELETE|BS_HEAP_STABLE);
|
||||
auto & pg_idx = block_index[get_pg_id(wr->inode, wr->stripe)];
|
||||
auto & inode_idx = pg_idx[wr->inode];
|
||||
heap_inode_map_t::iterator li_it;
|
||||
heap_list_item_t *old_li = NULL;
|
||||
inode_map_get(inode_idx, li_it, old_li, wr->stripe);
|
||||
inode_map_erase(pg_idx, inode_idx, li_it, old_li);
|
||||
}
|
||||
else
|
||||
{
|
||||
next->prev = prev;
|
||||
if (!prev && next->entry.entry_type == (BS_HEAP_DELETE|BS_HEAP_STABLE))
|
||||
{
|
||||
// free BS_HEAP_DELETEs when all previous entries are also freed
|
||||
mark_garbage(next->block_num, &next->entry, UINT32_MAX);
|
||||
}
|
||||
}
|
||||
if (li->entry.is_garbage())
|
||||
{
|
||||
garbage_entries--;
|
||||
garbage_memory -= list_item_overhead(li->entry.size);
|
||||
}
|
||||
live_entries--;
|
||||
live_memory -= list_item_overhead(li->entry.size);
|
||||
free(li);
|
||||
}
|
||||
|
||||
bool blockstore_heap_t::is_lsn_completed(uint64_t lsn)
|
||||
{
|
||||
if (lsn <= completed_lsn)
|
||||
|
||||
@@ -220,6 +220,7 @@ class blockstore_heap_t
|
||||
bool validate_object(heap_entry_t *obj);
|
||||
void fill_recheck_queue();
|
||||
int mark_used_blocks();
|
||||
void recheck_full_gc();
|
||||
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
||||
void defragment_block(uint32_t block_num);
|
||||
void reshard_add(heap_reshard_state_t *st, heap_list_item_t *li);
|
||||
@@ -227,6 +228,7 @@ class blockstore_heap_t
|
||||
void gc_block(heap_block_info_t & inf);
|
||||
int allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free);
|
||||
void insert_list_item(heap_list_item_t *li);
|
||||
void remove_list_item(heap_list_item_t *li);
|
||||
int add_entry(uint32_t wr_size, uint32_t *modified_block, bool allow_last_free,
|
||||
bool explicit_complete, std::function<void(heap_entry_t *wr)> fill_entry);
|
||||
int add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type);
|
||||
|
||||
@@ -1990,6 +1990,7 @@ void test_redirect_intent_csums()
|
||||
|
||||
// reload heap to check that the write is still here
|
||||
{
|
||||
dsk.gc_on_start = false;
|
||||
blockstore_heap_t heap(&dsk, buffer_area.data(), 10);
|
||||
uint64_t entries_loaded;
|
||||
heap.load_blocks(0, dsk.meta_block_size, tmp.data(), false, entries_loaded);
|
||||
|
||||
Reference in New Issue
Block a user