Object findObjectInSystem(KeyInfo keyInfo, boolean isCreate, TXStateInterface tx,
      boolean generateCallbacks, Object localValue, boolean disableCopyOnRead, boolean preferCD,
      ClientProxyMembershipID requestingClient, EntryEventImpl clientEvent,
      boolean returnTombstones) throws CacheLoaderException, TimeoutException {

    final Object key = keyInfo.getKey();
    final Object aCallbackArgument = keyInfo.getCallbackArg();
    Object value = null;
    boolean fromServer = false;
    VersionTagHolder holder = null;

    /*
     * First lets try the server
     */
    ServerRegionProxy mySRP = getServerProxy();
    if (mySRP != null) {
      holder = new VersionTagHolder();
      value = mySRP.get(key, aCallbackArgument, holder);
      fromServer = value != null;
    }

    /*
     * If we didn't get anything from the server, try the loader
     */
    if (!fromServer || value == Token.TOMBSTONE) {
      // copy into local var to prevent race condition
      CacheLoader loader = basicGetLoader();
      if (loader != null) {
        fromServer = false;
        CachePerfStats stats = getCachePerfStats();
        long statStart = stats.startLoad();
        try {
          value = callCacheLoader(loader, key, aCallbackArgument, preferCD);
        } finally {
          stats.endLoad(statStart);
        }
      }
    }

    // don't allow tombstones into a client cache if it doesn't
    // have concurrency checks enabled
    if (fromServer && value == Token.TOMBSTONE && !getConcurrencyChecksEnabled()) {
      value = null;
    }

    /*
     * If we got a value back, let's put it in the cache.
     */
    RegionEntry re = null;
    if (value != null && !isMemoryThresholdReachedForLoad()) {

      long startPut = getStatisticsClock().getTime();
      validateKey(key);
      Operation op;
      if (isCreate) {
        op = Operation.LOCAL_LOAD_CREATE;
      } else {
        op = Operation.LOCAL_LOAD_UPDATE;
      }

      @Released
      EntryEventImpl event =
          entryEventFactory.create(this, op, key, value, aCallbackArgument, false,
              getMyId(), generateCallbacks);
      try {

        // do not put an invalid entry into the cache if there's
        // already one there with the same version
        if (fromServer) {
          if (alreadyInvalid(key, event)) {
            return null;
          }
          event.setFromServer(fromServer);
          event.setVersionTag(holder.getVersionTag());
          if (clientEvent != null) {
            clientEvent.setVersionTag(holder.getVersionTag());
          }
        }

        // set the event id so that we can propagate the value to the server
        if (!fromServer) {
          event.setNewEventId(cache.getDistributedSystem());
        }
        try {
          try {
            re = basicPutEntry(event, 0L);
            if (!fromServer && clientEvent != null) {
              clientEvent.setVersionTag(event.getVersionTag());
              clientEvent.isConcurrencyConflict(event.isConcurrencyConflict());
            }
            if (fromServer && event.getRawNewValue() == Token.TOMBSTONE) {
              // tombstones are destroyed entries
              return null;
            }
          } catch (ConcurrentCacheModificationException ignore) {
            // this means the value attempted to overwrite a newer modification and was rejected
            if (logger.isDebugEnabled()) {
              logger.debug("caught concurrent modification attempt when applying {}", event);
            }
            notifyBridgeClients(event);
          }
          if (!getDataView().isDeferredStats()) {
            getCachePerfStats().endPut(startPut, event.isOriginRemote());
          }
        } catch (CacheWriterException cwe) {
          if (logger.isDebugEnabled()) {
            logger.debug("findObjectInSystem: writer exception putting entry {}", event, cwe);
          }
        }
      } finally {
        event.release();
      }
    }
    if (isCreate) {
      recordMiss(re, key);
    }
    return value;
  }
Search for the value in a server (if one exists), then try a loader.

If we find a value, we put it in the cache.

@param preferCD return the CacheDeserializable, if that's what the value is.
@param requestingClient the client making the request, if any
@param clientEvent the client's event, if any. If not null, we set the version tag
@return the deserialized value
geode-core/src/main/java/org/apache/geode/internal/cache/LocalRegion.java