alluxio.heartbeat.HeartbeatScheduler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alluxio-core-common Show documentation
Show all versions of alluxio-core-common Show documentation
Common utilities shared in Alluxio core modules
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.heartbeat;
import alluxio.resource.LockResource;
import com.google.common.base.Preconditions;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.concurrent.ThreadSafe;
/**
* This class can be used for controlling heartbeat execution of a thread.
*
* In particular, the {@link #await(String)} method can be used to wait for a thread to start
* waiting to be scheduled and the {@link #schedule(String)} method can be used to schedule a thread
* that is waiting to be scheduled.
*
* The contract of this class is that the {@link #schedule(String)} method should only be called for
* threads that are in fact waiting to be scheduled. If this contract is not met, concurrent
* execution of a thread and the heartbeat scheduler logic to schedule the thread can lead to a
* deadlock.
*
* For an example of how to use the {@link HeartbeatScheduler}, see unit test of
* {@link HeartbeatThread}.
*/
@ThreadSafe
public final class HeartbeatScheduler {
/**
* A map from thread name to active timer for that thread. A timer is active when its thread is
* waiting to be scheduled.
*/
private static Map sTimers = new HashMap<>();
private static Lock sLock = new ReentrantLock();
private static Condition sCondition = sLock.newCondition();
private HeartbeatScheduler() {} // to prevent initialization
/**
* @param timer a timer to add to the scheduler
*/
public static void addTimer(ScheduledTimer timer) {
Preconditions.checkNotNull(timer, "timer");
try (LockResource r = new LockResource(sLock)) {
Preconditions.checkState(!sTimers.containsKey(timer.getThreadName()),
"The timer for thread %s is already waiting to be scheduled", timer.getThreadName());
sTimers.put(timer.getThreadName(), timer);
sCondition.signalAll();
}
}
/**
* Removes a timer name from the scheduler if it exists.
*
* @param name the name to clear
*/
public static void clearTimer(String name) {
try (LockResource r = new LockResource(sLock)) {
sTimers.remove(name);
}
}
/**
* Removes a timer from the scheduler.
*
* This method will fail if the timer is not in the scheduler.
*
* @param timer the timer to remove
*/
public static void removeTimer(ScheduledTimer timer) {
Preconditions.checkNotNull(timer, "timer");
try (LockResource r = new LockResource(sLock)) {
ScheduledTimer removedTimer = sTimers.remove(timer.getThreadName());
Preconditions.checkNotNull(removedTimer, "sTimers should contain %s", timer.getThreadName());
Preconditions.checkState(removedTimer == timer,
"sTimers should contain the timer being removed");
}
}
/**
* @return the set of threads present in the scheduler
*/
public static Set getThreadNames() {
try (LockResource r = new LockResource(sLock)) {
return sTimers.keySet();
}
}
/**
* Schedules execution of a heartbeat for the given thread.
*
* @param threadName a name of the thread for which heartbeat is to be executed
*/
public static void schedule(String threadName) {
try (LockResource r = new LockResource(sLock)) {
ScheduledTimer timer = sTimers.get(threadName);
if (timer == null) {
throw new RuntimeException("Timer for thread " + threadName + " not found.");
}
timer.schedule();
}
}
/**
* Waits for the given thread to be ready to be scheduled.
*
* @param name a name of the thread to wait for
* @throws InterruptedException if the waiting thread is interrupted
*/
public static void await(String name) throws InterruptedException {
try (LockResource r = new LockResource(sLock)) {
while (!sTimers.containsKey(name)) {
sCondition.await();
}
}
}
/**
* Waits until the given thread can be executed, throwing an unchecked exception of the given
* timeout expires.
*
* @param name a name of the thread to wait for
* @param time the maximum time to wait
* @param unit the time unit of the {@code time} argument
* @throws InterruptedException if the waiting thread is interrupted
*/
public static void await(String name, long time, TimeUnit unit) throws InterruptedException {
try (LockResource r = new LockResource(sLock)) {
while (!sTimers.containsKey(name)) {
if (!sCondition.await(time, unit)) {
throw new RuntimeException(
"Timed out waiting for thread " + name + " to be ready for scheduling");
}
}
}
}
/**
* Convenience method for executing a heartbeat and waiting for it to complete.
*
* @param name the name of the heartbeat to execute
* @throws InterruptedException if the waiting thread is interrupted
*/
public static void execute(String name) throws InterruptedException {
await(name);
schedule(name);
await(name);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy