private boolean readKrf(OplogEntryIdSet deletedIds, boolean recoverValues,
      boolean recoverValuesSync, Set<Oplog> oplogsNeedingValueRecovery, boolean latestOplog) {
    File f = new File(diskFile.getPath() + KRF_FILE_EXT);
    if (!f.exists()) {
      return false;
    }

    if (!getParent().getDiskInitFile().hasKrf(oplogId)) {
      logger.info("Removing incomplete krf {} for oplog {}, disk store {}",
          new Object[] {f.getName(), oplogId, getParent().getName()});
      f.delete();
    }
    // Set krfCreated to true since we have a krf.
    krfCreated.set(true);

    // Fix for 42741 - we do this after creating setting the krfCreated flag
    // so that we don't try to recreate the krf.
    if (recoverValuesSync) {
      return false;
    }

    FileInputStream fis;
    try {
      fis = new FileInputStream(f);
    } catch (FileNotFoundException ignore) {
      return false;
    }
    try {
      if (getParent().isOffline() && !getParent().FORCE_KRF_RECOVERY) {
        return false;
      }
      logger.info("Recovering {} {} for disk store {}.",
          new Object[] {toString(), f.getAbsolutePath(), getParent().getName()});
      recoverNewEntryId = DiskStoreImpl.INVALID_ID;
      recoverModEntryId = DiskStoreImpl.INVALID_ID;
      recoverModEntryIdHWM = DiskStoreImpl.INVALID_ID;
      long oplogKeyIdHWM = DiskStoreImpl.INVALID_ID;
      int krfEntryCount = 0;
      DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 1024 * 1024));
      final KnownVersion version = getProductVersionIfOld();
      final ByteArrayDataInput in = new ByteArrayDataInput();
      try {
        try {
          validateOpcode(dis, OPLOG_MAGIC_SEQ_ID);
          readOplogMagicSeqRecord(dis, f, OPLOG_TYPE.KRF);

          validateOpcode(dis, OPLOG_DISK_STORE_ID);
          readDiskStoreRecord(dis, f);
        } catch (DiskAccessException | IllegalStateException ignore) {
          // Failed to read the file. There are two possibilities. Either this
          // file is in old format which does not have a magic seq in the
          // beginning or this is not a valid file at all. Try reading it as a
          // file in old format
          fis.close();
          fis = new FileInputStream(f);
          dis = new DataInputStream(new BufferedInputStream(fis, 1024 * 1024));
          readDiskStoreRecord(dis, f);
        }

        readGemfireVersionRecord(dis);
        readTotalCountRecord(dis);
        readRVVRecord(dis, false, latestOplog);
        long lastOffset = 0;
        byte[] keyBytes = DataSerializer.readByteArray(dis);
        while (keyBytes != null) {
          byte userBits = dis.readByte();
          int valueLength = InternalDataSerializer.readArrayLength(dis);
          byte[] valueBytes = null;
          long drId = DiskInitFile.readDiskRegionID(dis);
          DiskRecoveryStore drs = getOplogSet().getCurrentlyRecovering(drId);

          // read version
          VersionTag tag = null;
          if (EntryBits.isWithVersions(userBits)) {
            tag = readVersionsFromOplog(dis);
            if (drs != null && !drs.getDiskRegionView().getFlags()
                .contains(DiskRegionFlag.IS_WITH_VERSIONING)) {
              // 50044 Remove version tag from entry if we don't want versioning
              // for this region
              tag = null;
              userBits = EntryBits.setWithVersions(userBits, false);
            } else {
              // Update the RVV with the new entry
              if (drs != null) {
                drs.recordRecoveredVersionTag(tag);
              }
            }
          }

          long oplogKeyId = InternalDataSerializer.readVLOld(dis);
          long oplogOffset;
          if (EntryBits.isAnyInvalid(userBits) || EntryBits.isTombstone(userBits)) {
            oplogOffset = -1;
          } else {
            oplogOffset = lastOffset + InternalDataSerializer.readVLOld(dis);
            lastOffset = oplogOffset;
          }

          if (oplogKeyId > oplogKeyIdHWM) {
            oplogKeyIdHWM = oplogKeyId;
          }
          if (okToSkipModifyRecord(deletedIds, drId, drs, oplogKeyId, true, tag).skip()) {
            if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY_VERBOSE)) {
              logger.trace(LogMarker.PERSIST_RECOVERY_VERBOSE,
                  "readNewEntry skipping oplogKeyId=<{}> drId={} userBits={} oplogOffset={} valueLen={}",
                  oplogKeyId, drId, userBits, oplogOffset, valueLength);
            }
            stats.incRecoveryRecordsSkipped();
            incSkipped();
          } else {
            if (EntryBits.isAnyInvalid(userBits)) {
              if (EntryBits.isInvalid(userBits)) {
                valueBytes = DiskEntry.INVALID_BYTES;
              } else {
                valueBytes = DiskEntry.LOCAL_INVALID_BYTES;
              }
            } else if (EntryBits.isTombstone(userBits)) {
              valueBytes = DiskEntry.TOMBSTONE_BYTES;
            }
            Object key = deserializeKey(keyBytes, version, in);
            {
              Object oldValue = getRecoveryMap().put(oplogKeyId, key);
              if (oldValue != null) {
                throw new AssertionError(
                    String.format(
                        "Oplog::readNewEntry: Create is present in more than one Oplog. This should not be possible. The Oplog Key ID for this entry is %s.",
                        oplogKeyId));
              }
            }
            if (drs != null) {
              DiskEntry de = drs.getDiskEntry(key);
              if (de == null) {
                if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY_VERBOSE)) {
                  logger.trace(LogMarker.PERSIST_RECOVERY_VERBOSE,
                      "readNewEntry oplogKeyId=<{}> drId={} userBits={} oplogOffset={} valueLen={}",
                      oplogKeyId, drId, userBits, oplogOffset, valueLength);
                }
                DiskEntry.RecoveredEntry re =
                    createRecoveredEntry(valueBytes, valueLength, userBits,
                        getOplogId(), oplogOffset, oplogKeyId, false, version, in);
                if (tag != null) {
                  re.setVersionTag(tag);
                }
                initRecoveredEntry(drs.getDiskRegionView(), drs.initializeRecoveredEntry(key, re));
                drs.getDiskRegionView().incRecoveredEntryCount();
                stats.incRecoveredEntryCreates();
                krfEntryCount++;
              } else {
                DiskId curdid = de.getDiskId();
                // assert curdid.getOplogId() != getOplogId();
                if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY_VERBOSE)) {
                  logger.trace(LogMarker.PERSIST_RECOVERY_VERBOSE,
                      "ignore readNewEntry because getOplogId()={} != curdid.getOplogId()={} for drId={} key={}",
                      getOplogId(), curdid.getOplogId(), drId, key);
                }
              }
            }
          }
          keyBytes = DataSerializer.readByteArray(dis);
        } // while
        setRecoverNewEntryId(oplogKeyIdHWM);
        long tlc = totalLiveCount.get();
        if (totalCount.get() == 0 && tlc > 0) {
          totalCount.set(tlc);
        }
      } catch (IOException ex) {
        try {
          fis.close();
          fis = null;
        } catch (IOException ignore) {
        }
        throw new DiskAccessException("Unable to recover from krf file for oplogId=" + oplogId
            + ", file=" + f.getName() + ". This file is corrupt, but may be safely deleted.", ex,
            getParent());
      }
      if (recoverValues && krfEntryCount > 0) {
        oplogsNeedingValueRecovery.add(this);
        // TODO optimize this code and make it async
        // It should also honor the lru limit
        // The fault in logic might not work until
        // the region is actually created.
        // Instead of reading the crf it might be better to iterate the live
        // entry
        // list that was built during KRF recovery. Just fault values in until
        // we
        // hit the LRU limit (if we have one). Only fault in values for entries
        // recovered from disk that are still in this oplog.
        // Defer faulting in values until all oplogs for the ds have been
        // recovered.
      }
    } finally {
      if (fis != null) {
        try {
          fis.close();
        } catch (IOException ignore) {
        }
      }
    }
    return true;
  }
This map is used during recover to keep track of keys that are skipped. Later modify records in
the same oplog may use this map to retrieve the correct key.
geode-core/src/main/java/org/apache/geode/internal/cache/Oplog.java