/** @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; }
/** {@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; }
/** * 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; }
/** {@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); } } }
/** * 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; }
/** * @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); } }); }
/** {@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(); } }