Use ResourceLeakDetectorFactory in HashedWheelTimer

Motivation:

We recently added the ResourceLeakDetectorFactory but missed to updated HashedWheelTimer to use it.

Modifications:

- Add new abstract method to ResourceLeakDetectorFactory that allows to provide also samplingInterval and maxActive args.
- Deprecate most constructors in ResourceLeakDetector and add doc explaining that people should use ResourceLeakDetectorFactory

Result:

Custom ResourceLeakDetectorFactory will also be used in HashedWheelTimer if configured.
This commit is contained in:
Norman Maurer 2016-06-28 21:20:40 +02:00
parent bd0a74fca3
commit 57672d9854
3 changed files with 76 additions and 37 deletions

View File

@ -76,9 +76,8 @@ public class HashedWheelTimer implements Timer {
static final InternalLogger logger = static final InternalLogger logger =
InternalLoggerFactory.getInstance(HashedWheelTimer.class); InternalLoggerFactory.getInstance(HashedWheelTimer.class);
private static final ResourceLeakDetector<HashedWheelTimer> leakDetector = private static final ResourceLeakDetector<HashedWheelTimer> leakDetector = ResourceLeakDetectorFactory.instance()
new ResourceLeakDetector<HashedWheelTimer>( .newResourceLeakDetector(HashedWheelTimer.class, 1, Runtime.getRuntime().availableProcessors() * 4L);
HashedWheelTimer.class, 1, Runtime.getRuntime().availableProcessors() * 4);
private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER; private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER;
static { static {

View File

@ -109,7 +109,7 @@ public class ResourceLeakDetector<T> {
} }
// Should be power of two. // Should be power of two.
private static final int DEFAULT_SAMPLING_INTERVAL = 128; static final int DEFAULT_SAMPLING_INTERVAL = 128;
/** /**
* @deprecated Use {@link #setLevel(Level)} instead. * @deprecated Use {@link #setLevel(Level)} instead.
@ -159,18 +159,36 @@ public class ResourceLeakDetector<T> {
private long leakCheckCnt; private long leakCheckCnt;
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(Class<?> resourceType) { public ResourceLeakDetector(Class<?> resourceType) {
this(simpleClassName(resourceType)); this(simpleClassName(resourceType));
} }
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(String resourceType) { public ResourceLeakDetector(String resourceType) {
this(resourceType, DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE); this(resourceType, DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE);
} }
/**
* This should not be used directly by users of {@link ResourceLeakDetector}.
* Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)}
* or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}
*/
@SuppressWarnings("deprecation")
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) { public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) {
this(simpleClassName(resourceType), samplingInterval, maxActive); this(simpleClassName(resourceType), samplingInterval, maxActive);
} }
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) { public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
if (resourceType == null) { if (resourceType == null) {
throw new NullPointerException("resourceType"); throw new NullPointerException("resourceType");
@ -199,7 +217,7 @@ public class ResourceLeakDetector<T> {
* *
* @return the {@link ResourceLeak} or {@code null} * @return the {@link ResourceLeak} or {@code null}
*/ */
public ResourceLeak open(T obj) { public final ResourceLeak open(T obj) {
Level level = ResourceLeakDetector.level; Level level = ResourceLeakDetector.level;
if (level == Level.DISABLED) { if (level == Level.DISABLED) {
return null; return null;

View File

@ -61,60 +61,82 @@ public abstract class ResourceLeakDetectorFactory {
* @param <T> - the type of the resource class * @param <T> - the type of the resource class
* @return - a new instance of {@link ResourceLeakDetector} * @return - a new instance of {@link ResourceLeakDetector}
*/ */
public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector(final Class<T> resource); public final <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource) {
return newResourceLeakDetector(resource, ResourceLeakDetector.DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE);
}
/**
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
*
* @param resource - the resource class used to initialize the {@link ResourceLeakDetector}
* @param samplingInterval - the interval on which sampling takes place
* @param maxActive - the maximum active instances
* @param <T> - the type of the resource class
* @return - a new instance of {@link ResourceLeakDetector}
*/
public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector(
Class<T> resource, int samplingInterval, long maxActive);
/** /**
* Default implementation that loads custom leak detector via system property * Default implementation that loads custom leak detector via system property
*/ */
private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory { private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory {
private final Constructor<?> customClassConstructor;
private final String customLeakDetector; DefaultResourceLeakDetectorFactory() {
private final Constructor customClassConstructor; String customLeakDetector;
try {
public DefaultResourceLeakDetectorFactory() { customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() {
this.customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() { @Override
@Override public String run() {
public String run() { return SystemPropertyUtil.get("io.netty.customResourceLeakDetector");
return SystemPropertyUtil.get("io.netty.customResourceLeakDetector"); }
} });
}); } catch (Throwable cause) {
logger.error("Could not access System property: io.netty.customResourceLeakDetector", cause);
this.customClassConstructor = customClassConstructor(); customLeakDetector = null;
}
customClassConstructor = customLeakDetector == null ? null : customClassConstructor(customLeakDetector);
} }
private Constructor customClassConstructor() { private static Constructor<?> customClassConstructor(String customLeakDetector) {
try { try {
if (customLeakDetector != null) { final Class<?> detectorClass = Class.forName(customLeakDetector, true,
final Class<?> detectorClass = Class.forName(customLeakDetector, true, PlatformDependent.getSystemClassLoader());
PlatformDependent.getSystemClassLoader());
if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) { if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
return detectorClass.getConstructor(Class.class); return detectorClass.getConstructor(Class.class, int.class, long.class);
} else { } else {
logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector); logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
}
} }
} catch (Throwable t) { } catch (Throwable t) {
logger.error("Could not load custom resource leak detector class provided: " + customLeakDetector, t); logger.error("Could not load custom resource leak detector class provided: {}",
customLeakDetector, t);
} }
return null; return null;
} }
@Override @Override
public <T> ResourceLeakDetector<T> newResourceLeakDetector(final Class<T> resource) { public <T> ResourceLeakDetector<T> newResourceLeakDetector(
try { Class<T> resource, int samplingInterval, long maxActive) {
if (customClassConstructor != null) { if (customClassConstructor != null) {
try {
@SuppressWarnings("unchecked")
ResourceLeakDetector<T> leakDetector = ResourceLeakDetector<T> leakDetector =
(ResourceLeakDetector<T>) customClassConstructor.newInstance(resource); (ResourceLeakDetector<T>) customClassConstructor.newInstance(
logger.debug("Loaded custom ResourceLeakDetector: {}", customLeakDetector); resource, samplingInterval, maxActive);
logger.debug("Loaded custom ResourceLeakDetector: {}",
customClassConstructor.getDeclaringClass().getName());
return leakDetector; return leakDetector;
} catch (Throwable t) {
logger.error(
"Could not load custom resource leak detector provided: {} with the given resource: {}",
customClassConstructor.getDeclaringClass().getName(), resource, t);
} }
} catch (Throwable t) {
logger.error("Could not load custom resource leak detector provided: {} with the given resource: {}",
customLeakDetector, resource, t);
} }
ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<T>(resource); ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<T>(
resource, samplingInterval, maxActive);
logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector); logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector);
return resourceLeakDetector; return resourceLeakDetector;
} }