diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index d309dadcfd..ab3eccbbbb 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -113,13 +113,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private final CountDownLatch initedLatch = new CountDownLatch(2); - private boolean enable = true; + private volatile boolean enable = true; private boolean resetStatEnable = true; private String initStackTrace; - private boolean closed = false; + private volatile boolean closed = false; private long closeTimeMillis = -1L; private JdbcDataSourceStat dataSourceStat; @@ -320,11 +320,14 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat throw new SQLException("interrupt", e); } + boolean init = false; try { if (inited) { return; } + init = true; + initStackTrace = IOUtils.toString(Thread.currentThread().getStackTrace()); this.id = DruidDriver.createDataSourceId(); @@ -343,10 +346,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat throw new IllegalArgumentException("illegal maxActive " + maxActive); } - if (maxIdle <= 0 || maxIdle < minIdle) { - throw new IllegalArgumentException("illegal maxPoolSize"); - } - if (getInitialSize() > maxActive) { throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " + maxActive); @@ -437,7 +436,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat inited = true; lock.unlock(); - if (LOG.isInfoEnabled()) { + if (init && LOG.isInfoEnabled()) { LOG.info("{dataSource-" + this.getID() + "} inited"); } } @@ -669,8 +668,20 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException { - DruidPooledConnection poolalbeConnection; + if (closed) { + connectErrorCount.incrementAndGet(); + throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); + } + if (!enable) { + connectErrorCount.incrementAndGet(); + throw new DataSourceDisableException(); + } + + final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait); + final int maxWaitThreadCount = getMaxWaitThreadCount(); + + DruidConnectionHolder holder; try { lock.lockInterruptibly(); } catch (InterruptedException e) { @@ -679,17 +690,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } try { - if (closed) { - connectErrorCount.incrementAndGet(); - throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); - } - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } - - final int maxWaitThreadCount = getMaxWaitThreadCount(); if (maxWaitThreadCount > 0) { if (notEmptyWaitThreadCount >= maxWaitThreadCount) { connectErrorCount.incrementAndGet(); @@ -700,26 +700,18 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat connectCount++; - DruidConnectionHolder holder; - if (maxWait > 0) { - holder = pollLast(maxWait, TimeUnit.MILLISECONDS); + holder = pollLast(nanos); } else { holder = takeLast(); } - if (holder == null) { - throw new SQLException("can not get connection"); - } - - holder.incrementUseCount(); activeCount++; if (activeCount > activePeak) { activePeak = activeCount; activePeakTime = System.currentTimeMillis(); } - poolalbeConnection = new DruidPooledConnection(holder); } catch (InterruptedException e) { connectErrorCount.incrementAndGet(); throw new SQLException(e.getMessage(), e); @@ -729,6 +721,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } finally { lock.unlock(); } + + holder.incrementUseCount(); + + DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder); return poolalbeConnection; } @@ -815,12 +811,18 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + if (!enable) { + discardConnection(holder.getConnection()); + return; + } + + final long lastActiveTimeMillis = System.currentTimeMillis(); lock.lockInterruptibly(); try { activeCount--; closeCount++; - putLast(holder); + putLast(holder, lastActiveTimeMillis); recycleCount++; } finally { lock.unlock(); @@ -918,18 +920,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } - void putLast(DruidConnectionHolder e) throws SQLException { - if (!enable) { - discardConnection(e.getConnection()); - return; - } - - e.setLastActiveTimeMillis(System.currentTimeMillis()); + void putLast(DruidConnectionHolder e, long lastActiveTimeMillis) throws SQLException { + e.setLastActiveTimeMillis(lastActiveTimeMillis); connections[poolingCount++] = e; if (poolingCount > poolingPeak) { poolingPeak = poolingCount; - poolingPeakTime = System.currentTimeMillis(); + poolingPeakTime = lastActiveTimeMillis; } notEmpty.signal(); @@ -950,7 +947,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat notEmptyWaitThreadCount--; } notEmptyWaitCount++; - + if (!enable) { connectErrorCount.incrementAndGet(); throw new DataSourceDisableException(); @@ -969,8 +966,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return last; } - DruidConnectionHolder pollLast(long timeout, TimeUnit unit) throws InterruptedException, SQLException { - final long nanos = unit.toNanos(timeout); + DruidConnectionHolder pollLast(long nanos) throws InterruptedException, SQLException { long estimate = nanos; for (int i = 0;; ++i) { @@ -993,7 +989,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat // creator notEmptyWaitCount++; notEmptyWaitNanos += (startEstimate - estimate); - + if (!enable) { connectErrorCount.incrementAndGet(); throw new DataSourceDisableException(); @@ -1540,7 +1536,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat buf.append(entry.getKey().getSql()); buf.append("\""); buf.append("\t}"); - + entryIndex++; } } catch (ConcurrentModificationException e) { diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index 79559a2df3..fbf6e386f8 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -15,10 +15,11 @@ */ package com.alibaba.druid.stat; -import com.alibaba.druid.pool.DruidDataSource; +import java.lang.management.ManagementFactory; import java.sql.Driver; import java.sql.DriverManager; import java.util.ArrayList; +import java.util.Date; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.List; @@ -27,6 +28,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import com.alibaba.druid.VERSION; +import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.stat.WebAppStatManager; import com.alibaba.druid.support.spring.stat.SpringStatManager; import com.alibaba.druid.util.DruidDataSourceUtils; @@ -188,6 +190,10 @@ public class DruidStatManagerFacade { dataMap.put("Drivers", getDriversData()); dataMap.put("ResetEnable", isResetEnable()); dataMap.put("ResetCount", getResetCount()); + dataMap.put("JavaVMName", System.getProperty("java.vm.name")); + dataMap.put("JavaVersion", System.getProperty("java.version")); + dataMap.put("JavaClassPath", System.getProperty("java.class.path")); + dataMap.put("StartTime", new Date(ManagementFactory.getRuntimeMXBean().getStartTime())); return dataMap; } diff --git a/src/main/java/com/alibaba/druid/support/console/Option.java b/src/main/java/com/alibaba/druid/support/console/Option.java index 202e541be6..bf59ef4e54 100644 --- a/src/main/java/com/alibaba/druid/support/console/Option.java +++ b/src/main/java/com/alibaba/druid/support/console/Option.java @@ -25,6 +25,7 @@ public class Option { private PrintStyle style = PrintStyle.HORIZONTAL; private int printDataType = 0; private int vmid = -1; + private int id = -1; public void addPrintDataType(int newValue) { this.printDataType= this.printDataType | newValue; @@ -33,7 +34,7 @@ public class Option { public static boolean isPrintHelp(String[] args) { if (args == null ) return true; for (String arg: args) { - if (arg.equals("-h") || arg.equals("--help")) { + if (arg.equals("-help") ) { return true; } } @@ -112,6 +113,13 @@ public class Option { option.setStyle(PrintStyle.HORIZONTAL); } else if (args[i].equals("-s2")) { option.setStyle(PrintStyle.VERTICAL); + } else if (args[i].equals("-id")) { + try { + int id = Integer.parseInt(args[i+1]); + option.setId(id); + } catch (NumberFormatException e) { + throw new OptionParseException("vmid argument is not a integer!"); + } } i++; } @@ -122,7 +130,7 @@ public class Option { } public static void printHelp() { - System.out.println("Usage: druidStat -help | -sql -ds -act -s1 -s2 vmid"); + System.out.println("Usage: druidStat -help | -sql -ds -act -s1 -s2 -id vmid"); System.out.println(); System.out.println("arguments: "); System.out.println(" vmid the process id of jvm that running druid"); @@ -131,8 +139,17 @@ public class Option { System.out.println(" -act print active connection stacktrace data"); System.out.println(" -s1 print field name in first row"); System.out.println(" -s2 print field name in first column"); + System.out.println(" -id only print the sql data matched with id, use this with -sql argument" ); } + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + } diff --git a/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java b/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java index c6b8ece8f5..8645e71a51 100644 --- a/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java +++ b/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java @@ -19,11 +19,26 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.alibaba.druid.sql.SQLUtils; + public class TabledDataPrinter { private static final int SQL_MAX_LEN = 32; - - private static final String[] sqlFields = new String[] { + private static final int MAX_COL = 4; + + private static final String[] sqlRowTitle = new String[] { + "ID", "SQL", "ExecCount", "ExecTime", + "ExecMax","Txn", "Error","Update","FetchRow","Running","Concurrent", + "ExecHisto", "ExecRsHisto","FetchRowHisto","UpdateHisto" }; + + + private static final String[] sqlRowField = new String[] { + "ID", "SQL", "ExecuteCount", "TotalTime", "MaxTimespan", + "InTransactionCount", "ErrorCount", "EffectedRowCount", "FetchRowCount", + "RunningCount","ConcurrentMax","Histogram","ExecuteAndResultHoldTimeHistogram", + "FetchRowCountHistogram","EffectedRowCountHistogram" }; + + private static final String[] sqlColField = new String[] { "ID", "DataSource", "SQL", "ExecuteCount", "ErrorCount", "TotalTime", "LastTime", "MaxTimespan", "LastError", "EffectedRowCount", "FetchRowCount", "MaxTimespanOccurTime", "BatchSizeMax", "BatchSizeTotal", "ConcurrentMax", @@ -33,7 +48,21 @@ public class TabledDataPrinter { "Histogram", "LastSlowParameters", "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram", "EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram", "EffectedRowCountMax", "FetchRowCountMax", "ClobOpenCount" }; - private static final String[] dsFields = new String[] { + + private static final String[] dsRowTitle = new String[] { + "Name", "DbType", + "PoolingCount", "PoolingPeak", "PoolingPeakTime", + "ActiveCount", "ActivePeak", "ActivePeakTime", + "ExecuteCount", "ErrorCount", "CommitCount", "RollbackCount" }; + + private static final String[] dsRowField = new String[] { + "Name", "DbType", + "PoolingCount", "PoolingPeak", "PoolingPeakTime", + "ActiveCount", "ActivePeak", "ActivePeakTime", + "ExecuteCount", "ErrorCount", "CommitCount", "RollbackCount" }; + + + private static final String[] dsColField = new String[] { "Identity", "Name", "DbType", "DriverClassName", "URL", "UserName", "FilterClassNames", "WaitThreadCount", "NotEmptyWaitCount", "NotEmptyWaitMillis", "PoolingCount", "PoolingPeak", "PoolingPeakTime", @@ -60,29 +89,48 @@ public class TabledDataPrinter { public static void printDataSourceData(List> content,Option opt) { if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) { - System.out.println(getFormattedOutput(content, dsFields)); + System.out.println(getFormattedOutput(content, dsRowTitle, dsRowField)); } else { - System.out.println(getVerticalFormattedOutput(content, dsFields)); + System.out.println(getVerticalFormattedOutput(content, dsColField)); } } public static void printSqlData(List> content, Option opt) { + if (opt.getId() != -1) { + List> matchedContent = new ArrayList>(); + for (Map sqlStat : content) { + Integer idStr = (Integer)sqlStat.get("ID"); + if (idStr.intValue() == opt.getId()) { + matchedContent.add(sqlStat); + String dbType = (String) sqlStat.get("DbType"); + String sql = (String) sqlStat.get("SQL"); + System.out.println(SQLUtils.format(sql, dbType)); + System.out.println("===============================\n"); + break; + } + } + content = matchedContent; + + + } if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) { - System.out.println(getFormattedOutput(content, sqlFields)); + System.out.println(getFormattedOutput(content, sqlRowTitle, sqlRowField)); } else { - System.out.println(getVerticalFormattedOutput(content, sqlFields)); + System.out.println(getVerticalFormattedOutput(content, sqlColField)); } } - public static String getFormattedOutput(List> content, String[] titleFields) { + public static String getFormattedOutput(List> content, + String[] title , String[] rowField) { + List printContents = new ArrayList(); - printContents.add(titleFields); + printContents.add(title); for (Map sqlStat : content) { - String[] row = new String[titleFields.length]; - for (int i = 0; i < titleFields.length; ++i) { - Object value = sqlStat.get(titleFields[i]); - row[i] = handleAndConvert(value,titleFields[i]); + String[] row = new String[rowField.length]; + for (int i = 0; i < rowField.length; ++i) { + Object value = sqlStat.get(rowField[i]); + row[i] = handleAndConvert(value,rowField[i]); } printContents.add(row); } @@ -94,10 +142,12 @@ public class TabledDataPrinter { public static String getVerticalFormattedOutput(List> content, String[] titleFields) { List printContents = new ArrayList(); + int maxCol = content.size() > MAX_COL ? MAX_COL: content.size(); + for (int i = 0; i < titleFields.length; ++i) { - String[] row = new String[content.size()+1]; + String[] row = new String[maxCol+1]; row[0] = titleFields[i]; - for (int j=0; j sqlStat = content.get(j); Object value = sqlStat.get(titleFields[i]); row[j+1] = handleAndConvert(value, titleFields[i]); @@ -112,6 +162,8 @@ public class TabledDataPrinter { if (value == null) value = ""; if (fieldName.equals("SQL")) { String sql = (String)value; + sql = sql.replace("\n", " "); + sql = sql.replace("\t", " "); if (sql.length() > SQL_MAX_LEN) { sql = sql.substring(0,SQL_MAX_LEN-3) + "..."; } diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index 41a86f5bd2..61a105951c 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -212,7 +212,8 @@ public class StatViewServlet extends HttpServlet { return; } - if (isRequireAuth() && session.getAttribute(SESSION_USER_KEY) == null + if (isRequireAuth() + && session.getAttribute(SESSION_USER_KEY) == null && !("/login.html".equals(path) || path.startsWith("/css") || path.startsWith("/js") || path.startsWith("/img"))) { if (contextPath == null || contextPath.equals("") || contextPath.equals("/")) { response.sendRedirect("/login.html"); @@ -251,6 +252,15 @@ public class StatViewServlet extends HttpServlet { private void returnResourceFile(String fileName, String uri, HttpServletResponse response) throws ServletException, IOException { + if (fileName.endsWith(".jpg")) { + byte[] bytes = IOUtils.readByteArrayFromResource(RESOURCE_PATH + fileName); + if (bytes != null) { + response.getOutputStream().write(bytes); + } + + return; + } + String text = IOUtils.readFromResource(RESOURCE_PATH + fileName); if (text == null) { response.sendRedirect(uri + "/index.html"); diff --git a/src/main/java/com/alibaba/druid/util/IOUtils.java b/src/main/java/com/alibaba/druid/util/IOUtils.java index 496a1faa2e..eb5cba6956 100644 --- a/src/main/java/com/alibaba/druid/util/IOUtils.java +++ b/src/main/java/com/alibaba/druid/util/IOUtils.java @@ -15,9 +15,11 @@ */ package com.alibaba.druid.util; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; @@ -52,6 +54,37 @@ public class IOUtils { JdbcUtils.close(in); } } + + public static byte[] readByteArrayFromResource(String resource) throws IOException { + InputStream in = null; + try { + in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource); + if (in == null) { + return null; + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(in, output); + return output.toByteArray(); + } finally { + JdbcUtils.close(in); + } + } + + public static long copy(InputStream input, OutputStream output) + throws IOException { + final int EOF = -1; + + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } public static String read(Reader reader) { try { diff --git a/src/main/resources/support/http/resources/img/logo.jpg b/src/main/resources/support/http/resources/img/logo.jpg new file mode 100644 index 0000000000..fe2d4e9dbc Binary files /dev/null and b/src/main/resources/support/http/resources/img/logo.jpg differ diff --git a/src/main/resources/support/http/resources/index.html b/src/main/resources/support/http/resources/index.html index 4e96fc6250..ec9f2730b0 100644 --- a/src/main/resources/support/http/resources/index.html +++ b/src/main/resources/support/http/resources/index.html @@ -23,7 +23,7 @@ - drivers + Drivers @@ -34,6 +34,22 @@ ResetCount + + JavaVersion + + + + JavaVMName + + + + JavaClassPath + + + + StartTime + +