Beispiel #1
0
  /**
   * Local release.
   *
   * @param threadId ID of the thread.
   * @return Removed candidate.
   */
  @Nullable
  public GridCacheMvccCandidate releaseLocal(long threadId) {
    CacheLockCandidates owners = localOwners();

    // Release had no effect.
    if (owners == null) return null;

    GridCacheMvccCandidate owner = null;

    for (int i = 0; i < owners.size(); i++) {
      GridCacheMvccCandidate owner0 = owners.candidate(i);

      if (owner0.threadId() == threadId) {
        owner = owner0;

        break;
      }
    }

    if (owner != null) {
      owner.setUsed();

      remove0(owner.version(), true);

      return owner;
    } else return null;
  }
    /** @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);
          }
        }
      }
    }
Beispiel #3
0
  /**
   * For all remote candidates standing behind the candidate being salvaged marks their transactions
   * as system invalidate and marks these candidates as owned and used.
   *
   * @param ver Version to salvage.
   */
  public void salvageRemote(GridCacheVersion ver) {
    assert ver != null;

    GridCacheMvccCandidate cand = candidate(rmts, ver);

    if (cand != null) {
      assert rmts != null;
      assert !rmts.isEmpty();

      for (Iterator<GridCacheMvccCandidate> iter = rmts.iterator(); iter.hasNext(); ) {
        GridCacheMvccCandidate rmt = iter.next();

        // For salvaged candidate doneRemote will be called explicitly.
        if (rmt == cand) break;

        // Only Near and DHT remote candidates should be released.
        assert !rmt.nearLocal();

        IgniteInternalTx tx = cctx.tm().tx(rmt.version());

        if (tx != null) {
          tx.systemInvalidate(true);

          rmt.setOwner();
          rmt.setUsed();
        } else iter.remove();
      }
    }
  }
  /**
   * @param cacheCtx Cache context.
   * @param cand Cache lock candidate to add.
   * @return {@code True} if added as a result of this operation, {@code false} if was previously
   *     added.
   */
  public boolean addNext(GridCacheContext cacheCtx, GridCacheMvccCandidate cand) {
    assert cand != null;
    assert !cand.reentry() : "Lock reentries should not be linked: " + cand;

    // Don't order near candidates by thread as they will be ordered on
    // DHT node. Also, if candidate is implicit, no point to order him.
    if (cacheCtx.isNear() || cand.singleImplicit()) return true;

    LinkedList<GridCacheMvccCandidate> queue = pending.get();

    GridCacheMvccCandidate prev = null;

    if (!queue.isEmpty()) prev = queue.getLast();

    queue.add(cand);

    if (prev != null) {
      prev.next(cand);

      cand.previous(prev);
    }

    if (log.isDebugEnabled()) log.debug("Linked new candidate: " + cand);

    return true;
  }
  /**
   * Removes candidate from the list of near local candidates.
   *
   * @param cand Candidate to remove.
   */
  public void removeExplicitLock(GridCacheMvccCandidate cand) {
    GridCacheExplicitLockSpan span = pendingExplicit.get(cand.threadId());

    if (span == null) return;

    if (span.removeCandidate(cand)) pendingExplicit.remove(cand.threadId(), span);
  }
        /** {@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 #7
0
  /**
   * Near local candidate.
   *
   * @param nodeId Node ID.
   * @param threadId Thread ID.
   * @return Remote candidate.
   */
  @Nullable
  public GridCacheMvccCandidate localCandidate(UUID nodeId, long threadId) {
    if (locs != null)
      for (GridCacheMvccCandidate c : locs)
        if (c.nodeId().equals(nodeId) && c.threadId() == threadId) return c;

    return null;
  }
Beispiel #8
0
  /**
   * @param nodeId Node ID.
   * @param threadId Thread ID.
   * @return Remote candidate.
   */
  @Nullable
  GridCacheMvccCandidate remoteCandidate(UUID nodeId, long threadId) {
    if (rmts != null)
      for (GridCacheMvccCandidate c : rmts)
        if (c.nodeId().equals(nodeId) && c.threadId() == threadId) return c;

    return null;
  }
Beispiel #9
0
  /**
   * @param cand Candidate to check.
   * @return First predecessor that is owner or is not used.
   */
  @Nullable
  private GridCacheMvccCandidate nonRollbackPrevious(GridCacheMvccCandidate cand) {
    for (GridCacheMvccCandidate c = cand.previous(); c != null; c = c.previous()) {
      if (c.owner() || !c.used()) return c;
    }

    return null;
  }
Beispiel #10
0
  /**
   * @param cands Candidates to search.
   * @param ver Version.
   * @return Candidate for the version.
   */
  @Nullable
  private GridCacheMvccCandidate candidate(
      Iterable<GridCacheMvccCandidate> cands, GridCacheVersion ver) {
    assert ver != null;

    if (cands != null) for (GridCacheMvccCandidate c : cands) if (c.version().equals(ver)) return c;

    return null;
  }
Beispiel #11
0
  /**
   * Puts owned versions in front of base.
   *
   * @param baseVer Base version.
   * @param owned Owned list.
   */
  public void markOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
    if (owned == null) return;

    if (rmts != null) {
      GridCacheMvccCandidate baseCand = candidate(rmts, baseVer);

      if (baseCand != null) baseCand.ownerVersion(owned);
    }
  }
Beispiel #12
0
  /**
   * @param cand Local candidate added in any of the {@code addLocal(..)} methods.
   * @return Current lock owner.
   */
  @Nullable
  public CacheLockCandidates readyLocal(GridCacheMvccCandidate cand) {
    assert cand.local();

    cand.setReady();

    reassign();

    return allOwners();
  }
Beispiel #13
0
  /** @param cand Remote candidate. */
  private void addRemote(GridCacheMvccCandidate cand) {
    assert !cand.local();

    if (log.isDebugEnabled())
      log.debug("Adding remote candidate [mvcc=" + this + ", cand=" + cand + "]");

    cctx.versions().onReceived(cand.nodeId(), cand.version());

    add0(cand);
  }
Beispiel #14
0
  /**
   * @param ver Lock version to acquire or set to ready.
   * @return Current owner.
   */
  @Nullable
  public CacheLockCandidates readyLocal(GridCacheVersion ver) {
    GridCacheMvccCandidate cand = candidate(ver);

    if (cand == null) return allOwners();

    assert cand.local();

    return readyLocal(cand);
  }
Beispiel #15
0
  /** @return Local candidate only if it's first in the list and is marked as <tt>'owner'</tt>. */
  @Nullable
  GridCacheMvccCandidate localOwner() {
    if (locs != null) {
      assert !locs.isEmpty();

      GridCacheMvccCandidate first = locs.getFirst();

      return first.owner() ? first : null;
    }

    return null;
  }
  /**
   * @param cand Local candidate to remove.
   * @return {@code True} if removed.
   */
  public boolean removeLocal(GridCacheMvccCandidate cand) {
    assert cand.key() != null;
    assert cand.local();

    if (cand.dhtLocal() && dhtLocCands.remove(cand)) {
      if (log.isDebugEnabled()) log.debug("Removed local candidate: " + cand);

      return true;
    }

    return false;
  }
Beispiel #17
0
  /** @return Remote candidate only if it's first in the list and is marked as <tt>'used'</tt>. */
  @Nullable
  private GridCacheMvccCandidate remoteOwner() {
    if (rmts != null) {
      assert !rmts.isEmpty();

      GridCacheMvccCandidate first = rmts.getFirst();

      return first.used() && first.owner() ? first : null;
    }

    return null;
  }
    /** {@inheritDoc} */
    @Override
    public String toString() {
      if (!pendingLocks.isEmpty()) {
        Map<GridCacheVersion, IgniteInternalTx> txs = new HashMap<>(1, 1.0f);

        for (Collection<GridCacheMvccCandidate> cands : pendingLocks.values())
          for (GridCacheMvccCandidate c : cands) txs.put(c.version(), cctx.tm().tx(c.version()));

        return S.toString(
            FinishLockFuture.class, this, "txs=" + txs + ", super=" + super.toString());
      } else return S.toString(FinishLockFuture.class, this, super.toString());
    }
Beispiel #19
0
  /**
   * @param lockVer Lock ID.
   * @param threadId Thread ID.
   * @return {@code True} if locked by lock ID or thread ID.
   */
  boolean isLocallyOwnedByIdOrThread(GridCacheVersion lockVer, long threadId) {
    CacheLockCandidates owners = localOwners();

    if (owners != null) {
      for (int i = 0; i < owners.size(); i++) {
        GridCacheMvccCandidate owner = owners.candidate(i);

        if ((owner.version().equals(lockVer) || owner.threadId() == threadId)) return true;
      }
    }

    return false;
  }
Beispiel #20
0
  /**
   * @param threadId Thread ID.
   * @param reentry Reentry flag.
   * @return Local candidate for the thread.
   */
  @Nullable
  private GridCacheMvccCandidate localCandidate(long threadId, boolean reentry) {
    if (locs != null)
      for (GridCacheMvccCandidate cand : locs) {
        if (cand.threadId() == threadId) {
          if (cand.reentry() && !reentry) continue;

          return cand;
        }
      }

    return null;
  }
  /**
   * Removes explicit lock for given thread id, key and optional version.
   *
   * @param threadId Thread id.
   * @param key Key.
   * @param ver Optional version.
   * @return Candidate.
   */
  public GridCacheMvccCandidate removeExplicitLock(
      long threadId, KeyCacheObject key, @Nullable GridCacheVersion ver) {
    assert threadId > 0;

    GridCacheExplicitLockSpan span = pendingExplicit.get(threadId);

    if (span == null) return null;

    GridCacheMvccCandidate cand = span.removeCandidate(key, ver);

    if (cand != null && span.isEmpty()) pendingExplicit.remove(cand.threadId(), span);

    return cand;
  }
Beispiel #22
0
  /**
   * Sets remote candidate to done.
   *
   * @param ver Version.
   * @param pending Pending versions.
   * @param committed Committed versions.
   * @param rolledback Rolledback versions.
   * @return Lock owner.
   */
  @Nullable
  public CacheLockCandidates doneRemote(
      GridCacheVersion ver,
      Collection<GridCacheVersion> pending,
      Collection<GridCacheVersion> committed,
      Collection<GridCacheVersion> rolledback) {
    assert ver != null;

    if (log.isDebugEnabled())
      log.debug("Setting remote candidate to done [mvcc=" + this + ", ver=" + ver + "]");

    // Check remote candidate.
    GridCacheMvccCandidate cand = candidate(rmts, ver);

    if (cand != null) {
      assert rmts != null;
      assert !rmts.isEmpty();
      assert !cand.local() : "Remote candidate is marked as local: " + cand;
      assert !cand.nearLocal() : "Remote candidate is marked as near local: " + cand;

      cand.setOwner();
      cand.setUsed();

      List<GridCacheMvccCandidate> mvAfter = null;

      for (ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(); it.hasNext(); ) {
        GridCacheMvccCandidate c = it.next();

        assert !c.nearLocal() : "Remote candidate marked as near local: " + c;

        if (c == cand) {
          if (mvAfter != null) for (GridCacheMvccCandidate mv : mvAfter) it.add(mv);

          break;
        } else if (!committed.contains(c.version())
            && !rolledback.contains(c.version())
            && pending.contains(c.version())) {
          it.remove();

          if (mvAfter == null) mvAfter = new LinkedList<>();

          mvAfter.add(c);
        }
      }
    }

    return allOwners();
  }
Beispiel #23
0
  /**
   * @param threadId Thread ID to check.
   * @param exclude Versions to ignore.
   * @return {@code True} if lock is owned by the thread with given ID.
   */
  boolean isLocallyOwnedByThread(long threadId, boolean allowDhtLoc, GridCacheVersion... exclude) {
    CacheLockCandidates owners = localOwners();

    if (owners != null) {
      for (int i = 0; i < owners.size(); i++) {
        GridCacheMvccCandidate owner = owners.candidate(i);

        if (owner.threadId() == threadId
            && owner.nodeId().equals(cctx.nodeId())
            && (allowDhtLoc || !owner.dhtLocal())
            && !U.containsObjectArray(exclude, owner.version())) return true;
      }
    }

    return false;
  }
Beispiel #24
0
  /**
   * @param cand Existing candidate.
   * @param newCand New candidate.
   * @return {@code False} if new candidate can not be added.
   */
  private boolean compareSerializableVersion(
      GridCacheMvccCandidate cand, GridCacheMvccCandidate newCand) {
    assert cand.serializable() && newCand.serializable();

    GridCacheVersion candOrder = cand.serializableOrder();

    assert candOrder != null : cand;

    GridCacheVersion newCandOrder = newCand.serializableOrder();

    assert newCandOrder != null : newCand;

    int cmp = SER_VER_COMPARATOR.compare(candOrder, newCandOrder);

    assert cmp != 0;

    return cmp < 0;
  }
  /**
   * Checks if given key is locked by thread with given id or any thread.
   *
   * @param key Key to check.
   * @param threadId Thread id. If -1, all threads will be checked.
   * @return {@code True} if locked by any or given thread (depending on {@code threadId} value).
   */
  public boolean isLockedByThread(KeyCacheObject key, long threadId) {
    if (threadId < 0) {
      for (GridCacheExplicitLockSpan span : pendingExplicit.values()) {
        GridCacheMvccCandidate cand = span.candidate(key, null);

        if (cand != null && cand.owner()) return true;
      }
    } else {
      GridCacheExplicitLockSpan span = pendingExplicit.get(threadId);

      if (span != null) {
        GridCacheMvccCandidate cand = span.candidate(key, null);

        return cand != null && cand.owner();
      }
    }

    return false;
  }
Beispiel #26
0
  /**
   * Removes candidate from collection.
   *
   * @param col Collection.
   * @param ver Version of the candidate to remove.
   * @return {@code True} if candidate was removed.
   */
  private boolean remove0(Collection<GridCacheMvccCandidate> col, GridCacheVersion ver) {
    if (col != null) {
      for (Iterator<GridCacheMvccCandidate> it = col.iterator(); it.hasNext(); ) {
        GridCacheMvccCandidate cand = it.next();

        if (cand.version().equals(ver)) {
          cand.setUsed();
          cand.setRemoved();

          it.remove();

          reassign();

          return true;
        }
      }
    }

    return false;
  }
Beispiel #27
0
  /**
   * @param col Collection of candidates.
   * @param reentries Reentry flag.
   * @param cp Whether to copy or not.
   * @param excludeVers Exclude versions.
   * @return Collection of candidates minus the exclude versions.
   */
  private List<GridCacheMvccCandidate> candidates(
      List<GridCacheMvccCandidate> col,
      boolean reentries,
      boolean cp,
      GridCacheVersion... excludeVers) {
    if (col == null) return Collections.emptyList();

    assert !col.isEmpty();

    if (!cp && F.isEmpty(excludeVers)) return col;

    List<GridCacheMvccCandidate> cands = new ArrayList<>(col.size());

    for (GridCacheMvccCandidate c : col) {
      // Don't include reentries.
      if ((!c.reentry() || (reentries && c.reentry()))
          && !U.containsObjectArray(excludeVers, c.version())) cands.add(c);
    }

    return cands;
  }
Beispiel #28
0
  /**
   * @param exclude Versions to exclude form check.
   * @return {@code True} if lock is empty.
   */
  public boolean isEmpty(GridCacheVersion... exclude) {
    if (locs == null && rmts == null) return true;

    if (locs != null) {
      assert !locs.isEmpty();

      if (F.isEmpty(exclude)) return false;

      for (GridCacheMvccCandidate cand : locs)
        if (!U.containsObjectArray(exclude, cand.version())) return false;
    }

    if (rmts != null) {
      assert !rmts.isEmpty();

      if (F.isEmpty(exclude)) return false;

      for (GridCacheMvccCandidate cand : rmts)
        if (!U.containsObjectArray(exclude, cand.version())) return false;
    }

    return true;
  }
  /**
   * Adds candidate to the list of near local candidates.
   *
   * @param threadId Thread ID.
   * @param cand Candidate to add.
   * @param topVer Topology version.
   */
  public void addExplicitLock(
      long threadId, GridCacheMvccCandidate cand, AffinityTopologyVersion topVer) {
    while (true) {
      GridCacheExplicitLockSpan span = pendingExplicit.get(cand.threadId());

      if (span == null) {
        span = new GridCacheExplicitLockSpan(topVer, cand);

        GridCacheExplicitLockSpan old = pendingExplicit.putIfAbsent(threadId, span);

        if (old == null) break;
        else span = old;
      }

      // Either span was not empty, or concurrent put did not succeed.
      if (span.addCandidate(topVer, cand)) break;
      else pendingExplicit.remove(threadId, span);
    }
  }
Beispiel #30
0
  /** @return All local owners. */
  @Nullable
  public CacheLockCandidates localOwners() {
    if (locs != null) {
      assert !locs.isEmpty();

      CacheLockCandidates owners = null;

      GridCacheMvccCandidate first = locs.getFirst();

      if (first.read()) {
        for (GridCacheMvccCandidate cand : locs) {
          if (cand.owner()) {
            assert cand.read() : this;

            if (owners != null) {
              CacheLockCandidatesList list;

              if (owners.size() == 1) {
                GridCacheMvccCandidate owner = owners.candidate(0);

                owners = list = new CacheLockCandidatesList();

                ((CacheLockCandidatesList) owners).add(owner);
              } else list = ((CacheLockCandidatesList) owners);

              list.add(cand);
            } else owners = cand;
          }

          if (!cand.read()) break;
        }
      } else if (first.owner()) owners = first;

      return owners;
    }

    return null;
  }