private long createStateWithPutTtlUpdateAndDelete() throws Exception {
    // this sets up state such that there are a bunch of PUTs with TTL such that they expire immediately, TTL
    // updates for all but two PUTs and deletes for all PUTs. The key is that the first log segment contains some TTL
    // updates at least so that the the removal of the two PUTs without TTL updates will cause some TTL updates that
    // were originally in the second segment to move to the first.
    refreshState(false, false, false);
    // this code is trying to determine how many put records there should be (close is good enough). It aims to have
    // just enough PUT records such that a quarter of the TTL updates for these PUT records fits in the first log
    // segment along with the PUTs themselves
    // numPuts * PUT_RECORD_SIZE + numPuts/4 * TTL_UPDATE_RECORD_SIZE + HEADER_SIZE < SEGMENT_CAPACITY
    // we have to solve for numPuts
    // numPuts < (SEGMENT_CAPACITY - HEADER_SIZE) / (PUT_RECORD_SIZE + TTL_UPDATE_RECORD_SIZE/4)
    // the -1 in the below statement is make numPuts < the output of the RHS
    int numPuts = (int) Math.floorDiv(state.log.getSegmentCapacity() - LogSegment.HEADER_SIZE,
        PUT_RECORD_SIZE + (TTL_UPDATE_RECORD_SIZE) / 4) - 1;
    // this ensures that the crash test cases cause the crash in the middle of an index segment
    state.properties.setProperty("store.index.max.number.of.inmem.elements", Integer.toString(numPuts));
    // reload for new props to take effect
    state.reloadIndex(true, false);

    // insert numPuts PUT records with immediate expiry
    long expiryTimeMs = getInvalidationTime(1);
    List<IndexEntry> entries = state.addPutEntries(numPuts, PUT_RECORD_SIZE, expiryTimeMs);
    // insert ttl updates for all but two of the PUTs
    for (int i = 0; i < entries.size() - 2; i++) {
      state.makePermanent((MockId) entries.get(i).getKey(), false);
    }
    // advance time and delete all the data (some of the data will get deleted at deleteTimeMs + delta).
    state.advanceTime(expiryTimeMs + 1 - state.time.milliseconds());
    for (IndexEntry entry : entries) {
      state.addDeleteEntry((MockId) entry.getKey());
    }
    // add put entries so that the log segment rolls over
    writeDataToMeetRequiredSegmentCount(state.index.getLogSegmentCount() + 1, null);
    // reload index to make sure journal is on only the latest log segment
    state.reloadIndex(true, false);
    return expiryTimeMs;
  }
Creates state required for some TTL update specific tests that need PUTs, TTL updates and DELETEs.
@return the time at which the PUT records that don't have TTL update records expire.
@throws Exception
ambry-store/src/test/java/com/github/ambry/store/BlobStoreCompactorTest.java