From: Alex Ainscow Date: Sat, 6 Dec 2025 10:14:08 +0000 (+0000) Subject: osd: Fix fast EC truncate to whole stripe X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6075be4821e4a03b56c871a3b35fbd3375ee16e6;p=ceph.git osd: Fix fast EC truncate to whole stripe WritePlanObj has a key-not-found exception on truncates to exact stripe lengths. I have recreated in a unit test as well as on a real system. It is a concern that ceph_test_rados and ceph_test_rados_io_sequence never hit this pattern naturally. Signed-off-by: Alex Ainscow --- diff --git a/src/osd/ECTransaction.cc b/src/osd/ECTransaction.cc index b0c49f62b445..330c4a7e48dd 100644 --- a/src/osd/ECTransaction.cc +++ b/src/osd/ECTransaction.cc @@ -270,14 +270,14 @@ ECTransaction::WritePlanObj::WritePlanObj( * for the partial stripe and update the parity. For the purposes of * parity, the truncated shards are all zero. */ - extent_set truncate_write; + if (!truncate_read.empty()) { + extent_set truncate_write; - if (next_align != 0) { - truncate_write = truncate_read.at(shard_id_t(0)); - truncate_write.align(EC_ALIGN_SIZE); - } + if (next_align != 0) { + truncate_write = truncate_read.at(shard_id_t(0)); + truncate_write.align(EC_ALIGN_SIZE); + } - if (!truncate_read.empty()) { if (to_read) { to_read->insert(truncate_read); } else { diff --git a/src/test/osd/test_ec_transaction.cc b/src/test/osd/test_ec_transaction.cc index 252f4973812d..37ec6a467cc2 100644 --- a/src/test/osd/test_ec_transaction.cc +++ b/src/test/osd/test_ec_transaction.cc @@ -465,4 +465,43 @@ TEST(ectransaction, delete_and_write_misaligned) { ref_write[shard_id_t(1)].insert(0, 2*EC_ALIGN_SIZE); ref_write[shard_id_t(2)].insert(0, 2*EC_ALIGN_SIZE); ASSERT_EQ(ref_write, plan.will_write); +} + +TEST(ectransaction, truncate_to_stripe) { + hobject_t h; + PGTransaction::ObjectOperation op; + uint64_t new_size = 2 * EC_ALIGN_SIZE; + + // We have a 4k write quite a way after the current limit of a 4k object + op.truncate.emplace(new_size, new_size); + + pg_pool_t pool; + pool.set_flag(pg_pool_t::FLAG_EC_OPTIMIZATIONS); + ECUtil::stripe_info_t sinfo(2, 1, 2 * EC_ALIGN_SIZE, &pool, std::vector(0)); + object_info_t oi; + oi.size = new_size; + shard_id_set shards; + shards.insert_range(shard_id_t(0), 3); + + ECTransaction::WritePlanObj plan( + h, + op, + sinfo, + shards, + shards, + false, + 16*EC_ALIGN_SIZE, + std::nullopt, + std::nullopt, + 0); + + generic_derr << "plan " << plan << dendl; + + /* We are going to delete the object before writing it. Best not write anything + * from the old object... */ + ASSERT_FALSE(plan.to_read); + + // Truncating to a whole shard - no writes needed. + ECUtil::shard_extent_set_t ref_write(sinfo.get_k_plus_m()); + ASSERT_EQ(ref_write, plan.will_write); } \ No newline at end of file