com.hazelcast.internal.partition.impl.MigrationThread Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.internal.partition.impl;
import com.hazelcast.instance.impl.OutOfMemoryErrorDispatcher;
import com.hazelcast.internal.partition.impl.MigrationManager.MigrationPlanTask;
import com.hazelcast.logging.ILogger;
import com.hazelcast.spi.properties.ClusterProperty;
import java.util.concurrent.TimeUnit;
import static com.hazelcast.internal.util.ThreadUtil.createThreadName;
import static java.lang.Math.max;
/**
* MigrationThread is responsible to execute migration related tasks submitted to its
* migration-queue.
*/
class MigrationThread extends Thread implements Runnable {
private static final long DEFAULT_MIGRATION_SLEEP_INTERVAL = 250L;
private final MigrationManager migrationManager;
private final MigrationQueue queue;
private final ILogger logger;
/**
* Time in milliseconds to sleep after {@link MigrationManager.MigrateTask}
*/
private final long partitionMigrationInterval;
/**
* Time in milliseconds to sleep when the migration queue is empty or migrations are not allowed
*/
private final long sleepTime;
private volatile MigrationRunnable activeTask;
private volatile boolean running = true;
MigrationThread(MigrationManager migrationManager, String hzName, ILogger logger, MigrationQueue queue) {
super(createThreadName(hzName, "migration"));
this.migrationManager = migrationManager;
this.queue = queue;
this.partitionMigrationInterval = migrationManager.partitionMigrationInterval;
this.sleepTime = max(DEFAULT_MIGRATION_SLEEP_INTERVAL, partitionMigrationInterval);
this.logger = logger;
}
@Override
public void run() {
try {
while (running) {
doRun();
if (!migrationManager.areMigrationTasksAllowed()) {
Thread.sleep(sleepTime);
}
}
} catch (InterruptedException e) {
if (logger.isFinestEnabled()) {
logger.finest("MigrationThread is interrupted: " + e.getMessage());
}
} catch (OutOfMemoryError e) {
OutOfMemoryErrorDispatcher.onOutOfMemory(e);
} finally {
queue.clear();
}
}
/**
* Polls the migration queue and processes the tasks, sleeping if there are no tasks, if migration is not allowed or
* if configured to do so (see {@link ClusterProperty#PARTITION_MIGRATION_INTERVAL}).
*
* @throws InterruptedException if the sleep was interrupted
*/
private void doRun() throws InterruptedException {
while (migrationManager.areMigrationTasksAllowed()) {
MigrationRunnable runnable = queue.poll(1, TimeUnit.SECONDS);
if (runnable == null) {
break;
}
processTask(runnable);
}
}
private void processTask(MigrationRunnable runnable) {
try {
if (!running) {
return;
}
activeTask = runnable;
runnable.run();
} catch (Throwable t) {
logger.warning(t);
} finally {
queue.afterTaskCompletion(runnable);
activeTask = null;
}
}
void abortMigrationTask() {
MigrationRunnable task = activeTask;
if (task instanceof MigrationPlanTask) {
((MigrationPlanTask) task).abort();
}
}
/**
* Interrupts the migration thread and joins on it.
* Must not be called on the migration thread itself because it will result in infinite blocking.
*/
void stopNow() {
assert currentThread() != this : "stopNow must not be called on the migration thread";
running = false;
queue.clear();
interrupt();
boolean currentThreadInterrupted = false;
while (true) {
try {
join();
} catch (InterruptedException e) {
currentThreadInterrupted = true;
continue;
}
break;
}
if (currentThreadInterrupted) {
currentThread().interrupt();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy