diff --git a/src/blockstore/blockstore_flush.cpp b/src/blockstore/blockstore_flush.cpp index fad8b3b1..6986a419 100644 --- a/src/blockstore/blockstore_flush.cpp +++ b/src/blockstore/blockstore_flush.cpp @@ -253,7 +253,7 @@ resume_1: { // Read original checksum blocks to calculate padded checksums if required fill_partial_checksum_blocks(); - if (read_to_fill_incomplete) + if (read_to_fill_incomplete && bs->padded_csum_update) { flusher->wanting_meta_fsync++; } @@ -273,7 +273,7 @@ resume_3: // we'll have a correct checksum because it won't include overwritten parts! // The same thing actually happens even when csum_block_size == bitmap_granularity, but in that case // we never need to read (and thus verify) overwritten parts from the data device. - if (read_to_fill_incomplete) + if (read_to_fill_incomplete && bs->padded_csum_update) { flusher->wanting_meta_fsync--; } @@ -422,17 +422,17 @@ void journal_flusher_co::fill_partial_checksum_blocks() iterate_checksum_holes([&](int vec_pos, uint32_t hole_start, uint32_t hole_end) { read_to_fill_incomplete = true; - int pos = read_vec.size(); - bs->prepare_disk_read(read_vec, pos, cur_obj, end_wr, + int out_pos = read_vec.size(); + bs->prepare_disk_read(read_vec, out_pos, cur_obj, end_wr, hole_start - hole_start % bs->dsk.csum_block_size, hole_start - hole_start % bs->dsk.csum_block_size + bs->dsk.csum_block_size, - hole_start - hole_start % bs->dsk.csum_block_size, hole_start - hole_start % bs->dsk.csum_block_size + bs->dsk.csum_block_size); - pos--; - read_vec[pos].copy_flags |= COPY_BUF_CSUM_FILL; + hole_start - hole_start % bs->dsk.csum_block_size, hole_start - hole_start % bs->dsk.csum_block_size + bs->dsk.csum_block_size, + COPY_BUF_CSUM_FILL | (bs->padded_csum_update ? 0 : COPY_BUF_SKIP_CSUM)); + out_pos--; read_vec.insert(read_vec.begin()+vec_pos, (copy_buffer_t){ .copy_flags = COPY_BUF_JOURNAL|COPY_BUF_COALESCED, .offset = hole_start, .len = hole_end-hole_start, - .buf = read_vec[pos].buf + hole_start - read_vec[pos].offset, + .buf = read_vec[out_pos].buf + hole_start - read_vec[out_pos].offset, }); }); } @@ -465,7 +465,7 @@ int journal_flusher_co::check_and_punch_checksums() for (int i = 0; i < read_vec.size(); i++) { auto & vec = read_vec[i]; - if (!(vec.copy_flags & (COPY_BUF_COALESCED|COPY_BUF_ZERO))) + if (!(vec.copy_flags & (COPY_BUF_COALESCED|COPY_BUF_ZERO|COPY_BUF_SKIP_CSUM))) { heap_write_t *wr = cur_obj->get_writes(); while (wr && wr->lsn != vec.wr_lsn) @@ -490,7 +490,7 @@ int journal_flusher_co::check_and_punch_checksums() // FIXME: Report the corrupted object to the upper layer return EDOM; } - if (!read_to_fill_incomplete) + if (!read_to_fill_incomplete || !bs->padded_csum_update) { // Nothing to do return 0; diff --git a/src/blockstore/blockstore_flush.h b/src/blockstore/blockstore_flush.h index f079a7e7..2317f1a9 100644 --- a/src/blockstore/blockstore_flush.h +++ b/src/blockstore/blockstore_flush.h @@ -3,7 +3,7 @@ struct copy_buffer_t { - int copy_flags; + uint32_t copy_flags; uint64_t offset, len, disk_offset, disk_len; uint8_t *buf; uint64_t wr_lsn; diff --git a/src/blockstore/blockstore_impl.h b/src/blockstore/blockstore_impl.h index 638fb808..9bb4567d 100644 --- a/src/blockstore/blockstore_impl.h +++ b/src/blockstore/blockstore_impl.h @@ -103,6 +103,9 @@ class blockstore_impl_t: public blockstore_i uint64_t autosync_writes = 128; // Log level (0-10) int log_level = 0; + // Enable correct block checksum validation on objects updated with small writes when checksum block + // is larger than bitmap_granularity, at the expense of extra metadata fsyncs during compaction + bool padded_csum_update = false; /******* END OF OPTIONS *******/ struct ring_consumer_t ring_consumer; @@ -157,7 +160,7 @@ class blockstore_impl_t: public blockstore_i uint32_t prepare_read_zero(std::vector & read_vec, uint32_t start, uint32_t end); uint32_t prepare_read_simple(std::vector & read_vec, heap_object_t *obj, heap_write_t *wr, uint32_t start, uint32_t end); void prepare_disk_read(std::vector & read_vec, int & pos, heap_object_t *obj, heap_write_t *wr, - uint32_t blk_start, uint32_t blk_end, uint32_t start, uint32_t end); + uint32_t blk_start, uint32_t blk_end, uint32_t start, uint32_t end, uint32_t copy_flags); void find_holes(std::vector & read_vec, uint32_t item_start, uint32_t item_end, std::function callback); void handle_read_event(ring_data_t *data, blockstore_op_t *op); diff --git a/src/blockstore/blockstore_internal.h b/src/blockstore/blockstore_internal.h index cd07b688..3f226c1d 100644 --- a/src/blockstore/blockstore_internal.h +++ b/src/blockstore/blockstore_internal.h @@ -47,3 +47,4 @@ #define COPY_BUF_CSUM_FILL 8 #define COPY_BUF_COALESCED 16 #define COPY_BUF_PADDED 32 +#define COPY_BUF_SKIP_CSUM 64 diff --git a/src/blockstore/blockstore_open.cpp b/src/blockstore/blockstore_open.cpp index 97031732..f5d9c44d 100644 --- a/src/blockstore/blockstore_open.cpp +++ b/src/blockstore/blockstore_open.cpp @@ -26,6 +26,7 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config, bool init) throttle_target_mbs = strtoull(config["throttle_target_mbs"].c_str(), NULL, 10); throttle_target_parallelism = strtoull(config["throttle_target_parallelism"].c_str(), NULL, 10); throttle_threshold_us = strtoull(config["throttle_threshold_us"].c_str(), NULL, 10); + padded_csum_update = config["padded_csum_update"] == "true" || config["padded_csum_update"] == "1" || config["padded_csum_update"] == "yes"; if (config["autosync_writes"] != "") { autosync_writes = strtoull(config["autosync_writes"].c_str(), NULL, 10); diff --git a/src/blockstore/blockstore_read.cpp b/src/blockstore/blockstore_read.cpp index 7f84ee37..c4b918e1 100644 --- a/src/blockstore/blockstore_read.cpp +++ b/src/blockstore/blockstore_read.cpp @@ -200,7 +200,7 @@ uint32_t blockstore_impl_t::prepare_read_simple(std::vector & rea else if (dsk.csum_block_size <= dsk.bitmap_granularity) { // simple disk read - prepare_disk_read(read_vec, pos, obj, wr, start, end, start, end); + prepare_disk_read(read_vec, pos, obj, wr, start, end, start, end, 0); } else { @@ -210,12 +210,23 @@ uint32_t blockstore_impl_t::prepare_read_simple(std::vector & rea blk_start = blk_start < wr->offset ? wr->offset : blk_start; blk_end = ((end-1) / dsk.csum_block_size + 1) * dsk.csum_block_size; blk_end = blk_end > wr->offset+wr->len ? wr->offset+wr->len : blk_end; + uint32_t skip_csum = 0; + if (!padded_csum_update) + { + for (auto owr = obj->get_writes(); owr && owr != wr; owr = owr->next()) + { + if (owr->offset < blk_end && owr->offset+owr->len > blk_start) + { + skip_csum = COPY_BUF_SKIP_CSUM; + } + } + } if (blk_end == blk_start+dsk.csum_block_size || blk_end == blk_start+2*dsk.csum_block_size && blk_end != end && blk_start != start || blk_end == end && blk_start == start) { // single block, two partial blocks, or any number of full blocks - prepare_disk_read(read_vec, pos, obj, wr, blk_start, blk_end, start, end); + prepare_disk_read(read_vec, pos, obj, wr, blk_start, blk_end, start, end, skip_csum); } else { @@ -223,11 +234,11 @@ uint32_t blockstore_impl_t::prepare_read_simple(std::vector & rea uint32_t full_start = (blk_start != start ? blk_start+dsk.csum_block_size : blk_start); uint32_t full_end = (blk_end != end ? blk_end-dsk.csum_block_size : blk_end); if (blk_start != start) - prepare_disk_read(read_vec, pos, obj, wr, blk_start, full_start, start, full_start); + prepare_disk_read(read_vec, pos, obj, wr, blk_start, full_start, start, full_start, skip_csum); if (full_start > full_end) - prepare_disk_read(read_vec, pos, obj, wr, full_start, full_end, full_start, full_end); + prepare_disk_read(read_vec, pos, obj, wr, full_start, full_end, full_start, full_end, skip_csum); if (blk_end != end) - prepare_disk_read(read_vec, pos, obj, wr, full_end, blk_end, full_end, end); + prepare_disk_read(read_vec, pos, obj, wr, full_end, blk_end, full_end, end, skip_csum); } } }); @@ -235,10 +246,10 @@ uint32_t blockstore_impl_t::prepare_read_simple(std::vector & rea } void blockstore_impl_t::prepare_disk_read(std::vector & read_vec, int & pos, heap_object_t *obj, heap_write_t *wr, - uint32_t blk_start, uint32_t blk_end, uint32_t start, uint32_t end) + uint32_t blk_start, uint32_t blk_end, uint32_t start, uint32_t end, uint32_t copy_flags) { copy_buffer_t vec = { - .copy_flags = ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? COPY_BUF_JOURNAL : COPY_BUF_DATA), + .copy_flags = ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? COPY_BUF_JOURNAL : COPY_BUF_DATA) | copy_flags, .offset = start, .len = end-start, .disk_offset = wr->location + blk_start - wr->offset, @@ -326,7 +337,7 @@ bool blockstore_impl_t::verify_read_checksums(blockstore_op_t *op) auto & rv = PRIV(op)->read_vec; for (auto & vec: rv) { - if (vec.copy_flags & COPY_BUF_COALESCED) + if (vec.copy_flags & (COPY_BUF_COALESCED|COPY_BUF_SKIP_CSUM)) { continue; }