@Retained
    private static Object faultInValue(DiskEntry entry, InternalRegion region,
        boolean retainResult) {
      DiskRegion dr = region.getDiskRegion();
      @Retained
      Object v = entry.getValueRetain(region, true);

      boolean lruFaultedIn = false;
      boolean done = false;
      try {
        if (entry instanceof EvictableEntry && !dr.isSync()) {
          synchronized (entry) {
            DiskId did = entry.getDiskId();
            if (did != null && did.isPendingAsync()) {
              done = true;
              // See if it is pending async because of a faultOut.
              // If so then if we are not a backup then we can unschedule the pending async.
              // In either case we need to do the lruFaultIn logic.
              boolean evicted = ((EvictableEntry) entry).isEvicted();
              if (evicted) {
                if (!dr.isBackup()) {
                  // @todo do we also need a bit that tells us if it is in the async queue?
                  // Seems like we could end up adding it to the queue multiple times.
                  did.setPendingAsync(false);
                }
              }
              lruEntryFaultIn((EvictableEntry) entry, region);
              lruFaultedIn = true;
            }
          }
        }
        if (!done && (v == null || Token.isRemovedFromDisk(v) && !region.isIndexCreationThread())) {
          synchronized (entry) {
            v = entry.getValueRetain(region, true);

            if (v == null) {
              v = readValueFromDisk(entry, region);
              if (entry instanceof EvictableEntry) {
                if (v != null && !Token.isInvalid(v)) {
                  lruEntryFaultIn((EvictableEntry) entry, region);

                  lruFaultedIn = true;
                }
              }
            }
          }
        }
      } finally {
        if (!retainResult) {
          v = OffHeapHelper.copyAndReleaseIfNeeded(v, region.getCache());
          // At this point v should be either a heap object
        }
      }
      if (Token.isRemoved(v)) {
        // fix for bug 31800
        v = null;
      } else {
        entry.setRecentlyUsed(region);
      }
      if (lruFaultedIn) {
        lruUpdateCallback(region);
      }
      return v; // OFFHEAP: the value ends up being returned by RegionEntry.getValue
    }
@param retainResult if true then the result may be a retained off-heap reference
geode-core/src/main/java/org/apache/geode/internal/cache/entries/DiskEntry.java