@Test
  public void dataIntegrityCheckTest() throws Exception {
    long writeStartOffset = 0L;
    LogSegmentName logSegmentName = StoreTestUtils.getRandomLogSegmentName(null);
    Offset startOffset = new Offset(logSegmentName, writeStartOffset);
    IndexSegment indexSegment = generateIndexSegment(startOffset, STORE_KEY_FACTORY);
    time.setCurrentMilliseconds(System.currentTimeMillis() / 1000 * 1000);

    List<Long> offsets = new ArrayList<>();
    offsets.add(writeStartOffset);
    for (int i = 0; i < 4; i++) {
      // size has to be > 0 (no record is 0 sized)
      long size = Utils.getRandomLong(TestUtils.RANDOM, 1000) + 1;
      offsets.add(writeStartOffset + size);
      writeStartOffset += size;
    }
    long lastEntrySize = Utils.getRandomLong(TestUtils.RANDOM, 1000) + 1;
    long endOffset = offsets.get(offsets.size() - 1) + lastEntrySize;
    NavigableMap<MockId, NavigableSet<IndexValue>> referenceIndex = new TreeMap<>();
    addPutEntries(offsets, lastEntrySize, indexSegment, referenceIndex, false, false);
    // write to file
    indexSegment.writeIndexSegmentToFile(indexSegment.getEndOffset());
    // verify read from file
    Journal journal = new Journal(tempDir.getAbsolutePath(), Integer.MAX_VALUE, Integer.MAX_VALUE);
    IndexSegment fromDisk = createIndexSegmentFromFile(indexSegment.getFile(), true, journal);
    assertEquals("End offset doesn't match", endOffset, fromDisk.getEndOffset().getOffset());

    // read index file to byte buffer and manipulate one of the bytes
    File indexFile = indexSegment.getFile();
    ByteBuffer buf = ByteBuffer.allocate((int) indexFile.length());
    try (RandomAccessFile raf = new RandomAccessFile(indexFile, "r")) {
      raf.getChannel().read(buf);
    }
    // we use heap buffer here, so buf.array() should not be null
    byte[] bytes = buf.array();
    // make one of the bytes corrupted (avoid last 8 bytes as they are crc value)
    int corruptIndex = new Random().nextInt(bytes.length - 8);
    bytes[corruptIndex] ^= 0xff;
    // write corrupted bytes to file
    File temp = new File(indexFile.getAbsolutePath() + ".tmp");
    try (FileOutputStream stream = new FileOutputStream(temp)) {
      stream.write(bytes);
      stream.getChannel().force(true);
      temp.renameTo(indexFile);
    }
    try {
      createIndexSegmentFromFile(indexFile, true, journal);
      fail("Should fail as a sealed index file is corrupted");
    } catch (StoreException e) {
      assertEquals("Mismatch in error code", StoreErrorCodes.IndexCreationFailure, e.getErrorCode());
      StoreException rc = Utils.getRootCause(e, StoreException.class);
      assertEquals("Mismatch in error code", StoreErrorCodes.IndexFileFormatError, rc.getErrorCode());
    }

    // An unsealed index segment should ignore the corruption since it can be recovered later by log
    fromDisk = createIndexSegmentFromFile(indexFile, false, journal);
    verifyIndexSegmentDetails(fromDisk, startOffset, 0, 0, false, startOffset.getOffset(), time.milliseconds(), null,
        null, StoreFindToken.UNINITIALIZED_RESET_KEY_VERSION);
    assertEquals("End offset doesn't match", startOffset.getOffset(), fromDisk.getEndOffset().getOffset());
    // We should be able to insert entries to this index segment
    offsets = new ArrayList<>();
    offsets.add(writeStartOffset);
    for (int i = 0; i < 4; i++) {
      // size has to be > 0 (no record is 0 sized)
      long size = Utils.getRandomLong(TestUtils.RANDOM, 1000) + 1;
      offsets.add(writeStartOffset + size);
      writeStartOffset += size;
    }
    lastEntrySize = Utils.getRandomLong(TestUtils.RANDOM, 1000) + 1;
    endOffset = offsets.get(offsets.size() - 1) + lastEntrySize;
    referenceIndex = new TreeMap<>();
    List<IndexEntry> newEntries = addPutEntries(offsets, lastEntrySize, fromDisk, referenceIndex, false, false);
    // write to file
    fromDisk.writeIndexSegmentToFile(fromDisk.getEndOffset());
    // verify read from file
    journal = new Journal(tempDir.getAbsolutePath(), Integer.MAX_VALUE, Integer.MAX_VALUE);
    fromDisk = createIndexSegmentFromFile(fromDisk.getFile(), false, journal);
    assertEquals("End offset doesn't match", endOffset, fromDisk.getEndOffset().getOffset());
    StoreKey resetKey = null;
    PersistentIndex.IndexEntryType resetKeyType = null;
    short resetKeyLifeVersion = StoreFindToken.UNINITIALIZED_RESET_KEY_VERSION;
    if (formatVersion != PersistentIndex.VERSION_0) {
      resetKey = newEntries.get(0).getKey();
      resetKeyType = PersistentIndex.IndexEntryType.PUT;
      resetKeyLifeVersion = newEntries.get(0).getValue().getLifeVersion();
    }
    int expectedSizeWritten = (KEY_SIZE + fromDisk.getValueSize()) * 5;
    verifyAllForIndexSegmentFromFile(referenceIndex, fromDisk, startOffset, 5, expectedSizeWritten, false, endOffset,
        time.milliseconds(), resetKey, resetKeyType, resetKeyLifeVersion);

    // seal it and now reload it as a sealed index segment
    fromDisk.seal();
    journal = new Journal(tempDir.getAbsolutePath(), Integer.MAX_VALUE, Integer.MAX_VALUE);
    fromDisk = createIndexSegmentFromFile(fromDisk.getFile(), true, journal);
    verifyAllForIndexSegmentFromFile(referenceIndex, fromDisk, startOffset, 5, expectedSizeWritten, true, endOffset,
        time.milliseconds(), resetKey, resetKeyType, resetKeyLifeVersion);
  }
Tests data corruption case when loading index file to memory.
@throws Exception
ambry-store/src/test/java/com/github/ambry/store/IndexSegmentTest.java