/** @return Reentry candidate. */
  public GridCacheMvccCandidate<K> reenter() {
    GridCacheMvccCandidate<K> old = reentry;

    GridCacheMvccCandidate<K> reentry =
        new GridCacheMvccCandidate<>(
            parent,
            nodeId,
            otherNodeId,
            otherVer,
            threadId,
            ver,
            timeout,
            local(),
            /*reentry*/ true,
            tx(),
            singleImplicit(),
            nearLocal(),
            dhtLocal());

    reentry.topVer = topVer;

    if (old != null) reentry.reentry = old;

    this.reentry = reentry;

    return reentry;
  }
  /** {@inheritDoc} */
  @SuppressWarnings({"unchecked"})
  @Override
  public boolean equals(Object o) {
    if (o == null) return false;

    if (o == this) return true;

    GridCacheMvccCandidate<K> other = (GridCacheMvccCandidate<K>) o;

    assert key() != null && other.key() != null
        : "Key is null [this=" + this + ", other=" + o + ']';

    return ver.equals(other.ver) && key().equals(other.key());
  }
  /** {@inheritDoc} */
  @Override
  public String toString() {
    GridCacheMvccCandidate<?> prev = previous();
    GridCacheMvccCandidate<?> next = next();

    return S.toString(
        GridCacheMvccCandidate.class,
        this,
        "key",
        parent == null ? null : parent.key(),
        "masks",
        Mask.toString(flags()),
        "prevVer",
        (prev == null ? null : prev.version()),
        "nextVer",
        (next == null ? null : next.version()));
  }
  /** {@inheritDoc} */
  @Override
  public int compareTo(GridCacheMvccCandidate<K> o) {
    if (o == this) return 0;

    int c = ver.compareTo(o.ver);

    // This is done, so compare and equals methods will be consistent.
    if (c == 0) return key().equals(o.key()) ? 0 : id < o.id ? -1 : 1;

    return c;
  }