/** * @param nodeId Node ID. * @param res Response. */ private void processPrepareResponse(UUID nodeId, GridNearTxPrepareResponse<K, V> res) { GridNearTxPrepareFuture<K, V> fut = (GridNearTxPrepareFuture<K, V>) ctx.mvcc().<GridCacheTxEx<K, V>>future(res.version().id(), res.futureId()); if (fut == null) { if (log.isDebugEnabled()) log.debug( "Failed to find future for prepare response [sender=" + nodeId + ", res=" + res + ']'); return; } fut.onResult(nodeId, res); }
/** {@inheritDoc} */ @Override public void rollback() throws GridException { GridNearTxPrepareFuture<K, V> prepFut = this.prepFut.get(); GridNearTxFinishFuture<K, V> fut = rollbackFut.get(); if (fut == null && !rollbackFut.compareAndSet( null, fut = new GridNearTxFinishFuture<K, V>(cctx, this, false))) { rollbackFut.get(); return; } try { cctx.mvcc().addFuture(fut); if (prepFut == null) { finish(false); fut.finish(); } else { prepFut.listenAsync( new CI1<GridFuture<GridCacheTxEx<K, V>>>() { @Override public void apply(GridFuture<GridCacheTxEx<K, V>> f) { try { // Check for errors in prepare future. f.get(); } catch (GridException e) { if (log.isDebugEnabled()) log.debug("Got optimistic tx failure [tx=" + this + ", err=" + e + ']'); } try { finish(false); rollbackFut.get().finish(); } catch (GridException e) { U.error(log, "Failed to gracefully rollback transaction: " + this, e); rollbackFut.get().onError(e); } } }); } // TODO: Rollback Async? fut.get(); } catch (Error e) { U.addLastCause(e, commitErr.get()); throw e; } catch (RuntimeException e) { U.addLastCause(e, commitErr.get()); throw e; } catch (GridException e) { U.addLastCause(e, commitErr.get()); throw e; } finally { cctx.tm().txContextReset(); cctx.near().dht().context().tm().txContextReset(); } }
/** {@inheritDoc} */ @Override public GridFuture<GridCacheTxEx<K, V>> prepareAsync() { GridNearTxPrepareFuture<K, V> fut = prepFut.get(); if (fut == null) { // Future must be created before any exception can be thrown. if (!prepFut.compareAndSet(null, fut = new GridNearTxPrepareFuture<K, V>(cctx, this))) return prepFut.get(); } else // Prepare was called explicitly. return fut; if (!state(PREPARING)) { if (setRollbackOnly()) { if (timedOut()) fut.onError( new GridCacheTxTimeoutException( "Transaction timed out and was rolled back: " + this)); else fut.onError( new GridException( "Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']')); } else fut.onError( new GridCacheTxRollbackException( "Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']')); return fut; } // For pessimistic mode we don't distribute prepare request. if (pessimistic()) { try { userPrepare(); if (!state(PREPARED)) { setRollbackOnly(); fut.onError( new GridException( "Invalid transaction state for commit [state=" + state() + ", tx=" + this + ']')); return fut; } fut.complete(); return fut; } catch (GridException e) { fut.onError(e); return fut; } } try { cctx.topology().readLock(); try { topologyVersion(cctx.topology().topologyVersion()); userPrepare(); } finally { cctx.topology().readUnlock(); } // This will attempt to locally commit // EVENTUALLY CONSISTENT transactions. fut.onPreparedEC(); // Make sure to add future before calling prepare. cctx.mvcc().addFuture(fut); fut.prepare(); } catch (GridCacheTxTimeoutException e) { fut.onError(e); } catch (GridCacheTxOptimisticException e) { fut.onError(e); } catch (GridException e) { setRollbackOnly(); String msg = "Failed to prepare transaction (will attempt rollback): " + this; log.error(msg, e); try { rollback(); } catch (GridException e1) { U.error(log, "Failed to rollback transaction: " + this, e1); } fut.onError(new GridCacheTxRollbackException(msg, e)); } return fut; }
/** {@inheritDoc} */ @Override public boolean onOwnerChanged(GridCacheEntryEx<K, V> entry, GridCacheMvccCandidate<K> owner) { GridNearTxPrepareFuture<K, V> fut = prepFut.get(); return fut != null && fut.onOwnerChanged(entry, owner); }