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 =
InternalLoggerFactory.getInstance(HashedWheelTimer.class);
private static final ResourceLeakDetector<HashedWheelTimer> leakDetector =
new ResourceLeakDetector<HashedWheelTimer>(
HashedWheelTimer.class, 1, Runtime.getRuntime().availableProcessors() * 4);
private static final ResourceLeakDetector<HashedWheelTimer> leakDetector = ResourceLeakDetectorFactory.instance()
.newResourceLeakDetector(HashedWheelTimer.class, 1, Runtime.getRuntime().availableProcessors() * 4L);
private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER;
static {

View File

@ -109,7 +109,7 @@ public class ResourceLeakDetector<T> {
}
// 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.
@ -159,18 +159,36 @@ public class ResourceLeakDetector<T> {
private long leakCheckCnt;
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(Class<?> resourceType) {
this(simpleClassName(resourceType));
}
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(String resourceType) {
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) {
this(simpleClassName(resourceType), samplingInterval, maxActive);
}
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
if (resourceType == null) {
throw new NullPointerException("resourceType");
@ -199,7 +217,7 @@ public class ResourceLeakDetector<T> {
*
* @return the {@link ResourceLeak} or {@code null}
*/
public ResourceLeak open(T obj) {
public final ResourceLeak open(T obj) {
Level level = ResourceLeakDetector.level;
if (level == Level.DISABLED) {
return null;

View File

@ -61,60 +61,82 @@ public abstract class ResourceLeakDetectorFactory {
* @param <T> - the type of the resource class
* @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
*/
private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory {
private final Constructor<?> customClassConstructor;
private final String customLeakDetector;
private final Constructor customClassConstructor;
public DefaultResourceLeakDetectorFactory() {
this.customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run() {
return SystemPropertyUtil.get("io.netty.customResourceLeakDetector");
}
});
this.customClassConstructor = customClassConstructor();
DefaultResourceLeakDetectorFactory() {
String customLeakDetector;
try {
customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run() {
return SystemPropertyUtil.get("io.netty.customResourceLeakDetector");
}
});
} catch (Throwable cause) {
logger.error("Could not access System property: io.netty.customResourceLeakDetector", cause);
customLeakDetector = null;
}
customClassConstructor = customLeakDetector == null ? null : customClassConstructor(customLeakDetector);
}
private Constructor customClassConstructor() {
private static Constructor<?> customClassConstructor(String customLeakDetector) {
try {
if (customLeakDetector != null) {
final Class<?> detectorClass = Class.forName(customLeakDetector, true,
PlatformDependent.getSystemClassLoader());
final Class<?> detectorClass = Class.forName(customLeakDetector, true,
PlatformDependent.getSystemClassLoader());
if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
return detectorClass.getConstructor(Class.class);
} else {
logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
}
if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
return detectorClass.getConstructor(Class.class, int.class, long.class);
} else {
logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
}
} 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;
}
@Override
public <T> ResourceLeakDetector<T> newResourceLeakDetector(final Class<T> resource) {
try {
if (customClassConstructor != null) {
public <T> ResourceLeakDetector<T> newResourceLeakDetector(
Class<T> resource, int samplingInterval, long maxActive) {
if (customClassConstructor != null) {
try {
@SuppressWarnings("unchecked")
ResourceLeakDetector<T> leakDetector =
(ResourceLeakDetector<T>) customClassConstructor.newInstance(resource);
logger.debug("Loaded custom ResourceLeakDetector: {}", customLeakDetector);
(ResourceLeakDetector<T>) customClassConstructor.newInstance(
resource, samplingInterval, maxActive);
logger.debug("Loaded custom ResourceLeakDetector: {}",
customClassConstructor.getDeclaringClass().getName());
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);
return resourceLeakDetector;
}