1
16
17 package com.zaxxer.hikari.pool;
18
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26
32 class ProxyLeakTask implements Runnable
33 {
34 private static final Logger LOGGER = LoggerFactory.getLogger(ProxyLeakTask.class);
35 static final ProxyLeakTask NO_LEAK;
36
37 private ScheduledFuture<?> scheduledFuture;
38 private String connectionName;
39 private Exception exception;
40 private String threadName;
41 private boolean isLeaked;
42
43 static
44 {
45 NO_LEAK = new ProxyLeakTask() {
46 @Override
47 void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold) {}
48
49 @Override
50 public void run() {}
51
52 @Override
53 public void cancel() {}
54 };
55 }
56
57 ProxyLeakTask(final PoolEntry poolEntry)
58 {
59 this.exception = new Exception("Apparent connection leak detected");
60 this.threadName = Thread.currentThread().getName();
61 this.connectionName = poolEntry.connection.toString();
62 }
63
64 private ProxyLeakTask()
65 {
66 }
67
68 void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold)
69 {
70 scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS);
71 }
72
73
74 @Override
75 public void run()
76 {
77 isLeaked = true;
78
79 final StackTraceElement[] stackTrace = exception.getStackTrace();
80 final StackTraceElement[] trace = new StackTraceElement[stackTrace.length - 5];
81 System.arraycopy(stackTrace, 5, trace, 0, trace.length);
82
83 exception.setStackTrace(trace);
84 LOGGER.warn("Connection leak detection triggered for {} on thread {}, stack trace follows", connectionName, threadName, exception);
85 }
86
87 void cancel()
88 {
89 scheduledFuture.cancel(false);
90 if (isLeaked) {
91 LOGGER.info("Previously reported leaked connection {} on thread {} was returned to the pool (unleaked)", connectionName, threadName);
92 }
93 }
94 }
95