You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by re...@apache.org on 2019/06/19 14:32:54 UTC

svn commit: r1861630 - in /jackrabbit/oak/trunk/oak-store-document/src: main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java

Author: reschke
Date: Wed Jun 19 14:32:54 2019
New Revision: 1861630

URL: http://svn.apache.org/viewvc?rev=1861630&view=rev
Log:
OAK-8411: RDBConnectionHandler: add minimal open connection stats in TRACE log level

Added:
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java?rev=1861630&r1=1861629&r2=1861630&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandler.java Wed Jun 19 14:32:54 2019
@@ -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();
+    }
 }

Added: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java?rev=1861630&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java (added)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java Wed Jun 19 14:32:54 2019
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.document.rdb;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+
+import javax.sql.DataSource;
+
+import org.apache.jackrabbit.oak.commons.junit.LogCustomizer;
+import org.junit.Test;
+import org.slf4j.event.Level;
+
+public class RDBConnectionHandlerTest {
+
+    @Test
+    public void logging() throws Exception {
+        LogCustomizer customLogs = LogCustomizer.forLogger(RDBConnectionHandler.class.getName()).enable(Level.TRACE)
+                .contains("while obtaining new").create();
+        DataSource ds = RDBDataSourceFactory.forJdbcUrl("jdbc:h2:mem:", "", "");
+        Connection c1 = null, c2 = null, c3 = null;
+
+        try (RDBConnectionHandler ch = new RDBConnectionHandler(ds)) {
+            customLogs.starting();
+            c1 = ch.getROConnection();
+            long ts = System.currentTimeMillis();
+            assertEquals(0, customLogs.getLogs().size());
+            c2 = ch.getROConnection();
+            // age threshold not reached
+            assertEquals(0, customLogs.getLogs().size());
+            while (System.currentTimeMillis() - ts < 21) {
+                // busy wait for LOGTHRESHOLD to pass
+            }
+            c3 = ch.getROConnection();
+            assertEquals(1, customLogs.getLogs().size());
+            // System.out.println(customLogs.getLogs());
+        } finally {
+            close(c1);
+            close(c2);
+            close(c3);
+            customLogs.finished();
+        }
+    }
+
+    private static void close(AutoCloseable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (Exception ex) {
+            }
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBConnectionHandlerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native