/** @param nodeId Failed node ID. */
    boolean onNodeLeft(UUID nodeId) {
      if (nodeId.equals(m.node().id())) {
        if (log.isDebugEnabled())
          log.debug("Remote node left grid while sending or waiting for reply: " + this);

        if (isSync()) {
          Map<UUID, Collection<UUID>> txNodes = tx.transactionNodes();

          if (txNodes != null) {
            Collection<UUID> backups = txNodes.get(nodeId);

            if (!F.isEmpty(backups)) {
              final CheckRemoteTxMiniFuture mini =
                  new CheckRemoteTxMiniFuture(new HashSet<>(backups));

              add(mini);

              GridDhtTxFinishRequest req = checkCommittedRequest(mini.futureId());

              req.waitRemoteTransactions(true);

              for (UUID backupId : backups) {
                ClusterNode backup = cctx.discovery().node(backupId);

                if (backup != null && WAIT_REMOTE_TXS_SINCE.compareTo(backup.version()) <= 0) {
                  if (backup.isLocal()) {
                    IgniteInternalFuture<?> fut =
                        cctx.tm().remoteTxFinishFuture(tx.nearXidVersion());

                    fut.listen(
                        new CI1<IgniteInternalFuture<?>>() {
                          @Override
                          public void apply(IgniteInternalFuture<?> fut) {
                            mini.onDhtFinishResponse(cctx.localNodeId());
                          }
                        });
                  } else {
                    try {
                      cctx.io().send(backup, req, tx.ioPolicy());
                    } catch (ClusterTopologyCheckedException e) {
                      mini.onNodeLeft(backupId);
                    } catch (IgniteCheckedException e) {
                      mini.onDone(e);
                    }
                  }
                } else mini.onDhtFinishResponse(backupId);
              }
            }
          }
        }

        onDone(tx);

        return true;
      }

      return false;
    }
예제 #2
0
  /** {@inheritDoc} */
  @Override
  public IgniteInternalFuture<IgniteInternalTx> rollbackAsync() {
    if (log.isDebugEnabled()) log.debug("Rolling back near tx: " + this);

    GridNearTxFinishFuture fut = rollbackFut.get();

    if (fut != null) return fut;

    if (!rollbackFut.compareAndSet(null, fut = new GridNearTxFinishFuture<>(cctx, this, false)))
      return rollbackFut.get();

    cctx.mvcc().addFuture(fut, fut.futureId());

    IgniteInternalFuture<?> prepFut = this.prepFut.get();

    if (prepFut == null || prepFut.isDone()) {
      try {
        // Check for errors in prepare future.
        if (prepFut != null) prepFut.get();
      } catch (IgniteCheckedException e) {
        if (log.isDebugEnabled())
          log.debug("Got optimistic tx failure [tx=" + this + ", err=" + e + ']');
      }

      fut.finish();
    } else {
      prepFut.listen(
          new CI1<IgniteInternalFuture<?>>() {
            @Override
            public void apply(IgniteInternalFuture<?> f) {
              try {
                // Check for errors in prepare future.
                f.get();
              } catch (IgniteCheckedException e) {
                if (log.isDebugEnabled())
                  log.debug("Got optimistic tx failure [tx=" + this + ", err=" + e + ']');
              }

              GridNearTxFinishFuture fut0 = rollbackFut.get();

              fut0.finish();
            }
          });
    }

    return fut;
  }
예제 #3
0
  /**
   * Rolls back local part of colocated transaction.
   *
   * @return Commit future.
   */
  public IgniteInternalFuture<IgniteInternalTx> rollbackAsyncLocal() {
    if (log.isDebugEnabled()) log.debug("Rolling back colocated tx locally: " + this);

    final GridDhtTxFinishFuture fut = new GridDhtTxFinishFuture<>(cctx, this, /*commit*/ false);

    cctx.mvcc().addFuture(fut, fut.futureId());

    IgniteInternalFuture<?> prep = prepFut.get();

    if (prep == null || prep.isDone()) {
      try {
        if (prep != null) prep.get();
      } catch (IgniteCheckedException e) {
        if (log.isDebugEnabled())
          log.debug(
              "Failed to prepare transaction during rollback (will ignore) [tx="
                  + this
                  + ", msg="
                  + e.getMessage()
                  + ']');
      }

      fut.finish();
    } else
      prep.listen(
          new CI1<IgniteInternalFuture<?>>() {
            @Override
            public void apply(IgniteInternalFuture<?> f) {
              try {
                f.get(); // Check for errors of a parent future.
              } catch (IgniteCheckedException e) {
                log.debug(
                    "Failed to prepare transaction during rollback (will ignore) [tx="
                        + this
                        + ", msg="
                        + e.getMessage()
                        + ']');
              }

              fut.finish();
            }
          });

    return fut;
  }
예제 #4
0
  /** {@inheritDoc} */
  @SuppressWarnings({"ThrowableInstanceNeverThrown"})
  @Override
  public IgniteInternalFuture<IgniteInternalTx> commitAsync() {
    if (log.isDebugEnabled()) log.debug("Committing near local tx: " + this);

    prepareAsync();

    GridNearTxFinishFuture fut = commitFut.get();

    if (fut == null
        && !commitFut.compareAndSet(null, fut = new GridNearTxFinishFuture<>(cctx, this, true)))
      return commitFut.get();

    cctx.mvcc().addFuture(fut, fut.futureId());

    final IgniteInternalFuture<?> prepareFut = prepFut.get();

    prepareFut.listen(
        new CI1<IgniteInternalFuture<?>>() {
          @Override
          public void apply(IgniteInternalFuture<?> f) {
            GridNearTxFinishFuture fut0 = commitFut.get();

            try {
              // Make sure that here are no exceptions.
              prepareFut.get();

              fut0.finish();
            } catch (Error | RuntimeException e) {
              commitErr.compareAndSet(null, e);

              fut0.onDone(e);

              throw e;
            } catch (IgniteCheckedException e) {
              commitErr.compareAndSet(null, e);

              fut0.onDone(e);
            }
          }
        });

    return fut;
  }
  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);
    }
  }
    /** @param res Result callback. */
    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    void onResult(final GridNearGetResponse res) {
      final Collection<Integer> invalidParts = res.invalidPartitions();

      // If error happened on remote node, fail the whole future.
      if (res.error() != null) {
        onDone(res.error());

        return;
      }

      // Remap invalid partitions.
      if (!F.isEmpty(invalidParts)) {
        AffinityTopologyVersion rmtTopVer = res.topologyVersion();

        assert !rmtTopVer.equals(AffinityTopologyVersion.ZERO);

        if (rmtTopVer.compareTo(topVer) <= 0) {
          // Fail the whole get future.
          onDone(
              new IgniteCheckedException(
                  "Failed to process invalid partitions response (remote node reported "
                      + "invalid partitions but remote topology version does not differ from local) "
                      + "[topVer="
                      + topVer
                      + ", rmtTopVer="
                      + rmtTopVer
                      + ", invalidParts="
                      + invalidParts
                      + ", nodeId="
                      + node.id()
                      + ']'));

          return;
        }

        if (log.isDebugEnabled())
          log.debug(
              "Remapping mini get future [invalidParts=" + invalidParts + ", fut=" + this + ']');

        if (!canRemap) {
          map(
              F.view(
                  keys.keySet(),
                  new P1<KeyCacheObject>() {
                    @Override
                    public boolean apply(KeyCacheObject key) {
                      return invalidParts.contains(cctx.affinity().partition(key));
                    }
                  }),
              F.t(node, keys),
              topVer);

          onDone(createResultMap(res.entries()));

          return;
        }

        // Need to wait for next topology version to remap.
        IgniteInternalFuture<AffinityTopologyVersion> topFut =
            cctx.affinity().affinityReadyFuture(rmtTopVer);

        topFut.listen(
            new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
              @SuppressWarnings("unchecked")
              @Override
              public void applyx(IgniteInternalFuture<AffinityTopologyVersion> fut)
                  throws IgniteCheckedException {
                AffinityTopologyVersion topVer = fut.get();

                // This will append new futures to compound list.
                map(
                    F.view(
                        keys.keySet(),
                        new P1<KeyCacheObject>() {
                          @Override
                          public boolean apply(KeyCacheObject key) {
                            return invalidParts.contains(cctx.affinity().partition(key));
                          }
                        }),
                    F.t(node, keys),
                    topVer);

                onDone(createResultMap(res.entries()));
              }
            });
      } else {
        try {
          onDone(createResultMap(res.entries()));
        } catch (Exception e) {
          onDone(e);
        }
      }
    }
예제 #7
0
  /**
   * Commits local part of colocated transaction.
   *
   * @return Commit future.
   */
  public IgniteInternalFuture<IgniteInternalTx> commitAsyncLocal() {
    if (log.isDebugEnabled()) log.debug("Committing colocated tx locally: " + this);

    // In optimistic mode prepare was called explicitly.
    if (pessimistic()) prepareAsync();

    IgniteInternalFuture<?> prep = prepFut.get();

    // Do not create finish future if there are no remote nodes.
    if (F.isEmpty(dhtMap) && F.isEmpty(nearMap)) {
      if (prep != null) return (IgniteInternalFuture<IgniteInternalTx>) (IgniteInternalFuture) prep;

      return new GridFinishedFuture<IgniteInternalTx>(this);
    }

    final GridDhtTxFinishFuture fut = new GridDhtTxFinishFuture<>(cctx, this, /*commit*/ true);

    cctx.mvcc().addFuture(fut, fut.futureId());

    if (prep == null || prep.isDone()) {
      assert prep != null || optimistic();

      try {
        if (prep != null) prep.get(); // Check for errors of a parent future.

        fut.finish();
      } catch (IgniteTxOptimisticCheckedException e) {
        if (log.isDebugEnabled())
          log.debug("Failed optimistically to prepare transaction [tx=" + this + ", e=" + e + ']');

        fut.onError(e);
      } catch (IgniteCheckedException e) {
        U.error(log, "Failed to prepare transaction: " + this, e);

        fut.onError(e);
      }
    } else
      prep.listen(
          new CI1<IgniteInternalFuture<?>>() {
            @Override
            public void apply(IgniteInternalFuture<?> f) {
              try {
                f.get(); // Check for errors of a parent future.

                fut.finish();
              } catch (IgniteTxOptimisticCheckedException e) {
                if (log.isDebugEnabled())
                  log.debug(
                      "Failed optimistically to prepare transaction [tx="
                          + this
                          + ", e="
                          + e
                          + ']');

                fut.onError(e);
              } catch (IgniteCheckedException e) {
                U.error(log, "Failed to prepare transaction: " + this, e);

                fut.onError(e);
              }
            }
          });

    return fut;
  }
예제 #8
0
  /**
   * @param nodeId Node ID.
   * @param req Get request.
   */
  protected void processNearSingleGetRequest(
      final UUID nodeId, final GridNearSingleGetRequest req) {
    assert ctx.affinityNode();

    final CacheExpiryPolicy expiryPlc = CacheExpiryPolicy.forAccess(req.accessTtl());

    IgniteInternalFuture<GridCacheEntryInfo> fut =
        getDhtSingleAsync(
            nodeId,
            req.messageId(),
            req.key(),
            req.addReader(),
            req.readThrough(),
            req.topologyVersion(),
            req.subjectId(),
            req.taskNameHash(),
            expiryPlc,
            req.skipValues());

    fut.listen(
        new CI1<IgniteInternalFuture<GridCacheEntryInfo>>() {
          @Override
          public void apply(IgniteInternalFuture<GridCacheEntryInfo> f) {
            GridNearSingleGetResponse res;

            GridDhtFuture<GridCacheEntryInfo> fut = (GridDhtFuture<GridCacheEntryInfo>) f;

            try {
              GridCacheEntryInfo info = fut.get();

              if (F.isEmpty(fut.invalidPartitions())) {
                Message res0 = null;

                if (info != null) {
                  if (req.needEntryInfo()) {
                    info.key(null);

                    res0 = info;
                  } else if (req.needVersion())
                    res0 = new CacheVersionedValue(info.value(), info.version());
                  else res0 = info.value();
                }

                res =
                    new GridNearSingleGetResponse(
                        ctx.cacheId(),
                        req.futureId(),
                        req.topologyVersion(),
                        res0,
                        false,
                        req.addDeploymentInfo());

                if (info != null && req.skipValues()) res.setContainsValue();
              } else {
                AffinityTopologyVersion topVer = ctx.shared().exchange().readyAffinityVersion();

                assert topVer.compareTo(req.topologyVersion()) >= 0
                    : "Wrong ready topology version for "
                        + "invalid partitions response [topVer="
                        + topVer
                        + ", req="
                        + req
                        + ']';

                res =
                    new GridNearSingleGetResponse(
                        ctx.cacheId(), req.futureId(), topVer, null, true, req.addDeploymentInfo());
              }
            } catch (NodeStoppingException e) {
              return;
            } catch (IgniteCheckedException e) {
              U.error(log, "Failed processing get request: " + req, e);

              res =
                  new GridNearSingleGetResponse(
                      ctx.cacheId(),
                      req.futureId(),
                      req.topologyVersion(),
                      null,
                      false,
                      req.addDeploymentInfo());

              res.error(e);
            }

            try {
              ctx.io().send(nodeId, res, ctx.ioPolicy());
            } catch (IgniteCheckedException e) {
              U.error(
                  log,
                  "Failed to send get response to node (is node still alive?) [nodeId="
                      + nodeId
                      + ",req="
                      + req
                      + ", res="
                      + res
                      + ']',
                  e);
            }

            sendTtlUpdateRequest(expiryPlc);
          }
        });
  }
예제 #9
0
    /** {@inheritDoc} */
    @Override
    protected void body() throws InterruptedException, IgniteInterruptedCheckedException {
      try {
        IgfsDataInputStream dis = new IgfsDataInputStream(endpoint.inputStream());

        byte[] hdr = new byte[IgfsMarshaller.HEADER_SIZE];

        boolean first = true;

        while (!Thread.currentThread().isInterrupted()) {
          dis.readFully(hdr);

          final long reqId = U.bytesToLong(hdr, 0);

          int ordinal = U.bytesToInt(hdr, 8);

          if (first) { // First message must be HANDSHAKE.
            if (reqId != 0 || ordinal != IgfsIpcCommand.HANDSHAKE.ordinal()) {
              if (log.isDebugEnabled())
                log.debug(
                    "IGFS IPC handshake failed [reqId=" + reqId + ", ordinal=" + ordinal + ']');

              return;
            }

            first = false;
          }

          final IgfsIpcCommand cmd = IgfsIpcCommand.valueOf(ordinal);

          IgfsMessage msg = marsh.unmarshall(cmd, hdr, dis);

          IgniteInternalFuture<IgfsMessage> fut = hnd.handleAsync(ses, msg, dis);

          // If fut is null, no response is required.
          if (fut != null) {
            if (fut.isDone()) {
              IgfsMessage res;

              try {
                res = fut.get();
              } catch (IgniteCheckedException e) {
                res = new IgfsControlResponse();

                ((IgfsControlResponse) res).error(e);
              }

              try {
                synchronized (out) {
                  // Reuse header.
                  IgfsMarshaller.fillHeader(hdr, reqId, res.command());

                  marsh.marshall(res, hdr, out);

                  out.flush();
                }
              } catch (IOException | IgniteCheckedException e) {
                shutdown0(e);
              }
            } else {
              fut.listen(
                  new CIX1<IgniteInternalFuture<IgfsMessage>>() {
                    @Override
                    public void applyx(IgniteInternalFuture<IgfsMessage> fut) {
                      IgfsMessage res;

                      try {
                        res = fut.get();
                      } catch (IgniteCheckedException e) {
                        res = new IgfsControlResponse();

                        ((IgfsControlResponse) res).error(e);
                      }

                      try {
                        synchronized (out) {
                          byte[] hdr = IgfsMarshaller.createHeader(reqId, res.command());

                          marsh.marshall(res, hdr, out);

                          out.flush();
                        }
                      } catch (IOException | IgniteCheckedException e) {
                        shutdown0(e);
                      }
                    }
                  });
            }
          }
        }
      } catch (EOFException ignored) {
        // Client closed connection.
      } catch (IgniteCheckedException | IOException e) {
        if (!isCancelled())
          U.error(log, "Failed to read data from client (will close connection)", e);
      } finally {
        onFinished();
      }
    }