public void refreshEntriesFromServerKeys(Connection con, List serverKeys,
      InterestResultPolicy interestResultPolicy) {
    if (serverKeys == null) {
      return;
    }
    ServerRegionProxy proxy = getServerProxy();
    if (logger.isDebugEnabled()) {
      logKeys(serverKeys, interestResultPolicy);
    }

    if (interestResultPolicy == InterestResultPolicy.NONE) {
      return; // done
    }

    if (logger.isDebugEnabled()) {
      logger.debug("refreshEntries region={}", getFullPath());
    }
    for (Object serverKey : serverKeys) {
      ArrayList keysList = (ArrayList) serverKey;
      // The chunk can contain null data if there are no entries on the server
      // corresponding to the requested keys
      if (keysList == null) {
        continue;
      }
      if (EntryLogger.isEnabled()) {
        if (con != null) {
          Endpoint endpoint = con.getEndpoint();
          if (endpoint != null) {
            EntryLogger.setSource(endpoint.getMemberId(), "RIGII");
          }
        }
      }
      try {
        List list = new ArrayList(keysList);
        if (interestResultPolicy != InterestResultPolicy.KEYS_VALUES) {
          for (Object currentKey : keysList) {
            // Don't apply riResponse if the entry was destroyed when
            // ri is in progress
            if (currentKey == null || getImageState().hasDestroyedEntry(currentKey)) {
              list.remove(currentKey);
            }
          }
        }
        if (interestResultPolicy == InterestResultPolicy.KEYS) {
          // Attempt to create an invalid in without overwriting
          if (!isProxy()) {
            for (Object currentKey : list) {
              entries.initialImagePut(currentKey, 0, Token.LOCAL_INVALID, false, false, null,
                  null, false);
            }
          }
          // Size statistics don't take key into account, so we don't
          // need to modify the region's size.
        } else if (!list.isEmpty()) {
          Assert.assertTrue(interestResultPolicy == InterestResultPolicy.KEYS_VALUES);

          VersionedObjectList values = (VersionedObjectList) list.get(0);

          if (logger.isDebugEnabled()) {
            logger.debug("processing interest response: {}", values.size());
          }
          VersionedObjectList.Iterator listIt = values.iterator();
          while (listIt.hasNext()) {
            VersionedObjectList.Entry entry = listIt.next();
            Object currentKey = entry.getKey();
            if (currentKey == null || getImageState().hasDestroyedEntry(currentKey)) {
              continue;
            }
            Object val = entry.getObject();
            boolean isBytes = entry.isBytes();
            boolean isKeyOnServer = !entry.isKeyNotOnServer();
            boolean isTombstone = getConcurrencyChecksEnabled() && entry.isKeyNotOnServer()
                && entry.getVersionTag() != null;
            final VersionTag tag = entry.getVersionTag();
            if (val instanceof Throwable) {
              logger.warn(String.format(
                  "Caught the following exception for key %s while performing a remote getAll",
                  currentKey),
                  (Throwable) val);
              localDestroyNoCallbacks(currentKey);
              continue;
            }
            if (logger.isDebugEnabled()) {
              logger.debug("refreshEntries key={} value={} version={}", currentKey, entry, tag);
            }
            if (tag == null) { // no version checks
              localDestroyNoCallbacks(currentKey);
            }

            if (val instanceof byte[] && !isBytes) {
              val = CachedDeserializableFactory.create((byte[]) val, getCache());
            }

            if (isTombstone) {
              assert val == null : "server returned a value for a destroyed entry";
              val = Token.TOMBSTONE;
            }

            if (val != null || isTombstone) {
              // Sneakily drop in the value into our local cache,
              // but don't overwrite
              if (!isProxy()) {
                entries.initialImagePut(currentKey, 0, val, false, false, tag, null, false);
              }
            } else {
              RegionEntry regionEntry = entries.getEntry(currentKey);
              if (!isProxy() && isKeyOnServer) {
                entries.initialImagePut(currentKey, 0, Token.LOCAL_INVALID, false, false, tag,
                    null, false);
              } else {
                if (regionEntry != null) {
                  synchronized (regionEntry) {
                    if (regionEntry.isDestroyedOrRemovedButNotTombstone()) {
                      entries.removeEntry(currentKey, regionEntry, false);
                    }
                  }
                }
              }
              // In this case, if we didn't overwrite, we don't have a local
              // value, so no size change needs to be recorded.
            }
          }
        }
      } catch (DiskAccessException dae) {
        handleDiskAccessException(dae);
        throw dae;
      } finally {
        EntryLogger.clearSource();
      }
    } // for
  }
Refresh local entries based on server's list of keys
geode-core/src/main/java/org/apache/geode/internal/cache/LocalRegion.java