Remove creepy "metadata copying" during overwrite

Instead of it, just do not verify checksums of currently mutated objects.
When clean data modification during flush runs in parallel to a read request,
that request may read a mix of old and new data. It may even read a mix of
multiple flushed versions if it lasts too long... And attempts to verify it
using temporary copies of metadata make the algorithm too complex and creepy.
This commit is contained in:
Vitaliy Filippov
2023-07-29 12:17:18 +03:00
parent a8464c19af
commit 4181add1f4
4 changed files with 83 additions and 89 deletions
+39 -35
View File
@@ -160,6 +160,22 @@ void journal_flusher_t::remove_flush(object_id oid)
}
}
bool journal_flusher_t::is_flushed_over(obj_ver_id ov)
{
auto r_it = sync_to_repeat.find(ov.oid);
if (r_it != sync_to_repeat.end())
{
for (int i = 0; i < cur_flusher_count; i++)
{
if (co[i].wait_state != 0 && co[i].cur.oid == ov.oid)
{
return co[i].cur.version > ov.version;
}
}
}
return false;
}
void journal_flusher_t::request_trim()
{
dequeuing = true;
@@ -444,6 +460,7 @@ stop_flusher:
else
{
clean_loc = old_clean_loc;
clean_ver = old_clean_ver;
}
}
// Submit dirty data and old checksum data reads
@@ -479,6 +496,15 @@ resume_2:
wait_state = wait_base+13;
return false;
}
if (bs->dsk.csum_block_size)
{
// Mark objects used by reads as modified
auto uo_it = bs->used_clean_objects.find((obj_ver_id){ .oid = cur.oid, .version = clean_ver });
if (uo_it != bs->used_clean_objects.end())
{
uo_it->second.was_changed = true;
}
}
// Submit data writes
for (it = v.begin(); it != v.end(); it++)
{
@@ -601,34 +627,6 @@ void journal_flusher_co::update_metadata_entry()
}
else
{
if (bs->dsk.csum_block_size)
{
// Copy the whole old metadata entry before updating it if the updated object is being read
obj_ver_id ov = { .oid = new_entry->oid, .version = new_entry->version };
auto uo_it = bs->used_clean_objects.upper_bound(ov);
if (uo_it != bs->used_clean_objects.begin())
{
uo_it--;
if (uo_it->first.oid == new_entry->oid)
{
uint8_t *meta_copy = (uint8_t*)malloc_or_die(bs->dsk.clean_entry_size);
memcpy(meta_copy, new_entry, bs->dsk.clean_entry_size);
// The reads should free all metadata entry backups when they don't need them anymore
if (uo_it->first.version < new_entry->version)
{
// If ==, write in place
uo_it++;
bs->used_clean_objects.insert(uo_it, std::make_pair(ov, (used_clean_obj_t){
.meta = meta_copy,
}));
}
else
{
uo_it->second.meta = meta_copy;
}
}
}
}
// Set initial internal bitmap bits from the big write
if (clean_init_bitmap)
{
@@ -725,6 +723,7 @@ bool journal_flusher_co::write_meta_block(flusher_meta_write_t & meta_block, int
return true;
}
// Punch holes in incomplete checksum blocks
bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
{
if (wait_state == wait_base) goto resume_0;
@@ -805,12 +804,6 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
});
}
}
// Actually clear bits
for (auto it = v.begin(); it != v.end(); it++)
{
if (it->copy_flags == COPY_BUF_JOURNAL || it->copy_flags == (COPY_BUF_JOURNAL|COPY_BUF_COALESCED))
bitmap_clear(new_clean_bitmap, it->offset, it->len, bs->dsk.bitmap_granularity);
}
{
clean_disk_entry *new_entry = (clean_disk_entry*)((uint8_t*)meta_new.buf + meta_new.pos*bs->dsk.clean_entry_size);
if (new_entry->oid != cur.oid)
@@ -822,11 +815,20 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
);
}
assert(new_entry->oid == cur.oid);
// Actually clear bits
for (auto it = v.begin(); it != v.end(); it++)
{
if (it->copy_flags == COPY_BUF_JOURNAL || it->copy_flags == (COPY_BUF_JOURNAL|COPY_BUF_COALESCED))
bitmap_clear(new_clean_bitmap, it->offset, it->len, bs->dsk.bitmap_granularity);
}
// Calculate block checksums with new holes
uint32_t *new_data_csums = (uint32_t*)(new_clean_bitmap + 2*bs->dsk.clean_entry_bitmap_size);
calc_block_checksums(new_data_csums, true);
if (!bs->inmemory_meta)
memcpy(&new_entry->bitmap, new_clean_bitmap, bs->dsk.clean_dyn_size);
{
auto inmem_bmp = (uint8_t*)bs->clean_bitmaps + (clean_loc >> bs->dsk.block_order)*2*bs->dsk.clean_entry_bitmap_size;
memcpy(inmem_bmp, new_clean_bitmap, 2*bs->dsk.clean_entry_bitmap_size);
}
if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_V2)
{
// calculate metadata entry checksum
@@ -914,6 +916,7 @@ void journal_flusher_co::scan_dirty()
v.clear();
copy_count = 0;
clean_loc = UINT64_MAX;
clean_ver = 0;
has_delete = false;
has_writes = false;
skip_copy = false;
@@ -989,6 +992,7 @@ void journal_flusher_co::scan_dirty()
// There is an unflushed big write. Copy small writes in its position
has_writes = true;
clean_loc = dirty_it->second.location;
clean_ver = dirty_it->first.version;
clean_init_bitmap = true;
clean_bitmap_offset = dirty_it->second.offset;
clean_bitmap_len = dirty_it->second.len;