Skip to content

Commit 5f6634d

Browse files
Merge pull request #26090 from WillemKauf/manual-backport-26080-v24.1.x-556
[v24.1.x] `storage`: fix `non_data_timestamps` with overflow (Manual backport)
2 parents ff17397 + d92728a commit 5f6634d

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/v/storage/index_state.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,16 @@ bool index_state::maybe_index(
5959
// to override the timestamps of any config batch that was indexed
6060
// by virtue of being the first in the segment.
6161
if (user_data && non_data_timestamps) {
62-
vassert(relative_time_index.size() == 1, "");
62+
// We can only add a non-data timestamp to the empty index. This
63+
// is why we can assume that the index size is 1.
64+
// Otherwise it will be impossible to to reset the non-data timestamp.
65+
vassert(
66+
relative_time_index.size() == 1,
67+
"Relative time index can not be reset, unexpected index size {} "
68+
"(expected 1). This can only happen if more than one non-data "
69+
"timestamp was added to the index: {}.",
70+
relative_time_index.size(),
71+
*this);
6372
relative_time_index[0]
6473
= offset_time_index{last_timestamp, with_offset}.raw_value();
6574

@@ -70,14 +79,15 @@ bool index_state::maybe_index(
7079

7180
// index_state
7281
bool is_empty = false;
82+
bool should_set_non_data_timestamp = false;
7383
if (empty()) {
7484
// Ordinarily, we do not allow configuration batches to contribute to
7585
// the segment's timestamp bounds (because config batches use walltime
7686
// but user data timestamps may be anything). However, for the first
7787
// batch we set the timestamps, and then set a `non_data_timestamps`
7888
// flag so that the next time we see user data we will overwrite
7989
// the walltime timestamps with the user data timestamps.
80-
non_data_timestamps = !user_data;
90+
should_set_non_data_timestamp = !user_data;
8191

8292
base_timestamp = first_timestamp;
8393
max_timestamp = first_timestamp;
@@ -113,7 +123,9 @@ bool index_state::maybe_index(
113123
batch_base_offset() - base_offset(),
114124
offset_time_index{last_timestamp - base_timestamp, with_offset},
115125
starting_position_in_file);
116-
126+
if (should_set_non_data_timestamp) {
127+
non_data_timestamps = true;
128+
}
117129
return true;
118130
} else {
119131
// We can't index anything beyond uint32 space. Presumably no

src/v/storage/tests/index_state_test.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,34 @@ BOOST_AUTO_TEST_CASE(offset_time_index_test) {
244244
}
245245
}
246246
}
247+
248+
BOOST_AUTO_TEST_CASE(non_data_timestamps_with_overflow) {
249+
storage::index_state state;
250+
251+
// Need to ensure that non_data_timestamps in the segment_index is only set
252+
// iff there is an entry in the index_state. Otherwise, a call to
253+
// index.try_reset_relative_time_index() will trigger a vassert.
254+
constexpr long uint32_max = std::numeric_limits<uint32_t>::max();
255+
state.maybe_index(
256+
0,
257+
1,
258+
0,
259+
model::offset{uint32_max + 1},
260+
model::offset{uint32_max + 1},
261+
model::timestamp{0},
262+
model::timestamp{0},
263+
std::nullopt,
264+
false,
265+
0);
266+
state.maybe_index(
267+
1,
268+
1,
269+
1,
270+
model::offset{uint32_max + 2},
271+
model::offset{uint32_max + 2},
272+
model::timestamp{0},
273+
model::timestamp{0},
274+
std::nullopt,
275+
true,
276+
0);
277+
}

0 commit comments

Comments
 (0)