/**
   * @param nodeId Primary node ID.
   * @param req Request.
   * @return Remote transaction.
   * @throws GridException If failed.
   * @throws GridDistributedLockCancelledException If lock has been cancelled.
   */
  @SuppressWarnings({"RedundantTypeArguments"})
  @Nullable
  public GridNearTxRemote<K, V> startRemoteTxForFinish(
      UUID nodeId, GridDhtTxFinishRequest<K, V> req)
      throws GridException, GridDistributedLockCancelledException {
    GridNearTxRemote<K, V> tx = null;

    ClassLoader ldr = ctx.deploy().globalLoader();

    if (ldr != null) {
      for (GridCacheTxEntry<K, V> txEntry : req.nearWrites()) {
        GridDistributedCacheEntry<K, V> entry = null;

        while (true) {
          try {
            entry = peekExx(txEntry.key());

            if (entry != null) {
              entry.keyBytes(txEntry.keyBytes());

              // Handle implicit locks for pessimistic transactions.
              tx = ctx.tm().tx(req.version());

              if (tx != null) {
                if (tx.local()) return null;

                if (tx.markFinalizing()) tx.addWrite(txEntry.key(), txEntry.keyBytes());
                else return null;
              } else {
                tx =
                    new GridNearTxRemote<K, V>(
                        nodeId,
                        req.nearNodeId(),
                        req.threadId(),
                        req.version(),
                        null,
                        PESSIMISTIC,
                        req.isolation(),
                        req.isInvalidate(),
                        0,
                        txEntry.key(),
                        txEntry.keyBytes(),
                        txEntry.value(),
                        txEntry.valueBytes(),
                        ctx);

                if (tx.empty()) return tx;

                tx = ctx.tm().onCreated(tx);

                if (tx == null || !ctx.tm().onStarted(tx))
                  throw new GridCacheTxRollbackException(
                      "Failed to acquire lock "
                          + "(transaction has been completed): "
                          + req.version());

                if (!tx.markFinalizing()) return null;
              }

              // Add remote candidate before reordering.
              if (txEntry.explicitVersion() == null)
                entry.addRemote(
                    req.nearNodeId(),
                    nodeId,
                    req.threadId(),
                    req.version(),
                    0,
                    tx.ec(),
                    /*tx*/ true,
                    tx.implicitSingle());

              // Remote candidates for ordered lock queuing.
              entry.addRemoteCandidates(
                  Collections.<GridCacheMvccCandidate<K>>emptyList(),
                  req.version(),
                  req.committedVersions(),
                  req.rolledbackVersions());
            }

            // Double-check in case if sender node left the grid.
            if (ctx.discovery().node(req.nearNodeId()) == null) {
              if (log.isDebugEnabled())
                log.debug("Node requesting lock left grid (lock request will be ignored): " + req);

              if (tx != null) tx.rollback();

              return null;
            }

            // Entry is legit.
            break;
          } catch (GridCacheEntryRemovedException ignored) {
            assert entry.obsoleteVersion() != null
                : "Obsolete flag not set on removed entry: " + entry;

            if (log.isDebugEnabled())
              log.debug("Received entry removed exception (will retry on renewed entry): " + entry);

            if (tx != null) {
              tx.clearEntry(entry.key());

              if (log.isDebugEnabled())
                log.debug(
                    "Cleared removed entry from remote transaction (will retry) [entry="
                        + entry
                        + ", tx="
                        + tx
                        + ']');
            }
          }
        }
      }
    } else {
      String err = "Failed to acquire deployment class loader for message: " + req;

      U.warn(log, err);

      throw new GridException(err);
    }

    return tx;
  }
Exemplo n.º 2
0
  /**
   * @param dhtMap DHT map.
   * @param nearMap Near map.
   * @return {@code True} in case there is at least one synchronous {@code MiniFuture} to wait for.
   */
  private boolean finish(
      Map<UUID, GridDistributedTxMapping> dhtMap, Map<UUID, GridDistributedTxMapping> nearMap) {
    if (tx.onePhaseCommit()) return false;

    boolean sync = tx.syncMode() == FULL_SYNC;

    if (tx.explicitLock()) sync = true;

    boolean res = false;

    // Create mini futures.
    for (GridDistributedTxMapping dhtMapping : dhtMap.values()) {
      ClusterNode n = dhtMapping.node();

      assert !n.isLocal();

      GridDistributedTxMapping nearMapping = nearMap.get(n.id());

      if (dhtMapping.empty() && nearMapping != null && nearMapping.empty())
        // Nothing to send.
        continue;

      MiniFuture fut = new MiniFuture(dhtMapping, nearMapping);

      add(fut); // Append new future.

      Collection<Long> updCntrs = new ArrayList<>(dhtMapping.entries().size());

      for (IgniteTxEntry e : dhtMapping.entries()) updCntrs.add(e.updateCounter());

      GridDhtTxFinishRequest req =
          new GridDhtTxFinishRequest(
              tx.nearNodeId(),
              futId,
              fut.futureId(),
              tx.topologyVersion(),
              tx.xidVersion(),
              tx.commitVersion(),
              tx.threadId(),
              tx.isolation(),
              commit,
              tx.isInvalidate(),
              tx.system(),
              tx.ioPolicy(),
              tx.isSystemInvalidate(),
              sync,
              sync,
              tx.completedBase(),
              tx.committedVersions(),
              tx.rolledbackVersions(),
              tx.pendingVersions(),
              tx.size(),
              tx.subjectId(),
              tx.taskNameHash(),
              tx.activeCachesDeploymentEnabled(),
              updCntrs,
              false,
              false);

      req.writeVersion(tx.writeVersion() != null ? tx.writeVersion() : tx.xidVersion());

      try {
        cctx.io().send(n, req, tx.ioPolicy());

        if (msgLog.isDebugEnabled()) {
          msgLog.debug(
              "DHT finish fut, sent request dht [txId="
                  + tx.nearXidVersion()
                  + ", dhtTxId="
                  + tx.xidVersion()
                  + ", node="
                  + n.id()
                  + ']');
        }

        if (sync) res = true;
        else fut.onDone();
      } catch (IgniteCheckedException e) {
        // Fail the whole thing.
        if (e instanceof ClusterTopologyCheckedException)
          fut.onNodeLeft((ClusterTopologyCheckedException) e);
        else {
          if (msgLog.isDebugEnabled()) {
            msgLog.debug(
                "DHT finish fut, failed to send request dht [txId="
                    + tx.nearXidVersion()
                    + ", dhtTxId="
                    + tx.xidVersion()
                    + ", node="
                    + n.id()
                    + ", err="
                    + e
                    + ']');
          }

          fut.onResult(e);
        }
      }
    }

    for (GridDistributedTxMapping nearMapping : nearMap.values()) {
      if (!dhtMap.containsKey(nearMapping.node().id())) {
        if (nearMapping.empty())
          // Nothing to send.
          continue;

        MiniFuture fut = new MiniFuture(null, nearMapping);

        add(fut); // Append new future.

        GridDhtTxFinishRequest req =
            new GridDhtTxFinishRequest(
                tx.nearNodeId(),
                futId,
                fut.futureId(),
                tx.topologyVersion(),
                tx.xidVersion(),
                tx.commitVersion(),
                tx.threadId(),
                tx.isolation(),
                commit,
                tx.isInvalidate(),
                tx.system(),
                tx.ioPolicy(),
                tx.isSystemInvalidate(),
                sync,
                sync,
                tx.completedBase(),
                tx.committedVersions(),
                tx.rolledbackVersions(),
                tx.pendingVersions(),
                tx.size(),
                tx.subjectId(),
                tx.taskNameHash(),
                tx.activeCachesDeploymentEnabled(),
                false,
                false);

        req.writeVersion(tx.writeVersion());

        try {
          cctx.io().send(nearMapping.node(), req, tx.ioPolicy());

          if (msgLog.isDebugEnabled()) {
            msgLog.debug(
                "DHT finish fut, sent request near [txId="
                    + tx.nearXidVersion()
                    + ", dhtTxId="
                    + tx.xidVersion()
                    + ", node="
                    + nearMapping.node().id()
                    + ']');
          }

          if (sync) res = true;
          else fut.onDone();
        } catch (IgniteCheckedException e) {
          // Fail the whole thing.
          if (e instanceof ClusterTopologyCheckedException)
            fut.onNodeLeft((ClusterTopologyCheckedException) e);
          else {
            if (msgLog.isDebugEnabled()) {
              msgLog.debug(
                  "DHT finish fut, failed to send request near [txId="
                      + tx.nearXidVersion()
                      + ", dhtTxId="
                      + tx.xidVersion()
                      + ", node="
                      + nearMapping.node().id()
                      + ", err="
                      + e
                      + ']');
            }

            fut.onResult(e);
          }
        }
      }
    }

    return res;
  }