예제 #1
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();
      }
    }
  }
예제 #2
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();
  }
예제 #3
0
  /** Assigns local lock. */
  private void reassign() {
    GridCacheMvccCandidate firstRmt = null;

    if (rmts != null) {
      for (GridCacheMvccCandidate cand : rmts) {
        if (firstRmt == null) firstRmt = cand;

        // If there is a remote owner, then local cannot be an owner,
        // so no reassignment happens.
        if (cand.owner()) return;
      }
    }

    if (locs != null) {
      boolean first = true;

      ListIterator<GridCacheMvccCandidate> it = locs.listIterator();

      while (it.hasNext()) {
        GridCacheMvccCandidate cand = it.next();

        if (first) {
          if (cand.read()) {
            if (cand.ready() && !cand.owner()) cand.setOwner();

            while (it.hasNext()) {
              cand = it.next();

              if (!cand.read()) break;

              if (cand.ready() && !cand.owner()) cand.setOwner();
            }

            return;
          } else if (cand.serializable()) {
            if (cand.owner() || !cand.ready()) return;

            cand.setOwner();

            return;
          }

          first = false;
        }

        if (cand.owner()) return;

        if (cand.ready()) {
          GridCacheMvccCandidate prev = nonRollbackPrevious(cand);

          // If previous has not been acquired, this candidate cannot acquire lock either,
          // so we move on to the next one.
          if (prev != null && !prev.owner()) continue;

          boolean assigned = false;

          if (!cctx.isNear() && firstRmt != null && cand.version().isGreater(firstRmt.version())) {
            // Check previous candidates for 2 cases:
            // 1. If this candidate is waiting for a smaller remote version,
            //    then we must check if previous candidate is the owner and
            //    has the same remote candidate version. In that case, we can
            //    safely set this candidate to owner as well.
            // 2. If this candidate is waiting for a smaller remote version,
            //    then we must check if previous candidate is the owner and
            //    any of the local candidates with versions smaller than first
            //    remote version have the same key as the previous owner. In
            //    that case, we can safely set this candidate to owner as well.
            while (prev != null && prev.owner()) {
              for (GridCacheMvccCandidate c : prev.parent().remoteMvccSnapshot()) {
                if (c.version().equals(firstRmt.version())) {
                  cand.setOwner();

                  assigned = true;

                  break; // For.
                }
              }

              if (!assigned) {
                for (GridCacheMvccCandidate c : locs) {
                  if (c == cand || c.version().isGreater(firstRmt.version())) break;

                  for (GridCacheMvccCandidate p = c.previous(); p != null; p = p.previous()) {
                    if (p.key().equals(prev.key())) {
                      cand.setOwner();

                      assigned = true;

                      break; // For.
                    }
                  }

                  if (assigned) break; // For.
                }
              }

              if (assigned) break; // While.

              prev = prev.previous();
            }
          }

          if (!assigned) {
            if (!cctx.isNear() && firstRmt != null) {
              if (cand.version().isLess(firstRmt.version())) {
                assert !cand.nearLocal();

                cand.setOwner();

                assigned = true;
              }
            } else {
              cand.setOwner();

              assigned = true;
            }
          }

          if (assigned) {
            assert !cand.serializable() : cand;

            it.remove();

            // Owner must be first in the list.
            locs.addFirst(cand);
          }

          return;
        }
      }
    }
  }
예제 #4
0
  /**
   * Marks near-local candidate as ready and makes locks reassignment. Following reorderings are
   * performed when candidate is marked ready:
   *
   * <ul>
   *   <li/>All candidates preceding ready one are moved right after it.
   *   <li/>Near local candidate is assigned a mapped dht version. All remote non-pending candidates
   *       with version less then mapped dht version are marked as owned.
   * </ul>
   *
   * @param ver Version to mark as ready.
   * @param mappedVer Mapped dht version.
   * @param committedVers Committed versions.
   * @param rolledBackVers Rolled back versions.
   * @param pending Pending dht versions that are not owned and which version is less then mapped.
   * @return Lock owner after reassignment.
   */
  @Nullable
  public CacheLockCandidates readyNearLocal(
      GridCacheVersion ver,
      GridCacheVersion mappedVer,
      Collection<GridCacheVersion> committedVers,
      Collection<GridCacheVersion> rolledBackVers,
      Collection<GridCacheVersion> pending) {
    GridCacheMvccCandidate cand = candidate(locs, ver);

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

      cand.setReady();

      boolean setMapped = cand.otherVersion(mappedVer);

      assert setMapped
          : "Failed to set mapped dht version for near local candidate [mappedVer="
              + mappedVer
              + ", cand="
              + cand
              + ']';

      // For near locals we move all not owned candidates after this one.
      List<GridCacheMvccCandidate> mvAfter = null;

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

        assert c.nearLocal() : "Near local candidate is not marked as near local: " + c;

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

          break;
        } else {
          if (c.owner()) continue;

          assert !c.ready() || (c.read() && cand.read())
              : "Cannot have more then one ready near-local candidate [c="
                  + c
                  + ", cand="
                  + cand
                  + ", mvcc="
                  + this
                  + ']';

          it.remove();

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

          mvAfter.add(c);
        }
      }

      // Mark all remote candidates with less version as owner unless it is pending.
      if (rmts != null) {
        for (GridCacheMvccCandidate rmt : rmts) {
          GridCacheVersion rmtVer = rmt.version();

          if (rmtVer.isLess(mappedVer)) {
            if (!pending.contains(rmtVer) && !mappedVer.equals(rmt.ownerVersion())) rmt.setOwner();
          } else {
            // Remote version is greater, so need to check if it was committed or rolled back.
            if (committedVers.contains(rmtVer) || rolledBackVers.contains(rmtVer)) rmt.setOwner();
          }
        }
      }

      reassign();
    }

    return allOwners();
  }
예제 #5
0
  /**
   * Moves completed candidates right before the base one. Note that if base is not found, then
   * nothing happens and {@code false} is returned.
   *
   * @param baseVer Base version.
   * @param committedVers Committed versions relative to base.
   * @param rolledbackVers Rolled back versions relative to base.
   */
  public void orderCompleted(
      GridCacheVersion baseVer,
      Collection<GridCacheVersion> committedVers,
      Collection<GridCacheVersion> rolledbackVers) {
    assert baseVer != null;

    if (rmts != null && !F.isEmpty(committedVers)) {
      Deque<GridCacheMvccCandidate> mvAfter = null;

      int maxIdx = -1;

      for (ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(rmts.size());
          it.hasPrevious(); ) {
        GridCacheMvccCandidate cur = it.previous();

        if (!cur.version().equals(baseVer) && committedVers.contains(cur.version())) {
          cur.setOwner();

          assert localOwners() == null || localOwner().nearLocal()
              : "Cannot not have local owner and "
                  + "remote completed transactions at the same time [baseVer="
                  + baseVer
                  + ", committedVers="
                  + committedVers
                  + ", rolledbackVers="
                  + rolledbackVers
                  + ", localOwner="
                  + localOwner()
                  + ", locs="
                  + locs
                  + ", rmts="
                  + rmts
                  + ']';

          if (maxIdx < 0) maxIdx = it.nextIndex();
        } else if (maxIdx >= 0 && cur.version().isGreaterEqual(baseVer)) {
          if (--maxIdx >= 0) {
            if (mvAfter == null) mvAfter = new LinkedList<>();

            it.remove();

            mvAfter.addFirst(cur);
          }
        }

        // If base is completed, then set it to owner too.
        if (!cur.owner() && cur.version().equals(baseVer) && committedVers.contains(cur.version()))
          cur.setOwner();
      }

      if (maxIdx >= 0 && mvAfter != null) {
        ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(maxIdx + 1);

        for (GridCacheMvccCandidate cand : mvAfter) it.add(cand);
      }

      // Remove rolled back versions.
      if (!F.isEmpty(rolledbackVers)) {
        for (Iterator<GridCacheMvccCandidate> it = rmts.iterator(); it.hasNext(); ) {
          GridCacheMvccCandidate cand = it.next();

          if (rolledbackVers.contains(cand.version())) {
            cand.setUsed(); // Mark as used to be consistent, even though we are about to remove it.

            it.remove();
          }
        }

        if (rmts.isEmpty()) rmts = null;
      }
    }
  }
예제 #6
0
  /**
   * @param cand Candidate to add.
   * @return {@code False} if failed to add candidate and transaction should be cancelled.
   */
  private boolean add0(GridCacheMvccCandidate cand) {
    assert cand != null;

    // Local.
    if (cand.local()) {
      if (locs == null) locs = new LinkedList<>();

      if (!cand.nearLocal()) {
        if (!locs.isEmpty()) {
          if (cand.serializable()) {
            Iterator<GridCacheMvccCandidate> it = locs.descendingIterator();

            if (cand.read()) {
              while (it.hasNext()) {
                GridCacheMvccCandidate c = it.next();

                if (!c.serializable()) return false;

                if (!c.read()) {
                  if (compareSerializableVersion(c, cand)) break;
                  else return false;
                }
              }
            } else {
              while (it.hasNext()) {
                GridCacheMvccCandidate c = it.next();

                if (!c.serializable() || !compareSerializableVersion(c, cand)) return false;

                if (!c.read()) break;
              }
            }

            locs.addLast(cand);

            return true;
          }

          GridCacheMvccCandidate first = locs.getFirst();

          if (first.owner()) {
            // If reentry, add at the beginning. Note that
            // no reentry happens for DHT-local candidates.
            if (!cand.dhtLocal() && first.threadId() == cand.threadId()) {
              assert !first.serializable();

              cand.setOwner();
              cand.setReady();
              cand.setReentry();

              locs.addFirst(cand);

              return true;
            }
          }

          // Iterate in reverse order.
          for (ListIterator<GridCacheMvccCandidate> it = locs.listIterator(locs.size());
              it.hasPrevious(); ) {
            GridCacheMvccCandidate c = it.previous();

            assert !c.version().equals(cand.version())
                : "Versions can't match [existing=" + c + ", new=" + cand + ']';

            // Add after the owner or serializable tx.
            if (c.owner() || c.serializable()) {
              // Threads are checked above.
              assert cand.dhtLocal() || c.threadId() != cand.threadId();

              // Reposition.
              it.next();

              it.add(cand);

              return true;
            }

            // If not the owner, add after the lesser version.
            if (c.version().isLess(cand.version())) {
              // Reposition.
              it.next();

              it.add(cand);

              return true;
            }
          }
        }

        // Either list is empty or candidate is first.
        locs.addFirst(cand);
      } else
        // For near local candidates just add it to the end of list.
        locs.add(cand);
    }
    // Remote.
    else {
      assert !cand.serializable() && !cand.read() : cand;

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

      assert !cand.owner() || localOwners() == null
          : "Cannot have local and remote owners "
              + "at the same time [cand="
              + cand
              + ", locs="
              + locs
              + ", rmts="
              + rmts
              + ']';

      GridCacheMvccCandidate cur = candidate(rmts, cand.version());

      // For existing candidates, we only care about owners and keys.
      if (cur != null) {
        if (cand.owner()) cur.setOwner();

        return true;
      }

      // Either list is empty or candidate is last.
      rmts.add(cand);
    }

    return true;
  }