protected void processVersionTag(EntryEvent cacheEvent, boolean conflictCheck) {
    EntryEventImpl event = (EntryEventImpl) cacheEvent;
    VersionTag tag = event.getVersionTag();
    if (tag == null) {
      return;
    }

    try {
      if (tag.isGatewayTag()) {
        // this may throw ConcurrentCacheModificationException or modify the event
        if (processGatewayTag(cacheEvent)) {
          return;
        }
        assert false : "processGatewayTag failure - returned false";
      }

      if (!tag.isFromOtherMember()) {
        if (!event.getOperation().isNetSearch()) {
          // except for netsearch, all locally-generated tags can be ignored
          return;
        }
      }

      final InternalDistributedMember originator =
          (InternalDistributedMember) event.getDistributedMember();
      final VersionSource dmId = event.getRegion().getVersionMember();
      InternalRegion r = event.getRegion();
      boolean eventHasDelta = event.getDeltaBytes() != null && event.getRawNewValue() == null;

      VersionStamp stamp = getVersionStamp();
      // bug #46223, an event received from a peer or a server may be from a different
      // distributed system than the last modification made to this entry so we must
      // perform a gateway conflict check
      if (stamp != null && !tag.isAllowedByResolver()) {
        int stampDsId = stamp.getDistributedSystemId();
        int tagDsId = tag.getDistributedSystemId();

        if (stampDsId != 0 && stampDsId != tagDsId && stampDsId != -1) {
          StringBuilder verbose = null;
          if (logger.isTraceEnabled(LogMarker.TOMBSTONE_VERBOSE)) {
            verbose = new StringBuilder();
            verbose.append("processing tag for key ").append(getKey()).append(", stamp=")
                .append(stamp.asVersionTag()).append(", tag=").append(tag);
          }
          long stampTime = stamp.getVersionTimeStamp();
          long tagTime = tag.getVersionTimeStamp();
          if (stampTime > 0 && (tagTime > stampTime || (tagTime == stampTime
              && tag.getDistributedSystemId() >= stamp.getDistributedSystemId()))) {
            if (verbose != null) {
              verbose.append(" - allowing event");
              logger.trace(LogMarker.TOMBSTONE_VERBOSE, verbose);
            }
            // Update the stamp with event's version information.
            applyVersionTag(r, stamp, tag, originator);
            return;
          }

          if (stampTime > 0) {
            if (verbose != null) {
              verbose.append(" - disallowing event");
              logger.trace(LogMarker.TOMBSTONE_VERBOSE, verbose);
            }
            r.getCachePerfStats().incConflatedEventsCount();
            persistConflictingTag(r, tag);
            throw new ConcurrentCacheModificationException("conflicting event detected");
          }
        }
      }

      if (r.getVersionVector() != null && r.getServerProxy() == null
          && (r.getDataPolicy().withPersistence() || !r.getScope().isLocal())) {
        // bug #45258 - perf degradation for local regions and RVV
        VersionSource who = tag.getMemberID();
        if (who == null) {
          who = originator;
        }
        r.getVersionVector().recordVersion(who, tag);
      }

      assert !tag.isFromOtherMember()
          || tag.getMemberID() != null : "remote tag is missing memberID";

      // for a long time I had conflict checks turned off in clients when
      // receiving a response from a server and applying it to the cache. This lowered
      // the CPU cost of versioning but eventually had to be pulled for bug #45453

      // events coming from servers while a local sync is held on the entry
      // do not require a conflict check. Conflict checks were already
      // performed on the server and here we just consume whatever was sent back.
      // Event.isFromServer() returns true for client-update messages and
      // for putAll/getAll, which do not hold syncs during the server operation.

      // for a very long time we had conflict checks turned off for PR buckets.
      // Bug 45669 showed a primary dying in the middle of distribution. This caused
      // one backup bucket to have a v2. The other bucket was promoted to primary and
      // generated a conflicting v2. We need to do the check so that if this second
      // v2 loses to the original one in the delta-GII operation that the original v2
      // will be the winner in both buckets.

      // The new value in event is not from GII, even it could be tombstone
      basicProcessVersionTag(r, tag, false, eventHasDelta, dmId, originator, conflictCheck);
    } catch (ConcurrentCacheModificationException ex) {
      event.isConcurrencyConflict(true);
      throw ex;
    }
  }
This performs a concurrency check.

This check compares the version number first, followed by the member ID.

Wraparound of the version number is detected and handled by extending the range of versions by
one bit.

The normal membership ID comparison method is used.
<p>

Note that a tag from a remote (WAN) system may be in the event. If this is the case this method
will either invoke a user plugin that allows/disallows the event (and may modify the value) or
it determines whether to allow or disallow the event based on timestamps and
distributedSystemIDs.

@throws ConcurrentCacheModificationException if the event conflicts with an event that has
        already been applied to the entry.
geode-core/src/main/java/org/apache/geode/internal/cache/entries/AbstractRegionEntry.java