From 29a97d84a1bde5bb8939412e22f143b433f1d904 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 2 Aug 2015 08:55:36 +1200 Subject: [PATCH] No effective change - format only --- .../server/lib/sql/BusyConnectionBuffer.java | 338 ++-- .../server/lib/sql/DataSourceAlert.java | 24 +- .../server/lib/sql/DataSourcePool.java | 1722 ++++++++--------- .../lib/sql/DataSourcePoolListener.java | 18 +- .../lib/sql/DataSourcePoolStatistics.java | 8 +- .../lib/sql/ExtendedPreparedStatement.java | 629 +++--- .../server/lib/sql/ExtendedStatement.java | 537 +++-- .../server/lib/sql/FreeConnectionBuffer.java | 10 +- .../server/lib/sql/PooledConnectionQueue.java | 954 ++++----- .../lib/sql/PooledConnectionStatistics.java | 40 +- .../ebeaninternal/server/lib/sql/Prefix.java | 144 +- .../server/lib/sql/PstmtCache.java | 276 +-- .../server/lib/sql/TransactionIsolation.java | 106 +- .../ebeaninternal/server/lib/sql/package.html | 4 +- 14 files changed, 2401 insertions(+), 2409 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java index e10b8d3b6..f37a03a80 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java @@ -17,187 +17,185 @@ import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadVal * and this allows for fast addition and removal (by slotId without looping). * The capacity will increase on demand by the 'growBy' amount. *

- * + * * @author rbygrave - * */ class BusyConnectionBuffer { - private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class); - - private PooledConnection[] slots; - - private final int growBy; - - private int size; - - private int pos = -1; - - /** - * Create the buffer with an initial capacity and fixed growBy. - * We generally do not want the buffer to grow very often. - * - * @param capacity - * the initial capacity - * @param growBy - * the fixed amount to grow the buffer by. - */ - protected BusyConnectionBuffer(int capacity, int growBy) { - this.slots = new PooledConnection[capacity]; - this.growBy = growBy; - } - - /** - * We can only grow (not shrink) the capacity. - */ - protected void setCapacity(int newCapacity) { - if (newCapacity > slots.length){ - PooledConnection[] current = this.slots; - this.slots = new PooledConnection[newCapacity]; - System.arraycopy(current, 0, this.slots, 0, current.length); - } - } - - public String toString() { - return Arrays.toString(slots); - } - - protected int getCapacity() { - return slots.length; - } - - protected int size(){ - return size; - } - - protected boolean isEmpty() { - return size == 0; - } - - protected int add(PooledConnection pc){ - if (size == slots.length){ - // grow the capacity - setCapacity(slots.length + growBy); - } - int slot = nextEmptySlot(); - pc.setSlotId(slot); - slots[slot] = pc; - return ++size; - } - - protected boolean remove(PooledConnection pc) { - - int slotId = pc.getSlotId(); - if (slots[slotId] != pc){ - PooledConnection heldBy = slots[slotId]; - logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy); - return false; - } - slots[slotId] = null; - --size; - return true; - } - - /** - * Collect the load statistics from all the busy connections. - * @param reset - */ - protected void collectStatistics(LoadValues values, boolean reset) { - - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null){ - values.plus(slots[i].getStatistics().getValues(reset)); - } - } - } - - /** - * Close connections that should be considered leaked. - */ - protected void closeBusyConnections(long leakTimeMinutes) { + private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class); - long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes*60000); + private PooledConnection[] slots; - logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes); + private final int growBy; - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null){ - //tmp.add(slots[i]); - PooledConnection pc = slots[i]; - //noinspection StatementWithEmptyBody - if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) { - // PooledConnection has been used recently or - // expected to be longRunning so not closing... - } else { - slots[i] = null; - --size; - closeBusyConnection(pc); - } - } - } - } - - private void closeBusyConnection(PooledConnection pc) { - try { - - logger.warn("DataSourcePool closing busy connection? "+pc.getFullDescription()); - System.out.println("CLOSING busy connection: "+pc.getFullDescription()); - - pc.closeConnectionFully(false); + private int size; - } catch (Exception ex) { - // this should never actually happen - logger.error("Error when closing potentially leaked connection "+pc.getDescription(), ex); - } + private int pos = -1; + + /** + * Create the buffer with an initial capacity and fixed growBy. + * We generally do not want the buffer to grow very often. + * + * @param capacity the initial capacity + * @param growBy the fixed amount to grow the buffer by. + */ + protected BusyConnectionBuffer(int capacity, int growBy) { + this.slots = new PooledConnection[capacity]; + this.growBy = growBy; } - - /** - * Returns information describing connections that are currently being used. - */ - protected String getBusyConnectionInformation(boolean toLogger) { - - if (toLogger) { - logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size()); - } - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null){ - PooledConnection pc = slots[i]; - if (toLogger) { - logger.info("Busy Connection - {}", pc.getFullDescription()); - } else { - sb.append(pc.getFullDescription()).append("\r\n"); - } - } - } - - return sb.toString(); + /** + * We can only grow (not shrink) the capacity. + */ + protected void setCapacity(int newCapacity) { + if (newCapacity > slots.length) { + PooledConnection[] current = this.slots; + this.slots = new PooledConnection[newCapacity]; + System.arraycopy(current, 0, this.slots, 0, current.length); } - - - /** - * Return the position of the next empty slot. - */ - private int nextEmptySlot() { + } - // search forward - while(++pos < slots.length) { - if (slots[pos] == null){ - return pos; - } - } - // search from beginning - pos = -1; - while(++pos < slots.length) { - if (slots[pos] == null){ - return pos; - } - } - - // not expecting this - throw new RuntimeException("No Empty Slot Found?"); + public String toString() { + return Arrays.toString(slots); + } + + protected int getCapacity() { + return slots.length; + } + + protected int size() { + return size; + } + + protected boolean isEmpty() { + return size == 0; + } + + protected int add(PooledConnection pc) { + if (size == slots.length) { + // grow the capacity + setCapacity(slots.length + growBy); } - + int slot = nextEmptySlot(); + pc.setSlotId(slot); + slots[slot] = pc; + return ++size; + } + + protected boolean remove(PooledConnection pc) { + + int slotId = pc.getSlotId(); + if (slots[slotId] != pc) { + PooledConnection heldBy = slots[slotId]; + logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy); + return false; + } + slots[slotId] = null; + --size; + return true; + } + + /** + * Collect the load statistics from all the busy connections. + * + * @param reset + */ + protected void collectStatistics(LoadValues values, boolean reset) { + + for (int i = 0; i < slots.length; i++) { + if (slots[i] != null) { + values.plus(slots[i].getStatistics().getValues(reset)); + } + } + } + + /** + * Close connections that should be considered leaked. + */ + protected void closeBusyConnections(long leakTimeMinutes) { + + long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes * 60000); + + logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes); + + for (int i = 0; i < slots.length; i++) { + if (slots[i] != null) { + //tmp.add(slots[i]); + PooledConnection pc = slots[i]; + //noinspection StatementWithEmptyBody + if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) { + // PooledConnection has been used recently or + // expected to be longRunning so not closing... + } else { + slots[i] = null; + --size; + closeBusyConnection(pc); + } + } + } + } + + private void closeBusyConnection(PooledConnection pc) { + try { + + logger.warn("DataSourcePool closing busy connection? " + pc.getFullDescription()); + System.out.println("CLOSING busy connection: " + pc.getFullDescription()); + + pc.closeConnectionFully(false); + + } catch (Exception ex) { + // this should never actually happen + logger.error("Error when closing potentially leaked connection " + pc.getDescription(), ex); + } + } + + /** + * Returns information describing connections that are currently being used. + */ + protected String getBusyConnectionInformation(boolean toLogger) { + + if (toLogger) { + logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size()); + } + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < slots.length; i++) { + if (slots[i] != null) { + PooledConnection pc = slots[i]; + if (toLogger) { + logger.info("Busy Connection - {}", pc.getFullDescription()); + } else { + sb.append(pc.getFullDescription()).append("\r\n"); + } + } + } + + return sb.toString(); + } + + + /** + * Return the position of the next empty slot. + */ + private int nextEmptySlot() { + + // search forward + while (++pos < slots.length) { + if (slots[pos] == null) { + return pos; + } + } + // search from beginning + pos = -1; + while (++pos < slots.length) { + if (slots[pos] == null) { + return pos; + } + } + + // not expecting this + throw new RuntimeException("No Empty Slot Found?"); + } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java index 284ea06fd..863defa15 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java @@ -10,18 +10,18 @@ package com.avaje.ebeaninternal.server.lib.sql; */ public interface DataSourceAlert { - /** - * Send an alert to say the dataSource is back up. - */ - void dataSourceUp(String dataSourceName); + /** + * Send an alert to say the dataSource is back up. + */ + void dataSourceUp(String dataSourceName); - /** - * Send an alert to say the dataSource is down. - */ - void dataSourceDown(String dataSourceName); + /** + * Send an alert to say the dataSource is down. + */ + void dataSourceDown(String dataSourceName); - /** - * Send an alert to say the dataSource is getting close to its max size. - */ - void dataSourceWarning(String subject, String msg); + /** + * Send an alert to say the dataSource is getting close to its max size. + */ + void dataSourceWarning(String subject, String msg); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java index 9e2eb66aa..3401e5947 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java @@ -37,982 +37,980 @@ import com.avaje.ebeaninternal.api.ClassUtil; */ public class DataSourcePool implements DataSource { - private static final Logger logger = LoggerFactory.getLogger(DataSourcePool.class); + private static final Logger logger = LoggerFactory.getLogger(DataSourcePool.class); - /** - * The name given to this dataSource. - */ - private final String name; + /** + * The name given to this dataSource. + */ + private final String name; - /** - * Used to notify of changes to the DataSource status. - */ - private final DataSourceAlert notify; + /** + * Used to notify of changes to the DataSource status. + */ + private final DataSourceAlert notify; - /** - * Optional listener that can be notified when connections are got from and - * put back into the pool. - */ - private final DataSourcePoolListener poolListener; + /** + * Optional listener that can be notified when connections are got from and + * put back into the pool. + */ + private final DataSourcePoolListener poolListener; - /** - * Properties used to create a Connection. - */ - private final Properties connectionProps; + /** + * Properties used to create a Connection. + */ + private final Properties connectionProps; - /** - * The jdbc connection url. - */ - private final String databaseUrl; + /** + * The jdbc connection url. + */ + private final String databaseUrl; - /** - * The jdbc driver. - */ - private final String databaseDriver; + /** + * The jdbc driver. + */ + private final String databaseDriver; - /** - * The sql used to test a connection. - */ - private final String heartbeatsql; - - private final int heartbeatFreqSecs; - - private final int heartbeatTimeoutSeconds; - + /** + * The sql used to test a connection. + */ + private final String heartbeatsql; - private final long trimPoolFreqMillis; + private final int heartbeatFreqSecs; - /** - * The transaction isolation level as per java.sql.Connection. - */ - private final int transactionIsolation; + private final int heartbeatTimeoutSeconds; - /** - * The default autoCommit setting for Connections in this pool. - */ - private final boolean autoCommit; - /** - * Max idle time in millis. - */ - private final int maxInactiveMillis; - - /** - * Max age a connection is allowed in millis. - * A value of 0 means no limit (no trimming based on max age). - */ - private final long maxAgeMillis; + private final long trimPoolFreqMillis; - /** - * Flag set to true to capture stackTraces (can be expensive). - */ - private boolean captureStackTrace; + /** + * The transaction isolation level as per java.sql.Connection. + */ + private final int transactionIsolation; - /** - * The max size of the stack trace to report. - */ - private final int maxStackTraceSize; + /** + * The default autoCommit setting for Connections in this pool. + */ + private final boolean autoCommit; - /** - * flag to indicate we have sent an alert message. - */ - private boolean dataSourceDownAlertSent; + /** + * Max idle time in millis. + */ + private final int maxInactiveMillis; - /** - * The time the pool was last trimmed. - */ - private long lastTrimTime; + /** + * Max age a connection is allowed in millis. + * A value of 0 means no limit (no trimming based on max age). + */ + private final long maxAgeMillis; - /** - * Assume that the DataSource is up. heartBeat checking will discover when - * it goes down, and comes back up again. - */ - private boolean dataSourceUp = true; + /** + * Flag set to true to capture stackTraces (can be expensive). + */ + private boolean captureStackTrace; - /** - * The current alert. - */ - private boolean inWarningMode; + /** + * The max size of the stack trace to report. + */ + private final int maxStackTraceSize; - /** - * The minimum number of connections this pool will maintain. - */ - private int minConnections; + /** + * flag to indicate we have sent an alert message. + */ + private boolean dataSourceDownAlertSent; - /** - * The maximum number of connections this pool will grow to. - */ - private int maxConnections; + /** + * The time the pool was last trimmed. + */ + private long lastTrimTime; - /** - * The number of connections to exceed before a warning Alert is fired. - */ - private int warningSize; + /** + * Assume that the DataSource is up. heartBeat checking will discover when + * it goes down, and comes back up again. + */ + private boolean dataSourceUp = true; - /** - * The time a thread will wait for a connection to become available. - */ - private final int waitTimeoutMillis; + /** + * The current alert. + */ + private boolean inWarningMode; - /** - * The size of the preparedStatement cache; - */ - private int pstmtCacheSize; + /** + * The minimum number of connections this pool will maintain. + */ + private int minConnections; - private final PooledConnectionQueue queue; + /** + * The maximum number of connections this pool will grow to. + */ + private int maxConnections; - /** - * Used to find and close() leaked connections. Leaked connections are - * thought to be busy but have not been used for some time. Each time a - * connection is used it sets it's lastUsedTime. - */ - private long leakTimeMinutes; + /** + * The number of connections to exceed before a warning Alert is fired. + */ + private int warningSize; - private final Runnable heartbeatRunnable = new HeartBeatRunnable(); - - public DataSourcePool(DataSourceAlert notify, String name, DataSourceConfig params) { + /** + * The time a thread will wait for a connection to become available. + */ + private final int waitTimeoutMillis; - this.notify = notify; - this.name = name; - this.poolListener = createPoolListener(params.getPoolListener()); + /** + * The size of the preparedStatement cache; + */ + private int pstmtCacheSize; - this.autoCommit = params.isAutoCommit(); - this.transactionIsolation = params.getIsolationLevel(); - - this.maxInactiveMillis = 1000 * params.getMaxInactiveTimeSecs(); - this.maxAgeMillis = 60000 * params.getMaxAgeMinutes(); - this.leakTimeMinutes = params.getLeakTimeMinutes(); - this.captureStackTrace = params.isCaptureStackTrace(); - this.maxStackTraceSize = params.getMaxStackTraceSize(); - this.databaseDriver = params.getDriver(); - this.databaseUrl = params.getUrl(); - this.pstmtCacheSize = params.getPstmtCacheSize(); + private final PooledConnectionQueue queue; - this.minConnections = params.getMinConnections(); - this.maxConnections = params.getMaxConnections(); - this.waitTimeoutMillis = params.getWaitTimeoutMillis(); - this.heartbeatsql = params.getHeartbeatSql(); - this.heartbeatFreqSecs = params.getHeartbeatFreqSecs(); - this.heartbeatTimeoutSeconds = params.getHeartbeatTimeoutSeconds(); - this.trimPoolFreqMillis = 1000 * params.getTrimPoolFreqSecs(); - - queue = new PooledConnectionQueue(this); + /** + * Used to find and close() leaked connections. Leaked connections are + * thought to be busy but have not been used for some time. Each time a + * connection is used it sets it's lastUsedTime. + */ + private long leakTimeMinutes; - String un = params.getUsername(); - String pw = params.getPassword(); - if (un == null) { - throw new RuntimeException("DataSource user is null?"); - } - if (pw == null) { - throw new RuntimeException("DataSource password is null?"); - } - this.connectionProps = new Properties(); - this.connectionProps.setProperty("user", un); - this.connectionProps.setProperty("password", pw); - - Map customProperties = params.getCustomProperties(); - if (customProperties != null){ - Set> entrySet = customProperties.entrySet(); - for (Entry entry : entrySet) { - this.connectionProps.setProperty(entry.getKey(), entry.getValue()); - } - } + private final Runnable heartbeatRunnable = new HeartBeatRunnable(); - try { - initialise(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } + public DataSourcePool(DataSourceAlert notify, String name, DataSourceConfig params) { + + this.notify = notify; + this.name = name; + this.poolListener = createPoolListener(params.getPoolListener()); + + this.autoCommit = params.isAutoCommit(); + this.transactionIsolation = params.getIsolationLevel(); + + this.maxInactiveMillis = 1000 * params.getMaxInactiveTimeSecs(); + this.maxAgeMillis = 60000 * params.getMaxAgeMinutes(); + this.leakTimeMinutes = params.getLeakTimeMinutes(); + this.captureStackTrace = params.isCaptureStackTrace(); + this.maxStackTraceSize = params.getMaxStackTraceSize(); + this.databaseDriver = params.getDriver(); + this.databaseUrl = params.getUrl(); + this.pstmtCacheSize = params.getPstmtCacheSize(); + + this.minConnections = params.getMinConnections(); + this.maxConnections = params.getMaxConnections(); + this.waitTimeoutMillis = params.getWaitTimeoutMillis(); + this.heartbeatsql = params.getHeartbeatSql(); + this.heartbeatFreqSecs = params.getHeartbeatFreqSecs(); + this.heartbeatTimeoutSeconds = params.getHeartbeatTimeoutSeconds(); + this.trimPoolFreqMillis = 1000 * params.getTrimPoolFreqSecs(); + + queue = new PooledConnectionQueue(this); + + String un = params.getUsername(); + String pw = params.getPassword(); + if (un == null) { + throw new RuntimeException("DataSource user is null?"); } - - class HeartBeatRunnable implements Runnable { - @Override - public void run() { - checkDataSource(); + if (pw == null) { + throw new RuntimeException("DataSource password is null?"); + } + this.connectionProps = new Properties(); + this.connectionProps.setProperty("user", un); + this.connectionProps.setProperty("password", pw); + + Map customProperties = params.getCustomProperties(); + if (customProperties != null) { + Set> entrySet = customProperties.entrySet(); + for (Entry entry : entrySet) { + this.connectionProps.setProperty(entry.getKey(), entry.getValue()); } } - + try { + initialise(); + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + } + + class HeartBeatRunnable implements Runnable { @Override - public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException("We do not support java.util.logging"); + public void run() { + checkDataSource(); + } + } + + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException("We do not support java.util.logging"); + } + + /** + * Create the DataSourcePoolListener if there is one. + */ + private DataSourcePoolListener createPoolListener(String cn) { + if (cn == null) { + return null; + } + try { + return (DataSourcePoolListener) ClassUtil.newInstance(cn, this.getClass()); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + private void initialise() throws SQLException { + + // Ensure database driver is loaded + try { + ClassUtil.forName(this.databaseDriver, this.getClass()); + } catch (Throwable e) { + throw new PersistenceException("Problem loading Database Driver [" + this.databaseDriver + "]: " + + e.getMessage(), e); } - /** - * Create the DataSourcePoolListener if there is one. - */ - private DataSourcePoolListener createPoolListener(String cn) { - if (cn == null) { - return null; - } - try { - return (DataSourcePoolListener)ClassUtil.newInstance(cn, this.getClass()); - } catch (Exception e) { - throw new IllegalArgumentException(e); - } - } + String transIsolation = TransactionIsolation.getLevelDescription(transactionIsolation); + //noinspection StringBufferReplaceableByString + StringBuilder sb = new StringBuilder(70); + sb.append("DataSourcePool [").append(name); + sb.append("] autoCommit[").append(autoCommit); + sb.append("] transIsolation[").append(transIsolation); + sb.append("] min[").append(minConnections); + sb.append("] max[").append(maxConnections).append("]"); - private void initialise() throws SQLException { + logger.info(sb.toString()); - // Ensure database driver is loaded - try { - ClassUtil.forName(this.databaseDriver, this.getClass()); - } catch (Throwable e) { - throw new PersistenceException("Problem loading Database Driver [" + this.databaseDriver + "]: " - + e.getMessage(), e); - } + queue.ensureMinimumConnections(); + } - String transIsolation = TransactionIsolation.getLevelDescription(transactionIsolation); - //noinspection StringBufferReplaceableByString - StringBuilder sb = new StringBuilder(70); - sb.append("DataSourcePool [").append(name); - sb.append("] autoCommit[").append(autoCommit); - sb.append("] transIsolation[").append(transIsolation); - sb.append("] min[").append(minConnections); - sb.append("] max[").append(maxConnections).append("]"); + /** + * Returns false. + */ + public boolean isWrapperFor(Class arg0) throws SQLException { + return false; + } - logger.info(sb.toString()); + /** + * Not Implemented. + */ + public T unwrap(Class arg0) throws SQLException { + throw new SQLException("Not Implemented"); + } - queue.ensureMinimumConnections(); - } + /** + * Return the dataSource name. + */ + public String getName() { + return name; + } - /** - * Returns false. - */ - public boolean isWrapperFor(Class arg0) throws SQLException { - return false; - } + /** + * Return the max size of stack traces used when trying to find connection pool leaks. + *

+ * This is only used when {@link #isCaptureStackTrace()} is true. + *

+ */ + public int getMaxStackTraceSize() { + return maxStackTraceSize; + } - /** - * Not Implemented. - */ - public T unwrap(Class arg0) throws SQLException { - throw new SQLException("Not Implemented"); - } + /** + * Returns false when the dataSource is down. + */ + public boolean isDataSourceUp() { + return dataSourceUp; + } - /** - * Return the dataSource name. - */ - public String getName() { - return name; - } + /** + * Called when the pool hits the warning level. + */ + protected void notifyWarning(String msg) { - /** - * Return the max size of stack traces used when trying to find connection pool leaks. - *

- * This is only used when {@link #isCaptureStackTrace()} is true. - *

- */ - public int getMaxStackTraceSize() { - return maxStackTraceSize; - } - - /** - * Returns false when the dataSource is down. - */ - public boolean isDataSourceUp() { - return dataSourceUp; - } - - /** - * Called when the pool hits the warning level. - */ - protected void notifyWarning(String msg) { - - if (!inWarningMode) { - // send an Error to the event log... - inWarningMode = true; - logger.warn(msg); - if (notify != null) { - String subject = "DataSourcePool [" + name + "] warning"; - notify.dataSourceWarning(subject, msg); - } - } - } - - private void notifyDataSourceIsDown(SQLException ex) { - - if (!dataSourceDownAlertSent) { - logger.error("FATAL: DataSourcePool [" + name + "] is down or has network error!!!", ex); - if (notify != null) { - notify.dataSourceDown(name); - } - dataSourceDownAlertSent = true; - } - if (dataSourceUp) { - reset(); - } - dataSourceUp = false; - } - - private void notifyDataSourceIsUp() { - if (dataSourceDownAlertSent) { - logger.error("RESOLVED FATAL: DataSourcePool [" + name + "] is back up!"); - if (notify != null) { - notify.dataSourceUp(name); - } - dataSourceDownAlertSent = false; - - } else if (!dataSourceUp) { - logger.info("DataSourcePool [" + name + "] is back up!"); - } - - if (!dataSourceUp) { - dataSourceUp = true; - reset(); - } - } - - - /** - * Return the heartbeat frequency in seconds. - *

- * This is the frequency that the heartbeat runnable should be run. - *

- */ - public int getHeartbeatFreqSecs() { - return heartbeatFreqSecs; - } - - /** - * Returns the Runnable used to check the dataSource using a heartbeat query. - */ - public Runnable getHeartbeatRunnable() { - return heartbeatRunnable; - } - - /** - * Trim connections (in the free list) based on idle time and maximum age. - */ - private void trimIdleConnections() { - if (System.currentTimeMillis() > (lastTrimTime + trimPoolFreqMillis)) { - try { - queue.trim(maxInactiveMillis, maxAgeMillis); - lastTrimTime = System.currentTimeMillis(); - } catch (Exception e) { - logger.error("Error trying to trim idle connections", e); - } + if (!inWarningMode) { + // send an Error to the event log... + inWarningMode = true; + logger.warn(msg); + if (notify != null) { + String subject = "DataSourcePool [" + name + "] warning"; + notify.dataSourceWarning(subject, msg); } } - - /** - * Check the dataSource is up. Trim connections. - *

- * This is called by the HeartbeatRunnable which should be scheduled to - * run periodically (every heartbeatFreqSecs seconds actually). - *

- */ - public void checkDataSource() { - - // first trim idle connections - trimIdleConnections(); - - Connection conn = null; - try { - // Get a connection from the pool and test it - conn = getConnection(); - if (testConnection(conn)) { - notifyDataSourceIsUp(); - - } else { - notifyDataSourceIsDown(null); - } + } - } catch (SQLException ex) { - notifyDataSourceIsDown(ex); - - } finally { - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ex) { - logger.warn("Can't close connection in checkDataSource!"); - } + private void notifyDataSourceIsDown(SQLException ex) { + + if (!dataSourceDownAlertSent) { + logger.error("FATAL: DataSourcePool [" + name + "] is down or has network error!!!", ex); + if (notify != null) { + notify.dataSourceDown(name); + } + dataSourceDownAlertSent = true; + } + if (dataSourceUp) { + reset(); + } + dataSourceUp = false; + } + + private void notifyDataSourceIsUp() { + if (dataSourceDownAlertSent) { + logger.error("RESOLVED FATAL: DataSourcePool [" + name + "] is back up!"); + if (notify != null) { + notify.dataSourceUp(name); + } + dataSourceDownAlertSent = false; + + } else if (!dataSourceUp) { + logger.info("DataSourcePool [" + name + "] is back up!"); + } + + if (!dataSourceUp) { + dataSourceUp = true; + reset(); + } + } + + + /** + * Return the heartbeat frequency in seconds. + *

+ * This is the frequency that the heartbeat runnable should be run. + *

+ */ + public int getHeartbeatFreqSecs() { + return heartbeatFreqSecs; + } + + /** + * Returns the Runnable used to check the dataSource using a heartbeat query. + */ + public Runnable getHeartbeatRunnable() { + return heartbeatRunnable; + } + + /** + * Trim connections (in the free list) based on idle time and maximum age. + */ + private void trimIdleConnections() { + if (System.currentTimeMillis() > (lastTrimTime + trimPoolFreqMillis)) { + try { + queue.trim(maxInactiveMillis, maxAgeMillis); + lastTrimTime = System.currentTimeMillis(); + } catch (Exception e) { + logger.error("Error trying to trim idle connections", e); + } + } + } + + /** + * Check the dataSource is up. Trim connections. + *

+ * This is called by the HeartbeatRunnable which should be scheduled to + * run periodically (every heartbeatFreqSecs seconds actually). + *

+ */ + public void checkDataSource() { + + // first trim idle connections + trimIdleConnections(); + + Connection conn = null; + try { + // Get a connection from the pool and test it + conn = getConnection(); + if (testConnection(conn)) { + notifyDataSourceIsUp(); + + } else { + notifyDataSourceIsDown(null); + } + + } catch (SQLException ex) { + notifyDataSourceIsDown(ex); + + } finally { + try { + if (conn != null) { + conn.close(); } + } catch (SQLException ex) { + logger.warn("Can't close connection in checkDataSource!"); + } } + } - /** - * Create a Connection that will not be part of the connection pool. - * - *

- * When this connection is closed it will not go back into the pool. - *

- * - *

- * If withDefaults is true then the Connection will have the autoCommit and - * transaction isolation set to the defaults for the pool. - *

- */ - public Connection createUnpooledConnection() throws SQLException { + /** + * Create a Connection that will not be part of the connection pool. + *

+ *

+ * When this connection is closed it will not go back into the pool. + *

+ *

+ *

+ * If withDefaults is true then the Connection will have the autoCommit and + * transaction isolation set to the defaults for the pool. + *

+ */ + public Connection createUnpooledConnection() throws SQLException { - try { - Connection conn = DriverManager.getConnection(databaseUrl, connectionProps); - conn.setAutoCommit(autoCommit); - conn.setTransactionIsolation(transactionIsolation); - return conn; + try { + Connection conn = DriverManager.getConnection(databaseUrl, connectionProps); + conn.setAutoCommit(autoCommit); + conn.setTransactionIsolation(transactionIsolation); + return conn; - } catch (SQLException ex) { - notifyDataSourceIsDown(null); - throw ex; - } + } catch (SQLException ex) { + notifyDataSourceIsDown(null); + throw ex; } + } - /** - * Set a new maximum size. The pool should respect this new maximum - * immediately and not require a restart. You may want to increase the - * maxConnections if the pool gets large and hits the warning level. - */ - public void setMaxSize(int max) { - queue.setMaxSize(max); - this.maxConnections = max; - } + /** + * Set a new maximum size. The pool should respect this new maximum + * immediately and not require a restart. You may want to increase the + * maxConnections if the pool gets large and hits the warning level. + */ + public void setMaxSize(int max) { + queue.setMaxSize(max); + this.maxConnections = max; + } - /** - * Return the max size this pool can grow to. - */ - public int getMaxSize() { - return maxConnections; - } + /** + * Return the max size this pool can grow to. + */ + public int getMaxSize() { + return maxConnections; + } - /** - * Set the min size this pool should maintain. - */ - public void setMinSize(int min) { - queue.setMinSize(min); - this.minConnections = min; - } + /** + * Set the min size this pool should maintain. + */ + public void setMinSize(int min) { + queue.setMinSize(min); + this.minConnections = min; + } - /** - * Return the min size this pool should maintain. - */ - public int getMinSize() { - return minConnections; - } + /** + * Return the min size this pool should maintain. + */ + public int getMinSize() { + return minConnections; + } - /** - * Set a new maximum size. The pool should respect this new maximum - * immediately and not require a restart. You may want to increase the - * maxConnections if the pool gets large and hits the warning and or alert - * levels. - */ - public void setWarningSize(int warningSize) { - queue.setWarningSize(warningSize); - this.warningSize = warningSize; - } + /** + * Set a new maximum size. The pool should respect this new maximum + * immediately and not require a restart. You may want to increase the + * maxConnections if the pool gets large and hits the warning and or alert + * levels. + */ + public void setWarningSize(int warningSize) { + queue.setWarningSize(warningSize); + this.warningSize = warningSize; + } - /** - * Return the warning size. When the pool hits this size it can send a - * notify message to an administrator. - */ - public int getWarningSize() { - return warningSize; - } + /** + * Return the warning size. When the pool hits this size it can send a + * notify message to an administrator. + */ + public int getWarningSize() { + return warningSize; + } - /** - * Return the time in millis that threads will wait when the pool has hit - * the max size. These threads wait for connections to be returned by the - * busy connections. - */ - public int getWaitTimeoutMillis() { - return waitTimeoutMillis; - } + /** + * Return the time in millis that threads will wait when the pool has hit + * the max size. These threads wait for connections to be returned by the + * busy connections. + */ + public int getWaitTimeoutMillis() { + return waitTimeoutMillis; + } + + /** + * Return the time after which inactive connections are trimmed. + */ + public int getMaxInactiveMillis() { + return maxInactiveMillis; + } - /** - * Return the time after which inactive connections are trimmed. - */ - public int getMaxInactiveMillis() { - return maxInactiveMillis; - } - /** * Return the maximum age a connection is allowed to be before it is trimmed * out of the pool. This value can be 0 which means there is no maximum age. */ - public long getMaxAgeMillis() { - return maxAgeMillis; + public long getMaxAgeMillis() { + return maxAgeMillis; + } + + private boolean testConnection(Connection conn) throws SQLException { + + if (heartbeatsql == null) { + return conn.isValid(heartbeatTimeoutSeconds); } - - private boolean testConnection(Connection conn) throws SQLException { - - if (heartbeatsql == null) { - return conn.isValid(heartbeatTimeoutSeconds); - } - Statement stmt = null; - ResultSet rset = null; - try { - // It should only error IF the DataSource is down or a network issue - stmt = conn.createStatement(); - if (heartbeatTimeoutSeconds > 0) { - stmt.setQueryTimeout(heartbeatTimeoutSeconds); - } - rset = stmt.executeQuery(heartbeatsql); - conn.commit(); - - return true; - - } finally { - try { - if (rset != null) { - rset.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } - try { - if (stmt != null) { - stmt.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } - } - } - - /** - * Make sure the connection is still ok to use. If not then remove it from - * the pool. - */ - protected boolean validateConnection(PooledConnection conn) { - try { - return testConnection(conn); - - } catch (Exception e) { - logger.warn("heartbeatsql test failed on connection[" + conn.getName() + "]"); - return false; - } - } - - /** - * Called by the PooledConnection themselves, returning themselves to the - * pool when they have been finished with. - *

- * Note that connections may not be added back to the pool if returnToPool - * is false or if they where created before the recycleTime. In both of - * these cases the connection is fully closed and not pooled. - *

- * - * @param pooledConnection - * the returning connection - * - */ - protected void returnConnection(PooledConnection pooledConnection) { - - // return a normal 'good' connection - returnTheConnection(pooledConnection, false); - } - - /** - * This is a bad connection and must be removed from the pool's busy list and fully closed. - */ - protected void returnConnectionForceClose(PooledConnection pooledConnection) { - - returnTheConnection(pooledConnection, true); - } - - /** - * Return connection. If forceClose is true then this is a bad connection that - * must be removed and closed fully. - */ - private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) { - - if (poolListener != null && !forceClose) { - poolListener.onBeforeReturnConnection(pooledConnection); + Statement stmt = null; + ResultSet rset = null; + try { + // It should only error IF the DataSource is down or a network issue + stmt = conn.createStatement(); + if (heartbeatTimeoutSeconds > 0) { + stmt.setQueryTimeout(heartbeatTimeoutSeconds); } - queue.returnPooledConnection(pooledConnection, forceClose); - - if (forceClose) { - // Got a bad connection so check the pool - checkDataSource(); + rset = stmt.executeQuery(heartbeatsql); + conn.commit(); + + return true; + + } finally { + try { + if (rset != null) { + rset.close(); + } + } catch (SQLException e) { + logger.error(null, e); + } + try { + if (stmt != null) { + stmt.close(); + } + } catch (SQLException e) { + logger.error(null, e); } } + } - /** - * Collect statistics of a connection that is fully closing - */ - protected void reportClosingConnection(PooledConnection pooledConnection) { - - queue.reportClosingConnection(pooledConnection); + /** + * Make sure the connection is still ok to use. If not then remove it from + * the pool. + */ + protected boolean validateConnection(PooledConnection conn) { + try { + return testConnection(conn); + + } catch (Exception e) { + logger.warn("heartbeatsql test failed on connection[" + conn.getName() + "]"); + return false; } - - /** - * Returns information describing connections that are currently being used. - */ - public String getBusyConnectionInformation() { + } - return queue.getBusyConnectionInformation(); + /** + * Called by the PooledConnection themselves, returning themselves to the + * pool when they have been finished with. + *

+ * Note that connections may not be added back to the pool if returnToPool + * is false or if they where created before the recycleTime. In both of + * these cases the connection is fully closed and not pooled. + *

+ * + * @param pooledConnection the returning connection + */ + protected void returnConnection(PooledConnection pooledConnection) { + + // return a normal 'good' connection + returnTheConnection(pooledConnection, false); + } + + /** + * This is a bad connection and must be removed from the pool's busy list and fully closed. + */ + protected void returnConnectionForceClose(PooledConnection pooledConnection) { + + returnTheConnection(pooledConnection, true); + } + + /** + * Return connection. If forceClose is true then this is a bad connection that + * must be removed and closed fully. + */ + private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) { + + if (poolListener != null && !forceClose) { + poolListener.onBeforeReturnConnection(pooledConnection); + } + queue.returnPooledConnection(pooledConnection, forceClose); + + if (forceClose) { + // Got a bad connection so check the pool + checkDataSource(); + } + } + + /** + * Collect statistics of a connection that is fully closing + */ + protected void reportClosingConnection(PooledConnection pooledConnection) { + + queue.reportClosingConnection(pooledConnection); + } + + /** + * Returns information describing connections that are currently being used. + */ + public String getBusyConnectionInformation() { + + return queue.getBusyConnectionInformation(); + } + + /** + * Dumps the busy connection information to the logs. + *

+ * This includes the stackTrace elements if they are being captured. This is + * useful when needing to look a potential connection pool leaks. + *

+ */ + public void dumpBusyConnectionInformation() { + + queue.dumpBusyConnectionInformation(); + } + + /** + * Close any busy connections that have not been used for some time. + *

+ * These connections are considered to have leaked from the connection pool. + *

+ *

+ * Connection leaks occur when code doesn't ensure that connections are + * closed() after they have been finished with. There should be an + * appropriate try catch finally block to ensure connections are always + * closed and put back into the pool. + *

+ */ + public void closeBusyConnections(long leakTimeMinutes) { + + queue.closeBusyConnections(leakTimeMinutes); + } + + /** + * Grow the pool by creating a new connection. The connection can either be + * added to the available list, or returned. + *

+ * This method is protected by synchronization in calling methods. + *

+ */ + protected PooledConnection createConnectionForQueue(int connId) throws SQLException { + + try { + Connection c = createUnpooledConnection(); + + PooledConnection pc = new PooledConnection(this, connId, c); + pc.resetForUse(); + + if (!dataSourceUp) { + notifyDataSourceIsUp(); + } + return pc; + + } catch (SQLException ex) { + notifyDataSourceIsDown(ex); + throw ex; + } + } + + /** + * Close all the connections in the pool. + *

+ *

    + *
  • Checks that the database is up. + *
  • Resets the Alert level. + *
  • Closes busy connections that have not been used for some time (aka + * leaks). + *
  • This closes all the currently available connections. + *
  • Busy connections are closed when they are returned to the pool. + *
+ *

+ */ + public void reset() { + queue.reset(leakTimeMinutes); + inWarningMode = false; + } + + /** + * Return a pooled connection. + */ + public Connection getConnection() throws SQLException { + return getPooledConnection(); + } + + /** + * Get a connection from the pool. + *

+ * This will grow the pool if all the current connections are busy. This + * will go into a wait if the pool has hit its maximum size. + *

+ */ + public PooledConnection getPooledConnection() throws SQLException { + + PooledConnection c = queue.getPooledConnection(); + + if (captureStackTrace) { + c.setStackTrace(Thread.currentThread().getStackTrace()); + } + + if (poolListener != null) { + poolListener.onAfterBorrowConnection(c); + } + return c; + } + + /** + * Send a message to the DataSourceAlertListener to test it. This is so that + * you can make sure the alerter is configured correctly etc. + */ + public void testAlert() { + + String subject = "Test DataSourcePool [" + name + "]"; + String msg = "Just testing if alert message is sent successfully."; + + if (notify != null) { + notify.dataSourceWarning(subject, msg); + } + } + + /** + * This will close all the free connections, and then go into a wait loop, + * waiting for the busy connections to be freed. + *

+ *

+ * The DataSources's should be shutdown AFTER thread pools. Leaked + * Connections are not waited on, as that would hang the server. + *

+ */ + public void shutdown(boolean deregisterDriver) { + queue.shutdown(); + if (deregisterDriver) { + deregisterDriver(); + } + } + + /** + * Return the default autoCommit setting Connections in this pool will use. + * + * @return true if the pool defaults autoCommit to true + */ + public boolean getAutoCommit() { + return autoCommit; + } + + /** + * Return the default transaction isolation level connections in this pool + * should have. + * + * @return the default transaction isolation level + */ + public int getTransactionIsolation() { + return transactionIsolation; + } + + /** + * Return true if the connection pool is currently capturing the StackTrace + * when connections are 'got' from the pool. + *

+ * This is set to true to help diagnose connection pool leaks. + *

+ */ + public boolean isCaptureStackTrace() { + return captureStackTrace; + } + + /** + * Set this to true means that the StackElements are captured every time a + * connection is retrieved from the pool. This can be used to identify + * connection pool leaks. + */ + public void setCaptureStackTrace(boolean captureStackTrace) { + this.captureStackTrace = captureStackTrace; + } + + /** + * Not implemented and shouldn't be used. + */ + public Connection getConnection(String username, String password) throws SQLException { + throw new SQLException("Method not supported"); + } + + /** + * Not implemented and shouldn't be used. + */ + public int getLoginTimeout() throws SQLException { + throw new SQLException("Method not supported"); + } + + /** + * Not implemented and shouldn't be used. + */ + public void setLoginTimeout(int seconds) throws SQLException { + throw new SQLException("Method not supported"); + } + + /** + * Returns null. + */ + public PrintWriter getLogWriter() { + return null; + } + + /** + * Not implemented. + */ + public void setLogWriter(PrintWriter writer) throws SQLException { + throw new SQLException("Method not supported"); + } + + /** + * For detecting and closing leaked connections. Connections that have been + * busy for more than leakTimeMinutes are considered leaks and will be + * closed on a reset(). + *

+ * If you want to use a connection for that longer then you should consider + * creating an unpooled connection or setting longRunning to true on that + * connection. + *

+ */ + public void setLeakTimeMinutes(long leakTimeMinutes) { + this.leakTimeMinutes = leakTimeMinutes; + } + + /** + * Return the number of minutes after which a busy connection could be + * considered leaked from the connection pool. + */ + public long getLeakTimeMinutes() { + return leakTimeMinutes; + } + + /** + * Return the preparedStatement cache size. + */ + public int getPstmtCacheSize() { + return pstmtCacheSize; + } + + /** + * Set the preparedStatement cache size. + */ + public void setPstmtCacheSize(int pstmtCacheSize) { + this.pstmtCacheSize = pstmtCacheSize; + } + + /** + * Return the current status of the connection pool. + *

+ * If you pass reset = true then the counters such as + * hitCount, waitCount and highWaterMark are reset. + *

+ */ + public Status getStatus(boolean reset) { + return queue.getStatus(reset); + } + + /** + * Return the aggregated load statistics collected on all the connections in the pool. + */ + public DataSourcePoolStatistics getStatistics(boolean reset) { + + return queue.getStatistics(reset); + } + + /** + * Deregister the JDBC driver. + */ + public void deregisterDriver() { + try { + logger.debug("Deregistered the JDBC driver " + this.databaseDriver); + DriverManager.deregisterDriver(DriverManager.getDriver(this.databaseUrl)); + } catch (SQLException e) { + logger.warn("Error trying to deregister the JDBC driver " + this.databaseDriver, e); + } + } + + public static class Status { + + private final String name; + private final int minSize; + private final int maxSize; + private final int free; + private final int busy; + private final int waiting; + private final int highWaterMark; + private final int waitCount; + private final int hitCount; + + protected Status(String name, int minSize, int maxSize, int free, int busy, int waiting, int highWaterMark, + int waitCount, int hitCount) { + this.name = name; + this.minSize = minSize; + this.maxSize = maxSize; + this.free = free; + this.busy = busy; + this.waiting = waiting; + this.highWaterMark = highWaterMark; + this.waitCount = waitCount; + this.hitCount = hitCount; + } + + public String toString() { + return "min[" + minSize + "] max[" + maxSize + "] free[" + free + "] busy[" + busy + "] waiting[" + waiting + + "] highWaterMark[" + highWaterMark + "] waitCount[" + waitCount + "] hitCount[" + hitCount + "]"; } /** - * Dumps the busy connection information to the logs. - *

- * This includes the stackTrace elements if they are being captured. This is - * useful when needing to look a potential connection pool leaks. - *

+ * Return the DataSource name. */ - public void dumpBusyConnectionInformation() { - - queue.dumpBusyConnectionInformation(); + public String getName() { + return name; } /** - * Close any busy connections that have not been used for some time. - *

- * These connections are considered to have leaked from the connection pool. - *

- *

- * Connection leaks occur when code doesn't ensure that connections are - * closed() after they have been finished with. There should be an - * appropriate try catch finally block to ensure connections are always - * closed and put back into the pool. - *

+ * Return the min pool size. */ - public void closeBusyConnections(long leakTimeMinutes) { - - queue.closeBusyConnections(leakTimeMinutes); + public int getMinSize() { + return minSize; } /** - * Grow the pool by creating a new connection. The connection can either be - * added to the available list, or returned. - *

- * This method is protected by synchronization in calling methods. - *

+ * Return the max pool size. */ - protected PooledConnection createConnectionForQueue(int connId) throws SQLException { - - try { - Connection c = createUnpooledConnection(); - - PooledConnection pc = new PooledConnection(this, connId, c); - pc.resetForUse(); - - if (!dataSourceUp) { - notifyDataSourceIsUp(); - } - return pc; - - } catch (SQLException ex) { - notifyDataSourceIsDown(ex); - throw ex; - } + public int getMaxSize() { + return maxSize; } /** - * Close all the connections in the pool. - *

- *

    - *
  • Checks that the database is up. - *
  • Resets the Alert level. - *
  • Closes busy connections that have not been used for some time (aka - * leaks). - *
  • This closes all the currently available connections. - *
  • Busy connections are closed when they are returned to the pool. - *
- *

+ * Return the current number of free connections in the pool. */ - public void reset() { - queue.reset(leakTimeMinutes); - inWarningMode = false; + public int getFree() { + return free; } /** - * Return a pooled connection. + * Return the current number of busy connections in the pool. */ - public Connection getConnection() throws SQLException { - return getPooledConnection(); + public int getBusy() { + return busy; } /** - * Get a connection from the pool. - *

- * This will grow the pool if all the current connections are busy. This - * will go into a wait if the pool has hit its maximum size. - *

+ * Return the current number of threads waiting for a connection. */ - public PooledConnection getPooledConnection() throws SQLException { - - PooledConnection c = queue.getPooledConnection(); - - if (captureStackTrace) { - c.setStackTrace(Thread.currentThread().getStackTrace()); - } - - if (poolListener != null) { - poolListener.onAfterBorrowConnection(c); - } - return c; + public int getWaiting() { + return waiting; } /** - * Send a message to the DataSourceAlertListener to test it. This is so that - * you can make sure the alerter is configured correctly etc. + * Return the high water mark of busy connections. */ - public void testAlert() { - - String subject = "Test DataSourcePool [" + name + "]"; - String msg = "Just testing if alert message is sent successfully."; - - if (notify != null) { - notify.dataSourceWarning(subject, msg); - } + public int getHighWaterMark() { + return highWaterMark; } /** - * This will close all the free connections, and then go into a wait loop, - * waiting for the busy connections to be freed. - * - *

- * The DataSources's should be shutdown AFTER thread pools. Leaked - * Connections are not waited on, as that would hang the server. - *

+ * Return the total number of times a thread had to wait. */ - public void shutdown(boolean deregisterDriver) { - queue.shutdown(); - if (deregisterDriver){ - deregisterDriver(); - } + public int getWaitCount() { + return waitCount; } /** - * Return the default autoCommit setting Connections in this pool will use. - * - * @return true if the pool defaults autoCommit to true - */ - public boolean getAutoCommit() { - return autoCommit; - } - - /** - * Return the default transaction isolation level connections in this pool - * should have. - * - * @return the default transaction isolation level - */ - public int getTransactionIsolation() { - return transactionIsolation; - } - - /** - * Return true if the connection pool is currently capturing the StackTrace - * when connections are 'got' from the pool. - *

- * This is set to true to help diagnose connection pool leaks. - *

- */ - public boolean isCaptureStackTrace() { - return captureStackTrace; - } - - /** - * Set this to true means that the StackElements are captured every time a - * connection is retrieved from the pool. This can be used to identify - * connection pool leaks. - */ - public void setCaptureStackTrace(boolean captureStackTrace) { - this.captureStackTrace = captureStackTrace; - } - - /** - * Not implemented and shouldn't be used. - */ - public Connection getConnection(String username, String password) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Not implemented and shouldn't be used. - */ - public int getLoginTimeout() throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Not implemented and shouldn't be used. - */ - public void setLoginTimeout(int seconds) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Returns null. - */ - public PrintWriter getLogWriter() { - return null; - } - - /** - * Not implemented. - */ - public void setLogWriter(PrintWriter writer) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * For detecting and closing leaked connections. Connections that have been - * busy for more than leakTimeMinutes are considered leaks and will be - * closed on a reset(). - *

- * If you want to use a connection for that longer then you should consider - * creating an unpooled connection or setting longRunning to true on that + * Return the total number of times there was an attempt to get a * connection. - *

- */ - public void setLeakTimeMinutes(long leakTimeMinutes) { - this.leakTimeMinutes = leakTimeMinutes; - } - - /** - * Return the number of minutes after which a busy connection could be - * considered leaked from the connection pool. - */ - public long getLeakTimeMinutes() { - return leakTimeMinutes; - } - - /** - * Return the preparedStatement cache size. - */ - public int getPstmtCacheSize() { - return pstmtCacheSize; - } - - /** - * Set the preparedStatement cache size. - */ - public void setPstmtCacheSize(int pstmtCacheSize) { - this.pstmtCacheSize = pstmtCacheSize; - } - - /** - * Return the current status of the connection pool. *

- * If you pass reset = true then the counters such as - * hitCount, waitCount and highWaterMark are reset. + * If the attempt to get a connection failed with a timeout or other + * exception those attempts are still included in this hit count. *

*/ - public Status getStatus(boolean reset) { - return queue.getStatus(reset); - } - - /** - * Return the aggregated load statistics collected on all the connections in the pool. - */ - public DataSourcePoolStatistics getStatistics(boolean reset) { - - return queue.getStatistics(reset); + public int getHitCount() { + return hitCount; } - /** - * Deregister the JDBC driver. - */ - public void deregisterDriver() { - try { - logger.debug("Deregistered the JDBC driver "+this.databaseDriver); - DriverManager.deregisterDriver(DriverManager.getDriver(this.databaseUrl)); - } catch (SQLException e) { - logger.warn("Error trying to deregister the JDBC driver "+this.databaseDriver, e); - } - } - - public static class Status { - - private final String name; - private final int minSize; - private final int maxSize; - private final int free; - private final int busy; - private final int waiting; - private final int highWaterMark; - private final int waitCount; - private final int hitCount; - - protected Status(String name, int minSize, int maxSize, int free, int busy, int waiting, int highWaterMark, - int waitCount, int hitCount) { - this.name = name; - this.minSize = minSize; - this.maxSize = maxSize; - this.free = free; - this.busy = busy; - this.waiting = waiting; - this.highWaterMark = highWaterMark; - this.waitCount = waitCount; - this.hitCount = hitCount; - } - - public String toString() { - return "min[" + minSize + "] max[" + maxSize + "] free[" + free + "] busy[" + busy + "] waiting[" + waiting - + "] highWaterMark[" + highWaterMark + "] waitCount[" + waitCount + "] hitCount[" + hitCount+"]"; - } - - /** - * Return the DataSource name. - */ - public String getName() { - return name; - } - - /** - * Return the min pool size. - */ - public int getMinSize() { - return minSize; - } - - /** - * Return the max pool size. - */ - public int getMaxSize() { - return maxSize; - } - - /** - * Return the current number of free connections in the pool. - */ - public int getFree() { - return free; - } - - /** - * Return the current number of busy connections in the pool. - */ - public int getBusy() { - return busy; - } - - /** - * Return the current number of threads waiting for a connection. - */ - public int getWaiting() { - return waiting; - } - - /** - * Return the high water mark of busy connections. - */ - public int getHighWaterMark() { - return highWaterMark; - } - - /** - * Return the total number of times a thread had to wait. - */ - public int getWaitCount() { - return waitCount; - } - - /** - * Return the total number of times there was an attempt to get a - * connection. - *

- * If the attempt to get a connection failed with a timeout or other - * exception those attempts are still included in this hit count. - *

- */ - public int getHitCount() { - return hitCount; - } - - } + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java index d17b147f6..485384557 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java @@ -13,7 +13,7 @@ import java.sql.Connection; *

* Example: datasource.ora10.poolListener=my.very.fancy.PoolListener *

- * + *

*

* Notice: This listener only works if you are using the default Avaje * {@link DataSourcePool}. @@ -21,14 +21,14 @@ import java.sql.Connection; */ public interface DataSourcePoolListener { - /** - * Called after a connection has been retrieved from the connection pool - */ - void onAfterBorrowConnection(Connection c); + /** + * Called after a connection has been retrieved from the connection pool + */ + void onAfterBorrowConnection(Connection c); - /** - * Called before a connection will be put back to the connection pool - */ - void onBeforeReturnConnection(Connection c); + /** + * Called before a connection will be put back to the connection pool + */ + void onBeforeReturnConnection(Connection c); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java index 5bdc1c9ad..6fb5f1039 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java @@ -16,13 +16,13 @@ package com.avaje.ebeaninternal.server.lib.sql; public class DataSourcePoolStatistics { private final long collectionStart; - + private final long count; - + private final long errorCount; - + private final long hwmMicros; - + private final long totalMicros; /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java index 9e97996fc..dac54c3a5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java @@ -28,362 +28,363 @@ import java.util.Calendar; */ public class ExtendedPreparedStatement extends ExtendedStatement implements PreparedStatement { - /** - * The SQL used to create the underlying PreparedStatement. - */ - private final String sql; + /** + * The SQL used to create the underlying PreparedStatement. + */ + private final String sql; - /** - * The key used to cache this in the connection. - */ - private final String cacheKey; + /** + * The key used to cache this in the connection. + */ + private final String cacheKey; - /** - * Create a wrapped PreparedStatement that can be cached. - */ - public ExtendedPreparedStatement(PooledConnection pooledConnection, PreparedStatement pstmt, String sql, String cacheKey) { - super(pooledConnection, pstmt); - this.sql = sql; - this.cacheKey = cacheKey; - } - - public PreparedStatement getDelegate() { - return pstmt; - } + /** + * Create a wrapped PreparedStatement that can be cached. + */ + public ExtendedPreparedStatement(PooledConnection pooledConnection, PreparedStatement pstmt, String sql, String cacheKey) { + super(pooledConnection, pstmt); + this.sql = sql; + this.cacheKey = cacheKey; + } - /** - * Return the key used to cache this on the Connection. - */ - public String getCacheKey() { - return cacheKey; - } + public PreparedStatement getDelegate() { + return pstmt; + } - /** - * Return the SQL used to create this PreparedStatement. - */ - public String getSql() { - return sql; - } + /** + * Return the key used to cache this on the Connection. + */ + public String getCacheKey() { + return cacheKey; + } - /** - * Fully close the underlying PreparedStatement. After this we can no longer - * reuse the PreparedStatement. - */ - public void closeDestroy() throws SQLException { - pstmt.close(); - } + /** + * Return the SQL used to create this PreparedStatement. + */ + public String getSql() { + return sql; + } - /** - * Returns the PreparedStatement back into the cache. This doesn't fully - * close the underlying PreparedStatement. - */ - public void close() throws SQLException { - // return the connection back into the cache. - pooledConnection.returnPreparedStatement(this); - } + /** + * Fully close the underlying PreparedStatement. After this we can no longer + * reuse the PreparedStatement. + */ + public void closeDestroy() throws SQLException { + pstmt.close(); + } - /** - * Add the last binding for batch execution. - */ - public void addBatch() throws SQLException { - try { - pstmt.addBatch(); - } catch (SQLException e) { - // we got an error... need to check this - // connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * Returns the PreparedStatement back into the cache. This doesn't fully + * close the underlying PreparedStatement. + */ + public void close() throws SQLException { + // return the connection back into the cache. + pooledConnection.returnPreparedStatement(this); + } - /** - * Clear parameters. - */ - public void clearParameters() throws SQLException { - try { - pstmt.clearParameters(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * Add the last binding for batch execution. + */ + public void addBatch() throws SQLException { + try { + pstmt.addBatch(); + } catch (SQLException e) { + // we got an error... need to check this + // connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * execute the statement. - */ - public boolean execute() throws SQLException { - try { - return pstmt.execute(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * Clear parameters. + */ + public void clearParameters() throws SQLException { + try { + pstmt.clearParameters(); + } catch (SQLException e) { + // we got an error... need to check + // this connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * Execute teh query. - */ - public ResultSet executeQuery() throws SQLException { - try { - return pstmt.executeQuery(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * execute the statement. + */ + public boolean execute() throws SQLException { + try { + return pstmt.execute(); + } catch (SQLException e) { + // we got an error... need to check + // this connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * Execute the dml statement. - */ - public int executeUpdate() throws SQLException { - try { - return pstmt.executeUpdate(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * Execute teh query. + */ + public ResultSet executeQuery() throws SQLException { + try { + return pstmt.executeQuery(); + } catch (SQLException e) { + // we got an error... need to check + // this connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * Return the MetaData for the query. - */ - public ResultSetMetaData getMetaData() throws SQLException { - try { - return pstmt.getMetaData(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.addError(e); - throw e; - } - } + /** + * Execute the dml statement. + */ + public int executeUpdate() throws SQLException { + try { + return pstmt.executeUpdate(); + } catch (SQLException e) { + // we got an error... need to check + // this connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * Standard PreparedStatement method execution. - */ - public ParameterMetaData getParameterMetaData() throws SQLException { - return pstmt.getParameterMetaData(); - } + /** + * Return the MetaData for the query. + */ + public ResultSetMetaData getMetaData() throws SQLException { + try { + return pstmt.getMetaData(); + } catch (SQLException e) { + // we got an error... need to check + // this connection before returning it + pooledConnection.addError(e); + throw e; + } + } - /** - * Standard PreparedStatement method execution. - */ - public void setArray(int i, Array x) throws SQLException { - pstmt.setArray(i, x); - } + /** + * Standard PreparedStatement method execution. + */ + public ParameterMetaData getParameterMetaData() throws SQLException { + return pstmt.getParameterMetaData(); + } - /** - * Standard PreparedStatement method execution. - */ - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setAsciiStream(parameterIndex, x, length); - } + /** + * Standard PreparedStatement method execution. + */ + public void setArray(int i, Array x) throws SQLException { + pstmt.setArray(i, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { - pstmt.setBigDecimal(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + pstmt.setAsciiStream(parameterIndex, x, length); + } - /** - * Standard PreparedStatement method execution. - */ - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setBinaryStream(parameterIndex, x, length); - } + /** + * Standard PreparedStatement method execution. + */ + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + pstmt.setBigDecimal(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setBlob(int i, Blob x) throws SQLException { - pstmt.setBlob(i, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + pstmt.setBinaryStream(parameterIndex, x, length); + } - /** - * Standard PreparedStatement method execution. - */ - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - pstmt.setBoolean(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setBlob(int i, Blob x) throws SQLException { + pstmt.setBlob(i, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setByte(int parameterIndex, byte x) throws SQLException { - pstmt.setByte(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + pstmt.setBoolean(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setBytes(int parameterIndex, byte[] x) throws SQLException { - pstmt.setBytes(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setByte(int parameterIndex, byte x) throws SQLException { + pstmt.setByte(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setCharacterStream(int parameterIndex, Reader reader, int length) - throws SQLException { - pstmt.setCharacterStream(parameterIndex, reader, length); - } + /** + * Standard PreparedStatement method execution. + */ + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + pstmt.setBytes(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setClob(int i, Clob x) throws SQLException { - pstmt.setClob(i, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setCharacterStream(int parameterIndex, Reader reader, int length) + throws SQLException { + pstmt.setCharacterStream(parameterIndex, reader, length); + } - /** - * Standard PreparedStatement method execution. - */ - public void setDate(int parameterIndex, Date x) throws SQLException { - pstmt.setDate(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setClob(int i, Clob x) throws SQLException { + pstmt.setClob(i, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - pstmt.setDate(parameterIndex, x, cal); - } + /** + * Standard PreparedStatement method execution. + */ + public void setDate(int parameterIndex, Date x) throws SQLException { + pstmt.setDate(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setDouble(int parameterIndex, double x) throws SQLException { - pstmt.setDouble(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + pstmt.setDate(parameterIndex, x, cal); + } - /** - * Standard PreparedStatement method execution. - */ - public void setFloat(int parameterIndex, float x) throws SQLException { - pstmt.setFloat(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setDouble(int parameterIndex, double x) throws SQLException { + pstmt.setDouble(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setInt(int parameterIndex, int x) throws SQLException { - pstmt.setInt(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setFloat(int parameterIndex, float x) throws SQLException { + pstmt.setFloat(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setLong(int parameterIndex, long x) throws SQLException { - pstmt.setLong(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setInt(int parameterIndex, int x) throws SQLException { + pstmt.setInt(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setNull(int parameterIndex, int sqlType) throws SQLException { - pstmt.setNull(parameterIndex, sqlType); - } + /** + * Standard PreparedStatement method execution. + */ + public void setLong(int parameterIndex, long x) throws SQLException { + pstmt.setLong(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException { - pstmt.setNull(paramIndex, sqlType, typeName); - } + /** + * Standard PreparedStatement method execution. + */ + public void setNull(int parameterIndex, int sqlType) throws SQLException { + pstmt.setNull(parameterIndex, sqlType); + } - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x) throws SQLException { - pstmt.setObject(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException { + pstmt.setNull(paramIndex, sqlType, typeName); + } - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { - pstmt.setObject(parameterIndex, x, targetSqlType); - } + /** + * Standard PreparedStatement method execution. + */ + public void setObject(int parameterIndex, Object x) throws SQLException { + pstmt.setObject(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) - throws SQLException { - pstmt.setObject(parameterIndex, x, targetSqlType, scale); - } + /** + * Standard PreparedStatement method execution. + */ + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + pstmt.setObject(parameterIndex, x, targetSqlType); + } - /** - * Standard PreparedStatement method execution. - */ - public void setRef(int i, Ref x) throws SQLException { - pstmt.setRef(i, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) + throws SQLException { + pstmt.setObject(parameterIndex, x, targetSqlType, scale); + } - /** - * Standard PreparedStatement method execution. - */ - public void setShort(int parameterIndex, short x) throws SQLException { - pstmt.setShort(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setRef(int i, Ref x) throws SQLException { + pstmt.setRef(i, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setString(int parameterIndex, String x) throws SQLException { - pstmt.setString(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setShort(int parameterIndex, short x) throws SQLException { + pstmt.setShort(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setTime(int parameterIndex, Time x) throws SQLException { - pstmt.setTime(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setString(int parameterIndex, String x) throws SQLException { + pstmt.setString(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { - pstmt.setTime(parameterIndex, x, cal); - } + /** + * Standard PreparedStatement method execution. + */ + public void setTime(int parameterIndex, Time x) throws SQLException { + pstmt.setTime(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - */ - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - pstmt.setTimestamp(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + */ + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + pstmt.setTime(parameterIndex, x, cal); + } - /** - * Standard PreparedStatement method execution. - */ - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - pstmt.setTimestamp(parameterIndex, x, cal); - } + /** + * Standard PreparedStatement method execution. + */ + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + pstmt.setTimestamp(parameterIndex, x); + } - /** - * Standard PreparedStatement method execution. - * @deprecated - */ - public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setUnicodeStream(parameterIndex, x, length); - } + /** + * Standard PreparedStatement method execution. + */ + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + pstmt.setTimestamp(parameterIndex, x, cal); + } - /** - * Standard PreparedStatement method execution. - */ - public void setURL(int parameterIndex, URL x) throws SQLException { - pstmt.setURL(parameterIndex, x); - } + /** + * Standard PreparedStatement method execution. + * + * @deprecated + */ + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + pstmt.setUnicodeStream(parameterIndex, x, length); + } + + /** + * Standard PreparedStatement method execution. + */ + public void setURL(int parameterIndex, URL x) throws SQLException { + pstmt.setURL(parameterIndex, x); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java index 46fce0992..414a9c4af 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java @@ -16,313 +16,312 @@ import com.avaje.ebeaninternal.jdbc.PreparedStatementDelegator; * for the case where someone uses the Statement api on an ExtendedPreparedStatement. *

*/ -public abstract class ExtendedStatement extends PreparedStatementDelegator -{ +public abstract class ExtendedStatement extends PreparedStatementDelegator { - /** - * The pooled connection this Statement belongs to. - */ - protected final PooledConnection pooledConnection; + /** + * The pooled connection this Statement belongs to. + */ + protected final PooledConnection pooledConnection; - /** - * The underlying Statement that this object wraps. - */ - protected final PreparedStatement pstmt; + /** + * The underlying Statement that this object wraps. + */ + protected final PreparedStatement pstmt; - /** - * Create the ExtendedStatement for a given pooledConnection. - */ - public ExtendedStatement(PooledConnection pooledConnection, PreparedStatement pstmt) { - super(pstmt); + /** + * Create the ExtendedStatement for a given pooledConnection. + */ + public ExtendedStatement(PooledConnection pooledConnection, PreparedStatement pstmt) { + super(pstmt); - this.pooledConnection = pooledConnection; - this.pstmt = pstmt; - } + this.pooledConnection = pooledConnection; + this.pstmt = pstmt; + } - /** - * Put the statement back into the statement cache. - */ - public abstract void close() throws SQLException; + /** + * Put the statement back into the statement cache. + */ + public abstract void close() throws SQLException; - /** - * Return the underlying connection. - */ - public Connection getConnection() throws SQLException { - try { - return pstmt.getConnection(); - } catch (SQLException e) { - pooledConnection.addError(e); - throw e; - } - } + /** + * Return the underlying connection. + */ + public Connection getConnection() throws SQLException { + try { + return pstmt.getConnection(); + } catch (SQLException e) { + pooledConnection.addError(e); + throw e; + } + } - /** - * Add the sql for batch execution. - */ - public void addBatch(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - pstmt.addBatch(sql); - } catch (SQLException e) { - pooledConnection.addError(e); - throw e; - } - } + /** + * Add the sql for batch execution. + */ + public void addBatch(String sql) throws SQLException { + try { + pooledConnection.setLastStatement(sql); + pstmt.addBatch(sql); + } catch (SQLException e) { + pooledConnection.addError(e); + throw e; + } + } - /** - * Execute the sql. - */ - public boolean execute(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.execute(sql); - } catch (SQLException e) { - pooledConnection.addError(e); - throw e; - } - } + /** + * Execute the sql. + */ + public boolean execute(String sql) throws SQLException { + try { + pooledConnection.setLastStatement(sql); + return pstmt.execute(sql); + } catch (SQLException e) { + pooledConnection.addError(e); + throw e; + } + } - /** - * Execute the query. - */ - public ResultSet executeQuery(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.executeQuery(sql); - } catch (SQLException e) { - pooledConnection.addError(e); - throw e; - } - } + /** + * Execute the query. + */ + public ResultSet executeQuery(String sql) throws SQLException { + try { + pooledConnection.setLastStatement(sql); + return pstmt.executeQuery(sql); + } catch (SQLException e) { + pooledConnection.addError(e); + throw e; + } + } - /** - * Execute the dml sql. - */ - public int executeUpdate(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.executeUpdate(sql); - } catch (SQLException e) { - pooledConnection.addError(e); - throw e; - } - } + /** + * Execute the dml sql. + */ + public int executeUpdate(String sql) throws SQLException { + try { + pooledConnection.setLastStatement(sql); + return pstmt.executeUpdate(sql); + } catch (SQLException e) { + pooledConnection.addError(e); + throw e; + } + } - /** - * Standard Statement method call. - */ - public int[] executeBatch() throws SQLException { - return pstmt.executeBatch(); - } + /** + * Standard Statement method call. + */ + public int[] executeBatch() throws SQLException { + return pstmt.executeBatch(); + } - /** - * Standard Statement method call. - */ - public void cancel() throws SQLException { - pstmt.cancel(); - } + /** + * Standard Statement method call. + */ + public void cancel() throws SQLException { + pstmt.cancel(); + } - /** - * Standard Statement method call. - */ - public void clearBatch() throws SQLException { - pstmt.clearBatch(); - } + /** + * Standard Statement method call. + */ + public void clearBatch() throws SQLException { + pstmt.clearBatch(); + } - /** - * Standard Statement method call. - */ - public void clearWarnings() throws SQLException { - pstmt.clearWarnings(); - } + /** + * Standard Statement method call. + */ + public void clearWarnings() throws SQLException { + pstmt.clearWarnings(); + } - /** - * Standard Statement method call. - */ - public int getFetchDirection() throws SQLException { - return pstmt.getFetchDirection(); - } + /** + * Standard Statement method call. + */ + public int getFetchDirection() throws SQLException { + return pstmt.getFetchDirection(); + } - /** - * Standard Statement method call. - */ - public int getFetchSize() throws SQLException { - return pstmt.getFetchSize(); - } + /** + * Standard Statement method call. + */ + public int getFetchSize() throws SQLException { + return pstmt.getFetchSize(); + } - /** - * Standard Statement method call. - */ - public int getMaxFieldSize() throws SQLException { - return pstmt.getMaxFieldSize(); - } + /** + * Standard Statement method call. + */ + public int getMaxFieldSize() throws SQLException { + return pstmt.getMaxFieldSize(); + } - /** - * Standard Statement method call. - */ - public int getMaxRows() throws SQLException { - return pstmt.getMaxRows(); - } - - /** - * Standard Statement method call. - */ - public boolean getMoreResults() throws SQLException { - return pstmt.getMoreResults(); - } + /** + * Standard Statement method call. + */ + public int getMaxRows() throws SQLException { + return pstmt.getMaxRows(); + } - /** - * Standard Statement method call. - */ - public int getQueryTimeout() throws SQLException { - return pstmt.getQueryTimeout(); - } + /** + * Standard Statement method call. + */ + public boolean getMoreResults() throws SQLException { + return pstmt.getMoreResults(); + } - /** - * Standard Statement method call. - */ - public ResultSet getResultSet() throws SQLException { - return pstmt.getResultSet(); - } + /** + * Standard Statement method call. + */ + public int getQueryTimeout() throws SQLException { + return pstmt.getQueryTimeout(); + } - /** - * Standard Statement method call. - */ - public int getResultSetConcurrency() throws SQLException { - return pstmt.getResultSetConcurrency(); - } - - /** - * Standard Statement method call. - */ - public int getResultSetType() throws SQLException { - return pstmt.getResultSetType(); - } + /** + * Standard Statement method call. + */ + public ResultSet getResultSet() throws SQLException { + return pstmt.getResultSet(); + } - /** - * Standard Statement method call. - */ - public int getUpdateCount() throws SQLException { - return pstmt.getUpdateCount(); - } + /** + * Standard Statement method call. + */ + public int getResultSetConcurrency() throws SQLException { + return pstmt.getResultSetConcurrency(); + } - /** - * Standard Statement method call. - */ - public SQLWarning getWarnings() throws SQLException { - return pstmt.getWarnings(); - } + /** + * Standard Statement method call. + */ + public int getResultSetType() throws SQLException { + return pstmt.getResultSetType(); + } - /** - * Standard Statement method call. - */ - public void setCursorName(String name) throws SQLException { - pstmt.setCursorName(name); - } + /** + * Standard Statement method call. + */ + public int getUpdateCount() throws SQLException { + return pstmt.getUpdateCount(); + } - /** - * Standard Statement method call. - */ - public void setEscapeProcessing(boolean enable) throws SQLException { - pstmt.setEscapeProcessing(enable); - } + /** + * Standard Statement method call. + */ + public SQLWarning getWarnings() throws SQLException { + return pstmt.getWarnings(); + } - /** - * Standard Statement method call. - */ - public void setFetchDirection(int direction) throws SQLException { - pstmt.setFetchDirection(direction); - } + /** + * Standard Statement method call. + */ + public void setCursorName(String name) throws SQLException { + pstmt.setCursorName(name); + } - /** - * Standard Statement method call. - */ - public void setFetchSize(int rows) throws SQLException { - pstmt.setFetchSize(rows); - } + /** + * Standard Statement method call. + */ + public void setEscapeProcessing(boolean enable) throws SQLException { + pstmt.setEscapeProcessing(enable); + } - /** - * Standard Statement method call. - */ - public void setMaxFieldSize(int max) throws SQLException { - pstmt.setMaxFieldSize(max); - } + /** + * Standard Statement method call. + */ + public void setFetchDirection(int direction) throws SQLException { + pstmt.setFetchDirection(direction); + } - /** - * Standard Statement method call. - */ - public void setMaxRows(int max) throws SQLException { - pstmt.setMaxRows(max); - } + /** + * Standard Statement method call. + */ + public void setFetchSize(int rows) throws SQLException { + pstmt.setFetchSize(rows); + } - /** - * Standard Statement method call. - */ - public void setQueryTimeout(int seconds) throws SQLException { - pstmt.setQueryTimeout(seconds); - } + /** + * Standard Statement method call. + */ + public void setMaxFieldSize(int max) throws SQLException { + pstmt.setMaxFieldSize(max); + } - /** - * Standard Statement method call. - */ - public boolean getMoreResults(int i) throws SQLException { - return pstmt.getMoreResults(i); - } + /** + * Standard Statement method call. + */ + public void setMaxRows(int max) throws SQLException { + pstmt.setMaxRows(max); + } - /** - * Standard Statement method call. - */ - public ResultSet getGeneratedKeys() throws SQLException { - return pstmt.getGeneratedKeys(); - } + /** + * Standard Statement method call. + */ + public void setQueryTimeout(int seconds) throws SQLException { + pstmt.setQueryTimeout(seconds); + } - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, int i) throws SQLException { - return pstmt.executeUpdate(s, i); - } + /** + * Standard Statement method call. + */ + public boolean getMoreResults(int i) throws SQLException { + return pstmt.getMoreResults(i); + } - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, int[] i) throws SQLException { - return pstmt.executeUpdate(s, i); - } + /** + * Standard Statement method call. + */ + public ResultSet getGeneratedKeys() throws SQLException { + return pstmt.getGeneratedKeys(); + } - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, String[] i) throws SQLException { - return pstmt.executeUpdate(s, i); - } + /** + * Standard Statement method call. + */ + public int executeUpdate(String s, int i) throws SQLException { + return pstmt.executeUpdate(s, i); + } - /** - * Standard Statement method call. - */ - public boolean execute(String s, int i) throws SQLException { - return pstmt.execute(s, i); - } + /** + * Standard Statement method call. + */ + public int executeUpdate(String s, int[] i) throws SQLException { + return pstmt.executeUpdate(s, i); + } - /** - * Standard Statement method call. - */ - public boolean execute(String s, int[] i) throws SQLException { - return pstmt.execute(s, i); - } + /** + * Standard Statement method call. + */ + public int executeUpdate(String s, String[] i) throws SQLException { + return pstmt.executeUpdate(s, i); + } - /** - * Standard Statement method call. - */ - public boolean execute(String s, String[] i) throws SQLException { - return pstmt.execute(s, i); - } + /** + * Standard Statement method call. + */ + public boolean execute(String s, int i) throws SQLException { + return pstmt.execute(s, i); + } - /** - * Standard Statement method call. - */ - public int getResultSetHoldability() throws SQLException { - return pstmt.getResultSetHoldability(); - } + /** + * Standard Statement method call. + */ + public boolean execute(String s, int[] i) throws SQLException { + return pstmt.execute(s, i); + } + + /** + * Standard Statement method call. + */ + public boolean execute(String s, String[] i) throws SQLException { + return pstmt.execute(s, i); + } + + /** + * Standard Statement method call. + */ + public int getResultSetHoldability() throws SQLException { + return pstmt.getResultSetHoldability(); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java index 778410909..7fcb23ac9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java @@ -19,7 +19,7 @@ import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadVal class FreeConnectionBuffer { private static final Logger logger = LoggerFactory.getLogger(FreeConnectionBuffer.class); - + /** * Buffer oriented for add and remove. */ @@ -57,7 +57,7 @@ class FreeConnectionBuffer { // create a temporary list List tempList = new ArrayList(freeBuffer.size()); - + // add all the connections into it for (PooledConnection c : freeBuffer) { tempList.add(c); @@ -65,15 +65,15 @@ class FreeConnectionBuffer { // clear the buffer (in case it takes some time to close these connections). freeBuffer.clear(); - + logger.debug("... closing all {} connections from the free list with logErrors: {}", tempList.size(), logErrors); for (int i = 0; i < tempList.size(); i++) { PooledConnection pooledConnection = tempList.get(i); - logger.debug("... closing {} of {} connections from the free list", i, tempList.size()); + logger.debug("... closing {} of {} connections from the free list", i, tempList.size()); pooledConnection.closeConnectionFully(logErrors); } } - + /** * Trim any inactive connections that have not been used since usedSince. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java index 89088faff..833f68366 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java @@ -13,520 +13,520 @@ import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadVal public class PooledConnectionQueue { - private static final Logger logger = LoggerFactory.getLogger(PooledConnectionQueue.class); - - private static final TimeUnit MILLIS_TIME_UNIT = TimeUnit.MILLISECONDS; + private static final Logger logger = LoggerFactory.getLogger(PooledConnectionQueue.class); - private final String name; - - private final DataSourcePool pool; - - /** - * A 'circular' buffer designed specifically for free connections. - */ - private final FreeConnectionBuffer freeList; - - /** - * A 'slots' buffer designed specifically for busy connections. - * Fast add remove based on slot id. - */ - private final BusyConnectionBuffer busyList; + private static final TimeUnit MILLIS_TIME_UNIT = TimeUnit.MILLISECONDS; - /** - * Load statistics collected off connections that have closed fully (left the pool). - */ - private final PooledConnectionStatistics collectedStats = new PooledConnectionStatistics(); - - /** - * Currently accumulated load statistics. - */ - private LoadValues accumulatedValues = new LoadValues(); + private final String name; - /** - * Main lock guarding all access - */ - private final ReentrantLock lock; - - /** - * Condition for threads waiting to take a connection - */ - private final Condition notEmpty; + private final DataSourcePool pool; - private int connectionId; + /** + * A 'circular' buffer designed specifically for free connections. + */ + private final FreeConnectionBuffer freeList; - private final long waitTimeoutMillis; - - private final long leakTimeMinutes; - - private final long maxAgeMillis; + /** + * A 'slots' buffer designed specifically for busy connections. + * Fast add remove based on slot id. + */ + private final BusyConnectionBuffer busyList; - private int warningSize; - - private int maxSize; - - private int minSize; - - /** - * Number of threads in the wait queue. - */ - private int waitingThreads; - - /** - * Number of times a thread had to wait. - */ - private int waitCount; - - /** - * Number of times a connection was got from this queue. - */ - private int hitCount; - - /** - * The high water mark for the queue size. - */ - private int highWaterMark; - - /** - * Last time the pool was reset. Used to close busy connections as they are - * returned to the pool that where created prior to the lastResetTime. - */ - private long lastResetTime; + /** + * Load statistics collected off connections that have closed fully (left the pool). + */ + private final PooledConnectionStatistics collectedStats = new PooledConnectionStatistics(); - private boolean doingShutdown; + /** + * Currently accumulated load statistics. + */ + private LoadValues accumulatedValues = new LoadValues(); - public PooledConnectionQueue(DataSourcePool pool) { - - this.pool = pool; - this.name = pool.getName(); - this.minSize = pool.getMinSize(); - this.maxSize = pool.getMaxSize(); - - this.warningSize = pool.getWarningSize(); - this.waitTimeoutMillis = pool.getWaitTimeoutMillis(); - this.leakTimeMinutes = pool.getLeakTimeMinutes(); - this.maxAgeMillis = pool.getMaxAgeMillis(); + /** + * Main lock guarding all access + */ + private final ReentrantLock lock; - this.busyList = new BusyConnectionBuffer(maxSize, 20); - this.freeList = new FreeConnectionBuffer(); + /** + * Condition for threads waiting to take a connection + */ + private final Condition notEmpty; - this.lock = new ReentrantLock(false); - this.notEmpty = lock.newCondition(); - } - - private Status createStatus() { - return new Status(name, minSize, maxSize, freeList.size(), busyList.size(), waitingThreads, highWaterMark, waitCount, hitCount); - } - - public String toString() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return createStatus().toString(); - } finally { - lock.unlock(); - } - } - - /** - * Collect statistics of a connection that is fully closing - */ - protected void reportClosingConnection(PooledConnection pooledConnection) { - - collectedStats.add(pooledConnection.getStatistics()); - } + private int connectionId; - public DataSourcePoolStatistics getStatistics(boolean reset) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { + private final long waitTimeoutMillis; - LoadValues aggregate = collectedStats.getValues(reset); + private final long leakTimeMinutes; - freeList.collectStatistics(aggregate, reset); - busyList.collectStatistics(aggregate, reset); + private final long maxAgeMillis; - aggregate.plus(accumulatedValues); - - this.accumulatedValues = (reset) ? new LoadValues() : aggregate; - - return new DataSourcePoolStatistics(aggregate.getCollectionStart(), aggregate.getCount(), aggregate.getErrorCount(), aggregate.getHwmMicros(), aggregate.getTotalMicros()); - - } finally { - lock.unlock(); - } + private int warningSize; + + private int maxSize; + + private int minSize; + + /** + * Number of threads in the wait queue. + */ + private int waitingThreads; + + /** + * Number of times a thread had to wait. + */ + private int waitCount; + + /** + * Number of times a connection was got from this queue. + */ + private int hitCount; + + /** + * The high water mark for the queue size. + */ + private int highWaterMark; + + /** + * Last time the pool was reset. Used to close busy connections as they are + * returned to the pool that where created prior to the lastResetTime. + */ + private long lastResetTime; + + private boolean doingShutdown; + + public PooledConnectionQueue(DataSourcePool pool) { + + this.pool = pool; + this.name = pool.getName(); + this.minSize = pool.getMinSize(); + this.maxSize = pool.getMaxSize(); + + this.warningSize = pool.getWarningSize(); + this.waitTimeoutMillis = pool.getWaitTimeoutMillis(); + this.leakTimeMinutes = pool.getLeakTimeMinutes(); + this.maxAgeMillis = pool.getMaxAgeMillis(); + + this.busyList = new BusyConnectionBuffer(maxSize, 20); + this.freeList = new FreeConnectionBuffer(); + + this.lock = new ReentrantLock(false); + this.notEmpty = lock.newCondition(); } - - public Status getStatus(boolean reset) { - final ReentrantLock lock = this.lock; - lock.lock(); + + private Status createStatus() { + return new Status(name, minSize, maxSize, freeList.size(), busyList.size(), waitingThreads, highWaterMark, waitCount, hitCount); + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return createStatus().toString(); + } finally { + lock.unlock(); + } + } + + /** + * Collect statistics of a connection that is fully closing + */ + protected void reportClosingConnection(PooledConnection pooledConnection) { + + collectedStats.add(pooledConnection.getStatistics()); + } + + public DataSourcePoolStatistics getStatistics(boolean reset) { + + final ReentrantLock lock = this.lock; + lock.lock(); + try { + + LoadValues aggregate = collectedStats.getValues(reset); + + freeList.collectStatistics(aggregate, reset); + busyList.collectStatistics(aggregate, reset); + + aggregate.plus(accumulatedValues); + + this.accumulatedValues = (reset) ? new LoadValues() : aggregate; + + return new DataSourcePoolStatistics(aggregate.getCollectionStart(), aggregate.getCount(), aggregate.getErrorCount(), aggregate.getHwmMicros(), aggregate.getTotalMicros()); + + } finally { + lock.unlock(); + } + } + + public Status getStatus(boolean reset) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Status s = createStatus(); + if (reset) { + highWaterMark = busyList.size(); + hitCount = 0; + waitCount = 0; + } + return s; + } finally { + lock.unlock(); + } + } + + public void setMinSize(int minSize) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (minSize > this.maxSize) { + throw new IllegalArgumentException("minSize " + minSize + " > maxSize " + this.maxSize); + } + this.minSize = minSize; + } finally { + lock.unlock(); + } + } + + public void setMaxSize(int maxSize) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (maxSize < this.minSize) { + throw new IllegalArgumentException("maxSize " + maxSize + " < minSize " + this.minSize); + } + this.busyList.setCapacity(maxSize); + this.maxSize = maxSize; + } finally { + lock.unlock(); + } + } + + public void setWarningSize(int warningSize) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (warningSize > this.maxSize) { + throw new IllegalArgumentException("warningSize " + warningSize + " > maxSize " + this.maxSize); + } + this.warningSize = warningSize; + } finally { + lock.unlock(); + } + } + + private int totalConnections() { + return freeList.size() + busyList.size(); + } + + public void ensureMinimumConnections() throws SQLException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int add = minSize - totalConnections(); + if (add > 0) { + for (int i = 0; i < add; i++) { + PooledConnection c = pool.createConnectionForQueue(connectionId++); + freeList.add(c); + } + notEmpty.signal(); + } + + } finally { + lock.unlock(); + } + } + + /** + * Return a PooledConnection. + */ + protected void returnPooledConnection(PooledConnection c, boolean forceClose) { + + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (!busyList.remove(c)) { + logger.error("Connection [{}] not found in BusyList? ", c); + } + if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) { + c.closeConnectionFully(false); + + } else { + freeList.add(c); + notEmpty.signal(); + } + } finally { + lock.unlock(); + } + } + + private PooledConnection extractFromFreeList() { + PooledConnection c = freeList.remove(); + registerBusyConnection(c); + return c; + } + + public PooledConnection getPooledConnection() throws SQLException { + + try { + PooledConnection pc = _getPooledConnection(); + pc.resetForUse(); + return pc; + + } catch (InterruptedException e) { + String msg = "Interrupted getting connection from pool " + e; + throw new SQLException(msg); + } + } + + /** + * Register the PooledConnection with the busyList. + */ + private int registerBusyConnection(PooledConnection c) { + int busySize = busyList.add(c); + if (busySize > highWaterMark) { + highWaterMark = busySize; + } + return busySize; + } + + private PooledConnection _getPooledConnection() throws InterruptedException, SQLException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + if (doingShutdown) { + throw new SQLException("Trying to access the Connection Pool when it is shutting down"); + } + + // this includes attempts that fail with InterruptedException + // or SQLException but that is ok as its only an indicator + hitCount++; + + // are other threads already waiting? (they get priority) + if (waitingThreads == 0) { + + if (!freeList.isEmpty()) { + // we have a free connection to return + return extractFromFreeList(); + } + + if (busyList.size() < maxSize) { + // grow the connection pool + PooledConnection c = pool.createConnectionForQueue(connectionId++); + int busySize = registerBusyConnection(c); + + if (logger.isDebugEnabled()) { + logger.debug("DataSourcePool [{}] grow; id[{}] busy[{}] max[{}]", name, c.getName(), busySize, maxSize); + } + checkForWarningSize(); + return c; + } + } + + try { + // The pool is at maximum size. We are going to go into + // a wait loop until connections are returned into the pool. + waitCount++; + waitingThreads++; + return _getPooledConnectionWaitLoop(); + } finally { + waitingThreads--; + } + + } finally { + lock.unlock(); + } + } + + /** + * Got into a loop waiting for connections to be returned to the pool. + */ + private PooledConnection _getPooledConnectionWaitLoop() throws SQLException, InterruptedException { + + long nanos = MILLIS_TIME_UNIT.toNanos(waitTimeoutMillis); + for (; ; ) { + + if (nanos <= 0) { + String msg = "Unsuccessfully waited [" + waitTimeoutMillis + "] millis for a connection to be returned." + + " No connections are free. You need to Increase the max connections of [" + maxSize + "]" + + " or look for a connection pool leak using datasource.xxx.capturestacktrace=true"; + if (pool.isCaptureStackTrace()) { + dumpBusyConnectionInformation(); + } + + throw new SQLException(msg); + } + + try { + nanos = notEmpty.awaitNanos(nanos); + if (!freeList.isEmpty()) { + // successfully waited + return extractFromFreeList(); + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } + + public void shutdown() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + doingShutdown = true; + Status status = createStatus(); + DataSourcePoolStatistics statistics = pool.getStatistics(false); + logger.debug("DataSourcePool [{}] shutdown {} - Statistics {}", name, status, statistics); + + closeFreeConnections(true); + + if (!busyList.isEmpty()) { + logger.warn("Closing busy connections on shutdown size: " + busyList.size()); + dumpBusyConnectionInformation(); + closeBusyConnections(0); + } + } finally { + lock.unlock(); + } + } + + /** + * Close all the connections in the pool and any current busy connections + * when they are returned. New connections will be then created on demand. + *

+ * This is typically done when a database down event occurs. + *

+ */ + public void reset(long leakTimeMinutes) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Status status = createStatus(); + logger.info("Reseting DataSourcePool [{}] {}", name, status); + lastResetTime = System.currentTimeMillis(); + + closeFreeConnections(false); + closeBusyConnections(leakTimeMinutes); + + logger.info("Busy Connections:\n" + getBusyConnectionInformation()); + + } finally { + lock.unlock(); + } + } + + public void trim(long maxInactiveMillis, long maxAgeMillis) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (trimInactiveConnections(maxInactiveMillis, maxAgeMillis) > 0) { try { - Status s = createStatus(); - if (reset){ - highWaterMark = busyList.size(); - hitCount = 0; - waitCount = 0; - } - return s; - } finally { - lock.unlock(); - } - } - - public void setMinSize(int minSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (minSize > this.maxSize){ - throw new IllegalArgumentException("minSize "+minSize+" > maxSize "+this.maxSize); - } - this.minSize = minSize; - } finally { - lock.unlock(); - } - } - - public void setMaxSize(int maxSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (maxSize < this.minSize){ - throw new IllegalArgumentException("maxSize "+maxSize+" < minSize "+this.minSize); - } - this.busyList.setCapacity(maxSize); - this.maxSize = maxSize; - } finally { - lock.unlock(); - } - } - - public void setWarningSize(int warningSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (warningSize > this.maxSize){ - throw new IllegalArgumentException("warningSize "+warningSize+" > maxSize "+this.maxSize); - } - this.warningSize = warningSize; - } finally { - lock.unlock(); - } - } - - private int totalConnections() { - return freeList.size() + busyList.size(); - } - - public void ensureMinimumConnections() throws SQLException { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - int add = minSize - totalConnections(); - if (add > 0){ - for (int i = 0; i < add; i++) { - PooledConnection c = pool.createConnectionForQueue(connectionId++); - freeList.add(c); - } - notEmpty.signal(); - } - - } finally { - lock.unlock(); - } - } - - /** - * Return a PooledConnection. - */ - protected void returnPooledConnection(PooledConnection c, boolean forceClose) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (!busyList.remove(c)) { - logger.error("Connection [{}] not found in BusyList? ", c); - } - if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) { - c.closeConnectionFully(false); - - } else { - freeList.add(c); - notEmpty.signal(); - } - } finally { - lock.unlock(); + ensureMinimumConnections(); + } catch (SQLException e) { + logger.error("Error trying to ensure minimum connections", e); } + } + } finally { + lock.unlock(); } + } - private PooledConnection extractFromFreeList() { - PooledConnection c = freeList.remove(); - registerBusyConnection(c); - return c; - } + /** + * Trim connections that have been not used for some time. + */ + private int trimInactiveConnections(long maxInactiveMillis, long maxAgeMillis) { - public PooledConnection getPooledConnection() throws SQLException { - - try { - PooledConnection pc = _getPooledConnection(); - pc.resetForUse(); - return pc; - - } catch (InterruptedException e) { - String msg = "Interrupted getting connection from pool "+e; - throw new SQLException(msg); - } - } - - /** - * Register the PooledConnection with the busyList. - */ - private int registerBusyConnection(PooledConnection c) { - int busySize = busyList.add(c); - if (busySize > highWaterMark){ - highWaterMark = busySize; - } - return busySize; - } - - private PooledConnection _getPooledConnection() throws InterruptedException, SQLException { - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - if (doingShutdown) { - throw new SQLException("Trying to access the Connection Pool when it is shutting down"); - } - - // this includes attempts that fail with InterruptedException - // or SQLException but that is ok as its only an indicator - hitCount++; - - // are other threads already waiting? (they get priority) - if (waitingThreads == 0){ - - if (!freeList.isEmpty()){ - // we have a free connection to return - return extractFromFreeList(); - } - - if (busyList.size() < maxSize){ - // grow the connection pool - PooledConnection c = pool.createConnectionForQueue(connectionId++); - int busySize = registerBusyConnection(c); - - if (logger.isDebugEnabled()) { - logger.debug("DataSourcePool [{}] grow; id[{}] busy[{}] max[{}]", name, c.getName(), busySize, maxSize); - } - checkForWarningSize(); - return c; - } - } - - try { - // The pool is at maximum size. We are going to go into - // a wait loop until connections are returned into the pool. - waitCount++; - waitingThreads++; - return _getPooledConnectionWaitLoop(); - } finally { - waitingThreads--; - } + long usedSince = System.currentTimeMillis() - maxInactiveMillis; + long createdSince = (maxAgeMillis == 0) ? 0 : System.currentTimeMillis() - maxAgeMillis; - } finally { - lock.unlock(); - } + int trimedCount = freeList.trim(usedSince, createdSince); + if (trimedCount > 0) { + logger.debug("DataSourcePool [{}] trimmed [{}] inactive connections. New size[{}]", name, trimedCount, totalConnections()); } - - /** - * Got into a loop waiting for connections to be returned to the pool. - */ - private PooledConnection _getPooledConnectionWaitLoop() throws SQLException, InterruptedException { + return trimedCount; + } - long nanos = MILLIS_TIME_UNIT.toNanos(waitTimeoutMillis); - for (;;) { - - if (nanos <= 0) { - String msg = "Unsuccessfully waited ["+waitTimeoutMillis+"] millis for a connection to be returned." - + " No connections are free. You need to Increase the max connections of ["+maxSize+"]" - + " or look for a connection pool leak using datasource.xxx.capturestacktrace=true"; - if (pool.isCaptureStackTrace()) { - dumpBusyConnectionInformation(); - } - - throw new SQLException(msg); - } - - try { - nanos = notEmpty.awaitNanos(nanos); - if (!freeList.isEmpty()) { - // successfully waited - return extractFromFreeList(); - } - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to non-interrupted thread - throw ie; - } - } + /** + * Close all the connections that are in the free list. + */ + public void closeFreeConnections(boolean logErrors) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + freeList.closeAll(logErrors); + } finally { + lock.unlock(); } - - public void shutdown() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - doingShutdown = true; - Status status = createStatus(); - DataSourcePoolStatistics statistics = pool.getStatistics(false); - logger.debug("DataSourcePool [{}] shutdown {} - Statistics {}", name, status, statistics); - - closeFreeConnections(true); - - if (!busyList.isEmpty()) { - logger.warn("Closing busy connections on shutdown size: "+ busyList.size()); - dumpBusyConnectionInformation(); - closeBusyConnections(0); - } - } finally { - lock.unlock(); - } + } + + /** + * Close any busy connections that have not been used for some time. + *

+ * These connections are considered to have leaked from the connection pool. + *

+ *

+ * Connection leaks occur when code doesn't ensure that connections are + * closed() after they have been finished with. There should be an + * appropriate try catch finally block to ensure connections are always + * closed and put back into the pool. + *

+ */ + public void closeBusyConnections(long leakTimeMinutes) { + + final ReentrantLock lock = this.lock; + lock.lock(); + try { + busyList.closeBusyConnections(leakTimeMinutes); + } finally { + lock.unlock(); } + } - /** - * Close all the connections in the pool and any current busy connections - * when they are returned. New connections will be then created on demand. - *

- * This is typically done when a database down event occurs. - *

- */ - public void reset(long leakTimeMinutes) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - Status status = createStatus(); - logger.info("Reseting DataSourcePool [{}] {}", name, status); - lastResetTime = System.currentTimeMillis(); + /** + * As the pool grows it gets closer to the maxConnections limit. We can send + * an Alert (or warning) as we get close to this limit and hence an + * Administrator could increase the pool size if desired. + *

+ * This is called whenever the pool grows in size (towards the max limit). + *

+ */ + private void checkForWarningSize() { - closeFreeConnections(false); - closeBusyConnections(leakTimeMinutes); + // the the total number of connections that we can add + // to the pool before it hits the maximum + int availableGrowth = (maxSize - totalConnections()); - logger.info("Busy Connections:\n" + getBusyConnectionInformation()); + if (availableGrowth < warningSize) { - } finally { - lock.unlock(); - } + closeBusyConnections(leakTimeMinutes); + + String msg = "DataSourcePool [" + name + "] is [" + availableGrowth + "] connections from its maximum size."; + pool.notifyWarning(msg); } + } - public void trim(long maxInactiveMillis, long maxAgeMillis) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (trimInactiveConnections(maxInactiveMillis, maxAgeMillis) > 0) { - try { - ensureMinimumConnections(); - } catch (SQLException e) { - logger.error("Error trying to ensure minimum connections", e); - } - } - } finally { - lock.unlock(); - } - } - - /** - * Trim connections that have been not used for some time. - */ - private int trimInactiveConnections(long maxInactiveMillis, long maxAgeMillis) { - - long usedSince = System.currentTimeMillis() - maxInactiveMillis; - long createdSince = (maxAgeMillis == 0) ? 0 : System.currentTimeMillis() - maxAgeMillis; - - int trimedCount = freeList.trim(usedSince, createdSince); - if (trimedCount > 0) { - logger.debug("DataSourcePool [{}] trimmed [{}] inactive connections. New size[{}]", name, trimedCount, totalConnections()); - } - return trimedCount; - } - - /** - * Close all the connections that are in the free list. - */ - public void closeFreeConnections(boolean logErrors) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - freeList.closeAll(logErrors); - } finally { - lock.unlock(); - } - } - - /** - * Close any busy connections that have not been used for some time. - *

- * These connections are considered to have leaked from the connection pool. - *

- *

- * Connection leaks occur when code doesn't ensure that connections are - * closed() after they have been finished with. There should be an - * appropriate try catch finally block to ensure connections are always - * closed and put back into the pool. - *

- */ - public void closeBusyConnections(long leakTimeMinutes) { + public String getBusyConnectionInformation() { + return getBusyConnectionInformation(false); + } - final ReentrantLock lock = this.lock; - lock.lock(); - try { - busyList.closeBusyConnections(leakTimeMinutes); - } finally { - lock.unlock(); - } - } - - /** - * As the pool grows it gets closer to the maxConnections limit. We can send - * an Alert (or warning) as we get close to this limit and hence an - * Administrator could increase the pool size if desired. - *

- * This is called whenever the pool grows in size (towards the max limit). - *

- */ - private void checkForWarningSize() { + public void dumpBusyConnectionInformation() { + getBusyConnectionInformation(true); + } - // the the total number of connections that we can add - // to the pool before it hits the maximum - int availableGrowth = (maxSize - totalConnections()); + /** + * Returns information describing connections that are currently being used. + */ + private String getBusyConnectionInformation(boolean toLogger) { - if (availableGrowth < warningSize) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { - closeBusyConnections(leakTimeMinutes); + return busyList.getBusyConnectionInformation(toLogger); - String msg = "DataSourcePool [" + name + "] is [" + availableGrowth+ "] connections from its maximum size."; - pool.notifyWarning(msg); - } + } finally { + lock.unlock(); } - - public String getBusyConnectionInformation() { - return getBusyConnectionInformation(false); - } - - public void dumpBusyConnectionInformation() { - getBusyConnectionInformation(true); - } - - /** - * Returns information describing connections that are currently being used. - */ - private String getBusyConnectionInformation(boolean toLogger) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { + } - return busyList.getBusyConnectionInformation(toLogger); - - } finally { - lock.unlock(); - } - } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java index 6f9eeac53..50c746ded 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java @@ -7,13 +7,13 @@ import java.util.concurrent.atomic.AtomicLong; * Collects load statistics for a PooledConnection. */ public class PooledConnectionStatistics { - + private final AtomicLong count = new AtomicLong(); - + private final AtomicLong errorCount = new AtomicLong(); - + private final AtomicLong hwmNanos = new AtomicLong(); - + private final AtomicLong totalNanos = new AtomicLong(); private final AtomicLong collectionStart; @@ -21,22 +21,22 @@ public class PooledConnectionStatistics { public PooledConnectionStatistics() { this.collectionStart = new AtomicLong(System.currentTimeMillis()); } - + /** * Add statistics from another collector. */ public void add(PooledConnectionStatistics other) { - + errorCount.addAndGet(other.getErrorCount()); totalNanos.addAndGet(other.totalNanos.get()); count.addAndGet(other.getCount()); - + final long otherHwm = other.hwmNanos.get(); if (otherHwm > hwmNanos.get()) { hwmNanos.set(otherHwm); } } - + /** * Add some time duration to the statistics. */ @@ -44,7 +44,7 @@ public class PooledConnectionStatistics { // This will be done in pretty much single threaded fashion // as the Connections generally are not shared across threads - + if (hasError) { errorCount.incrementAndGet(); } @@ -54,11 +54,11 @@ public class PooledConnectionStatistics { hwmNanos.set(durationNanos); } } - + public String toString() { - return "count["+count+"] errors["+errorCount+"] totalMicros["+getTotalMicros()+"] hwmMicros["+getHwmMicros()+"]"; + return "count[" + count + "] errors[" + errorCount + "] totalMicros[" + getTotalMicros() + "] hwmMicros[" + getHwmMicros() + "]"; } - + public long getCollectionStart() { return collectionStart.get(); } @@ -74,7 +74,7 @@ public class PooledConnectionStatistics { public long getTotalMicros() { return TimeUnit.MICROSECONDS.convert(totalNanos.get(), TimeUnit.NANOSECONDS); } - + public long getHwmMicros() { return TimeUnit.MICROSECONDS.convert(hwmNanos.get(), TimeUnit.NANOSECONDS); } @@ -101,16 +101,16 @@ public class PooledConnectionStatistics { *

*/ public static class LoadValues { - + private long collectionStart; private long count; private long errorCount; private long hwmMicros; private long totalMicros; - + public LoadValues() { } - + public LoadValues(long collectionStart, long count, long errorCount, long hwmMicros, long totalMicros) { this.collectionStart = collectionStart; this.count = count; @@ -128,7 +128,7 @@ public class PooledConnectionStatistics { } public String toString() { - return "count["+count+"] errors["+errorCount+"] totalMicros["+totalMicros+"] hwmMicros["+hwmMicros+"] avgMicros["+getAvgMicros()+"]"; + return "count[" + count + "] errors[" + errorCount + "] totalMicros[" + totalMicros + "] hwmMicros[" + hwmMicros + "] avgMicros[" + getAvgMicros() + "]"; } public long getCollectionStart() { @@ -150,13 +150,11 @@ public class PooledConnectionStatistics { public long getTotalMicros() { return totalMicros; } - + public long getAvgMicros() { - return (count == 0) ? 0 : totalMicros/count; + return (count == 0) ? 0 : totalMicros / count; } } - - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/Prefix.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/Prefix.java index bed1fad49..0eec390a5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/Prefix.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/Prefix.java @@ -10,89 +10,89 @@ import java.util.Random; */ public class Prefix { - private static final Logger logger = LoggerFactory.getLogger(Prefix.class); - - private static final int[] oa = { 50, 12, 4, 6, 8, 10, 7, 23, 45, 23, 6, 9, 12, 2, 8, 34 }; + private static final Logger logger = LoggerFactory.getLogger(Prefix.class); - public static String getProp(String prop) { - String v = dec(prop); - int p = v.indexOf(":"); - return v.substring(1, p); - } + private static final int[] oa = {50, 12, 4, 6, 8, 10, 7, 23, 45, 23, 6, 9, 12, 2, 8, 34}; - public static void main(String[] args) { - String m = e(args[0]); - logger.info("[" + m + "]"); - String o = getProp(m); - logger.info("[" + o + "]"); - } + public static String getProp(String prop) { + String v = dec(prop); + int p = v.indexOf(":"); + return v.substring(1, p); + } - public static String e(String msg) { - msg = elen(msg, 40); - return enc(msg); - } + public static void main(String[] args) { + String m = e(args[0]); + logger.info("[" + m + "]"); + String o = getProp(m); + logger.info("[" + o + "]"); + } - public static byte az(byte c, int offset) { + public static String e(String msg) { + msg = elen(msg, 40); + return enc(msg); + } - int z = c + offset; - if (z > 122) { - // dp("z> "+z); - z = z - 122 + 48 - 1; - } - // dp("z="+z+" c:"+(int)c); - return (byte) z; - } + public static byte az(byte c, int offset) { - public static byte bz(byte c, int offset) { - int z = c - offset; - if (z < (48)) { - // dp("z< "+z); - z = z + 122 - 48 + 1; - } - return (byte) z; - } + int z = c + offset; + if (z > 122) { + // dp("z> "+z); + z = z - 122 + 48 - 1; + } + // dp("z="+z+" c:"+(int)c); + return (byte) z; + } - public static String enc(String msg) { - byte[] msgbytes = msg.getBytes(); - byte[] encbytes = new byte[msgbytes.length + 1]; - Random r = new Random(); - int key = r.nextInt(70); + public static byte bz(byte c, int offset) { + int z = c - offset; + if (z < (48)) { + // dp("z< "+z); + z = z + 122 - 48 + 1; + } + return (byte) z; + } - char k = (char) (key + 48); + public static String enc(String msg) { + byte[] msgbytes = msg.getBytes(); + byte[] encbytes = new byte[msgbytes.length + 1]; + Random r = new Random(); + int key = r.nextInt(70); - encbytes[0] = az((byte) k, oa[0]); - // dp("key:"+key+" encbytes[0]:"+(byte)encbytes[0]); + char k = (char) (key + 48); + + encbytes[0] = az((byte) k, oa[0]); + // dp("key:"+key+" encbytes[0]:"+(byte)encbytes[0]); for (int i = 1; i < (msgbytes.length + 1); i++) { - encbytes[i] = az(msgbytes[i - 1], (oa[(i + key) % oa.length])); - } - return new String(encbytes); - } + encbytes[i] = az(msgbytes[i - 1], (oa[(i + key) % oa.length])); + } + return new String(encbytes); + } - public static String dec(String msg) { - byte[] msgbytes = msg.getBytes(); - byte[] encbytes = new byte[msgbytes.length]; + public static String dec(String msg) { + byte[] msgbytes = msg.getBytes(); + byte[] encbytes = new byte[msgbytes.length]; - encbytes[0] = bz(msgbytes[0], oa[0]); - byte key = encbytes[0]; - int ios = (key - 48); - for (int i = 1; i < msgbytes.length; i++) { - encbytes[i] = bz(msgbytes[i], oa[(i + ios) % oa.length]); - } - return new String(encbytes); - } + encbytes[0] = bz(msgbytes[0], oa[0]); + byte key = encbytes[0]; + int ios = (key - 48); + for (int i = 1; i < msgbytes.length; i++) { + encbytes[i] = bz(msgbytes[i], oa[(i + ios) % oa.length]); + } + return new String(encbytes); + } - public static String elen(String msg, int len) { - Random r = new Random(); - if (msg.length() < len) { - int max = len - msg.length(); - StringBuilder sb = new StringBuilder(); - sb.append(msg).append(":"); - for (int i = 1; i < max; i++) { - int bc = r.nextInt(122 - 48); - sb.append(Character.toString((char) (bc + 48))); - } - return sb.toString(); - } - return msg; - } + public static String elen(String msg, int len) { + Random r = new Random(); + if (msg.length() < len) { + int max = len - msg.length(); + StringBuilder sb = new StringBuilder(); + sb.append(msg).append(":"); + for (int i = 1; i < max; i++) { + int bc = r.nextInt(122 - 48); + sb.append(Character.toString((char) (bc + 48))); + } + return sb.toString(); + } + return msg; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java index 2d6adc436..f8fecdbc4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java @@ -12,103 +12,103 @@ import java.util.Map; */ public class PstmtCache extends LinkedHashMap { - private static final Logger logger = LoggerFactory.getLogger(PstmtCache.class); - + private static final Logger logger = LoggerFactory.getLogger(PstmtCache.class); + static final long serialVersionUID = -3096406924865550697L; - /** - * The name of the cache, for tracing purposes. - */ - protected final String cacheName; - - /** - * The maximum size of the cache. When this is exceeded the oldest entry is removed. - */ - private final int maxSize; + /** + * The name of the cache, for tracing purposes. + */ + protected final String cacheName; - /** - * The total number of entries removed from this cache. - */ - private int removeCounter; + /** + * The maximum size of the cache. When this is exceeded the oldest entry is removed. + */ + private final int maxSize; - /** - * The number of get hits. - */ - private int hitCounter; + /** + * The total number of entries removed from this cache. + */ + private int removeCounter; - /** - * The number of get() misses. - */ - private int missCounter; + /** + * The number of get hits. + */ + private int hitCounter; - /** - * The number of puts into this cache. - */ - private int putCounter; + /** + * The number of get() misses. + */ + private int missCounter; - public PstmtCache(String cacheName, int maxCacheSize) { + /** + * The number of puts into this cache. + */ + private int putCounter; - // note = access ordered list. This is what gives it the LRU order - super(maxCacheSize*3, 0.75f, true); - this.cacheName = cacheName; - this.maxSize = maxCacheSize; - } + public PstmtCache(String cacheName, int maxCacheSize) { - /** - * Return a summary description of this cache. - */ - public String getDescription() { - return "size["+size()+"] max["+maxSize+"] hits["+hitCounter+"] miss["+missCounter+"] hitRatio["+getHitRatio()+"] removes["+removeCounter+"]"; - } - - /** - * returns the current maximum size of the cache. - */ - public int getMaxSize() { - return maxSize; - } + // note = access ordered list. This is what gives it the LRU order + super(maxCacheSize * 3, 0.75f, true); + this.cacheName = cacheName; + this.maxSize = maxCacheSize; + } - /** - * Gets the hit ratio. A number between 0 and 100 indicating the number of - * hits to misses. A number approaching 100 is desirable. - */ - public int getHitRatio() { - if (hitCounter == 0) { - return 0; - } else { - return hitCounter*100/(hitCounter+missCounter); - } - } + /** + * Return a summary description of this cache. + */ + public String getDescription() { + return "size[" + size() + "] max[" + maxSize + "] hits[" + hitCounter + "] miss[" + missCounter + "] hitRatio[" + getHitRatio() + "] removes[" + removeCounter + "]"; + } - /** - * The total number of hits against this cache. - */ - public int getHitCounter() { - return hitCounter; - } + /** + * returns the current maximum size of the cache. + */ + public int getMaxSize() { + return maxSize; + } - /** - * The total number of misses against this cache. - */ - public int getMissCounter() { - return missCounter; - } + /** + * Gets the hit ratio. A number between 0 and 100 indicating the number of + * hits to misses. A number approaching 100 is desirable. + */ + public int getHitRatio() { + if (hitCounter == 0) { + return 0; + } else { + return hitCounter * 100 / (hitCounter + missCounter); + } + } - /** - * The total number of puts against this cache. - */ - public int getPutCounter() { - return putCounter; - } + /** + * The total number of hits against this cache. + */ + public int getHitCounter() { + return hitCounter; + } - /** - * Try to add the returning statement to the cache. If there is already a - * matching ExtendedPreparedStatement in the cache return false else add - * the statement to the cache and return true. - */ - public boolean returnStatement(ExtendedPreparedStatement pstmt) { - - ExtendedPreparedStatement alreadyInCache = super.get(pstmt.getCacheKey()); + /** + * The total number of misses against this cache. + */ + public int getMissCounter() { + return missCounter; + } + + /** + * The total number of puts against this cache. + */ + public int getPutCounter() { + return putCounter; + } + + /** + * Try to add the returning statement to the cache. If there is already a + * matching ExtendedPreparedStatement in the cache return false else add + * the statement to the cache and return true. + */ + public boolean returnStatement(ExtendedPreparedStatement pstmt) { + + ExtendedPreparedStatement alreadyInCache = super.get(pstmt.getCacheKey()); if (alreadyInCache != null) { return false; } @@ -117,67 +117,67 @@ public class PstmtCache extends LinkedHashMap // PStmts when the cache has hit its maximum size. put(pstmt.getCacheKey(), pstmt); return true; - } - - /** - * additionally maintains hit and miss statistics. - */ - public ExtendedPreparedStatement get(Object key) { + } - ExtendedPreparedStatement o = super.get(key); - if (o == null) { - missCounter++; - } else { - hitCounter++; - } - return o; - } + /** + * additionally maintains hit and miss statistics. + */ + public ExtendedPreparedStatement get(Object key) { - /** - * additionally maintains hit and miss statistics. - */ - public ExtendedPreparedStatement remove(Object key) { + ExtendedPreparedStatement o = super.get(key); + if (o == null) { + missCounter++; + } else { + hitCounter++; + } + return o; + } - ExtendedPreparedStatement o = super.remove(key); - if (o == null) { - missCounter++; - } else { - hitCounter++; - } - return o; - } + /** + * additionally maintains hit and miss statistics. + */ + public ExtendedPreparedStatement remove(Object key) { - /** - * additionally maintains put counter statistics. - */ - public ExtendedPreparedStatement put(String key, ExtendedPreparedStatement value) { + ExtendedPreparedStatement o = super.remove(key); + if (o == null) { + missCounter++; + } else { + hitCounter++; + } + return o; + } - putCounter++; - return super.put(key, value); - } + /** + * additionally maintains put counter statistics. + */ + public ExtendedPreparedStatement put(String key, ExtendedPreparedStatement value) { + + putCounter++; + return super.put(key, value); + } + + /** + * will check to see if we need to remove entries and + * if so call the cacheCleanup.cleanupEldestLRUCacheEntry() if + * one has been set. + */ + protected boolean removeEldestEntry(Map.Entry eldest) { + + if (size() < maxSize) { + return false; + } + + removeCounter++; + + try { + ExtendedPreparedStatement pstmt = eldest.getValue(); + pstmt.closeDestroy(); + } catch (SQLException e) { + logger.error("Error closing ExtendedPreparedStatement", e); + } + return true; + } - /** - * will check to see if we need to remove entries and - * if so call the cacheCleanup.cleanupEldestLRUCacheEntry() if - * one has been set. - */ - protected boolean removeEldestEntry(Map.Entry eldest) { - - if (size() < maxSize) { - return false; - } - - removeCounter++; - - try { - ExtendedPreparedStatement pstmt = eldest.getValue(); - pstmt.closeDestroy(); - } catch (SQLException e) { - logger.error("Error closing ExtendedPreparedStatement", e); - } - return true; - } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java index b87ead5f4..9ec520077 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java @@ -4,66 +4,64 @@ import java.sql.Connection; /** * Helper object that can convert between transaction isolation descriptions and values. - * */ public class TransactionIsolation { - /** - * return the isolation level for a given string description. - */ - public static int getLevel(String level) { - level = level.toUpperCase(); - if (level.startsWith("TRANSACTION")){ - level = level.substring("TRANSACTION".length()); - } - level = level.replace("_", ""); - if ("NONE".equalsIgnoreCase(level)){ - return Connection.TRANSACTION_NONE; - } - if ("READCOMMITTED".equalsIgnoreCase(level)){ - return Connection.TRANSACTION_READ_COMMITTED; - } - if ("READUNCOMMITTED".equalsIgnoreCase(level)){ - return Connection.TRANSACTION_READ_UNCOMMITTED; - } - if ("REPEATABLEREAD".equalsIgnoreCase(level)){ - return Connection.TRANSACTION_REPEATABLE_READ; - } - if ("SERIALIZABLE".equalsIgnoreCase(level)){ - return Connection.TRANSACTION_SERIALIZABLE; - } + /** + * return the isolation level for a given string description. + */ + public static int getLevel(String level) { + level = level.toUpperCase(); + if (level.startsWith("TRANSACTION")) { + level = level.substring("TRANSACTION".length()); + } + level = level.replace("_", ""); + if ("NONE".equalsIgnoreCase(level)) { + return Connection.TRANSACTION_NONE; + } + if ("READCOMMITTED".equalsIgnoreCase(level)) { + return Connection.TRANSACTION_READ_COMMITTED; + } + if ("READUNCOMMITTED".equalsIgnoreCase(level)) { + return Connection.TRANSACTION_READ_UNCOMMITTED; + } + if ("REPEATABLEREAD".equalsIgnoreCase(level)) { + return Connection.TRANSACTION_REPEATABLE_READ; + } + if ("SERIALIZABLE".equalsIgnoreCase(level)) { + return Connection.TRANSACTION_SERIALIZABLE; + } - throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known."); - } - - /** - * Return the string description of the transaction isolation level specified. - *

Returned value is one of NONE, READ_COMMITTED,READ_UNCOMMITTED, - * REPEATABLE_READ or SERIALIZABLE.

- * - * @param level the transaction isolation level as per java.sql.Connection - * @return the level description as a string. - */ - public static String getLevelDescription(int level) { - switch (level) { - case Connection.TRANSACTION_NONE : - return "NONE"; - case Connection.TRANSACTION_READ_COMMITTED : - return "READ_COMMITTED"; - case Connection.TRANSACTION_READ_UNCOMMITTED : - return "READ_UNCOMMITTED"; - case Connection.TRANSACTION_REPEATABLE_READ : - return "REPEATABLE_READ"; - case Connection.TRANSACTION_SERIALIZABLE : - return "SERIALIZABLE"; - case -1 : - return "NotSet"; - default : - throw new RuntimeException("Transaction Isolaction level [" + level + "] is not defined."); - } - } + throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known."); + } + /** + * Return the string description of the transaction isolation level specified. + *

Returned value is one of NONE, READ_COMMITTED,READ_UNCOMMITTED, + * REPEATABLE_READ or SERIALIZABLE.

+ * + * @param level the transaction isolation level as per java.sql.Connection + * @return the level description as a string. + */ + public static String getLevelDescription(int level) { + switch (level) { + case Connection.TRANSACTION_NONE: + return "NONE"; + case Connection.TRANSACTION_READ_COMMITTED: + return "READ_COMMITTED"; + case Connection.TRANSACTION_READ_UNCOMMITTED: + return "READ_UNCOMMITTED"; + case Connection.TRANSACTION_REPEATABLE_READ: + return "REPEATABLE_READ"; + case Connection.TRANSACTION_SERIALIZABLE: + return "SERIALIZABLE"; + case -1: + return "NotSet"; + default: + throw new RuntimeException("Transaction Isolaction level [" + level + "] is not defined."); + } + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html index 4f39901a2..6c537f2a6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html @@ -1,7 +1,7 @@ - - AvajeLib + + AvajeLib Enhanced JDBC objects and connection pool.