/** @throws Exception If failed. */ public void testRanges() throws Exception { IgfsFileMap map = new IgfsFileMap(); IgniteUuid[] affKeys = new IgniteUuid[20]; for (int i = 0; i < affKeys.length; i++) affKeys[i] = IgniteUuid.randomUuid(); int numOfRanges = 0; do { for (int i = 0; i < 2 * numOfRanges + 1; i++) { long off1 = i * 10; long off2 = i * 10 + 5; long off3 = i * 10 + 8; IgniteUuid affKey = i % 2 == 0 ? null : affKeys[i / 2]; assertEquals("For i: " + i, affKey, map.affinityKey(off1, false)); assertEquals("For i: " + i, affKey, map.affinityKey(off2, false)); assertEquals("For i: " + i, affKey, map.affinityKey(off3, false)); } map.addRange( new IgfsFileAffinityRange( 10 + 20 * numOfRanges, 19 + 20 * numOfRanges, affKeys[numOfRanges])); numOfRanges++; } while (numOfRanges < 20); }
/** @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); } } }
/** * Starts multi-update lock. Will wait for topology future is ready. * * @return Topology version. * @throws IgniteCheckedException If failed. */ public AffinityTopologyVersion beginMultiUpdate() throws IgniteCheckedException { IgniteBiTuple<IgniteUuid, GridDhtTopologyFuture> tup = multiTxHolder.get(); if (tup != null) throw new IgniteCheckedException("Nested multi-update locks are not supported"); top.readLock(); GridDhtTopologyFuture topFut; AffinityTopologyVersion topVer; try { // While we are holding read lock, register lock future for partition release future. IgniteUuid lockId = IgniteUuid.fromUuid(ctx.localNodeId()); topVer = top.topologyVersion(); MultiUpdateFuture fut = new MultiUpdateFuture(topVer); MultiUpdateFuture old = multiTxFuts.putIfAbsent(lockId, fut); assert old == null; topFut = top.topologyVersionFuture(); multiTxHolder.set(F.t(lockId, topFut)); } finally { top.readUnlock(); } topFut.get(); return topVer; }
private abstract class MinFuture extends GridFutureAdapter<IgniteInternalTx> { /** */ private final IgniteUuid futId = IgniteUuid.randomUuid(); /** * @param nodeId Node ID. * @return {@code True} if future processed node failure. */ abstract boolean onNodeLeft(UUID nodeId); /** @return Future ID. */ final IgniteUuid futureId() { return futId; } }
/** * @param cctx Context. * @param tx Transaction. * @param commit Commit flag. */ public GridNearTxFinishFuture( GridCacheSharedContext<K, V> cctx, GridNearTxLocal tx, boolean commit) { super(F.<IgniteInternalTx>identityReducer(tx)); this.cctx = cctx; this.tx = tx; this.commit = commit; ignoreInterrupts(true); mappings = tx.mappings(); futId = IgniteUuid.randomUuid(); if (log == null) log = U.logger(cctx.kernalContext(), logRef, GridNearTxFinishFuture.class); }
/** @throws Exception If failed. */ public void testRangeSplit() throws Exception { IgniteUuid affKey = IgniteUuid.randomUuid(); IgfsFileAffinityRange range = new IgfsFileAffinityRange(0, 9999, affKey); Collection<IgfsFileAffinityRange> split = range.split(10000); assertEquals(1, split.size()); assertTrue(range.regionEqual(F.first(split))); split = range.split(5000); assertEquals(2, split.size()); Iterator<IgfsFileAffinityRange> it = split.iterator(); IgfsFileAffinityRange part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(0, 4999, affKey))); part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(5000, 9999, affKey))); split = range.split(3000); assertEquals(4, split.size()); it = split.iterator(); part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(0, 2999, affKey))); part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(3000, 5999, affKey))); part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(6000, 8999, affKey))); part = it.next(); assertTrue(part.regionEqual(new IgfsFileAffinityRange(9000, 9999, affKey))); }
/** * @param cctx Context. * @param tx Transaction. * @param commit Commit flag. */ public GridDhtTxFinishFuture( GridCacheSharedContext<K, V> cctx, GridDhtTxLocalAdapter tx, boolean commit) { super(F.<IgniteInternalTx>identityReducer(tx)); this.cctx = cctx; this.tx = tx; this.commit = commit; dhtMap = tx.dhtMap(); nearMap = tx.nearMap(); futId = IgniteUuid.randomUuid(); if (log == null) { msgLog = cctx.txFinishMessageLogger(); log = U.logger(cctx.kernalContext(), logRef, GridDhtTxFinishFuture.class); } }
/** @throws Exception If failed. */ public void testRangeUpdate1() throws Exception { IgfsFileMap map = new IgfsFileMap(); IgniteUuid affKey = IgniteUuid.randomUuid(); for (int i = 0; i < 4; i++) map.addRange(new IgfsFileAffinityRange(i * 20 + 10, i * 20 + 19, affKey)); // Middle, first, last. map.updateRangeStatus(new IgfsFileAffinityRange(30, 39, affKey), RANGE_STATUS_MOVING); map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey), RANGE_STATUS_MOVING); map.updateRangeStatus(new IgfsFileAffinityRange(70, 79, affKey), RANGE_STATUS_MOVING); List<IgfsFileAffinityRange> ranges = map.ranges(); assertEquals(RANGE_STATUS_MOVING, ranges.get(0).status()); assertEquals(RANGE_STATUS_MOVING, ranges.get(1).status()); assertEquals(RANGE_STATUS_INITIAL, ranges.get(2).status()); assertEquals(RANGE_STATUS_MOVING, ranges.get(3).status()); // Middle, first, last. map.updateRangeStatus(new IgfsFileAffinityRange(30, 39, affKey), RANGE_STATUS_MOVED); map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey), RANGE_STATUS_MOVED); map.updateRangeStatus(new IgfsFileAffinityRange(70, 79, affKey), RANGE_STATUS_MOVED); ranges = map.ranges(); assertEquals(RANGE_STATUS_MOVED, ranges.get(0).status()); assertEquals(RANGE_STATUS_MOVED, ranges.get(1).status()); assertEquals(RANGE_STATUS_INITIAL, ranges.get(2).status()); assertEquals(RANGE_STATUS_MOVED, ranges.get(3).status()); // Middle, first, last. map.deleteRange(new IgfsFileAffinityRange(30, 39, affKey)); map.deleteRange(new IgfsFileAffinityRange(10, 19, affKey)); map.deleteRange(new IgfsFileAffinityRange(70, 79, affKey)); ranges = map.ranges(); assertEquals(1, ranges.size()); assertEquals(RANGE_STATUS_INITIAL, ranges.get(0).status()); assertTrue(ranges.get(0).regionEqual(new IgfsFileAffinityRange(50, 59, affKey))); }
/** @throws Exception If failed. */ public void testAddUpdateAdd() throws Exception { IgfsFileMap map = new IgfsFileMap(); IgniteUuid affKey = IgniteUuid.randomUuid(); map.addRange(new IgfsFileAffinityRange(0, 9, affKey)); map.updateRangeStatus(new IgfsFileAffinityRange(0, 9, affKey), RANGE_STATUS_MOVING); map.addRange(new IgfsFileAffinityRange(10, 19, affKey)); List<IgfsFileAffinityRange> ranges = map.ranges(); assertEquals(2, ranges.size()); assertEquals(RANGE_STATUS_MOVING, ranges.get(0).status()); assertTrue(ranges.get(0).regionEqual(new IgfsFileAffinityRange(0, 9, affKey))); assertEquals(RANGE_STATUS_INITIAL, ranges.get(1).status()); assertTrue(ranges.get(1).regionEqual(new IgfsFileAffinityRange(10, 19, affKey))); }
/** * Mini-future for get operations. Mini-futures are only waiting on a single node as opposed to * multiple nodes. */ private class MiniFuture extends GridFutureAdapter<Map<K, V>> { /** */ private static final long serialVersionUID = 0L; /** */ private final IgniteUuid futId = IgniteUuid.randomUuid(); /** Node ID. */ private final ClusterNode node; /** Keys. */ @GridToStringInclude private final LinkedHashMap<KeyCacheObject, Boolean> keys; /** Topology version on which this future was mapped. */ private final AffinityTopologyVersion topVer; /** {@code True} if remapped after node left. */ private boolean remapped; /** * @param node Node. * @param keys Keys. * @param topVer Topology version. */ MiniFuture( ClusterNode node, LinkedHashMap<KeyCacheObject, Boolean> keys, AffinityTopologyVersion topVer) { this.node = node; this.keys = keys; this.topVer = topVer; } /** @return Future ID. */ IgniteUuid futureId() { return futId; } /** @return Node ID. */ public ClusterNode node() { return node; } /** @return Keys. */ public Collection<KeyCacheObject> keys() { return keys.keySet(); } /** @param e Error. */ void onResult(Throwable e) { if (log.isDebugEnabled()) log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']'); // Fail. onDone(e); } /** @param e Failure exception. */ @SuppressWarnings("UnusedParameters") synchronized void onNodeLeft(ClusterTopologyCheckedException e) { if (remapped) return; remapped = true; if (log.isDebugEnabled()) log.debug("Remote node left grid while sending or waiting for reply (will retry): " + this); // Try getting from existing nodes. if (!canRemap) { map(keys.keySet(), F.t(node, keys), topVer); onDone(Collections.<K, V>emptyMap()); } else { final AffinityTopologyVersion updTopVer = new AffinityTopologyVersion( Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion())); cctx.affinity() .affinityReadyFuture(updTopVer) .listen( new CI1<IgniteInternalFuture<AffinityTopologyVersion>>() { @Override public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) { try { fut.get(); // Remap. map(keys.keySet(), F.t(node, keys), updTopVer); onDone(Collections.<K, V>emptyMap()); } catch (IgniteCheckedException e) { GridPartitionedGetFuture.this.onDone(e); } } }); } } /** @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); } } } /** {@inheritDoc} */ @Override public String toString() { return S.toString(MiniFuture.class, this); } }
/** @throws Exception If failed. */ public void testInvalidRangeUpdates() throws Exception { final IgfsFileMap map = new IgfsFileMap(); final IgniteUuid affKey1 = IgniteUuid.randomUuid(); final IgniteUuid affKey2 = IgniteUuid.randomUuid(); map.addRange(new IgfsFileAffinityRange(10, 19, affKey1)); map.addRange(new IgfsFileAffinityRange(30, 39, affKey1)); GridTestUtils.assertThrows( log, new Callable<Object>() { @Override public Object call() throws Exception { map.updateRangeStatus(new IgfsFileAffinityRange(0, 5, affKey1), RANGE_STATUS_MOVING); return null; } }, IgfsInvalidRangeException.class, null); GridTestUtils.assertThrows( log, new Callable<Object>() { @Override public Object call() throws Exception { map.updateRangeStatus(new IgfsFileAffinityRange(15, 19, affKey1), RANGE_STATUS_MOVING); return null; } }, IgfsInvalidRangeException.class, null); GridTestUtils.assertThrows( log, new Callable<Object>() { @Override public Object call() throws Exception { map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey2), RANGE_STATUS_MOVING); return null; } }, AssertionError.class, null); GridTestUtils.assertThrows( log, new Callable<Object>() { @Override public Object call() throws Exception { map.updateRangeStatus(new IgfsFileAffinityRange(10, 22, affKey1), RANGE_STATUS_MOVING); return null; } }, AssertionError.class, null); assertEquals(2, map.ranges().size()); }
/** * Prepares next batch of entries in dht transaction. * * @param reads Read entries. * @param writes Write entries. * @param txNodes Transaction nodes mapping. * @param last {@code True} if this is last prepare request. * @return Future that will be completed when locks are acquired. */ @SuppressWarnings("TypeMayBeWeakened") public IgniteInternalFuture<GridNearTxPrepareResponse> prepareAsyncLocal( @Nullable Collection<IgniteTxEntry> reads, @Nullable Collection<IgniteTxEntry> writes, Map<UUID, Collection<UUID>> txNodes, boolean last) { if (state() != PREPARING) { if (timedOut()) return new GridFinishedFuture<>( new IgniteTxTimeoutCheckedException("Transaction timed out: " + this)); setRollbackOnly(); return new GridFinishedFuture<>( new IgniteCheckedException( "Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']')); } init(); GridDhtTxPrepareFuture fut = new GridDhtTxPrepareFuture( cctx, this, IgniteUuid.randomUuid(), Collections.<IgniteTxKey, GridCacheVersion>emptyMap(), last, needReturnValue() && implicit()); try { // At this point all the entries passed in must be enlisted in transaction because this is an // optimistic transaction. optimisticLockEntries = (serializable() && optimistic()) ? F.concat(false, writes, reads) : writes; userPrepare(); // Make sure to add future before calling prepare on it. cctx.mvcc().addFuture(fut); if (isSystemInvalidate()) fut.complete(); else fut.prepare(reads, writes, txNodes); } catch (IgniteTxTimeoutCheckedException | IgniteTxOptimisticCheckedException e) { fut.onError(e); } catch (IgniteCheckedException e) { setRollbackOnly(); fut.onError( new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + this, e)); try { rollback(); } catch (IgniteTxOptimisticCheckedException e1) { if (log.isDebugEnabled()) log.debug("Failed optimistically to prepare transaction [tx=" + this + ", e=" + e1 + ']'); fut.onError(e); } catch (IgniteCheckedException e1) { U.error(log, "Failed to rollback transaction: " + this, e1); } } return chainOnePhasePrepare(fut); }
/** {@inheritDoc} */ @Override public boolean equals(Object o) { return o == this || o instanceof GridDeploymentInfoBean && clsLdrId.equals(((GridDeploymentInfoBean) o).clsLdrId); }
/** {@inheritDoc} */ @Override public int hashCode() { return clsLdrId.hashCode(); }
/** {@inheritDoc} */ @Override public long sequenceNumber() { return clsLdrId.localId(); }
/** * Mini-future for get operations. Mini-futures are only waiting on a single node as opposed to * multiple nodes. */ private class MiniFuture extends GridFutureAdapter<IgniteInternalTx> { /** */ private static final long serialVersionUID = 0L; /** */ private final IgniteUuid futId = IgniteUuid.randomUuid(); /** DHT mapping. */ @GridToStringInclude private GridDistributedTxMapping dhtMapping; /** Near mapping. */ @GridToStringInclude private GridDistributedTxMapping nearMapping; /** */ @GridToStringInclude private ClusterNode node; /** @param node Node. */ private MiniFuture(ClusterNode node) { this.node = node; } /** * @param dhtMapping Mapping. * @param nearMapping nearMapping. */ MiniFuture(GridDistributedTxMapping dhtMapping, GridDistributedTxMapping nearMapping) { assert dhtMapping == null || nearMapping == null || dhtMapping.node().equals(nearMapping.node()); this.dhtMapping = dhtMapping; this.nearMapping = nearMapping; } /** @return Future ID. */ IgniteUuid futureId() { return futId; } /** @return Node ID. */ public ClusterNode node() { return node != null ? node : dhtMapping != null ? dhtMapping.node() : nearMapping.node(); } /** @param e Error. */ void onResult(Throwable e) { if (log.isDebugEnabled()) log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']'); // Fail. onDone(e); } /** @param e Node failure. */ void onNodeLeft(ClusterTopologyCheckedException e) { onNodeLeft(e, false); } /** * @param e Node failure. * @param discoThread {@code True} if executed from discovery thread. */ void onNodeLeft(ClusterTopologyCheckedException e, boolean discoThread) { if (msgLog.isDebugEnabled()) { msgLog.debug( "DHT finish fut, mini future node left [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + node().id() + ']'); } // If node left, then there is nothing to commit on it. onDone(tx); } /** @param res Result callback. */ void onResult(GridDhtTxFinishResponse res) { if (log.isDebugEnabled()) log.debug( "Transaction synchronously completed on node [node=" + node() + ", res=" + res + ']'); onDone(); } /** {@inheritDoc} */ @Override public String toString() { return S.toString( MiniFuture.class, this, "done", isDone(), "cancelled", isCancelled(), "err", error()); } }