Author: reschke Date: Thu Apr 23 08:43:40 2020 New Revision: 1876868 URL: http://svn.apache.org/viewvc?rev=1876868&view=rev Log: OAK-8411: RDBConnectionHandler: add minimal open connection stats in TRACE log level (merged 1861630 into 1.8)
Added: jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java - copied unchanged from r1861630, jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java Modified: jackrabbit/oak/branches/1.8/ (props changed) jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java Propchange: jackrabbit/oak/branches/1.8/ ------------------------------------------------------------------------------ Merged /jackrabbit/oak/trunk:r1861630 Modified: jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java?rev=1876868&r1=1876867&r2=1876868&view=diff ============================================================================== --- jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java (original) +++ jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java Thu Apr 23 08:43:40 2020 @@ -18,8 +18,11 @@ package org.apache.jackrabbit.oak.plugin import java.io.Closeable; import java.io.IOException; +import java.lang.ref.WeakReference; import java.sql.Connection; import java.sql.SQLException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.sql.DataSource; @@ -143,11 +146,13 @@ public class RDBConnectionHandler implem @NotNull private Connection getConnection() throws IllegalStateException, SQLException { long ts = System.currentTimeMillis(); + dumpConnectionMap(ts); Connection c = getDataSource().getConnection(); + remember(c); if (LOG.isDebugEnabled()) { long elapsed = System.currentTimeMillis() - ts; if (elapsed >= 100) { - LOG.debug("Obtaining a new connection from " + this.ds + " took " + elapsed + "ms"); + LOG.debug("Obtaining a new connection from " + this.ds + " took " + elapsed + "ms", new Exception("call stack")); } } return c; @@ -191,4 +196,96 @@ public class RDBConnectionHandler implem } } } + + private static class ConnectionHolder { + public String thread; + public String caller; + public long ts; + + public ConnectionHolder() { + Thread t = Thread.currentThread(); + this.thread = t.getName(); + this.caller = getCaller(t.getStackTrace()); + this.ts = System.currentTimeMillis(); + } + + public long getTimestamp() { + return ts; + } + + public String dump(long now) { + return "(thread=" + thread + ", caller=" + caller + ", age=" + (now - ts) + ")"; + } + } + + private final int LOGTHRESHOLD = 20; + + private ConcurrentMap<WeakReference<Connection>, ConnectionHolder> connectionMap = new ConcurrentHashMap<>(); + + private void dumpConnectionMap(long ts) { + if (LOG.isTraceEnabled()) { + connectionMap.forEach((k, v) -> { + try { + Connection con = k.get(); + if (con == null || con.isClosed()) { + connectionMap.remove(k); + } + } catch (SQLException ex) { + } + }); + + int size = connectionMap.size(); + if (size > 0) { + int cnt = 0; + StringBuilder sb = new StringBuilder(); + for (ConnectionHolder ch : connectionMap.values()) { + if (ts - ch.getTimestamp() >= LOGTHRESHOLD) { + if (cnt != 0) { + sb.append(", "); + } + cnt += 1; + sb.append(ch.dump(ts)); + } + } + if (cnt > 0) { + LOG.trace(cnt + " connections with age >= " + LOGTHRESHOLD + "ms active while obtaining new connection: " + + sb.toString()); + } + } + } + } + + private void remember(Connection c) { + if (LOG.isTraceEnabled()) { + connectionMap.put(new WeakReference<Connection>(c), new ConnectionHolder()); + } + } + + private static String getCaller(StackTraceElement[] elements) { + StringBuilder sb = new StringBuilder(); + String prevClass = null; + for (StackTraceElement e : elements) { + String cn = e.getClassName(); + if (!cn.startsWith(RDBConnectionHandler.class.getName()) && !(cn.startsWith(Thread.class.getName()))) { + if (sb.length() != 0) { + sb.append(" "); + } + if (e.getClassName().equals(prevClass)) { + String loc; + if (e.isNativeMethod()) { + loc = "Native Method"; + } else if (e.getFileName() == null) { + loc = "Unknown Source"; + } else { + loc = e.getFileName() + ":" + e.getLineNumber(); + } + sb.append('.').append(e.getMethodName()).append('(').append(loc).append(')'); + } else { + sb.append(e.toString()); + } + prevClass = e.getClassName(); + } + } + return sb.toString(); + } }