[ https://issues.apache.org/jira/browse/JAMES-3724?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Benoit Tellier closed JAMES-3724. --------------------------------- Fix Version/s: 3.8.0 Resolution: Fixed We now have a leak detector! > Lifecycle API should embed a leak detector > ------------------------------------------ > > Key: JAMES-3724 > URL: https://issues.apache.org/jira/browse/JAMES-3724 > Project: James Server > Issue Type: Improvement > Components: James Core > Affects Versions: 3.7.0 > Reporter: Benoit Tellier > Priority: Major > Fix For: 3.8.0 > > Time Spent: 4h 40m > Remaining Estimate: 0h > > h3. Why ? > JAMES-3720 showed how easy to miss calling Lifecycle::dispose on email > objects, which causes potentially temporary file leaks. If core developer / > core components are subject to leaks while core contributors are aware of the > importance of life-cycle management of mail objects, I cannot but be worry of > users writing extensions and messing up. > h3. Goals > Thus I would like a defense mechanism that: > - Log errors if an email is not disposed, and ideally contains a stacktrace > to where that email was created to ease debug. > - GC should eventually reclaim those temporary files, this is better than > leaking them. > h3. Solution overview > I have in mind something much similar to Netty 4 pooled buffer leak detection: > - Rely on phantom references to track GCed items > - Fill a stack trace upon object creation > - Upon GC verify that resources were released, if not do it and warn the > user about it. > References: > - About phantom references: https://www.baeldung.com/java-phantom-reference > - Netty resource leak detector: > https://github.com/netty/netty/blob/4.1/common/src/main/java/io/netty/util/ResourceLeakDetector.java > h3. API overview > Use system properties to configure leak detection: > - `-Djames.ligecycle.leak.detection.mode=none` would behave as today. > - `-Djames.ligecycle.leak.detection.mode=simple` would output a simple ERROR > log if a leak is encountered and would free the resources. > - `-Djames.ligecycle.leak.detection.mode=advanced` would output an extented > ERROR log implying the place of allocation of the underlying object and would > free resources. > - `-Djames.ligecycle.leak.detection.mode=testing` would output an extented > ERROR log implying the place of allocation of the underlying object and > rethrow an error, unsuring test fails and that action is being taken by the > development team. > `jvm.properties` files and documentation would document this setting. > Also we IMO should default to `simple`. > h3. Implementation details > Provide an abstract class, Disposable.LeakAware: > {code:java} > public interface Disposable { > /** > * Dispose the object > */ > void dispose(); > static abstract class LeakAware implements Disposable { > private static final ReferenceQueue<Object> REFERENCE_QUEUE = new > ReferenceQueue<>(); > private Atomic<Boolean> isDisposed: > protected LeakAware() { > isDisposed = new AtomicBoolean(false); > } > public void track() { > // Create a phantom reference, of course if detection mode is > none > new LeakAwareFinalizer(this, REFERENCE_QUEUE) > // POLL the reference queue here to check for leaks! > // of course don't do it if the leak detection mode is none > while ((referenceFromQueue = REFERENCE_QUEUE.poll()) != null) { > ((LeakAwareFinalizer)referenceFromQueue).detectLeak(); > referenceFromQueue.clear(); > } > } > } > public class LeakAwareFinalizer extends PhantomReference<LeakAware> { > public LeakAwareFinalizer(LeakAware referent, ReferenceQueue<? super > LeakAware> q) { > super(referent, q); > } > public void detectLeak() { > if (!referent.isDisposed()) { > // add starttrace of creation if needed > LOGGER.error("Leak detected!!!"); > // clean if needed > referent.dispose(); > } > } > } > } > {code} > Then sensitive classes, likely only `MimeMessageInputStreamSource` would > extend it, and thus automatically gain leak detection. > We can turn `MimeMessageSource` into an interface with a default size method > if needed. > h3. Acceptance criteria > - Run tests in testing leak detection mode. This can be done by passing > system properties to the surefire plugin. > - Unit tests including logging checks for each mode. > - See this for logging assertions: PeriodicalHealthCheckTest > - Call System.gc() to force a GC and get the leak detection running > - Manage dynamically system variables in unit tests to test each mode. > - Verify release was called (via atomic boolean in a custom > Disposable.LeakAware object?) > - Document this feature. -- This message was sent by Atlassian Jira (v8.20.1#820001) --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org