private void basicPut(Object object) throws CacheException, InterruptedException {
    // optmistically decrease the put count
    Conflatable event = (Conflatable) object;
    try {
      waitForPermission();
    } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
      region.getCache().getCancelCriterion().checkCancelInProgress(ie);
    }

    // Get the EventID object & from it obtain the ThreadIdentifier
    EventID eventId = event.getEventId();
    ThreadIdentifier ti = getThreadIdentifier(eventId);
    long sequenceID = eventId.getSequenceID();
    // Check from Events Map if the put operation should proceed or not
    DispatchedAndCurrentEvents dace = (DispatchedAndCurrentEvents) eventsMap.get(ti);
    if (dace != null && dace.isGIIDace && puttingGIIDataInQueue.get()) {
      // we only need to retain DACE for which there are no entries in the queue.
      // for other thread identifiers we build up a new DACE
      dace = null;
    }
    if (dace != null) {
      // check the last dispatched sequence Id
      if (puttingGIIDataInQueue.get() || (sequenceID > dace.lastDispatchedSequenceId)) {
        // Asif:Insert the Event into the Region with proper locking.
        // It is possible that by the time put operation proceeds , the
        // Last dispatched id has changed so it is possible that the object at
        // this point also does not get added
        if (!dace.putObject(event, sequenceID)) {
          // dace encountered a DESTROYED token - stop adding GII data
          if (!puttingGIIDataInQueue.get()) {
            put(object);
          }
        } else {
          if (logger.isTraceEnabled(LogMarker.BRIDGE_SERVER_VERBOSE)) {
            logger.trace(LogMarker.BRIDGE_SERVER_VERBOSE, "{}: Adding message to queue: {}", this,
                object);
          }
        }

      } else {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "{}: This queue has already seen this event.  The highest sequence number in the queue for {} is {}, but this event's sequence number is {}",
              regionName, ti, dace.lastDispatchedSequenceId, sequenceID);
        }
        incrementTakeSidePutPermits();
      }
    } else {
      dace = new DispatchedAndCurrentEvents(this);
      DispatchedAndCurrentEvents oldDace =
          (DispatchedAndCurrentEvents) eventsMap.putIfAbsent(ti, dace);
      if (oldDace != null) {
        dace = oldDace;
      } else {
        // Add the recently added ThreadIdentifier to the RegionQueue for expiry
        region.put(ti, dace.lastDispatchedSequenceId);
        // update the stats
        stats.incThreadIdentifiers();
      }
      if (!dace.putObject(event, sequenceID)) {
        put(object);
      } else {
        if (logger.isTraceEnabled(LogMarker.BRIDGE_SERVER_VERBOSE)) {
          logger.trace(LogMarker.BRIDGE_SERVER_VERBOSE, "{}: Adding message to queue: {}", this,
              object);
        }
      }
    }
  }
Adds an object at the queue's tail. The implementation supports concurrent put operations in a
performant manner. This is done in following steps: <br>
1)Check if the Event being added has a sequence ID less than the Last Dispatched SequenceId. If
yes do not add the Event to the Queue <br>
2)If no then Do a "put-if-absent" on the eventsMap ,inserting the
LastDispatchedAndCurrentEvents object or adding the position to the existing object for the
ThreadIdentifier

It is possible that DispatchedAnCurrentEvents object just retrieved by the put thread has
expired thus a one level recursion can occur to do a valid put

The operation is thread safe & is guarded by taking a lock on LastDispatchedAndCurrentEvents
object & SIZE Lock

@param object object to put onto the queue
geode-core/src/main/java/org/apache/geode/internal/cache/ha/HARegionQueue.java