/** {@inheritDoc} */ @Override public Collection<ClusterNode> nodes(int p, AffinityTopologyVersion topVer) { Collection<ClusterNode> affNodes = cctx.affinity().nodes(p, topVer); lock.readLock().lock(); try { assert node2part != null && node2part.valid() : "Invalid node-to-partitions map [topVer1=" + topVer + ", topVer2=" + this.topVer + ", cache=" + cctx.name() + ", node2part=" + node2part + ']'; Collection<ClusterNode> nodes = null; Collection<UUID> nodeIds = part2node.get(p); if (!F.isEmpty(nodeIds)) { Collection<UUID> affIds = new HashSet<>(F.viewReadOnly(affNodes, F.node2id())); for (UUID nodeId : nodeIds) { if (!affIds.contains(nodeId) && hasState(p, nodeId, OWNING, MOVING, RENTING)) { ClusterNode n = cctx.discovery().node(nodeId); if (n != null && (topVer.topologyVersion() < 0 || n.order() <= topVer.topologyVersion())) { if (nodes == null) { nodes = new ArrayList<>(affNodes.size() + 2); nodes.addAll(affNodes); } nodes.add(n); } } } } return nodes != null ? nodes : affNodes; } finally { lock.readLock().unlock(); } }
/** * @param p Partition. * @param topVer Topology version ({@code -1} for all nodes). * @param state Partition state. * @param states Additional partition states. * @return List of nodes for the partition. */ private List<ClusterNode> nodes( int p, AffinityTopologyVersion topVer, GridDhtPartitionState state, GridDhtPartitionState... states) { Collection<UUID> allIds = topVer.topologyVersion() > 0 ? F.nodeIds(CU.affinityNodes(cctx, topVer)) : null; lock.readLock().lock(); try { assert node2part != null && node2part.valid() : "Invalid node-to-partitions map [topVer=" + topVer + ", allIds=" + allIds + ", node2part=" + node2part + ", cache=" + cctx.name() + ']'; Collection<UUID> nodeIds = part2node.get(p); // Node IDs can be null if both, primary and backup, nodes disappear. int size = nodeIds == null ? 0 : nodeIds.size(); if (size == 0) return Collections.emptyList(); List<ClusterNode> nodes = new ArrayList<>(size); for (UUID id : nodeIds) { if (topVer.topologyVersion() > 0 && !allIds.contains(id)) continue; if (hasState(p, id, state, states)) { ClusterNode n = cctx.discovery().node(id); if (n != null && (topVer.topologyVersion() < 0 || n.order() <= topVer.topologyVersion())) nodes.add(n); } } return nodes; } finally { lock.readLock().unlock(); } }
/** * @param log Logger. * @param topVer Topology version. * @param initCntr Update counters. */ public PartitionRecovery( IgniteLogger log, AffinityTopologyVersion topVer, @Nullable Long initCntr) { assert topVer.topologyVersion() > 0 : topVer; this.log = log; if (initCntr != null) { this.lastFiredEvt = initCntr; curTop = topVer; } }
/** {@inheritDoc} */ @Override public AffinityTopologyVersion topologyVersion() { lock.readLock().lock(); try { assert topVer.topologyVersion() > 0 : "Invalid topology version [topVer=" + topVer + ", cacheName=" + cctx.name() + ']'; return topVer; } finally { lock.readLock().unlock(); } }
/** @return Filter. */ private IgnitePredicate<GridCacheMvccCandidate> versionFilter() { assert topVer.topologyVersion() > 0; return new P1<GridCacheMvccCandidate>() { @Override public boolean apply(GridCacheMvccCandidate c) { assert c.nearLocal() || c.dhtLocal(); // Wait for explicit locks. return c.topologyVersion().equals(AffinityTopologyVersion.ZERO) || c.topologyVersion().compareTo(topVer) < 0; } }; }
/** @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 keyFilter Key filter. * @param topVer Topology version. * @return Future that signals when all locks for given partitions will be released. */ private IgniteInternalFuture<?> finishLocks( @Nullable final IgnitePredicate<KeyCacheObject> keyFilter, AffinityTopologyVersion topVer) { assert topVer.topologyVersion() != 0; if (topVer.equals(AffinityTopologyVersion.NONE)) return new GridFinishedFuture(); final FinishLockFuture finishFut = new FinishLockFuture( keyFilter == null ? locked() : F.view( locked(), new P1<GridDistributedCacheEntry>() { @Override public boolean apply(GridDistributedCacheEntry e) { return F.isAll(e.key(), keyFilter); } }), topVer); finishFuts.add(finishFut); finishFut.listen( new CI1<IgniteInternalFuture<?>>() { @Override public void apply(IgniteInternalFuture<?> e) { finishFuts.remove(finishFut); // This call is required to make sure that the concurrent queue // clears memory occupied by internal nodes. finishFuts.peek(); } }); finishFut.recheck(); return finishFut; }
/** @throws InterruptedException If interrupted. */ @SuppressWarnings("BusyWait") protected void awaitPartitionMapExchange() throws InterruptedException { for (Ignite g : G.allGrids()) { IgniteKernal g0 = (IgniteKernal) g; for (IgniteCacheProxy<?, ?> c : g0.context().cache().jcaches()) { CacheConfiguration cfg = c.context().config(); if (cfg.getCacheMode() == PARTITIONED && cfg.getRebalanceMode() != NONE && g.cluster().nodes().size() > 1) { AffinityFunction aff = cfg.getAffinity(); GridDhtCacheAdapter<?, ?> dht = dht(c); GridDhtPartitionTopology top = dht.topology(); for (int p = 0; p < aff.partitions(); p++) { long start = 0; for (int i = 0; ; i++) { boolean match = false; AffinityTopologyVersion readyVer = dht.context().shared().exchange().readyAffinityVersion(); if (readyVer.topologyVersion() > 0 && c.context().started()) { // Must map on updated version of topology. Collection<ClusterNode> affNodes = g0.affinity(cfg.getName()).mapPartitionToPrimaryAndBackups(p); int exp = affNodes.size(); GridDhtTopologyFuture topFut = top.topologyVersionFuture(); Collection<ClusterNode> owners = (topFut != null && topFut.isDone()) ? top.nodes(p, AffinityTopologyVersion.NONE) : Collections.<ClusterNode>emptyList(); int actual = owners.size(); if (affNodes.size() != owners.size() || !affNodes.containsAll(owners)) { LT.warn( log(), null, "Waiting for topology map update [" + "grid=" + g.name() + ", cache=" + cfg.getName() + ", cacheId=" + dht.context().cacheId() + ", topVer=" + top.topologyVersion() + ", topFut=" + topFut + ", p=" + p + ", affNodesCnt=" + exp + ", ownersCnt=" + actual + ", affNodes=" + affNodes + ", owners=" + owners + ", locNode=" + g.cluster().localNode() + ']'); } else match = true; } else { LT.warn( log(), null, "Waiting for topology map update [" + "grid=" + g.name() + ", cache=" + cfg.getName() + ", cacheId=" + dht.context().cacheId() + ", topVer=" + top.topologyVersion() + ", started=" + dht.context().started() + ", p=" + p + ", readVer=" + readyVer + ", locNode=" + g.cluster().localNode() + ']'); } if (!match) { if (i == 0) start = System.currentTimeMillis(); if (System.currentTimeMillis() - start > 30_000) throw new IgniteException( "Timeout of waiting for topology map update [" + "grid=" + g.name() + ", cache=" + cfg.getName() + ", cacheId=" + dht.context().cacheId() + ", topVer=" + top.topologyVersion() + ", p=" + p + ", readVer=" + readyVer + ", locNode=" + g.cluster().localNode() + ']'); Thread.sleep(200); // Busy wait. continue; } if (i > 0) log() .warning( "Finished waiting for topology map update [grid=" + g.name() + ", p=" + p + ", duration=" + (System.currentTimeMillis() - start) + "ms]"); break; } } } } } }