+ * StupidPool already has a mechanism by which it will log resource leaks (ResourceHolder objects that are not + * closed), over time, we've built up a test suite that contains lots of those logs and generally they get swept + * away to a perrenial Priority #2. This is not a good state as the justification is usually that the logs are + * coming from test harness, the production code is obviously good. Anyway, we need tests to actually fail if there + * are leaks like this so that the tests and the code can be improved. Catching leaks is hard, though, because it + * either requires reference counting and all tests sites to check the counts, or it requires catching objects being + * GC'd, which is asynchronous. We opt for this latter approach. + *
+ * Specifically, when poisoned, the StupidPool will + * 1) Maintain an exception (i.e. stack trace) object from each time that a resource holder is checked out + * 2) If the ResourceHolder is GCd without being closed, the exception object will be registered back with the + * stupid pool + * 3) If an exception is registered with the StupidPool, then any attempt to take an object from that Pool will have + * the exception thrown instead. + *
+ * This means that we have a delayed reaction to the leak, in that the object must first be GCd before we can
+ * identify the leak. *Also* it means that the test that failed is not actually the test that leaked the object,
+ * instead, developers must look at the stacktrace thrown to see which test actually checked out the object and did
+ * not return it. Additionally, it means that one test run can only discover a single leak (as once the pool is
+ * poisoned, it will return the same exception constantly). So, if there is some leaky code, it will likely require
+ * multiple test runs to actually whack-a-mole all of the sources of the leaks.
+ */
+ private static final AtomicBoolean POISONED = new AtomicBoolean(false);
+
+ static {
+ if (Boolean.parseBoolean(System.getProperty("druid.test.stupidPool.poison"))) {
+ POISONED.set(true);
+ }
+ }
+
+ public static boolean isPoisoned()
+ {
+ return POISONED.get();
+ }
+
/**
* StupidPool Implementation Note
* It is assumed that StupidPools are never reclaimed by the GC, either stored in static fields or global singleton
@@ -65,6 +104,8 @@ public class StupidPool
* This is not entirely CompactionTask related, but it's similar conceptually and it requires
* similar setup to what this test suite already has.
- *
+ *
* It could be moved to a separate test class if needed.
*/
@Test
@@ -1642,11 +1720,10 @@ public class CompactionTaskRunTest extends IngestionTestBase
private List