@@ -410,3 +410,36 @@ TEST(IndexState, NonDataTimestampsWithOverflow) {
410
410
true ,
411
411
0 );
412
412
}
413
+
414
+ BOOST_AUTO_TEST_CASE (index_overflow_truncate) {
415
+ storage::index_state state;
416
+
417
+ // Previous versions of Redpanda can have an index with offsets spanning
418
+ // greater than uint32 offset space. In these cases, the index is not
419
+ // reliable and truncation shouldn't attempt to truncate entries based on
420
+ // an overflown lookup. But, queries should fallback to returning the
421
+ // beginning of the index.
422
+ const model::timestamp dummy_ts;
423
+ const storage::offset_delta_time should_offset{false };
424
+ storage::offset_time_index time_idx{dummy_ts, should_offset};
425
+ constexpr long uint32_max = std::numeric_limits<uint32_t >::max ();
426
+ state.add_entry (0 , time_idx, 1 );
427
+ state.add_entry (100 , time_idx, 2 );
428
+ state.add_entry (static_cast <uint32_t >(uint32_max + 1 ), time_idx, 3 );
429
+ state.add_entry (static_cast <uint32_t >(uint32_max + 10 ), time_idx, 4 );
430
+ state.max_offset = model::offset{uint32_max + 10 };
431
+ BOOST_CHECK_EQUAL (4 , state.size ());
432
+
433
+ // The truncation shouldn't remove index entries, given the overflow.
434
+ auto needs_flush = state.truncate (
435
+ model::offset (uint32_max + 1 ), model::timestamp::now ());
436
+ BOOST_CHECK (needs_flush);
437
+ BOOST_CHECK_EQUAL (4 , state.size ());
438
+ BOOST_CHECK_EQUAL (state.max_offset , model::offset{uint32_max + 1 });
439
+
440
+ // Queries for the offset should start from the beginning of the segment.
441
+ auto res = state.find_nearest (model::offset (uint32_max + 1 ));
442
+ BOOST_REQUIRE (res.has_value ());
443
+ BOOST_CHECK_EQUAL (res->offset , model::offset{0 });
444
+ BOOST_CHECK_EQUAL (res->filepos , 1 );
445
+ }
0 commit comments