use of org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionExchangeId in project ignite by apache.
the class GridClientPartitionTopology method beforeExchange0.
/**
* @param loc Local node.
* @param exchFut Exchange future.
*/
private void beforeExchange0(ClusterNode loc, GridDhtPartitionsExchangeFuture exchFut) {
GridDhtPartitionExchangeId exchId = exchFut.exchangeId();
if (exchFut.context().events().hasServerLeft()) {
List<DiscoveryEvent> evts0 = exchFut.context().events().events();
for (int i = 0; i < evts0.size(); i++) {
DiscoveryEvent evt = evts0.get(i);
if (ExchangeDiscoveryEvents.serverLeftEvent(evt))
removeNode(evt.eventNode().id());
}
}
// In case if node joins, get topology at the time of joining node.
ClusterNode oldest = discoCache.oldestAliveServerNode();
assert oldest != null;
if (log.isDebugEnabled())
log.debug("Partition map beforeExchange [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
long updateSeq = this.updateSeq.incrementAndGet();
// If this is the oldest node.
if (oldest.id().equals(loc.id()) || exchFut.dynamicCacheGroupStarted(grpId)) {
if (node2part == null) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq);
if (log.isDebugEnabled())
log.debug("Created brand new full topology map on oldest node [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
} else if (!node2part.valid()) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq, node2part, false);
if (log.isDebugEnabled())
log.debug("Created new full topology map on oldest node [exchId=" + exchId + ", fullMap=" + node2part + ']');
} else if (!node2part.nodeId().equals(loc.id())) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq, node2part, false);
if (log.isDebugEnabled())
log.debug("Copied old map into new map on oldest node (previous oldest node left) [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
}
}
consistencyCheck();
if (log.isDebugEnabled())
log.debug("Partition map after beforeExchange [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionExchangeId in project ignite by apache.
the class GridClientPartitionTopology method beforeExchange0.
/**
* @param loc Local node.
* @param exchFut Exchange future.
*/
private void beforeExchange0(ClusterNode loc, GridDhtPartitionsExchangeFuture exchFut) {
GridDhtPartitionExchangeId exchId = exchFut.exchangeId();
if (exchFut.context().events().hasServerLeft()) {
for (DiscoveryEvent evt : exchFut.context().events().events()) {
if (ExchangeDiscoveryEvents.serverLeftEvent(evt))
removeNode(evt.eventNode().id());
}
}
// In case if node joins, get topology at the time of joining node.
ClusterNode oldest = discoCache.oldestAliveServerNode();
assert oldest != null;
if (log.isDebugEnabled())
log.debug("Partition map beforeExchange [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
long updateSeq = this.updateSeq.incrementAndGet();
// If this is the oldest node (coordinator) or cache was added during this exchange
if (oldest.id().equals(loc.id()) || exchFut.dynamicCacheGroupStarted(grpId)) {
if (node2part == null) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq);
if (log.isDebugEnabled())
log.debug("Created brand new full topology map on oldest node [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
} else if (!node2part.valid()) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq, node2part, false);
if (log.isDebugEnabled())
log.debug("Created new full topology map on oldest node [exchId=" + exchId + ", fullMap=" + node2part + ']');
} else if (!node2part.nodeId().equals(loc.id())) {
node2part = new GridDhtPartitionFullMap(oldest.id(), oldest.order(), updateSeq, node2part, false);
if (log.isDebugEnabled())
log.debug("Copied old map into new map on oldest node (previous oldest node left) [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
}
}
consistencyCheck();
if (log.isDebugEnabled())
log.debug("Partition map after beforeExchange [exchId=" + exchId + ", fullMap=" + fullMapString() + ']');
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionExchangeId in project ignite by apache.
the class GridCachePartitionExchangeManager method onKernalStart.
/**
* @param active Cluster state.
* @param reconnect Reconnect flag.
* @return Topology version of local join exchange if cluster is active.
* Topology version NONE if cluster is not active or reconnect.
* @throws IgniteCheckedException If failed.
*/
public AffinityTopologyVersion onKernalStart(boolean active, boolean reconnect) throws IgniteCheckedException {
for (ClusterNode n : cctx.discovery().remoteNodes()) cctx.versions().onReceived(n.id(), n.metrics().getLastDataVersion());
DiscoveryLocalJoinData locJoin = cctx.discovery().localJoin();
GridDhtPartitionsExchangeFuture fut = null;
if (reconnect)
reconnectExchangeFut = new GridFutureAdapter<>();
if (active) {
DiscoveryEvent discoEvt = locJoin.event();
DiscoCache discoCache = locJoin.discoCache();
GridDhtPartitionExchangeId exchId = initialExchangeId();
fut = exchangeFuture(exchId, reconnect ? null : discoEvt, reconnect ? null : discoCache, null, null);
} else if (reconnect)
reconnectExchangeFut.onDone();
new IgniteThread(cctx.igniteInstanceName(), "exchange-worker", exchWorker).start();
if (reconnect) {
if (fut != null) {
fut.listen(new CI1<IgniteInternalFuture<AffinityTopologyVersion>>() {
@Override
public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) {
try {
fut.get();
for (CacheGroupContext grp : cctx.cache().cacheGroups()) grp.preloader().onInitialExchangeComplete(null);
reconnectExchangeFut.onDone();
} catch (IgniteCheckedException e) {
for (CacheGroupContext grp : cctx.cache().cacheGroups()) grp.preloader().onInitialExchangeComplete(e);
reconnectExchangeFut.onDone(e);
}
}
});
}
} else if (fut != null) {
if (log.isDebugEnabled())
log.debug("Beginning to wait on local exchange future: " + fut);
boolean first = true;
while (true) {
try {
fut.get(cctx.preloadExchangeTimeout());
break;
} catch (IgniteFutureTimeoutCheckedException ignored) {
if (first) {
U.warn(log, "Failed to wait for initial partition map exchange. " + "Possible reasons are: " + U.nl() + " ^-- Transactions in deadlock." + U.nl() + " ^-- Long running transactions (ignore if this is the case)." + U.nl() + " ^-- Unreleased explicit locks.");
first = false;
} else
U.warn(log, "Still waiting for initial partition map exchange [fut=" + fut + ']');
} catch (IgniteNeedReconnectException e) {
throw e;
} catch (Exception e) {
if (fut.reconnectOnError(e))
throw new IgniteNeedReconnectException(cctx.localNode(), e);
throw e;
}
}
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
if (locJoin.joinTopologyVersion().equals(grp.localStartVersion()))
grp.preloader().onInitialExchangeComplete(null);
}
if (log.isDebugEnabled())
log.debug("Finished waiting for initial exchange: " + fut.exchangeId());
return fut.initialVersion();
}
return NONE;
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionExchangeId in project ignite by apache.
the class GridCachePartitionExchangeManager method onDiscoveryEvent.
/**
* @param evt Event.
* @param cache Discovery data cache.
*/
private void onDiscoveryEvent(DiscoveryEvent evt, DiscoCache cache) {
ClusterNode loc = cctx.localNode();
assert evt.type() == EVT_NODE_JOINED || evt.type() == EVT_NODE_LEFT || evt.type() == EVT_NODE_FAILED || evt.type() == EVT_DISCOVERY_CUSTOM_EVT;
final ClusterNode n = evt.eventNode();
GridDhtPartitionExchangeId exchId = null;
GridDhtPartitionsExchangeFuture exchFut = null;
if (evt.type() != EVT_DISCOVERY_CUSTOM_EVT) {
assert evt.type() != EVT_NODE_JOINED || n.isLocal() || n.order() > loc.order() : "Node joined with smaller-than-local " + "order [newOrder=" + n.order() + ", locOrder=" + loc.order() + ", evt=" + evt + ']';
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
ExchangeActions exchActs = null;
boolean locJoin = evt.type() == EVT_NODE_JOINED && evt.eventNode().isLocal();
if (locJoin) {
LocalJoinCachesContext locJoinCtx = cctx.cache().localJoinCachesContext();
if (locJoinCtx != null) {
exchActs = new ExchangeActions();
exchActs.localJoinContext(locJoinCtx);
}
}
if (!n.isClient() && !n.isDaemon())
exchActs = cctx.kernalContext().state().autoAdjustExchangeActions(exchActs);
exchFut = exchangeFuture(exchId, evt, cache, exchActs, null);
} else {
DiscoveryCustomMessage customMsg = ((DiscoveryCustomEvent) evt).customMessage();
if (customMsg instanceof ChangeGlobalStateMessage) {
ChangeGlobalStateMessage stateChangeMsg = (ChangeGlobalStateMessage) customMsg;
ExchangeActions exchActions = stateChangeMsg.exchangeActions();
if (exchActions != null) {
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
exchFut = exchangeFuture(exchId, evt, cache, exchActions, null);
boolean baselineChanging;
if (stateChangeMsg.forceChangeBaselineTopology())
baselineChanging = true;
else {
DiscoveryDataClusterState state = cctx.kernalContext().state().clusterState();
assert state.transition() : state;
baselineChanging = exchActions.changedBaseline() || // Or it is the first activation.
state.state() != ClusterState.INACTIVE && !state.previouslyActive() && state.previousBaselineTopology() == null;
}
exchFut.listen(f -> onClusterStateChangeFinish(f, exchActions, baselineChanging));
}
} else if (customMsg instanceof DynamicCacheChangeBatch) {
DynamicCacheChangeBatch batch = (DynamicCacheChangeBatch) customMsg;
ExchangeActions exchActions = batch.exchangeActions();
if (exchActions != null) {
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
exchFut = exchangeFuture(exchId, evt, cache, exchActions, null);
}
} else if (customMsg instanceof CacheAffinityChangeMessage) {
CacheAffinityChangeMessage msg = (CacheAffinityChangeMessage) customMsg;
if (msg.exchangeId() == null) {
if (msg.exchangeNeeded()) {
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
exchFut = exchangeFuture(exchId, evt, cache, null, msg);
}
} else if (msg.exchangeId().topologyVersion().topologyVersion() >= cctx.discovery().localJoinEvent().topologyVersion())
exchangeFuture(msg.exchangeId(), null, null, null, null).onAffinityChangeMessage(evt.eventNode(), msg);
} else if (customMsg instanceof DynamicCacheChangeFailureMessage) {
DynamicCacheChangeFailureMessage msg = (DynamicCacheChangeFailureMessage) customMsg;
if (msg.exchangeId().topologyVersion().topologyVersion() >= affinityTopologyVersion(cctx.discovery().localJoinEvent()).topologyVersion())
exchangeFuture(msg.exchangeId(), null, null, null, null).onDynamicCacheChangeFail(evt.eventNode(), msg);
} else if (customMsg instanceof SnapshotDiscoveryMessage && ((SnapshotDiscoveryMessage) customMsg).needExchange()) {
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
exchFut = exchangeFuture(exchId, evt, null, null, null);
} else if (customMsg instanceof WalStateAbstractMessage && ((WalStateAbstractMessage) customMsg).needExchange()) {
exchId = exchangeId(n.id(), affinityTopologyVersion(evt), evt);
exchFut = exchangeFuture(exchId, evt, null, null, null);
} else {
// Process event as custom discovery task if needed.
CachePartitionExchangeWorkerTask task = cctx.cache().exchangeTaskForCustomDiscoveryMessage(customMsg);
if (task != null)
exchWorker.addCustomTask(task);
}
}
if (exchId != null) {
if (log.isDebugEnabled())
log.debug("Discovery event (will start exchange): " + exchId);
// Event callback - without this callback future will never complete.
exchFut.onEvent(exchId, evt, cache);
Span span = cctx.kernalContext().tracing().create(EXCHANGE_FUTURE, evt.span());
if (exchId != null) {
GridDhtPartitionExchangeId exchIdf = exchId;
span.addTag(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID), () -> evt.eventNode().id().toString());
span.addTag(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.CONSISTENT_ID), () -> evt.eventNode().consistentId().toString());
span.addTag(SpanTags.tag(SpanTags.EVENT, SpanTags.TYPE), () -> String.valueOf(evt.type()));
span.addTag(SpanTags.tag(SpanTags.EXCHANGE, SpanTags.ID), () -> String.valueOf(exchIdf.toString()));
span.addTag(SpanTags.tag(SpanTags.INITIAL, SpanTags.TOPOLOGY_VERSION, SpanTags.MAJOR), () -> String.valueOf(exchIdf.topologyVersion().topologyVersion()));
span.addTag(SpanTags.tag(SpanTags.INITIAL, SpanTags.TOPOLOGY_VERSION, SpanTags.MINOR), () -> String.valueOf(exchIdf.topologyVersion().minorTopologyVersion()));
}
span.addTag(SpanTags.NODE_ID, () -> cctx.localNodeId().toString());
span.addLog(() -> "Created");
exchFut.span(span);
// Start exchange process.
addFuture(exchFut);
} else {
if (log.isDebugEnabled())
log.debug("Do not start exchange for discovery event: " + evt);
}
notifyNodeFail(evt);
// Notify indexing engine about node leave so that we can re-map coordinator accordingly.
if (evt.type() == EVT_NODE_LEFT || evt.type() == EVT_NODE_FAILED) {
SecurityContext secCtx = remoteSecurityContext(cctx.kernalContext());
exchWorker.addCustomTask(new SchemaNodeLeaveExchangeWorkerTask(secCtx, evt.eventNode()));
exchWorker.addCustomTask(new WalStateNodeLeaveExchangeTask(secCtx, evt.eventNode()));
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionExchangeId in project ignite by apache.
the class ClientSlowDiscoveryTopologyChangeTest method testClientJoinAndCacheStop.
/**
* Test check that client join works well if cache configured on it stopped on server nodes
* but discovery event about cache stop is not delivered to client node immediately.
* When client node joins to cluster it sends SingleMessage to coordinator.
* During this time topology on server nodes can be changed,
* because client exchange doesn't require acknowledgement for SingleMessage on coordinator.
* Delay is simulated by blocking sending this SingleMessage and resume sending after topology is changed.
*/
@Test
public void testClientJoinAndCacheStop() throws Exception {
IgniteEx crd = (IgniteEx) startGridsMultiThreaded(3);
awaitPartitionMapExchange();
for (int k = 0; k < 64; k++) crd.cache(CACHE_NAME).put(k, k);
TestRecordingCommunicationSpi clientCommSpi = new TestRecordingCommunicationSpi();
// Delay client join process.
clientCommSpi.blockMessages((node, msg) -> {
if (!(msg instanceof GridDhtPartitionsSingleMessage))
return false;
GridDhtPartitionsSingleMessage singleMsg = (GridDhtPartitionsSingleMessage) msg;
return Optional.ofNullable(singleMsg.exchangeId()).map(GridDhtPartitionExchangeId::topologyVersion).filter(topVer -> topVer.equals(new AffinityTopologyVersion(4, 0))).isPresent();
});
communicationSpiSupplier = () -> clientCommSpi;
CustomMessageInterceptingDiscoverySpi clientDiscoSpi = new CustomMessageInterceptingDiscoverySpi();
CountDownLatch clientDiscoSpiBlock = new CountDownLatch(1);
// Delay cache destroying on client node.
clientDiscoSpi.interceptor = (msg) -> {
if (!(msg instanceof DynamicCacheChangeBatch))
return;
DynamicCacheChangeBatch cacheChangeBatch = (DynamicCacheChangeBatch) msg;
boolean hasCacheStopReq = cacheChangeBatch.requests().stream().anyMatch(req -> req.stop() && req.cacheName().equals(CACHE_NAME));
if (hasCacheStopReq)
U.awaitQuiet(clientDiscoSpiBlock);
};
discoverySpiSupplier = () -> clientDiscoSpi;
IgniteInternalFuture<IgniteEx> clientStartFut = GridTestUtils.runAsync(() -> startClientGrid(3));
// Wait till client node starts join process.
clientCommSpi.waitForBlocked();
// Destroy cache on server nodes.
crd.destroyCache(CACHE_NAME);
// Resume client join.
clientCommSpi.stopBlock();
// Client join should succeed.
IgniteEx client = clientStartFut.get();
IgniteCache<Object, Object> clientCache = client.cache(CACHE_NAME);
Assert.assertNotNull("Cache should exists on client node", clientCache);
IgniteInternalFuture<?> cacheGet = GridTestUtils.runAsync(() -> clientCache.get(0));
try {
// Reasonable timeout.
cacheGet.get(5_000);
fail("Cache get operation should throw " + CacheStoppedException.class);
} catch (Exception e) {
assertTrue("Got unexpected exception during cache get " + e, X.hasCause(e, CacheStoppedException.class));
} finally {
// Resume processing cache destroy on client node.
clientDiscoSpiBlock.countDown();
}
// Wait till cache destroyed on client node.
GridTestUtils.waitForCondition(() -> {
AffinityTopologyVersion topVer = client.context().cache().context().exchange().lastFinishedFuture().topologyVersion();
// Cache destroy version.
return topVer.equals(new AffinityTopologyVersion(4, 1));
}, // Reasonable timeout.
5_000);
Assert.assertNull("Cache should be destroyed on client node", client.cache(CACHE_NAME));
}
Aggregations