/** @param entry Entry. */
    @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"})
    void recheck(@Nullable GridCacheEntryEx entry) {
      if (entry == null) return;

      if (exchLog.isDebugEnabled())
        exchLog.debug("Rechecking entry for completion [entry=" + entry + ", finFut=" + this + ']');

      Collection<GridCacheMvccCandidate> cands = pendingLocks.get(entry.txKey());

      if (cands != null) {
        synchronized (cands) {
          for (Iterator<GridCacheMvccCandidate> it = cands.iterator(); it.hasNext(); ) {
            GridCacheMvccCandidate cand = it.next();

            // Check exclude ID again, as key could have been reassigned.
            if (cand.removed()) it.remove();
          }

          if (cands.isEmpty()) pendingLocks.remove(entry.txKey());

          if (pendingLocks.isEmpty()) {
            onDone();

            if (exchLog.isDebugEnabled()) exchLog.debug("Finish lock future is done: " + this);
          }
        }
      }
    }
  /** {@inheritDoc} */
  @Override
  public boolean onDone(GridCacheTx tx, Throwable err) {
    if ((initialized() || err != null) && super.onDone(tx, err)) {
      if (error() instanceof GridCacheTxHeuristicException) {
        long topVer = this.tx.topologyVersion();

        for (GridCacheTxEntry<K, V> e : this.tx.writeMap().values()) {
          try {
            if (e.op() != NOOP && !cctx.affinity().localNode(e.key(), topVer)) {
              GridCacheEntryEx<K, V> cacheEntry = cctx.cache().peekEx(e.key());

              if (cacheEntry != null) cacheEntry.invalidate(null, this.tx.xidVersion());
            }
          } catch (Throwable t) {
            U.error(log, "Failed to invalidate entry.", t);

            if (t instanceof Error) throw (Error) t;
          }
        }
      }

      // Don't forget to clean up.
      cctx.mvcc().removeFuture(this);

      return true;
    }

    return false;
  }
    /**
     * @param topVer Topology version.
     * @param entries Entries.
     */
    FinishLockFuture(Iterable<GridDistributedCacheEntry> entries, AffinityTopologyVersion topVer) {
      assert topVer.compareTo(AffinityTopologyVersion.ZERO) > 0;

      this.topVer = topVer;

      for (GridCacheEntryEx entry : entries) {
        // Either local or near local candidates.
        try {
          Collection<GridCacheMvccCandidate> locs = entry.localCandidates();

          if (!F.isEmpty(locs)) {
            Collection<GridCacheMvccCandidate> cands = new ConcurrentLinkedQueue<>();

            cands.addAll(F.view(locs, versionFilter()));

            if (!F.isEmpty(cands)) pendingLocks.put(entry.txKey(), cands);
          }
        } catch (GridCacheEntryRemovedException ignored) {
          if (exchLog.isDebugEnabled())
            exchLog.debug(
                "Got removed entry when adding it to finish lock future (will ignore): " + entry);
        }
      }

      if (exchLog.isDebugEnabled())
        exchLog.debug("Pending lock set [topVer=" + topVer + ", locks=" + pendingLocks + ']');
    }
  /** @return Key. */
  public K key() {
    GridCacheEntryEx<K, ?> parent0 = parent;

    if (parent0 == null)
      throw new IllegalStateException(
          "Parent entry was not initialized for MVCC candidate: " + this);

    return parent0.key();
  }
        /** {@inheritDoc} */
        @SuppressWarnings({"unchecked"})
        @Override
        public void onOwnerChanged(
            GridCacheEntryEx entry, GridCacheMvccCandidate prev, GridCacheMvccCandidate owner) {
          assert entry != null;
          assert owner != prev : "New and previous owner are identical instances: " + owner;
          assert owner == null || prev == null || !owner.version().equals(prev.version())
              : "New and previous owners have identical versions [owner="
                  + owner
                  + ", prev="
                  + prev
                  + ']';

          if (log.isDebugEnabled())
            log.debug(
                "Received owner changed callback ["
                    + entry.key()
                    + ", owner="
                    + owner
                    + ", prev="
                    + prev
                    + ']');

          if (owner != null && (owner.local() || owner.nearLocal())) {
            Collection<? extends GridCacheFuture> futCol = futs.get(owner.version());

            if (futCol != null) {
              for (GridCacheFuture fut : futCol) {
                if (fut instanceof GridCacheMvccFuture && !fut.isDone()) {
                  GridCacheMvccFuture<Boolean> mvccFut = (GridCacheMvccFuture<Boolean>) fut;

                  // Since this method is called outside of entry synchronization,
                  // we can safely invoke any method on the future.
                  // Also note that we don't remove future here if it is done.
                  // The removal is initiated from within future itself.
                  if (mvccFut.onOwnerChanged(entry, owner)) return;
                }
              }
            }
          }

          if (log.isDebugEnabled())
            log.debug(
                "Lock future not found for owner change callback (will try transaction futures) [owner="
                    + owner
                    + ", prev="
                    + prev
                    + ", entry="
                    + entry
                    + ']');

          // If no future was found, delegate to transaction manager.
          if (cctx.tm().onOwnerChanged(entry, owner)) {
            if (log.isDebugEnabled()) log.debug("Found transaction for changed owner: " + owner);
          } else if (log.isDebugEnabled())
            log.debug("Failed to find transaction for changed owner: " + owner);

          for (FinishLockFuture f : finishFuts) f.recheck(entry);
        }
Beispiel #6
0
  /** @return {@code True} if locks have been acquired. */
  private boolean checkLocks() {
    if (!isDone() && initialized() && !hasPending()) {
      for (int i = 0; i < entries.size(); i++) {
        while (true) {
          GridCacheEntryEx<K, V> cached = entries.get(i);

          try {
            if (!locked(cached)) {
              if (log.isDebugEnabled())
                log.debug(
                    "Lock is still not acquired for entry (will keep waiting) [entry="
                        + cached
                        + ", fut="
                        + this
                        + ']');

              return false;
            }

            break;
          }
          // Possible in concurrent cases, when owner is changed after locks
          // have been released or cancelled.
          catch (GridCacheEntryRemovedException ignore) {
            if (log.isDebugEnabled())
              log.debug("Got removed entry in onOwnerChanged method (will retry): " + cached);

            // Replace old entry with new one.
            entries.set(i, (GridDistributedCacheEntry<K, V>) cctx.cache().entryEx(cached.key()));
          }
        }
      }

      if (log.isDebugEnabled())
        log.debug("Local lock acquired for entries [fut=" + this + ", entries=" + entries + "]");

      onComplete(true, true);

      return true;
    }

    return false;
  }
Beispiel #7
0
  /**
   * Undoes all locks.
   *
   * @param dist If {@code true}, then remove locks from remote nodes as well.
   */
  private void undoLocks(boolean dist) {
    // Transactions will undo during rollback.
    if (dist && tx == null) cctx.nearTx().removeLocks(lockVer, keys);
    else {
      if (tx != null) {
        if (tx.setRollbackOnly()) {
          if (log.isDebugEnabled())
            log.debug(
                "Marked transaction as rollback only because locks could not be acquired: " + tx);
        } else if (log.isDebugEnabled())
          log.debug(
              "Transaction was not marked rollback-only while locks were not acquired: " + tx);
      }

      for (GridCacheEntryEx<K, V> e : entriesCopy()) {
        try {
          e.removeLock(lockVer);
        } catch (GridCacheEntryRemovedException ignored) {
          while (true) {
            try {
              e = cctx.cache().peekEx(e.key());

              if (e != null) e.removeLock(lockVer);

              break;
            } catch (GridCacheEntryRemovedException ignore) {
              if (log.isDebugEnabled())
                log.debug(
                    "Attempted to remove lock on removed entry (will retry) [ver="
                        + lockVer
                        + ", entry="
                        + e
                        + ']');
            }
          }
        }
      }
    }

    cctx.mvcc().recheckPendingLocks();
  }
  /**
   * @param e Entry to evict if it qualifies for eviction.
   * @param obsoleteVer Obsolete version.
   * @return {@code True} if attempt was made to evict the entry.
   */
  protected boolean evictNearEntry(GridCacheEntryEx<K, V> e, GridCacheVersion obsoleteVer) {
    assert e != null;
    assert obsoleteVer != null;

    if (isNearLocallyMapped(e)) {
      if (log.isDebugEnabled())
        log.debug("Evicting dht-local entry from near cache [entry=" + e + ", tx=" + this + ']');

      if (e.markObsolete(obsoleteVer, true)) return true;
    }

    return false;
  }
  /** {@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()));
  }
 /**
  * @param e Transaction entry.
  * @return {@code True} if entry is locally mapped as a primary or back up node.
  */
 protected boolean isNearLocallyMapped(GridCacheEntryEx<K, V> e) {
   return F.contains(ctx.affinity(e.key(), CU.allNodes(ctx)), ctx.localNode());
 }
Beispiel #11
0
 /**
  * @param cached Entry.
  * @return {@code True} if locked.
  * @throws GridCacheEntryRemovedException If removed.
  */
 private boolean locked(GridCacheEntryEx<K, V> cached) throws GridCacheEntryRemovedException {
   // Reentry-aware check (If filter failed, lock is failed).
   return cached.lockedLocallyByIdOrThread(lockVer, threadId) && filter(cached);
 }