use of org.apache.ignite.internal.processors.cache.GridCacheContext in project ignite by apache.
the class GridDhtPartitionDemander method handleSupplyMessage.
/**
* Handles supply message from {@code nodeId} with specified {@code topicId}.
*
* Supply message contains entries to populate rebalancing partitions.
*
* There is a cyclic process:
* Populate rebalancing partitions with entries from Supply message.
* If not all partitions specified in {@link #rebalanceFut} were rebalanced or marked as missed
* send new Demand message to request next batch of entries.
*
* @param topicId Topic id.
* @param nodeId Node id.
* @param supply Supply message.
*/
public void handleSupplyMessage(int topicId, final UUID nodeId, final GridDhtPartitionSupplyMessage supply) {
AffinityTopologyVersion topVer = supply.topologyVersion();
final RebalanceFuture fut = rebalanceFut;
ClusterNode node = ctx.node(nodeId);
if (node == null)
return;
if (// Topology already changed (for the future that supply message based on).
topologyChanged(fut))
return;
if (!fut.isActual(supply.rebalanceId())) {
// Supple message based on another future.
return;
}
if (log.isDebugEnabled())
log.debug("Received supply message [grp=" + grp.cacheOrGroupName() + ", msg=" + supply + ']');
// Check whether there were class loading errors on unmarshal
if (supply.classError() != null) {
U.warn(log, "Rebalancing from node cancelled [grp=" + grp.cacheOrGroupName() + ", node=" + nodeId + "]. Class got undeployed during preloading: " + supply.classError());
fut.cancel(nodeId);
return;
}
final GridDhtPartitionTopology top = grp.topology();
if (grp.sharedGroup()) {
for (GridCacheContext cctx : grp.caches()) {
if (cctx.statisticsEnabled()) {
long keysCnt = supply.keysForCache(cctx.cacheId());
if (keysCnt != -1)
cctx.cache().metrics0().onRebalancingKeysCountEstimateReceived(keysCnt);
// Can not be calculated per cache.
cctx.cache().metrics0().onRebalanceBatchReceived(supply.messageSize());
}
}
} else {
GridCacheContext cctx = grp.singleCacheContext();
if (cctx.statisticsEnabled()) {
if (supply.estimatedKeysCount() != -1)
cctx.cache().metrics0().onRebalancingKeysCountEstimateReceived(supply.estimatedKeysCount());
cctx.cache().metrics0().onRebalanceBatchReceived(supply.messageSize());
}
}
try {
AffinityAssignment aff = grp.affinity().cachedAffinity(topVer);
GridCacheContext cctx = grp.sharedGroup() ? null : grp.singleCacheContext();
// Preload.
for (Map.Entry<Integer, CacheEntryInfoCollection> e : supply.infos().entrySet()) {
int p = e.getKey();
if (aff.get(p).contains(ctx.localNode())) {
GridDhtLocalPartition part = top.localPartition(p, topVer, true);
assert part != null;
boolean last = supply.last().containsKey(p);
if (part.state() == MOVING) {
boolean reserved = part.reserve();
assert reserved : "Failed to reserve partition [igniteInstanceName=" + ctx.igniteInstanceName() + ", grp=" + grp.cacheOrGroupName() + ", part=" + part + ']';
part.lock();
try {
// Loop through all received entries and try to preload them.
for (GridCacheEntryInfo entry : e.getValue().infos()) {
if (!preloadEntry(node, p, entry, topVer)) {
if (log.isDebugEnabled())
log.debug("Got entries for invalid partition during " + "preloading (will skip) [p=" + p + ", entry=" + entry + ']');
break;
}
if (grp.sharedGroup() && (cctx == null || cctx.cacheId() != entry.cacheId()))
cctx = ctx.cacheContext(entry.cacheId());
if (cctx != null && cctx.statisticsEnabled())
cctx.cache().metrics0().onRebalanceKeyReceived();
}
// then we take ownership.
if (last) {
top.own(part);
fut.partitionDone(nodeId, p);
if (log.isDebugEnabled())
log.debug("Finished rebalancing partition: " + part);
}
} finally {
part.unlock();
part.release();
}
} else {
if (last)
fut.partitionDone(nodeId, p);
if (log.isDebugEnabled())
log.debug("Skipping rebalancing partition (state is not MOVING): " + part);
}
} else {
fut.partitionDone(nodeId, p);
if (log.isDebugEnabled())
log.debug("Skipping rebalancing partition (it does not belong on current node): " + p);
}
}
// Only request partitions based on latest topology version.
for (Integer miss : supply.missed()) {
if (aff.get(miss).contains(ctx.localNode()))
fut.partitionMissed(nodeId, miss);
}
for (Integer miss : supply.missed()) fut.partitionDone(nodeId, miss);
GridDhtPartitionDemandMessage d = new GridDhtPartitionDemandMessage(supply.rebalanceId(), supply.topologyVersion(), grp.groupId());
d.timeout(grp.config().getRebalanceTimeout());
d.topic(rebalanceTopics.get(topicId));
if (!topologyChanged(fut) && !fut.isDone()) {
// Send demand message.
try {
ctx.io().sendOrderedMessage(node, rebalanceTopics.get(topicId), d.convertIfNeeded(node.version()), grp.ioPolicy(), grp.config().getRebalanceTimeout());
} catch (ClusterTopologyCheckedException e) {
if (log.isDebugEnabled()) {
log.debug("Node left during rebalancing [grp=" + grp.cacheOrGroupName() + ", node=" + node.id() + ", msg=" + e.getMessage() + ']');
}
}
}
} catch (IgniteSpiException | IgniteCheckedException e) {
LT.error(log, e, "Error during rebalancing [grp=" + grp.cacheOrGroupName() + ", srcNode=" + node.id() + ", err=" + e + ']');
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheContext in project ignite by apache.
the class GridDhtPartitionDemander method awaitClearingAndStartRebalance.
/**
* Awaits partitions clearing for full partitions and sends initial demand request
* after all partitions are cleared and safe to consume data.
*
* @param fut Rebalance future.
* @param demandMessage Initial demand message which contains set of full partitions to await.
* @param initDemandRequestTask Task which sends initial demand request.
*/
private void awaitClearingAndStartRebalance(RebalanceFuture fut, GridDhtPartitionDemandMessage demandMessage, Runnable initDemandRequestTask) {
Set<Integer> fullPartitions = demandMessage.partitions().fullSet();
if (fullPartitions.isEmpty()) {
ctx.kernalContext().closure().runLocalSafe(initDemandRequestTask, true);
return;
}
for (GridCacheContext cctx : grp.caches()) {
if (cctx.statisticsEnabled()) {
final CacheMetricsImpl metrics = cctx.cache().metrics0();
metrics.rebalanceClearingPartitions(fullPartitions.size());
}
}
final AtomicInteger clearingPartitions = new AtomicInteger(fullPartitions.size());
for (int partId : fullPartitions) {
if (fut.isDone())
return;
GridDhtLocalPartition part = grp.topology().localPartition(partId);
if (part != null && part.state() == MOVING) {
part.onClearFinished(f -> {
// Cancel rebalance if partition clearing was failed.
if (f.error() != null) {
if (!fut.isDone()) {
for (GridCacheContext cctx : grp.caches()) {
if (cctx.statisticsEnabled()) {
final CacheMetricsImpl metrics = cctx.cache().metrics0();
metrics.rebalanceClearingPartitions(0);
}
}
log.error("Unable to await partition clearing " + part, f.error());
fut.cancel();
}
} else {
if (!fut.isDone()) {
int existed = clearingPartitions.decrementAndGet();
for (GridCacheContext cctx : grp.caches()) {
if (cctx.statisticsEnabled()) {
final CacheMetricsImpl metrics = cctx.cache().metrics0();
metrics.rebalanceClearingPartitions(existed);
}
}
// If all partitions are cleared send initial demand message.
if (existed == 0)
ctx.kernalContext().closure().runLocalSafe(initDemandRequestTask, true);
}
}
});
} else
clearingPartitions.decrementAndGet();
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheContext in project ignite by apache.
the class GridDhtPartitionsExchangeFuture method onDone.
/**
* {@inheritDoc}
*/
@Override
public boolean onDone(@Nullable AffinityTopologyVersion res, @Nullable Throwable err) {
if (isDone() || !done.compareAndSet(false, true))
return false;
if (log.isInfoEnabled()) {
log.info("Finish exchange future [startVer=" + initialVersion() + ", resVer=" + res + ", err=" + err + ']');
}
assert res != null || err != null;
if (err == null && !cctx.kernalContext().clientNode() && (serverNodeDiscoveryEvent() || affChangeMsg != null)) {
for (GridCacheContext cacheCtx : cctx.cacheContexts()) {
if (!cacheCtx.affinityNode() || cacheCtx.isLocal())
continue;
cacheCtx.continuousQueries().flushBackupQueue(res);
}
}
if (err == null) {
if (centralizedAff || forceAffReassignment) {
assert !exchCtx.mergeExchanges();
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
if (grp.isLocal())
continue;
boolean needRefresh = false;
try {
needRefresh = grp.topology().initPartitionsWhenAffinityReady(res, this);
} catch (IgniteInterruptedCheckedException e) {
U.error(log, "Failed to initialize partitions.", e);
}
if (needRefresh)
cctx.exchange().refreshPartitions();
}
}
for (GridCacheContext cacheCtx : cctx.cacheContexts()) {
GridCacheContext drCacheCtx = cacheCtx.isNear() ? cacheCtx.near().dht().context() : cacheCtx;
if (drCacheCtx.isDrEnabled()) {
try {
drCacheCtx.dr().onExchange(res, exchId.isLeft());
} catch (IgniteCheckedException e) {
U.error(log, "Failed to notify DR: " + e, e);
}
}
}
if (serverNodeDiscoveryEvent())
detectLostPartitions(res);
Map<Integer, CacheValidation> m = U.newHashMap(cctx.cache().cacheGroups().size());
for (CacheGroupContext grp : cctx.cache().cacheGroups()) m.put(grp.groupId(), validateCacheGroup(grp, events().lastEvent().topologyNodes()));
grpValidRes = m;
}
if (!cctx.localNode().isClient())
tryToPerformLocalSnapshotOperation();
cctx.cache().onExchangeDone(initialVersion(), exchActions, err);
cctx.exchange().onExchangeDone(res, initialVersion(), err);
cctx.kernalContext().authentication().onActivate();
if (exchActions != null && err == null)
exchActions.completeRequestFutures(cctx);
if (stateChangeExchange() && err == null)
cctx.kernalContext().state().onStateChangeExchangeDone(exchActions.stateChangeRequest());
Map<T2<Integer, Integer>, Long> localReserved = partHistSuppliers.getReservations(cctx.localNodeId());
if (localReserved != null) {
for (Map.Entry<T2<Integer, Integer>, Long> e : localReserved.entrySet()) {
boolean success = cctx.database().reserveHistoryForPreloading(e.getKey().get1(), e.getKey().get2(), e.getValue());
if (!success) {
// TODO: how to handle?
err = new IgniteCheckedException("Could not reserve history");
}
}
}
cctx.database().releaseHistoryForExchange();
cctx.database().rebuildIndexesIfNeeded(this);
if (err == null) {
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
if (!grp.isLocal())
grp.topology().onExchangeDone(this, grp.affinity().readyAffinity(res), false);
}
}
if (super.onDone(res, err)) {
if (log.isDebugEnabled())
log.debug("Completed partition exchange [localNode=" + cctx.localNodeId() + ", exchange= " + this + ", durationFromInit=" + (U.currentTimeMillis() - initTs) + ']');
initFut.onDone(err == null);
if (exchCtx != null && exchCtx.events().hasServerLeft()) {
ExchangeDiscoveryEvents evts = exchCtx.events();
for (DiscoveryEvent evt : exchCtx.events().events()) {
if (serverLeftEvent(evt)) {
for (CacheGroupContext grp : cctx.cache().cacheGroups()) grp.affinityFunction().removeNode(evt.eventNode().id());
}
}
}
exchActions = null;
if (firstDiscoEvt instanceof DiscoveryCustomEvent)
((DiscoveryCustomEvent) firstDiscoEvt).customMessage(null);
if (err == null) {
cctx.exchange().lastFinishedFuture(this);
if (exchCtx != null && (exchCtx.events().hasServerLeft() || exchCtx.events().hasServerJoin())) {
ExchangeDiscoveryEvents evts = exchCtx.events();
for (DiscoveryEvent evt : exchCtx.events().events()) {
if (serverLeftEvent(evt) || serverJoinEvent(evt))
logExchange(evt);
}
}
}
return true;
}
return false;
}
use of org.apache.ignite.internal.processors.cache.GridCacheContext in project ignite by apache.
the class GridDhtPartitionsExchangeFuture method distributedExchange.
/**
* @throws IgniteCheckedException If failed.
*/
private void distributedExchange() throws IgniteCheckedException {
assert crd != null;
assert !cctx.kernalContext().clientNode();
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
if (grp.isLocal())
continue;
grp.preloader().onTopologyChanged(this);
}
cctx.database().releaseHistoryForPreloading();
// To correctly rebalance when persistence is enabled, it is necessary to reserve history within exchange.
partHistReserved = cctx.database().reserveHistoryForExchange();
waitPartitionRelease();
boolean topChanged = firstDiscoEvt.type() != EVT_DISCOVERY_CUSTOM_EVT || affChangeMsg != null;
for (GridCacheContext cacheCtx : cctx.cacheContexts()) {
if (cacheCtx.isLocal() || cacheStopping(cacheCtx.cacheId()))
continue;
if (topChanged) {
// Partition release future is done so we can flush the write-behind store.
cacheCtx.store().forceFlush();
}
}
if (!exchCtx.mergeExchanges()) {
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
if (grp.isLocal() || cacheGroupStopping(grp.groupId()))
continue;
// It is possible affinity is not initialized yet if node joins to cluster.
if (grp.affinity().lastVersion().topologyVersion() > 0)
grp.topology().beforeExchange(this, !centralizedAff && !forceAffReassignment, false);
}
}
// It is necessary to run database callback after all topology callbacks, so partition states could be
// correctly restored from the persistent store.
cctx.database().beforeExchange(this);
changeWalModeIfNeeded();
if (crd.isLocal()) {
if (remaining.isEmpty())
onAllReceived(null);
} else
sendPartitions(crd);
initDone();
}
use of org.apache.ignite.internal.processors.cache.GridCacheContext in project ignite by apache.
the class GridNearGetResponse method prepareMarshal.
/**
* {@inheritDoc}
* @param ctx
*/
@Override
public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException {
super.prepareMarshal(ctx);
GridCacheContext cctx = ctx.cacheContext(cacheId);
if (entries != null) {
for (GridCacheEntryInfo info : entries) info.marshal(cctx);
}
if (err != null && errBytes == null)
errBytes = U.marshal(ctx, err);
}
Aggregations