/**
   * Adds group reservation to this partition.
   *
   * @param r Reservation.
   * @return {@code false} If such reservation already added.
   */
  public boolean addReservation(GridDhtPartitionsReservation r) {
    assert state.getReference() != EVICTED : "we can reserve only active partitions";
    assert state.getStamp() != 0
        : "partition must be already reserved before adding group reservation";

    return reservations.addIfAbsent(r);
  }
  /**
   * @param updateSeq Update sequence.
   * @return {@code True} if entry has been transitioned to state EVICTED.
   */
  boolean tryEvict(boolean updateSeq) {
    if (state.getReference() != RENTING || state.getStamp() != 0 || groupReserved()) return false;

    // Attempt to evict partition entries from cache.
    clearAll();

    if (map.isEmpty() && state.compareAndSet(RENTING, EVICTED, 0, 0)) {
      if (log.isDebugEnabled()) log.debug("Evicted partition: " + this);

      if (!GridQueryProcessor.isEnabled(cctx.config())) clearSwap();

      if (cctx.isDrEnabled()) cctx.dr().partitionEvicted(id);

      cctx.dataStructures().onPartitionEvicted(id);

      rent.onDone();

      ((GridDhtPreloader) cctx.preloader()).onPartitionEvicted(this, updateSeq);

      clearDeferredDeletes();

      return true;
    }

    return false;
  }
  /**
   * Reserves a partition so it won't be cleared.
   *
   * @return {@code True} if reserved.
   */
  @Override
  public boolean reserve() {
    while (true) {
      int reservations = state.getStamp();

      GridDhtPartitionState s = state.getReference();

      if (s == EVICTED) return false;

      if (state.compareAndSet(s, s, reservations, reservations + 1)) return true;
    }
  }
  /**
   * @param updateSeq Update sequence.
   * @return Future for evict attempt.
   */
  IgniteInternalFuture<Boolean> tryEvictAsync(boolean updateSeq) {
    if (map.isEmpty()
        && !GridQueryProcessor.isEnabled(cctx.config())
        && state.compareAndSet(RENTING, EVICTED, 0, 0)) {
      if (log.isDebugEnabled()) log.debug("Evicted partition: " + this);

      clearSwap();

      if (cctx.isDrEnabled()) cctx.dr().partitionEvicted(id);

      cctx.dataStructures().onPartitionEvicted(id);

      rent.onDone();

      ((GridDhtPreloader) cctx.preloader()).onPartitionEvicted(this, updateSeq);

      clearDeferredDeletes();

      return new GridFinishedFuture<>(true);
    }

    return cctx.closures()
        .callLocalSafe(
            new GPC<Boolean>() {
              @Override
              public Boolean call() {
                return tryEvict(true);
              }
            }, /*system pool*/
            true);
  }
  /** Releases previously reserved partition. */
  @Override
  public void release() {
    while (true) {
      int reservations = state.getStamp();

      if (reservations == 0) return;

      GridDhtPartitionState s = state.getReference();

      assert s != EVICTED;

      // Decrement reservations.
      if (state.compareAndSet(s, s, reservations, --reservations)) {
        tryEvict(true);

        break;
      }
    }
  }
  /**
   * @param updateSeq Update sequence.
   * @return Future to signal that this node is no longer an owner or backup.
   */
  IgniteInternalFuture<?> rent(boolean updateSeq) {
    while (true) {
      int reservations = state.getStamp();

      GridDhtPartitionState s = state.getReference();

      if (s == RENTING || s == EVICTED) return rent;

      if (state.compareAndSet(s, RENTING, reservations, reservations)) {
        if (log.isDebugEnabled()) log.debug("Moved partition to RENTING state: " + this);

        // Evict asynchronously, as the 'rent' method may be called
        // from within write locks on local partition.
        tryEvictAsync(updateSeq);

        break;
      }
    }

    return rent;
  }
  /** @return {@code True} if transitioned to OWNING state. */
  boolean own() {
    while (true) {
      int reservations = state.getStamp();

      GridDhtPartitionState s = state.getReference();

      if (s == RENTING || s == EVICTED) return false;

      if (s == OWNING) return true;

      assert s == MOVING;

      if (state.compareAndSet(MOVING, OWNING, reservations, reservations)) {
        if (log.isDebugEnabled()) log.debug("Owned partition: " + this);

        // No need to keep history any more.
        evictHist = null;

        return true;
      }
    }
  }
 /** @return Reservations. */
 public int reservations() {
   return state.getStamp();
 }
 /** @return Partition state. */
 public GridDhtPartitionState state() {
   return state.getReference();
 }