@Override
    public void sanityCheck() {
        TimestampOffset entry = lastEntry();
        long lastTimestamp = entry.timestamp;
        long lastOffset = entry.offset;
        if (entries() != 0 && lastTimestamp < timestamp(mmap(), 0))
            throw new CorruptIndexException("Corrupt time index found, time index file (" + file().getAbsolutePath() + ") has "
                + "non-zero size but the last timestamp is " + lastTimestamp + " which is less than the first timestamp "
                + timestamp(mmap(), 0));
        if (entries() != 0 && lastOffset < baseOffset())
            throw new CorruptIndexException("Corrupt time index found, time index file (" + file().getAbsolutePath() + ") has "
                + "non-zero size but the last offset is " + lastOffset + " which is less than the first offset " + baseOffset());
        if (length() % ENTRY_SIZE != 0)
            throw new CorruptIndexException("Time index file " + file().getAbsolutePath() + " is corrupt, found " + length()
                + " bytes which is neither positive nor a multiple of " + ENTRY_SIZE);
    }
An index that maps from the timestamp to the logical offsets of the messages in a segment. This index might be
sparse, i.e. it may not hold an entry for all the messages in the segment.

The index is stored in a file that is preallocated to hold a fixed maximum amount of 12-byte time index entries.
The file format is a series of time index entries. The physical format is a 8 bytes timestamp and a 4 bytes "relative"
offset used in the [[OffsetIndex]]. A time index entry (TIMESTAMP, OFFSET) means that the biggest timestamp seen
before OFFSET is TIMESTAMP. i.e. Any message whose timestamp is greater than TIMESTAMP must come after OFFSET.

All external APIs translate from relative offsets to full offsets, so users of this class do not interact with the internal
storage format.

The timestamps in the same time index file are guaranteed to be monotonically increasing.

The index supports timestamp lookup for a memory map of this file. The lookup is done using a binary search to find
the offset of the message whose indexed timestamp is closest but smaller or equals to the target timestamp.

Time index files can be opened in two ways: either as an empty, mutable index that allows appending or
an immutable read-only index file that has previously been populated. The makeReadOnly method will turn a mutable file into an
immutable one and truncate off any extra bytes. This is done when the index file is rolled over.

No attempt is made to checksum the contents of this file, in the event of a crash it is rebuilt.
storage/src/main/java/org/apache/kafka/storage/internals/log/TimeIndex.java