Skip to content

HADOOP-16341. ShutDownHookManager: Regressed performance on Hook removals after HADOOP-15679 #1086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void run() {
return;
}
long started = System.currentTimeMillis();
int timeoutCount = executeShutdown();
int timeoutCount = MGR.executeShutdown();
long ended = System.currentTimeMillis();
LOG.debug(String.format(
"Completed shutdown in %.3f seconds; Timeouts: %d",
Expand All @@ -116,9 +116,9 @@ public void run() {
*/
@InterfaceAudience.Private
@VisibleForTesting
static int executeShutdown() {
int executeShutdown() {
int timeouts = 0;
for (HookEntry entry: MGR.getShutdownHooksInOrder()) {
for (HookEntry entry: getShutdownHooksInOrder()) {
Future<?> future = EXECUTOR.submit(entry.getHook());
try {
future.get(entry.getTimeout(), entry.getTimeUnit());
Expand Down Expand Up @@ -254,7 +254,9 @@ TimeUnit getTimeUnit() {
private AtomicBoolean shutdownInProgress = new AtomicBoolean(false);

//private to constructor to ensure singularity
private ShutdownHookManager() {
@VisibleForTesting
@InterfaceAudience.Private
ShutdownHookManager() {
}

/**
Expand All @@ -267,8 +269,8 @@ private ShutdownHookManager() {
@VisibleForTesting
List<HookEntry> getShutdownHooksInOrder() {
List<HookEntry> list;
synchronized (MGR.hooks) {
list = new ArrayList<>(MGR.hooks);
synchronized (hooks) {
list = new ArrayList<>(hooks);
}
Collections.sort(list, new Comparator<HookEntry>() {

Expand Down Expand Up @@ -342,7 +344,9 @@ public boolean removeShutdownHook(Runnable shutdownHook) {
throw new IllegalStateException("Shutdown in progress, cannot remove a " +
"shutdownHook");
}
return hooks.remove(new HookEntry(shutdownHook, 0));
// hooks are only == by runnable
return hooks.remove(new HookEntry(shutdownHook, 0, TIMEOUT_MINIMUM,
TIME_UNIT_DEFAULT));
}

/**
Expand All @@ -354,7 +358,8 @@ public boolean removeShutdownHook(Runnable shutdownHook) {
@InterfaceAudience.Public
@InterfaceStability.Stable
public boolean hasShutdownHook(Runnable shutdownHook) {
return hooks.contains(new HookEntry(shutdownHook, 0));
return hooks.contains(new HookEntry(shutdownHook, 0, TIMEOUT_MINIMUM,
TIME_UNIT_DEFAULT));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.After;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -43,13 +42,10 @@ public class TestShutdownHookManager {
LoggerFactory.getLogger(TestShutdownHookManager.class.getName());

/**
* remove all the shutdown hooks so that they never get invoked later
* on in this test process.
* A new instance of ShutdownHookManager to ensure parallel tests
* don't have shared context.
*/
@After
public void clearShutdownHooks() {
ShutdownHookManager.get().clearShutdownHooks();
}
private final ShutdownHookManager mgr = new ShutdownHookManager();

/**
* Verify hook registration, then execute the hook callback stage
Expand All @@ -58,7 +54,6 @@ public void clearShutdownHooks() {
*/
@Test
public void shutdownHookManager() {
ShutdownHookManager mgr = ShutdownHookManager.get();
assertNotNull("No ShutdownHookManager", mgr);
assertEquals(0, mgr.getShutdownHooksInOrder().size());
Hook hook1 = new Hook("hook1", 0, false);
Expand Down Expand Up @@ -119,7 +114,7 @@ public void shutdownHookManager() {
// now execute the hook shutdown sequence
INVOCATION_COUNT.set(0);
LOG.info("invoking executeShutdown()");
int timeouts = ShutdownHookManager.executeShutdown();
int timeouts = mgr.executeShutdown();
LOG.info("Shutdown completed");
assertEquals("Number of timed out hooks", 1, timeouts);

Expand Down Expand Up @@ -193,7 +188,6 @@ public void testShutdownTimeoutBadConfiguration() throws Throwable {
*/
@Test
public void testDuplicateRegistration() throws Throwable {
ShutdownHookManager mgr = ShutdownHookManager.get();
Hook hook = new Hook("hook1", 0, false);

// add the hook
Expand Down Expand Up @@ -222,6 +216,21 @@ public void testDuplicateRegistration() throws Throwable {

}

@Test
public void testShutdownRemove() throws Throwable {
assertNotNull("No ShutdownHookManager", mgr);
assertEquals(0, mgr.getShutdownHooksInOrder().size());
Hook hook1 = new Hook("hook1", 0, false);
Hook hook2 = new Hook("hook2", 0, false);
mgr.addShutdownHook(hook1, 9); // create Hook1 with priority 9
assertTrue("No hook1", mgr.hasShutdownHook(hook1)); // hook1 lookup works
assertEquals(1, mgr.getShutdownHooksInOrder().size()); // 1 hook
assertFalse("Delete hook2 should not be allowed",
mgr.removeShutdownHook(hook2));
assertTrue("Can't delete hook1", mgr.removeShutdownHook(hook1));
assertEquals(0, mgr.getShutdownHooksInOrder().size());
}

private static final AtomicInteger INVOCATION_COUNT = new AtomicInteger();

/**
Expand Down