From a1eb692cc38d358cbab85a93b9e0fc24666e604e Mon Sep 17 00:00:00 2001 From: Michael Vorburger Date: Wed, 17 May 2017 12:36:46 +0200 Subject: [PATCH] Listener base classes should not throw exception if close()'d for AsyncClusteredDataTreeChangeListenerBase and AsyncDataTreeChangeListenerBase, by introducing a new ShutdownLoggingExecutorService infra util. related to -1 discussion in https://git.opendaylight.org/gerrit/#/c/57004/ This is an alternative proposal to the ShutdownLoggingExecutorService idea from https://git.opendaylight.org/gerrit/#/c/57156/ Change-Id: I5884a188fb5ea3581f99cc559acb158ed370ed7b Signed-off-by: Michael Vorburger --- ...ncClusteredDataTreeChangeListenerBase.java | 4 +- .../AsyncDataTreeChangeListenerBase.java | 4 +- .../LoggingRejectedExecutionHandler.java | 47 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/infra/LoggingRejectedExecutionHandler.java diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncClusteredDataTreeChangeListenerBase.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncClusteredDataTreeChangeListenerBase.java index 37a73f67e..67df09b64 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncClusteredDataTreeChangeListenerBase.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncClusteredDataTreeChangeListenerBase.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.infra.LoggingRejectedExecutionHandler; import org.opendaylight.genius.utils.SuperTypeUtil; import org.opendaylight.infrautils.utils.concurrent.ThreadFactoryProvider; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -52,7 +53,8 @@ public abstract class AsyncClusteredDataTreeChangeListenerBase ThreadFactoryProvider.builder() .namePrefix("AsyncClusteredDataTreeChangeListenerBase-DataTreeChangeHandler") .logger(LOG) - .build().get()); + .build().get(), + new LoggingRejectedExecutionHandler()); protected final Class clazz; diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncDataTreeChangeListenerBase.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncDataTreeChangeListenerBase.java index a8248e5ae..7c011af05 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncDataTreeChangeListenerBase.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/datastoreutils/AsyncDataTreeChangeListenerBase.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.infra.LoggingRejectedExecutionHandler; import org.opendaylight.genius.utils.SuperTypeUtil; import org.opendaylight.infrautils.utils.concurrent.ThreadFactoryProvider; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -51,7 +52,8 @@ public abstract class AsyncDataTreeChangeListenerBase clazz; diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/infra/LoggingRejectedExecutionHandler.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/infra/LoggingRejectedExecutionHandler.java new file mode 100644 index 000000000..9589aced2 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/infra/LoggingRejectedExecutionHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.genius.infra; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor.AbortPolicy; +import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link RejectedExecutionHandler} which logs + * instead of throwing an exception (like e.g. {@link ThreadPoolExecutor}'s default + * {@link AbortPolicy} does) or just completely silently ignores the execute + * (like e.g. {@link DiscardPolicy} does). + * + *

This logs an ERROR level message (because typically that's a real problem), + * unless the {@link ExecutorService#isShutdown()} - then it logs only an INFO level message + * (because typically that's "just" a shutdown ordering issue, and not a real problem). + * + * @author Michael Vorburger.ch + */ +public class LoggingRejectedExecutionHandler implements RejectedExecutionHandler { + + // TODO This utility could eventually be moved to org.opendaylight.infrautils.utils.concurrent + + private static final Logger LOG = LoggerFactory.getLogger(LoggingRejectedExecutionHandler.class); + + @Override + public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { + if (executor.isShutdown() || executor.isTerminating() || executor.isTerminated()) { + LOG.info("rejectedExecution, but OK as ExecutorService is terminating or shutdown; " + + "executor: {}, runnable: {}", executor, runnable); + } else { + LOG.error("rejectedExecution (BUT ExecutorService is NOT terminating or shutdown, so that's a PROBLEM); " + + "executor: {}, runnable: {}", executor, runnable); + } + } + +} -- 2.36.6