From 963ff237c08eef00a09b49cd4af1d9ee15ef20c1 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Tue, 11 Jun 2024 23:58:29 +0200 Subject: [PATCH] s/disk_log_impl: don't prefix-truncate empty segments Consider the following sequence of events: 1. there is a single segment in the log, with offsets [0-9] 2. we call prefix_truncate(10) 3. concurrently, another batch of 5 messages is being appended. 4. empty segment with base_offset=10, dirty_offset=9 is created 5. the appended batch is placed at offsets 10-14 Previously, the empty segment would have passed the dirty_offset check and (after waiting for the append to finish) would get deleted (including the data at offsets 10-14). Check also the segment base_offset to prevent that. Fixes https://github.com/redpanda-data/redpanda/issues/19632 --- src/v/storage/disk_log_impl.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v/storage/disk_log_impl.cc b/src/v/storage/disk_log_impl.cc index 9a876cb9aa905..57ccd737c5e3f 100644 --- a/src/v/storage/disk_log_impl.cc +++ b/src/v/storage/disk_log_impl.cc @@ -2511,7 +2511,12 @@ ss::future<> disk_log_impl::remove_prefix_full_segments(truncate_prefix_config cfg) { return ss::do_until( [this, cfg] { + // base_offset check is for the case of an empty segment + // (where dirty = base - 1). We don't want to remove it because + // batches may be concurrently appended to it and we should keep them. return _segs.empty() + || _segs.front()->offsets().get_base_offset() + >= cfg.start_offset || _segs.front()->offsets().get_dirty_offset() >= cfg.start_offset; },