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"]);
|
csum_block_size = parse_size(config["csum_block_size"]);
|
||||||
discard_on_start = config.find("discard_on_start") != config.end() &&
|
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");
|
(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"]);
|
min_discard_size = parse_size(config["min_discard_size"]);
|
||||||
if (!min_discard_size)
|
if (!min_discard_size)
|
||||||
min_discard_size = 1024*1024;
|
min_discard_size = 1024*1024;
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ struct blockstore_disk_t
|
|||||||
bool inmemory_journal = true;
|
bool inmemory_journal = true;
|
||||||
// Data discard granularity and minimum size (for the sake of performance)
|
// Data discard granularity and minimum size (for the sake of performance)
|
||||||
bool discard_on_start = false;
|
bool discard_on_start = false;
|
||||||
|
// GC on start (new store)
|
||||||
|
bool gc_on_start = true;
|
||||||
uint64_t min_discard_size = 1024*1024;
|
uint64_t min_discard_size = 1024*1024;
|
||||||
uint64_t discard_granularity = 0;
|
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;
|
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)
|
void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
|
||||||
{
|
{
|
||||||
auto free_entry = [&](heap_list_item_t *li)
|
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
|
// Remove entry
|
||||||
auto li = list_item(wr);
|
auto li = list_item(wr);
|
||||||
auto prev = li->prev;
|
remove_list_item(li);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
bool blockstore_heap_t::is_lsn_completed(uint64_t lsn)
|
||||||
{
|
{
|
||||||
if (lsn <= completed_lsn)
|
if (lsn <= completed_lsn)
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ class blockstore_heap_t
|
|||||||
bool validate_object(heap_entry_t *obj);
|
bool validate_object(heap_entry_t *obj);
|
||||||
void fill_recheck_queue();
|
void fill_recheck_queue();
|
||||||
int mark_used_blocks();
|
int mark_used_blocks();
|
||||||
|
void recheck_full_gc();
|
||||||
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
||||||
void defragment_block(uint32_t block_num);
|
void defragment_block(uint32_t block_num);
|
||||||
void reshard_add(heap_reshard_state_t *st, heap_list_item_t *li);
|
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);
|
void gc_block(heap_block_info_t & inf);
|
||||||
int allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free);
|
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 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,
|
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);
|
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);
|
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
|
// reload heap to check that the write is still here
|
||||||
{
|
{
|
||||||
|
dsk.gc_on_start = false;
|
||||||
blockstore_heap_t heap(&dsk, buffer_area.data(), 10);
|
blockstore_heap_t heap(&dsk, buffer_area.data(), 10);
|
||||||
uint64_t entries_loaded;
|
uint64_t entries_loaded;
|
||||||
heap.load_blocks(0, dsk.meta_block_size, tmp.data(), false, entries_loaded);
|
heap.load_blocks(0, dsk.meta_block_size, tmp.data(), false, entries_loaded);
|
||||||
|
|||||||
Reference in New Issue
Block a user