diff options
author | Apollon Oikonomopoulos <apoikos@debian.org> | 2017-03-01 14:21:59 +0200 |
---|---|---|
committer | Apollon Oikonomopoulos <apoikos@debian.org> | 2017-03-01 14:21:59 +0200 |
commit | bd7b6679cea5620446718911de7a6764f81a9a7a (patch) | |
tree | a725b29afd153ae0d18c47e41c1197e2b409313d /src/main/java/com/zaxxer/hikari/HikariDataSource.java |
New upstream version 2.6.0
Diffstat (limited to 'src/main/java/com/zaxxer/hikari/HikariDataSource.java')
-rw-r--r-- | src/main/java/com/zaxxer/hikari/HikariDataSource.java | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/main/java/com/zaxxer/hikari/HikariDataSource.java b/src/main/java/com/zaxxer/hikari/HikariDataSource.java new file mode 100644 index 0000000..29b8953 --- /dev/null +++ b/src/main/java/com/zaxxer/hikari/HikariDataSource.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2013 Brett Wooldridge + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.zaxxer.hikari; + +import java.io.Closeable; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.zaxxer.hikari.metrics.MetricsTrackerFactory; +import com.zaxxer.hikari.pool.HikariPool; +import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; + +/** + * The HikariCP pooled DataSource. + * + * @author Brett Wooldridge + */ +public class HikariDataSource extends HikariConfig implements DataSource, Closeable +{ + private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class); + + private final AtomicBoolean isShutdown = new AtomicBoolean(); + + private final HikariPool fastPathPool; + private volatile HikariPool pool; + + /** + * Default constructor. Setters be used to configure the pool. Using + * this constructor vs. {@link #HikariDataSource(HikariConfig)} will + * result in {@link #getConnection()} performance that is slightly lower + * due to lazy initialization checks. + */ + public HikariDataSource() + { + super(); + fastPathPool = null; + } + + /** + * Construct a HikariDataSource with the specified configuration. + * + * @param configuration a HikariConfig instance + */ + public HikariDataSource(HikariConfig configuration) + { + configuration.validate(); + configuration.copyState(this); + + LOGGER.info("{} - Starting...", configuration.getPoolName()); + pool = fastPathPool = new HikariPool(this); + LOGGER.info("{} - Start completed.", configuration.getPoolName()); + } + + /** {@inheritDoc} */ + @Override + public Connection getConnection() throws SQLException + { + if (isClosed()) { + throw new SQLException("HikariDataSource " + this + " has been closed."); + } + + if (fastPathPool != null) { + return fastPathPool.getConnection(); + } + + // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java + HikariPool result = pool; + if (result == null) { + synchronized (this) { + result = pool; + if (result == null) { + validate(); + LOGGER.info("{} - Starting...", getPoolName()); + try { + pool = result = new HikariPool(this); + } + catch (PoolInitializationException pie) { + if (pie.getCause() instanceof SQLException) { + throw (SQLException) pie.getCause(); + } + else { + throw pie; + } + } + LOGGER.info("{} - Start completed.", getPoolName()); + } + } + } + + return result.getConnection(); + } + + /** {@inheritDoc} */ + @Override + public Connection getConnection(String username, String password) throws SQLException + { + throw new SQLFeatureNotSupportedException(); + } + + /** {@inheritDoc} */ + @Override + public PrintWriter getLogWriter() throws SQLException + { + HikariPool p = pool; + return (p != null ? p.getUnwrappedDataSource().getLogWriter() : null); + } + + /** {@inheritDoc} */ + @Override + public void setLogWriter(PrintWriter out) throws SQLException + { + HikariPool p = pool; + if (p != null) { + p.getUnwrappedDataSource().setLogWriter(out); + } + } + + /** {@inheritDoc} */ + @Override + public void setLoginTimeout(int seconds) throws SQLException + { + HikariPool p = pool; + if (p != null) { + p.getUnwrappedDataSource().setLoginTimeout(seconds); + } + } + + /** {@inheritDoc} */ + @Override + public int getLoginTimeout() throws SQLException + { + HikariPool p = pool; + return (p != null ? p.getUnwrappedDataSource().getLoginTimeout() : 0); + } + + /** {@inheritDoc} */ + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException + { + throw new SQLFeatureNotSupportedException(); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("unchecked") + public <T> T unwrap(Class<T> iface) throws SQLException + { + if (iface.isInstance(this)) { + return (T) this; + } + + HikariPool p = pool; + if (p != null) { + final DataSource unwrappedDataSource = p.getUnwrappedDataSource(); + if (iface.isInstance(unwrappedDataSource)) { + return (T) unwrappedDataSource; + } + + if (unwrappedDataSource != null) { + return unwrappedDataSource.unwrap(iface); + } + } + + throw new SQLException("Wrapped DataSource is not an instance of " + iface); + } + + /** {@inheritDoc} */ + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException + { + if (iface.isInstance(this)) { + return true; + } + + HikariPool p = pool; + if (p != null) { + final DataSource unwrappedDataSource = p.getUnwrappedDataSource(); + if (iface.isInstance(unwrappedDataSource)) { + return true; + } + + if (unwrappedDataSource != null) { + return unwrappedDataSource.isWrapperFor(iface); + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public void setMetricRegistry(Object metricRegistry) + { + boolean isAlreadySet = getMetricRegistry() != null; + super.setMetricRegistry(metricRegistry); + + HikariPool p = pool; + if (p != null) { + if (isAlreadySet) { + throw new IllegalStateException("MetricRegistry can only be set one time"); + } + else { + p.setMetricRegistry(super.getMetricRegistry()); + } + } + } + + /** {@inheritDoc} */ + @Override + public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory) + { + boolean isAlreadySet = getMetricsTrackerFactory() != null; + super.setMetricsTrackerFactory(metricsTrackerFactory); + + HikariPool p = pool; + if (p != null) { + if (isAlreadySet) { + throw new IllegalStateException("MetricsTrackerFactory can only be set one time"); + } + else { + p.setMetricsTrackerFactory(super.getMetricsTrackerFactory()); + } + } + } + + /** {@inheritDoc} */ + @Override + public void setHealthCheckRegistry(Object healthCheckRegistry) + { + boolean isAlreadySet = getHealthCheckRegistry() != null; + super.setHealthCheckRegistry(healthCheckRegistry); + + HikariPool p = pool; + if (p != null) { + if (isAlreadySet) { + throw new IllegalStateException("HealthCheckRegistry can only be set one time"); + } + else { + p.setHealthCheckRegistry(super.getHealthCheckRegistry()); + } + } + } + + /** + * Evict a connection from the pool. If the connection has already been closed (returned to the pool) + * this may result in a "soft" eviction; the connection will be evicted sometime in the future if it is + * currently in use. If the connection has not been closed, the eviction is immediate. + * + * @param connection the connection to evict from the pool + */ + public void evictConnection(Connection connection) + { + HikariPool p; + if (!isClosed() && (p = pool) != null && connection.getClass().getName().startsWith("com.zaxxer.hikari")) { + p.evictConnection(connection); + } + } + + /** + * Suspend allocation of connections from the pool. All callers to <code>getConnection()</code> + * will block indefinitely until <code>resumePool()</code> is called. + */ + public void suspendPool() + { + HikariPool p; + if (!isClosed() && (p = pool) != null) { + p.suspendPool(); + } + } + + /** + * Resume allocation of connections from the pool. + */ + public void resumePool() + { + HikariPool p; + if (!isClosed() && (p = pool) != null) { + p.resumePool(); + } + } + + /** + * Shutdown the DataSource and its associated pool. + */ + @Override + public void close() + { + if (isShutdown.getAndSet(true)) { + return; + } + + HikariPool p = pool; + if (p != null) { + try { + LOGGER.info("{} - Shutdown initiated...", getPoolName()); + p.shutdown(); + LOGGER.info("{} - Shutdown completed.", getPoolName()); + } + catch (InterruptedException e) { + LOGGER.warn("{} - Interrupted during closing", getPoolName(), e); + Thread.currentThread().interrupt(); + } + } + } + + /** + * Determine whether the HikariDataSource has been closed. + * + * @return true if the HikariDataSource has been closed, false otherwise + */ + public boolean isClosed() + { + return isShutdown.get(); + } + + /** + * Shutdown the DataSource and its associated pool. + * + * @deprecated This method has been deprecated, please use {@link #close()} instead + */ + @Deprecated + public void shutdown() + { + LOGGER.warn("The shutdown() method has been deprecated, please use the close() method instead"); + close(); + } + + /** {@inheritDoc} */ + @Override + public String toString() + { + return "HikariDataSource (" + pool + ")"; + } +} |