in modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java [2131:2312]
private synchronized void stop0(boolean cancel, ShutdownPolicy shutdown) {
IgniteKernal grid0 = grid;
// Double check.
if (grid0 == null) {
if (log != null)
U.warn(log, "Attempting to stop an already stopped Ignite instance (ignore): " + name);
return;
}
if (shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
shutdownHook = null;
if (log != null && log.isDebugEnabled())
log.debug("Shutdown hook is removed.");
}
catch (IllegalStateException e) {
// Shutdown is in progress...
if (log != null && log.isDebugEnabled())
log.debug("Shutdown is in progress (ignoring): " + e.getMessage());
}
}
if (shutdown == ShutdownPolicy.GRACEFUL && !grid.context().clientNode() && grid.cluster().state().active()) {
delayedShutdown = true;
if (log.isInfoEnabled())
log.info("Ensuring that caches have sufficient backups and local rebalance completion...");
DistributedMetaStorage metaStorage = grid.context().distributedMetastorage();
while (delayedShutdown) {
boolean safeToStop = true;
long topVer = grid.cluster().topologyVersion();
HashSet<UUID> originalNodesToExclude;
HashSet<UUID> nodesToExclude;
try {
originalNodesToExclude = metaStorage.read(GRACEFUL_SHUTDOWN_METASTORE_KEY);
nodesToExclude = originalNodesToExclude != null ? new HashSet<>(originalNodesToExclude) :
new HashSet<>();
}
catch (IgniteCheckedException e) {
U.error(log, "Unable to read " + GRACEFUL_SHUTDOWN_METASTORE_KEY +
" value from metastore.", e);
continue;
}
Map<UUID, Map<Integer, Set<Integer>>> proposedSuppliers = new HashMap<>();
for (CacheGroupContext grpCtx : grid.context().cache().cacheGroups()) {
if (grpCtx.systemCache())
continue;
if (grpCtx.config().getCacheMode() == PARTITIONED && grpCtx.config().getBackups() == 0) {
LT.warn(log, "Ignoring potential data loss on cache without backups [name="
+ grpCtx.cacheOrGroupName() + "]");
continue;
}
if (topVer != grpCtx.topology().readyTopologyVersion().topologyVersion()) {
// At the moment, there is an exchange.
safeToStop = false;
break;
}
GridDhtPartitionFullMap fullMap = grpCtx.topology().partitionMap(false);
if (fullMap == null) {
safeToStop = false;
break;
}
nodesToExclude.retainAll(fullMap.keySet());
if (!haveCopyLocalPartitions(grpCtx, nodesToExclude, proposedSuppliers)) {
safeToStop = false;
if (log.isInfoEnabled()) {
LT.info(log, "This node is waiting for backups of local partitions for group [id="
+ grpCtx.groupId() + ", name=" + grpCtx.cacheOrGroupName() + "]");
}
break;
}
if (!isRebalanceCompleted(grpCtx)) {
safeToStop = false;
if (log.isInfoEnabled()) {
LT.info(log, "This node is waiting for completion of rebalance for group [id="
+ grpCtx.groupId() + ", name=" + grpCtx.cacheOrGroupName() + "]");
}
break;
}
}
if (topVer != grid.cluster().topologyVersion())
safeToStop = false;
if (safeToStop && !proposedSuppliers.isEmpty()) {
try {
safeToStop = grid0.context().task().execute(
CheckCpHistTask.class,
proposedSuppliers,
options(grid0.cluster().forNodeIds(proposedSuppliers.keySet()).nodes())
).get();
}
catch (IgniteCheckedException e) {
U.error(log, "Failed to check availability of historical rebalance", e);
safeToStop = false;
}
}
if (safeToStop) {
try {
HashSet<UUID> newNodesToExclude = new HashSet<>(nodesToExclude);
newNodesToExclude.add(grid.localNodeId());
if (metaStorage.compareAndSet(GRACEFUL_SHUTDOWN_METASTORE_KEY, originalNodesToExclude,
newNodesToExclude))
break;
}
catch (IgniteCheckedException e) {
U.error(log, "Unable to write " + GRACEFUL_SHUTDOWN_METASTORE_KEY +
" value from metastore.", e);
continue;
}
}
try {
IgniteUtils.sleep(WAIT_FOR_BACKUPS_CHECK_INTERVAL);
}
catch (IgniteInterruptedCheckedException e) {
Thread.currentThread().interrupt();
}
}
}
// Unregister Ignite MBean.
unregisterFactoryMBean();
try {
grid0.stop(cancel);
if (log != null && log.isDebugEnabled())
log.debug("Ignite instance stopped ok: " + name);
}
catch (Throwable e) {
U.error(log, "Failed to properly stop grid instance due to undeclared exception.", e);
if (e instanceof Error)
throw e;
}
finally {
if (grid0.context().segmented())
state = STOPPED_ON_SEGMENTATION;
else if (grid0.context().invalid())
state = STOPPED_ON_FAILURE;
else
state = STOPPED;
grid = null;
log = null;
}
}