Example #1
0
  /** @param maps Mappings. */
  void addEntryMapping(@Nullable Collection<GridDistributedTxMapping> maps) {
    if (!F.isEmpty(maps)) {
      for (GridDistributedTxMapping map : maps) {
        ClusterNode n = map.node();

        GridDistributedTxMapping m = mappings.get(n.id());

        if (m == null) {
          mappings.put(m = new GridDistributedTxMapping(n));

          m.near(map.near());

          if (map.explicitLock()) m.markExplicitLock();
        }

        for (IgniteTxEntry entry : map.entries()) m.add(entry);
      }

      if (log.isDebugEnabled())
        log.debug(
            "Added mappings to transaction [locId="
                + cctx.localNodeId()
                + ", mappings="
                + maps
                + ", tx="
                + this
                + ']');
    }
  }
Example #2
0
  /**
   * Adds key mapping to dht mapping.
   *
   * @param key Key to add.
   * @param node Node this key mapped to.
   */
  public void addKeyMapping(IgniteTxKey key, ClusterNode node) {
    GridDistributedTxMapping m = mappings.get(node.id());

    if (m == null) mappings.put(m = new GridDistributedTxMapping(node));

    IgniteTxEntry txEntry = entry(key);

    assert txEntry != null;

    txEntry.nodeId(node.id());

    m.add(txEntry);

    if (log.isDebugEnabled())
      log.debug(
          "Added mappings to transaction [locId="
              + cctx.localNodeId()
              + ", key="
              + key
              + ", node="
              + node
              + ", tx="
              + this
              + ']');
  }
  /** Initializes future. */
  @SuppressWarnings("ForLoopReplaceableByForEach")
  void finish() {
    if (tx.onNeedCheckBackup()) {
      assert tx.onePhaseCommit();

      checkBackup();

      // If checkBackup is set, it means that primary node has crashed and we will not need to send
      // finish request to it, so we can mark future as initialized.
      markInitialized();

      return;
    }

    try {
      if (tx.finish(commit) || (!commit && tx.state() == UNKNOWN)) {
        if ((tx.onePhaseCommit() && needFinishOnePhase())
            || (!tx.onePhaseCommit() && mappings != null)) {
          if (mappings.single()) {
            GridDistributedTxMapping mapping = mappings.singleMapping();

            if (mapping != null) finish(mapping);
          } else finish(mappings.mappings());
        }

        markInitialized();

        if (!isSync() && !isDone()) {
          boolean complete = true;

          synchronized (futs) {
            // Avoid collection copy and iterator creation.
            for (int i = 0; i < futs.size(); i++) {
              IgniteInternalFuture<IgniteInternalTx> f = futs.get(i);

              if (isMini(f) && !f.isDone()) {
                complete = false;

                break;
              }
            }
          }

          if (complete) onComplete();
        }
      } else onDone(new IgniteCheckedException("Failed to commit transaction: " + CU.txString(tx)));
    } catch (Error | RuntimeException e) {
      onDone(e);

      throw e;
    } catch (IgniteCheckedException e) {
      onDone(e);
    }
  }
  /** @param m Mapping. */
  private void finish(GridDistributedTxMapping m) {
    ClusterNode n = m.node();

    assert !m.empty();

    GridNearTxFinishRequest req =
        new GridNearTxFinishRequest(
            futId,
            tx.xidVersion(),
            tx.threadId(),
            commit,
            tx.isInvalidate(),
            tx.system(),
            tx.ioPolicy(),
            tx.syncCommit(),
            tx.syncRollback(),
            m.explicitLock(),
            tx.storeEnabled(),
            tx.topologyVersion(),
            null,
            null,
            null,
            tx.size(),
            tx.subjectId(),
            tx.taskNameHash(),
            tx.activeCachesDeploymentEnabled());

    // If this is the primary node for the keys.
    if (n.isLocal()) {
      req.miniId(IgniteUuid.randomUuid());

      IgniteInternalFuture<IgniteInternalTx> fut = cctx.tm().txHandler().finish(n.id(), tx, req);

      // Add new future.
      if (fut != null) add(fut);
    } else {
      FinishMiniFuture fut = new FinishMiniFuture(m);

      req.miniId(fut.futureId());

      add(fut); // Append new future.

      if (tx.pessimistic()) cctx.tm().beforeFinishRemote(n.id(), tx.threadId());

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

        // If we don't wait for result, then mark future as done.
        if (!isSync() && !m.explicitLock()) fut.onDone();
      } catch (ClusterTopologyCheckedException e) {
        // Remove previous mapping.
        mappings.remove(m.node().id());

        fut.onNodeLeft(n.id());
      } catch (IgniteCheckedException e) {
        // Fail the whole thing.
        fut.onDone(e);
      }
    }
  }
Example #5
0
  /**
   * @param nodeId Node ID to mark with explicit lock.
   * @return {@code True} if mapping was found.
   */
  public boolean markExplicit(UUID nodeId) {
    explicitLock = true;

    GridDistributedTxMapping m = mappings.get(nodeId);

    if (m != null) {
      m.markExplicitLock();

      return true;
    }

    return false;
  }
Example #6
0
  /**
   * @param map Mapping.
   * @param entry Entry.
   */
  void addSingleEntryMapping(GridDistributedTxMapping map, IgniteTxEntry entry) {
    ClusterNode n = map.node();

    GridDistributedTxMapping m = new GridDistributedTxMapping(n);

    mappings.put(m);

    m.near(map.near());

    if (map.explicitLock()) m.markExplicitLock();

    m.add(entry);
  }
Example #7
0
  /** @param nodeId Undo mapping. */
  @Override
  public boolean removeMapping(UUID nodeId) {
    if (mappings.remove(nodeId) != null) {
      if (log.isDebugEnabled())
        log.debug("Removed mapping for node [nodeId=" + nodeId + ", tx=" + this + ']');

      return true;
    } else {
      if (log.isDebugEnabled())
        log.debug("Mapping for node was not found [nodeId=" + nodeId + ", tx=" + this + ']');

      return false;
    }
  }
Example #8
0
  /** {@inheritDoc} */
  @Override
  public void onRemap(AffinityTopologyVersion topVer) {
    assert cctx.kernalContext().clientNode();

    mapped = false;
    nearLocallyMapped = false;
    colocatedLocallyMapped = false;
    txNodes = null;
    onePhaseCommit = false;
    nearMap.clear();
    dhtMap.clear();
    mappings.clear();

    synchronized (this) {
      this.topVer = topVer;
    }
  }
  /** @param commit Commit flag. */
  private void finishOnePhase(boolean commit) {
    assert Thread.holdsLock(this);

    if (finishOnePhaseCalled) return;

    finishOnePhaseCalled = true;

    GridDistributedTxMapping locMapping = mappings.localMapping();

    if (locMapping != null) {
      // No need to send messages as transaction was already committed on remote node.
      // Finish local mapping only as we need send commit message to backups.
      IgniteInternalFuture<IgniteInternalTx> fut =
          cctx.tm().txHandler().finishColocatedLocal(commit, tx);

      // Add new future.
      if (fut != null) add(fut);
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public boolean onNodeLeft(UUID nodeId) {
    boolean found = false;

    for (IgniteInternalFuture<?> fut : futures())
      if (isMini(fut)) {
        MinFuture f = (MinFuture) fut;

        if (f.onNodeLeft(nodeId)) {
          // Remove previous mapping.
          mappings.remove(nodeId);

          found = true;
        }
      }

    return found;
  }
  private void checkBackup() {
    GridDistributedTxMapping mapping = mappings.singleMapping();

    if (mapping != null) {
      UUID nodeId = mapping.node().id();

      Collection<UUID> backups = tx.transactionNodes().get(nodeId);

      if (!F.isEmpty(backups)) {
        assert backups.size() == 1;

        UUID backupId = F.first(backups);

        ClusterNode backup = cctx.discovery().node(backupId);

        // Nothing to do if backup has left the grid.
        if (backup == null) {
          readyNearMappingFromBackup(mapping);

          ClusterTopologyCheckedException cause =
              new ClusterTopologyCheckedException("Backup node left grid: " + backupId);

          cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));

          onDone(
              new IgniteTxRollbackCheckedException(
                  "Failed to commit transaction " + "(backup has left grid): " + tx.xidVersion(),
                  cause));
        } else {
          final CheckBackupMiniFuture mini = new CheckBackupMiniFuture(backup, mapping);

          add(mini);

          if (backup.isLocal()) {
            boolean committed = !cctx.tm().addRolledbackTx(tx);

            readyNearMappingFromBackup(mapping);

            if (committed) {
              if (tx.syncCommit()) {
                GridCacheVersion nearXidVer = tx.nearXidVersion();

                assert nearXidVer != null : tx;

                IgniteInternalFuture<?> fut = cctx.tm().remoteTxFinishFuture(nearXidVer);

                fut.listen(
                    new CI1<IgniteInternalFuture<?>>() {
                      @Override
                      public void apply(IgniteInternalFuture<?> fut) {
                        mini.onDone(tx);
                      }
                    });

                return;
              }

              mini.onDone(tx);
            } else {
              ClusterTopologyCheckedException cause =
                  new ClusterTopologyCheckedException("Primary node left grid: " + nodeId);

              cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));

              mini.onDone(
                  new IgniteTxRollbackCheckedException(
                      "Failed to commit transaction "
                          + "(transaction has been rolled back on backup node): "
                          + tx.xidVersion(),
                      cause));
            }
          } else {
            GridDhtTxFinishRequest finishReq = checkCommittedRequest(mini.futureId());

            // Preserve old behavior, otherwise response is not sent.
            if (WAIT_REMOTE_TXS_SINCE.compareTo(backup.version()) > 0) finishReq.syncCommit(true);

            try {
              if (FINISH_NEAR_ONE_PHASE_SINCE.compareTo(backup.version()) <= 0)
                cctx.io().send(backup, finishReq, tx.ioPolicy());
              else {
                mini.onDone(
                    new IgniteTxHeuristicCheckedException(
                        "Failed to check for tx commit on "
                            + "the backup node (node has an old Ignite version) [rmtNodeId="
                            + backup.id()
                            + ", ver="
                            + backup.version()
                            + ']'));
              }
            } catch (ClusterTopologyCheckedException e) {
              mini.onNodeLeft(backupId);
            } catch (IgniteCheckedException e) {
              mini.onDone(e);
            }
          }
        }
      } else readyNearMappingFromBackup(mapping);
    }
  }