pax_global_header00006660000000000000000000000064131543164200014511gustar00rootroot0000000000000052 comment=ec8510710ac71f79f513c19f35d5da320c92e2f2 HikariCP-HikariCP-2.7.1/000077500000000000000000000000001315431642000146025ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/.editorconfig000066400000000000000000000004271315431642000172620ustar00rootroot00000000000000# EditorConfig is awesome: http://EditorConfig.org # top-most EditorConfig file root = true [**] end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = space trim_trailing_whitespace = true [**.{java,xml}] indent_size = 3 [**.{yaml,yml}] indent_size = 2 HikariCP-HikariCP-2.7.1/.github/000077500000000000000000000000001315431642000161425ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000003461315431642000206520ustar00rootroot00000000000000#### Environment ``` HikariCP version: x.x.x JDK version : 1.8.0_111 Database : PostgreSQL|MySQL|... Driver version : x.x.x ``` ----------------------------------------------------------------------------------------- HikariCP-HikariCP-2.7.1/.gitignore000066400000000000000000000003001315431642000165630ustar00rootroot00000000000000.classpath .project .settings/ target/ dependency-reduced-pom.xml .DS_Store **/*.iml *.class *.jar *.war *.ear *.iml *.iws *.ipr .tm_* .classpath .project .settings/ .idea/ .gradle/ out/ HikariCP-HikariCP-2.7.1/.travis.yml000066400000000000000000000014361315431642000167170ustar00rootroot00000000000000sudo: false language: java dist: - trusty before_script: - if [[ "x$JDK" == *'x9'* ]]; then export MAVEN_SKIP_RC=true; fi - if [[ "x$JDK" != *'x9'* ]]; then export COVERALLS=coveralls:report; fi script: - export JDK8_HOME=$(jdk_switcher home oraclejdk8) - export JDK9_HOME=/usr/lib/jvm/java-9-oracle - test -d "${JDK9_HOME}" || export JDK9_HOME=$(jdk_switcher home oraclejdk8) before_cache: # No sense in caching current build artifacts - rm -rf $HOME/.m2/repository/com/zaxxer cache: directories: - $HOME/.m2/repository matrix: fast_finish: true include: - jdk: oraclejdk8 - jdk: oraclejdk9 env: - JDK=9 install: /bin/true script: - mvn package -Dskip.unit.tests=true -Dmaven.javadoc.skip=true -V -B - mvn test $COVERALLS -V -P coverage HikariCP-HikariCP-2.7.1/CHANGES000066400000000000000000000731041315431642000156020ustar00rootroot00000000000000HikariCP Changes Changes in 2.7.1 * issue 968 Wrong label order in MicrometerMetricsTracker for the connection usage metric. * issue 967 incorrect bitwise operator value in ConcurrentBag.requite method intended to cause parkNanos() to be called every 256 iterations. Thanks to @ztkmkoo for finding this. Changes in 2.7.0 * added support for micrometer metrics (currently Alpha-level support). * issue 905 mask JDBC password in URLs * issue 940 fix Prometheus metric collector for multiple data config * issue 941 add support for setting a default schema * issue 955 fix possible race condition when Statements are closed on different threads from which they were created. Changes in 2.6.3 * issue 878 load driver class from ThreadContext classloader if it is not found via the regular classloader. Changes in 2.6.2 * issue 890 add support for Prometheus metrics and multiple HikariCP pools. * issue 880 fix race condition caused by sorting collection while the condition of sort can change. * issue 876 add support for using a Prometheus CollectorRegistry other than the default one. * issue 867 support network timeout even for Connection.isValid(). * issue 866 mark commit state dirty when Connection.getMetaData() is called. Changes in 2.6.1 * issue 821 if a disconnection class exception is thrown during initial connection setup, do not set the flag that indicates that checkDriverSupport() is complete. * issue 835 fix increased CPU consumption under heavy load caused by excessive spinning in the ConcurrentBag.requite() method. * issue 817 updated behavior of new initializationFailTimeout, please see the official documentation for details. * issue 742 add direct MXBean accessor methods to HikariDataSource for users who do not want run run JMX. Changes in 2.6.0 * Redesign of the contention code path resulting in doubling contended throughput; now contended pool access retains 98% of the uncontended throughput. * issue 793 add new HikariConfig method, setScheduledExecutor(ScheduledExecutorService), and deprecate method setScheduledExecutorService(ScheduledThreadPoolExecutor). It is unfortunate that the deprecated method has the more accurate name, but its signature cannot be changed without breaking binary compatibility. * issue 770 add a new property initializationFailTimeout, and deprecate configuration property initializationFailFast. * issue 774 significantly improve spike load handling. * issues 518/769 add new metric for tracking how long physical connection acquisition is taking. DropWizard histogram name "ConnectionCreation", and Prometheus summary name "hikaricp_connection_creation_millis". * issue 741 cancel HouseKeeper task on pool shutdown. If the ScheduledExecutor being used did not belong to HikariCP, this task would remain scheduled after shutdown, causing a memory leak. * issue 781 more technically accurate wording of pool startup and shutdown log messages. Changes in 2.5.1 * issue 719 only reset lastConnectionFailure after a successful dataSource.getConnection() call. * issue 716 do not scan deeper than 10 nested SQLExceptions, it's typically a trap ... a chain that never terminates. * issue 714 fix possible issue with cross-thread visibility. Change pool entry state from AtomicInteger w/lazySet() to a volatile int with use of AtomicIntegerFieldUpdater. Changes in 2.5.0 * Release 2.5.0 marks the start of a Java 8 HikariCP artifact. The Java 7 artifact is now called "HikariCP-java7". * HikariCP 2.5.0 and HikariCP-java7 2.4.8 have identical functionality. Changes in 2.4.12 * issue 878 search for driverClass in both HikariCP class classloader and Thread Context ClassLoader Changes in 2.4.11 * issue 793 add new HikariConfig method, setScheduledExecutor(ScheduledExecutorService), and deprecate method setScheduledExecutorService(ScheduledThreadPoolExecutor). It is unfortunate that the deprecated method has the more accurate name, but its signature cannot be changed without breaking binary compatibility. * issue 600 ignore Java 8 default methods when generating proxy classes for Java 7. Changes in 2.4.10 * Redesign of the contention code path resulting in doubling contended throughput; now contended pool access retains 98% of the uncontended throughput. * issue 770 add a new property initializationFailTimeout, and deprecate configuration property initializationFailFast. * issue 774 significantly improve spike load handling. * issue 741 cancel HouseKeeper task on pool shutdown. If the ScheduledExecutor being used did not belong to HikariCP, this task would remain scheduled after shutdown, causing a memory leak. Changes in 2.4.9 * issue 719 only reset lastConnectionFailure after a successful dataSource.getConnection() call. * issue 716 do not scan deeper than 10 nested SQLExceptions, it's typically a trap ... a chain that never terminates. * issue 714 fix possible issue with cross-thread visibility. Change pool entry state from AtomicInteger w/lazySet() to a volatile int with use of AtomicIntegerFieldUpdater. Changes in 2.4.8 * Release 2.4.8 marks the start of a Java 7 HikariCP artifact, HikariCP-java7, representing support for Java 7 entering maintenance mode. * Added Connection.commit() call to the fail-fast initialization for databases that automatically start a new Connection in a transaction and throw an exception on close if it is not committed. * feature 694: report if a previously reported leaked connection is returned to the pool * issue 689: log a warning if default transaction isolation level cannot be detected. This can occur with pseudo-database drivers such as the one for JSonar * issue 674: fix regression caused by pull request #450 (overzealous optimisation) Changes in 2.4.7 * Miscellaneous stability improvements. * Removed Oracle SQL state 61000, added specific error code (2399) to evict connections when it is encountered. * issue 664: do not recycle PoolEntry objects that have closed their held connection. * issue 641, 643: reflection used method String.toUpperCase() without a Locale, which causes problems in some locales such as Turkish. * pull 632: added support for Prometheus metrics tracker. * issue 650: detect Amazon Redshift connection refused error codes. Changes in 2.4.6 * Added Oracle SQL error code 61000 (exceeded maximum connect time) to evict connections when it is encountered. * issue 621: fix NPE in shutdown if invoked during initialization. * issue 606, 610: housekeeper thread was running before all class members were initialized, causing an unrecoverable exception and disabling idle connection retirement (maximumLifetime still applied). Changes in 2.4.5 * issue 596: fix bug that occurs when minimumIdle is set to 0, but maximumPoolSize is not explicitly set. * issue 594: fix incompatibility with various libraries caused by storing a non-String object in System properties. * issue 593: improve logging when network timeout is not supported by the driver * issue 591: improve thread-safety of Statement proxies Changes in 2.4.4 * Generate unique sequential pool names, even across container classloaders to avoid JMX name collisions when registering pools. * Improve pool stability when running on computers using power-saving or sleep modes where wake-up previously caused pool to grow to maximum size. * Improve pool stability under severe thread-starvation conditions. Previous code could interpret prolonged starvation (exceeding one minute) as non-contiguous clock advancement, and reacted by soft-evicting connections (unnecessarily). * Added connection timeout rate to Dropwizard metrics (ConnectionTimeoutRate). * issue 563: Do not start the house-keeping thread until after pool initialisation has succeeded. * issue 559: Ensure the pool refill after house-keeping does not enqueue more add connection requests if there are already minimumIdle requests pending. * issue 555: include support for Java 8 interface 'default' methods during proxy generation. * issue 547: decreased allowable minimum connectionTimeout and validationTimeout to 250ms. * issue 495: implemented iterator() method on custom FastList to support Tomcat memory leak detection. Changes in 2.3.13 * issue 512: reduce the number of calls made to Connection.getAutoCommit(). Changes in 2.4.3 * Improve pool shutdown behavior. Stop active connection acquisition once the shutdown sequence has initiated. * Improved detection and reporting of ambiguous pool configuration, when both the connection URL and DataSource class names are specified. Changes in 2.4.2 * Improve accuracy of timeouts for getConnection() calls by accounting for possibly long delay aliveness tests. * Improve adherence to minimumIdle goal by closing idle connections starting from longest idle time to shortest. Additionally, stop when minimumIdle is reached even if connections exceeding idleTimeout remain (but are still within maxLifetime). * Introduce larger variance into maxLifetime to avoid mass connection closing and subsequent new connection creation load on the database. Connections now have a maximum lifetime between 97.5-100% of configured maxLifetime. In the case of the default 30 minute lifetime, this generates actual lifetimes with a maximum deviation of 45 seconds. Currently, no attempt is made to further avoid clustering that may occur due to randomness. * Ongoing com.zaxxer.hikari.metrics refactors. This is not considered public API until such time as we announce it. Caveat lector. * Performance improvements in the getConnection()/close() hot path. * issue 452: fixed race condition when creating an rapidly ramping connections in the pool. * issue 415: removed use of java.beans classes to allow use of HikariCP with the Zulu JRE compact3 profile. * issue 406: execute validation query during connection setup to make sure it is valid SQL. Changes in 2.3.12 * Fixed issue with proxy generation whereby the generated classes contain the major version number for Java 8, which makes them incompatible with the Java 7 runtime. Changes in 2.4.1 * issue 380: housekeeper was not being scheduled in the case of a user specified ScheduledExecutorService instance. * issue 340: rollback change that elides setting the readonly property if the user never explicitly configured it. See discussion in the Github issue tracker. Also fixes binary ABI breakage between 2.3.9 and 2.4.0. * issue 379: stop closing idle connections, to keep minimumIdle connections in pool * issue 375: fixed InvalidPathException in HikariConfig * issue 362: fixed NullPointerException in closing connection (closing statements) * issue 357: allow altering the username & password through JMX at runtime * issue 349: handle integer Transaction isolation level * Throw SQLTransientConnectionException instead of SQLTimeoutException * for validating connection, if network time out is set, do not set query timeout too * ResultSet.getStatement() should return StatementProxy Changes in 2.4.0 * Consolidated distribution into single JVM target (Java 7/8). Java 6 support has entered maintenance mode, bug fixes will continue on the 2.3.x branch. * Removed runtime dependency on Javassist by pre-generating proxy classes at build-time. * Significantly reduced overhead, and increased reliability, of ConcurrentBag. * Reduced garbage generation by 2-3x. * Add connection soft-eviction and replacement if backward system clock motion or significant forward jumps (greater than 1 minute) are detected. * Pool configuration properties and DataSource methods previously marked as @Deprecated have been removed. * Deprecated HikariDataSource.shutdown() in favor of close(). * Improve shutdown performance. * Allow user specified ScheduledThreadPoolExecutor for housekeeping timer. Useful in applications with dozens or hundreds of pools in the same JVM. * Reduce overhead and accuracy of Dropwizard gauges. Changes in 2.3.7 * Try harder at resolving the driver by various means when both driverClassName and jdbcUrl have been specified. * Allow a specifically set DataSource instance to override other settings such as jdbcUrl, dataSourceClassName, or driverClassName. * Fixed issue where, in the case of a driver-based configuration (jdbcUrl), we were not initialising the network timeout Executor. * Fixed race condition uncovered during load-testing in which the connections in the pool can spike to the maximum pool size when many connections reach their maxLifetime at the same time. Changes in 2.3.6 * Allow explicit definition of driverClassName to override DriverManager.getDriver(url) located driver. * Fixed a rare issue where a Connection that is held out of the pool, and never used by the holding thread, upon returning to the pool might be given to another thread without an aliveness test. Changes in 2.3.5 * Fixed regression caused by enhancement #279 that imposed a runtime dependency on Dropwizard metrics. Changes in 2.3.4 * Fixed class cast exception when setting the HealthCheckRegistry via JNDI lookup. * Allow Dropwizard MetricRegistry/HealthCheckRegistry to be set after pool startup -- one time only. * Make logger in BaseHikariPool non-static and use getClass() to log messages as the implementation class rather than as BaseHikariPool. * Removed deprecation from connectionInitSql, it will be allowed. * Made suspect/resume lock non-static (should be be shared across pools). * Improved unwrap() behavior in the Hibernate HikariConnectionProvider. * Improved leak detection log Changes in 2.3.3 * Fixed bad interaction with PostgeSQL JDBC driver whereby a SQLException thrown by PostgreSQL where the getNextException() call returns the original exception and causes an infinite loop in HikariCP (and eventual stack overflow). * Throw a typed Exception rather than a simple RuntimeException when pool initialization fails. * Allow Dropwizard Metrics and HealthChecks to be configured by a JNDI lookup. Changes in 2.3.2 * Add support for Dropwizard HealthChecks through the introduction of two initial health checks: ConnectivityCheck and Connection99Percent. See the Github project wiki for documentation. * Allow a lower maxLifetime setting of 30 seconds (compared to previous 120 second limit) * Improve the message displayed when a connection leak is detected. * Fixed a bug where Connection.setNetworkTimeout() was called on an already closed connection resulting in a warning log from the AS400 JDBC driver. Changes in 2.3.1 * Work around a bug in the MySQL Connector/J implementation of Connection.setNetworkTimeout() that results in non-deterministic asynchronous application of the timeout, resulting in an NPE from the MySQL driver when setNetworkTimeout() is followed immediately by close(). * Introduced a separate validationTimeout property, distict from connectionTimeout, to allow greater control for some deployments that desire a long (or infinite) connectionTimeout but expect the aliveness check to succeed for fail within a different (shorter) amount of time. Changes in 2.3.0 * Support pool suspend/resume to support certain failover scenarios. * Fix theoretical race in JDBC 4.0 detection support. * Improve shutdown() semantics to avoid exceptions as connections are forcefully aborted. * Unregister Codahale metrics at shutdown, if metrics are enabled. * Major internal project layout restructuring to allow shared use of common code between the Java 6/7 and Java 8 versions. * Fixed bug where two pools in the same VM (and ClassLoading domain), using drivers with differing JDBC support levels, would fail unless both pools were using connectionTestQuery. * Improved timeliness of maxLifetime evictions, while increasing performance of getConnection() slightly as a side-effect. * Fixed bug in HikariDataSource unwrap() semantics. * Allow a lower leakDetectionThreshold of 2 seconds. * Fixed bug when using the HikariJNDIFactory that required the presence of Codahale metrics. * Support initializationFailFast even when minimumIdle = 0 * Log internal pool inconsistencies rather than throwing exceptions that might disrupt internal executors. * Guard against poor or unreliable System.nanoTime() implementations. Changes in 2.2.5 * Fixes for Java 6 compatibility. * Implement full transaction state tracking. This allows HikariCP to bypass the automatic rollback when connections are returned to the pool if the transaction state is "clean". * Rename MBean closeIdleConnections() to softEvictConnections() and implement "evict on return" semantics. * Fixed bug in code that sets HikariConfig values from a Properties instance that prevented defaults from being read properly. * Fixed an obscure bug in connection creation with a driver that throws an exception when setTransactionIsolation() is called with the value returned by getTransactionIsolation(). We now bypass setTransactionIsolation() if the user has not configured an isolation level (using the default). * Fix a bug where DataSource.loginTimeout() was always being set to 1 second. * Fix bug where some drivers return 0 from Connection.getNetworkTimeout(), and yet throw SQLFeatureNotSupportedException when setNetworkTimeout() is called. This broke they way that HikariCP had implemented JDBC 4.1 support detection. Changes in 2.2.4 * Generate proxy classes into the same protection domain as the HikariCP loaded classes. This solves issues with signed jars. * Improve accuracy of pool statistics available to JMX and logged at debug level (at a slight performance cost). * Fixed issue where after a database down condition, and when minimumIdle is set to 0, when the database connectivity is restored the connections could ramp up to the maximum pool size. Eventually, idleTimeout and maxLifetime would restore normal pool conditions, but it was still undesirable behavior. * Improved connection timeout handling by using Connection.setNetworkTimeout() if available (JDBC 4.1). * driverClassName is no longer a required property when jdbcUrl is specified. Omitting this property only works for compliant drivers. * Add auto-detection of support for Statement.setQueryTimeout() used in the alive check. Fixes failures with test queries on the PostgreSQL driver when not using JDBC4 isValid() alive checks. * The pool now defaults to fail-fast initialization. If you need to start your application without/before the database, you will need to explicitly set initializationFailFast to false. * Dropwizard/Codahale metrics are now supported via the setMetricRegistry() method in HikariConfig and in HikariDataSource. * Fixed issue with pool initialization of MySQL after default value of initializationFailFast property was changed to false. * Further shadow runtime dependency on Codahale metrics from reflection performed by Spring and other IoC containers. * Fix issue where network timeout was not properly restored to its default value after modifying it for the duration of the addConnection() method. Changes in 2.1.0 * Significant internal refactor supporting creation of new proxy instances (throwaway) around Connections for each call to getConnection(). This can avoid issues where a thread continues to try to use a connection after it is closed [returned to the pool]. * Allow HikariConfig(String propertyFileName) to load properties file from classloader as a stream, with fall-back to the file-system. * Allow loading of properties file specified by -Dhikaricp.configurationFile system property when using the default HikariConfig() or HikariDataSource() constructors. * Fixed accounting issue with totalConnections when aborting connections during shutdown, causing a warning message to be logged. * Fixed regression in Java 8 codeline that would prevent minimumIdle from being set before maxPoolSize. * Fixed regression with Tomcat carping about ThreadLocal variables held after web application restart * Change to make HikariConfig.getTransactionIsolation()/setTransactionIsolation() follow proper bean semantics. * Fixed issue where connections created in the pool would skip the alive check the first time they were used. Changes in 2.0.1 * Split project into Java 6/7 and Java 8 components. * Fixed issue in JNDI object factory which would not allow JNDI-defined DataSource properties to pass-thru to the pool. * Fixed issue where under certain conditions getConnection() could timeout prematurely. * Fixed issue where user-defined pool name would be overridden by the automatically generated name. * Fixed NPE when one of either username and password is defined, and the other is null. * Fixed issue tracking the statements when there are mixed statement types (Statement, PreparedStatement, etc.) open on the connection and the number of unclosed statements exceeds 32. * Fixed issue where housekeeping threads would add idle connections even when minimumIdle was 0. * Fixed issue where Wrapper.isWrapperFor() and Wrapper.unwrap() calls did not recurse as per specification. * HikariDataSource now implements the Closable interface. * Integrated change to allow specifying a ThreadGroup for thread creation is certain restricted environments. Changes in 1.4.0 *) Fix bug that did not allow minIdle property to be set. Changes in 1.3.9 *) Added pool name to housekeeping thread name to make thread dumps more meaningful in containers with multiple pools. *) Improved shutdown semantics; make a concerted effort to close idle connections and abort or close active connections. *) Performance enhancements. Changes in 1.3.8 *) Fixed incorrect logic when using JDBC4 isValid() test for alive status of connection. Changes in 1.3.7 *) Added JNDI object factory (com.zaxxer.hikari.HikariJNDIFactory) for Tomcat and other containers that prefer JNDI-registered DataSource factories. *) Fix NPE that can occur when connections cannot be created and callers to getConnection() timeout. *) Various bug fixes and minor enhancements. Changes in 1.3.6 *) Include connection failure cause in calls to getConnection() that timeout (due to connection failure). Removed chatty logging. *) Java8 Compatibility fixes. *) Include pool name in logging messages. Thanks for the contribution @jaredstehler. Changes in 1.3.5 *) Fixed a regression in the Javassist code generation. *) Various bug fixes and minor enhancements. Changes in 1.3.4 *) Added new property isolateInternalQueries used to control whether internal pool queries such as connection alive tests are isolated in their own transaction. *) Added properties for DriverManager (driverClassName) and JDBC URL-based (jdbcUrl) configuration. 1999 called and wants its JDBC driver back. *) Added new username and password properties to allow default authentication for connections. *) Added support for the getConnection(username, password) method signature to HikariDataSource. *) Added new property readOnly to control the default read-only status of connections in the pool. *) Deprecated acquireIncrement property. *) Deprecated acquireRetries property. *) Deprecated acquireRetryDelay property. *) Deprecated minimumPoolSize property. *) Added new property minimumIdle used to control the minimum number of idle connections the pool should try to maintain on a running basis. *) Added evictConnection(Connection) method to HikariDataSource to allow special cases where users wish to forcibly eject a connection from the pool. To use used cautiously, read the JavaDoc before using. *) Various bug fixes and minor enhancements. Changes in 1.3.3 *) Removed shared state contention that was causing excessive CPU cache-line flushing. Nearly 4x improvement in Connection acquisition/release performance. *) Fixed issue with Tomcat carping about ThreadLocal variables held after web application restart. *) Fixed issue where the maximum configured connections could be overrun during large burst requests for connections. Changes in 1.3.2 *) Java 6 compatibility. *) HikariDataSource now extends HikariConfig, so pool properties can be set directly on a HikariDataSource without need to create a HikariConfig. The cost of doing so is a small runtime cost due to the fact that an "is initialized" check must be performed on every invocation of getConnection() due to lazy initialization of the pool. *) Added Sybase-specific disconnect error codes to SQLException snooping. *) Added HikariConfig.setCatalog() method to set DataSource catalog. *) Add DataSource.close() method that is synonymous with shutdown(). *) More performance improvements (never ending). *) Moved benchmarks to https://github.com/brettwooldridge/HikariCP-benchmark Changes in 1.3.0 *) Pool is now backed by a custom lock-less ConcurrentBag that provides superior performance to LinkedBlockingQueue and LinkedTransferQueue for usage patterns of connection pools. *) Fixed bugs reported against the 1.2.9 release. *) Added more detailed logging for broken connections and failures during new connection creation. Changes in 1.2.9 *) Added a fail-fast option for pool initialization. If enabled, a RuntimeException will be thrown if there are errors during pool initialization. *) Made the registration of the HikariCP MBeans optional. They now default to not being registered. Registering them causes a minor performance hit due to additional pool data collection in HikariDataSource.getConnection(). *) Added the SQLException message to the log entry when an exception occurs during physical connection acquisition. *) Implemented an orderly shutdown of the pool via the shutdown() method on HikariDataSource. *) Listened to "Adele - Live At The Royal Albert Hall" on endless loop. Changes in 1.2.8 *) Fixed a critical bug introduced in 1.2.7 occurring when the number of concurrently open statements exceeds sixteen. Changes in 1.2.7 *) Finally achieved performance parity between the generated delegates and the former method of instrumenting driver classes directly. *) Improved generated delegate code. Removed unnecessary casts, moved to a static proxy factory rather than a singleton (performance win). *) Improved performance of FastStatementList (primary source of speed-up to reach parity with former instrumentation code). *) Removed aliveness check on connection creation. *) Track connection isolation level and only reset if the state has become "dirty". Avoids unnecessary round trip to the DB during the aliveness check. *) Added interface IConnectionCustomizer and related HikariConfig property 'connectionCustomizerClassName' to allow users to specify a connection customization implementation. Changes in 1.2.6 *) Fixed regression that caused IndexOutOfBounds when multiple unclosed Statements existed at the time of Connection.close(). *) Fixed incorrect pom.xml dependency on Hibernate. Changes in 1.2.5 *) Instrumentation mode (agent) removed due to narrowing gap between delegation mode and instrumentation (and to simplify the code base). *) Added setDataSource() to HikariConfig to allow a DataSource instance to be explicitly wrapped by the pool. Only available when creating HikariConfig programmatically or constructing HikariConfig from a java.util.Properties instance. *) Fixed Hibernate threading issue (certain usage patterns) introduced in 1.2.2. *) Fixed issue observed with PostgreSQL whereby the query that tests the connection for "aliveness" also starts a transaction (when auto-commit is false), thereby causing a later failure when we tried to set the transaction isolation level. *) Fixed issue where idleTimeout could not be set to 0, thereby disabling it. Incorrect value validation caused 0 to be rejected as a valid value. Changes in 1.2.4 *) Fix another Hibernate-related issue whereby an NPE is encountered when a thread that was not the thread that obtained a Connection tries to interact with that Connection. Changes in 1.2.3 *) Fix internal (but suppressed) exception during rollback of connections returned to the pool with auto-commit turned off. *) Fix a reflection issue that causes Hibernate failures due to the CallableStatement interface being incorrectly injected into statement proxies that are PreparedStatement or Statement instances. Changes in 1.2.2 *) Perform a rollback() on connections returned to the pool with auto commit disabled. *) Add a constructor for HikariConfig that accepts a Properties object. *) Speed improvements for delegate mode. *) Fix a bug where connection timeouts could not be disabled. *) Permit setting the DataSource logWriter either on the HikariDataSource or via addDataSourceProperty() on the HikariConfig. *) Add transactionIsolation property to allow setting the default transaction isolation level for connections. Changes in 1.2.1 *) Clear SQL warnings before returning a connection to the user. *) Added asynchronous connection backfill strategy that triggers when the pool becomes empty as a result of dispatching a connection. *) Changed default acquireIncrement to 1, set minimum timeout of 100ms for acquiring a connection. Changes in 1.1.9 *) Added connectionInitSql property to allow setting connection properties when a new connection is created. *) Added setDataSourceProperties() setter to HikariConfig to allow easier configuration though Spring. HikariCP-HikariCP-2.7.1/LICENSE000066400000000000000000000240411315431642000156100ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. HikariCP-HikariCP-2.7.1/README.md000066400000000000000000000724601315431642000160720ustar00rootroot00000000000000

HikariCP It's Faster.Hi·ka·ri [hi·ka·'lē] (Origin: Japanese): light; ray.


[![][Build Status img]][Build Status] [![][Coverage Status img]][Coverage Status] [![][Dependency Status img]][Dependency Status] [![][license img]][license] [![][Maven Central img]][Maven Central] [![][Javadocs img]][Javadocs] Fast, simple, reliable. HikariCP is a "zero-overhead" production ready JDBC connection pool. At roughly 130Kb, the library is very light. Read about [how we do it here](https://github.com/brettwooldridge/HikariCP/wiki/Down-the-Rabbit-Hole).    **"Simplicity is prerequisite for reliability."**
         - *Edsger Dijkstra*
---------------------------------------------------- _Java 8 maven artifact:_ ```xml com.zaxxer HikariCP 2.7.0 ``` _Java 9 Early Access maven artifact:_ ```xml com.zaxxer HikariCP-java9ea 2.6.1 ``` _Java 7 maven artifact (*maintenance mode*):_ ```xml com.zaxxer HikariCP-java7 2.4.12 ``` _Java 6 maven artifact (*maintenance mode*):_ ```xml com.zaxxer HikariCP-java6 2.3.13 ``` Or [download from here](http://search.maven.org/#search%7Cga%7C1%7Ccom.zaxxer.hikaricp). ---------------------------------------------------- ##### JMH Benchmarks :checkered_flag: Microbenchmarks were created to isolate and measure the overhead of pools using the [JMH microbenchmark framework](http://openjdk.java.net/projects/code-tools/jmh/). You can checkout the [HikariCP benchmark project for details](https://github.com/brettwooldridge/HikariCP-benchmark) and review/run the benchmarks yourself. ![](https://github.com/brettwooldridge/HikariCP/wiki/HikariCP-bench-2.6.0.png) * One *Connection Cycle* is defined as single ``DataSource.getConnection()``/``Connection.close()``. * One *Statement Cycle* is defined as single ``Connection.prepareStatement()``, ``Statement.execute()``, ``Statement.close()``. 1 Versions: HikariCP 2.6.0, commons-dbcp2 2.1.1, Tomcat 8.0.24, Vibur 16.1, c3p0 0.9.5.2, Java 8u111
2 Intel Core i7-3770 CPU @ 3.40GHz
3 Uncontended benchmark: 32 threads/32 connections, Contended benchmark: 32 threads, 16 connections
4 Apache Tomcat fails to complete the Statement benchmark when the Tomcat StatementFinalizer is used due to excessive garbage collection times
5 Apache DBCP fails to complete the Statement benchmark due to excessive garbage collection times
---------------------------------------------------- #### Analyses :microscope: #### Spike Demand Pool Comparison Anaylsis of HikariCP v2.6, in comparison to other pools, in relation to a unique "spike demand" load. The customer's environment imposed a high cost of new connection acquisition, and a requirement for a dynamically-sized pool, but yet a need for responsiveness to request spikes. Read about the spike demand handling [here](https://github.com/brettwooldridge/HikariCP/blob/dev/documents/Welcome-To-The-Jungle.md).

#### You're [probably] doing it wrong. AKA *"What you probably didn't know about connection pool sizing"*. Watch a video from the Oracle Real-world Performance group, and learn about why connection pools do not need to be sized as large as they often are. In fact, oversized connection pools have a clear and demonstrable *negative* impact on performance; a 50x difference in the case of the Oracle demonstration. [Read on to find out](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing).
#### WIX Engineering Analysis We'd like to thank the guys over at WIX for the unsolicited and deep write-up about HikariCP on their [engineering blog](http://engineering.wix.com/2015/04/28/how-does-hikaricp-compare-to-other-connection-pools/). Take a look if you have time.


#### Failure: Pools behaving badly Read our interesting ["Database down" pool challenge](https://github.com/brettwooldridge/HikariCP/wiki/Bad-Behavior:-Handling-Database-Down). ---------------------------------------------------- #### "Imitation Is The Sincerest Form Of Plagiarism" - anonymous Open source software like HikariCP, like any product, competes in the free market. We get it. We understand that product advancements, once public, are often co-opted. And we understand that ideas can arise from the zeitgeist; simultaneously and independently. But the timeline of innovation, particularly in open source projects, is also clear and we want our users to understand the direction of flow of innovation in our space. It could be demoralizing to see the result of hundreds of hours of thought and research co-opted so easily, and perhaps that is inherent in a free marketplace, but we are not demoralized. *We are motivated; to widen the gap.* ---------------------------------------------------- ##### User Testimonials [![](https://github.com/brettwooldridge/HikariCP/wiki/tweet3.png)](https://twitter.com/jkuipers)
[![](https://github.com/brettwooldridge/HikariCP/wiki/tweet1.png)](https://twitter.com/steve_objectify)
[![](https://github.com/brettwooldridge/HikariCP/wiki/tweet2.png)](https://twitter.com/brettemeyer)
[![](https://github.com/brettwooldridge/HikariCP/wiki/tweet4.png)](https://twitter.com/dgomesbr/status/527521925401419776) ------------------------------ #### Configuration (knobs, baby!) HikariCP comes with *sane* defaults that perform well in most deployments without additional tweaking. **Every property is optional, except for the "essentials" marked below.** 📎 *HikariCP uses milliseconds for all time values.* 🚨 HikariCP relies on accurate timers for both performance and reliability. It is *imperative* that your server is synchronized with a time-source such as an NTP server. *Especially* if your server is running within a virtual machine. Why? [Read more here](https://dba.stackexchange.com/questions/171002/choice-of-connection-pooling-library-for-vm-deploys/171020). **Do not rely on hypervisor settings to "synchronize" the clock of the virtual machine. Configure time-source synchronization inside the virtual machine.** If you come asking for support on an issue that turns out to be caused by lack time synchronization, you will be taunted publicly on Twitter. ##### Essentials 🔠``dataSourceClassName``
This is the name of the ``DataSource`` class provided by the JDBC driver. Consult the documentation for your specific JDBC driver to get this class name, or see the [table](https://github.com/brettwooldridge/HikariCP#popular-datasource-class-names) below. Note XA data sources are not supported. XA requires a real transaction manager like [bitronix](https://github.com/bitronix/btm). Note that you do not need this property if you are using ``jdbcUrl`` for "old-school" DriverManager-based JDBC driver configuration. *Default: none* *- or -* 🔠``jdbcUrl``
This property directs HikariCP to use "DriverManager-based" configuration. We feel that DataSource-based configuration (above) is superior for a variety of reasons (see below), but for many deployments there is little significant difference. **When using this property with "old" drivers, you may also need to set the ``driverClassName`` property, but try it first without.** Note that if this property is used, you may still use *DataSource* properties to configure your driver and is in fact recommended over driver parameters specified in the URL itself. *Default: none* *** 🔠``username``
This property sets the default authentication username used when obtaining *Connections* from the underlying driver. Note that for DataSources this works in a very deterministic fashion by calling ``DataSource.getConnection(*username*, password)`` on the underlying DataSource. However, for Driver-based configurations, every driver is different. In the case of Driver-based, HikariCP will use this ``username`` property to set a ``user`` property in the ``Properties`` passed to the driver's ``DriverManager.getConnection(jdbcUrl, props)`` call. If this is not what you need, skip this method entirely and call ``addDataSourceProperty("username", ...)``, for example. *Default: none* 🔠``password``
This property sets the default authentication password used when obtaining *Connections* from the underlying driver. Note that for DataSources this works in a very deterministic fashion by calling ``DataSource.getConnection(username, *password*)`` on the underlying DataSource. However, for Driver-based configurations, every driver is different. In the case of Driver-based, HikariCP will use this ``password`` property to set a ``password`` property in the ``Properties`` passed to the driver's ``DriverManager.getConnection(jdbcUrl, props)`` call. If this is not what you need, skip this method entirely and call ``addDataSourceProperty("pass", ...)``, for example. *Default: none* ##### Frequently used ✅``autoCommit``
This property controls the default auto-commit behavior of connections returned from the pool. It is a boolean value. *Default: true* ⌚``connectionTimeout``
This property controls the maximum number of milliseconds that a client (that's you) will wait for a connection from the pool. If this time is exceeded without a connection becoming available, a SQLException will be thrown. Lowest acceptable connection timeout is 250 ms. *Default: 30000 (30 seconds)* ⌚``idleTimeout``
This property controls the maximum amount of time that a connection is allowed to sit idle in the pool. **This setting only applies when ``minimumIdle`` is defined to be less than ``maximumPoolSize``.** Whether a connection is retired as idle or not is subject to a maximum variation of +30 seconds, and average variation of +15 seconds. A connection will never be retired as idle *before* this timeout. A value of 0 means that idle connections are never removed from the pool. The minimum allowed value is 10000ms (10 seconds). *Default: 600000 (10 minutes)* ⌚``maxLifetime``
This property controls the maximum lifetime of a connection in the pool. An in-use connection will never be retired, only when it is closed will it then be removed. **We strongly recommend setting this value, and it should be at least 30 seconds less than any database or infrastructure imposed connection time limit.** A value of 0 indicates no maximum lifetime (infinite lifetime), subject of course to the ``idleTimeout`` setting. *Default: 1800000 (30 minutes)* 🔠``connectionTestQuery``
**If your driver supports JDBC4 we strongly recommend not setting this property.** This is for "legacy" drivers that do not support the JDBC4 ``Connection.isValid() API``. This is the query that will be executed just before a connection is given to you from the pool to validate that the connection to the database is still alive. *Again, try running the pool without this property, HikariCP will log an error if your driver is not JDBC4 compliant to let you know.* *Default: none* 🔢``minimumIdle``
This property controls the minimum number of *idle connections* that HikariCP tries to maintain in the pool. If the idle connections dip below this value and total connections in the pool are less than ``maximumPoolSize``, HikariCP will make a best effort to add additional connections quickly and efficiently. However, for maximum performance and responsiveness to spike demands, we recommend *not* setting this value and instead allowing HikariCP to act as a *fixed size* connection pool. *Default: same as maximumPoolSize* 🔢``maximumPoolSize``
This property controls the maximum size that the pool is allowed to reach, including both idle and in-use connections. Basically this value will determine the maximum number of actual connections to the database backend. A reasonable value for this is best determined by your execution environment. When the pool reaches this size, and no idle connections are available, calls to getConnection() will block for up to ``connectionTimeout`` milliseconds before timing out. Please read [about pool sizing](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing). *Default: 10* 📈``metricRegistry``
This property is only available via programmatic configuration or IoC container. This property allows you to specify an instance of a *Codahale/Dropwizard* ``MetricRegistry`` to be used by the pool to record various metrics. See the [Metrics](https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-Metrics) wiki page for details. *Default: none* 📈``healthCheckRegistry``
This property is only available via programmatic configuration or IoC container. This property allows you to specify an instance of a *Codahale/Dropwizard* ``HealthCheckRegistry`` to be used by the pool to report current health information. See the [Health Checks](https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-HealthChecks) wiki page for details. *Default: none* 🔠``poolName``
This property represents a user-defined name for the connection pool and appears mainly in logging and JMX management consoles to identify pools and pool configurations. *Default: auto-generated* ##### Infrequently used ⌚``initializationFailTimeout``
This property controls whether the pool will "fail fast" if the pool cannot be seeded with an initial connection successfully. Any positive number is taken to be the number of milliseconds to attempt to acquire an initial connection; the application thread will be blocked during this period. If a connection cannot be acquired before this timeout occurs, an exception will be thrown. This timeout is applied *after* the ``connectionTimeout`` period. If the value is zero (0), HikariCP will attempt to obtain and validate a connection. If a connection is obtained, but fails validation, an exception will be thrown and the pool not started. However, if a connection cannot be obtained, the pool will start, but later efforts to obtain a connection may fail. A value less than zero will bypass any initial connection attempt, and the pool will start immediately while trying to obtain connections in the background. Consequently, later efforts to obtain a connection may fail. *Default: 1* ❎``isolateInternalQueries``
This property determines whether HikariCP isolates internal pool queries, such as the connection alive test, in their own transaction. Since these are typically read-only queries, it is rarely necessary to encapsulate them in their own transaction. This property only applies if ``autoCommit`` is disabled. *Default: false* ❎``allowPoolSuspension``
This property controls whether the pool can be suspended and resumed through JMX. This is useful for certain failover automation scenarios. When the pool is suspended, calls to ``getConnection()`` will *not* timeout and will be held until the pool is resumed. *Default: false* ❎``readOnly``
This property controls whether *Connections* obtained from the pool are in read-only mode by default. Note some databases do not support the concept of read-only mode, while others provide query optimizations when the *Connection* is set to read-only. Whether you need this property or not will depend largely on your application and database. *Default: false* ❎``registerMbeans``
This property controls whether or not JMX Management Beans ("MBeans") are registered or not. *Default: false* 🔠``catalog``
This property sets the default *catalog* for databases that support the concept of catalogs. If this property is not specified, the default catalog defined by the JDBC driver is used. *Default: driver default* 🔠``connectionInitSql``
This property sets a SQL statement that will be executed after every new connection creation before adding it to the pool. If this SQL is not valid or throws an exception, it will be treated as a connection failure and the standard retry logic will be followed. *Default: none* 🔠``driverClassName``
HikariCP will attempt to resolve a driver through the DriverManager based solely on the ``jdbcUrl``, but for some older drivers the ``driverClassName`` must also be specified. Omit this property unless you get an obvious error message indicating that the driver was not found. *Default: none* 🔠``transactionIsolation``
This property controls the default transaction isolation level of connections returned from the pool. If this property is not specified, the default transaction isolation level defined by the JDBC driver is used. Only use this property if you have specific isolation requirements that are common for all queries. The value of this property is the constant name from the ``Connection`` class such as ``TRANSACTION_READ_COMMITTED``, ``TRANSACTION_REPEATABLE_READ``, etc. *Default: driver default* ⌚``validationTimeout``
This property controls the maximum amount of time that a connection will be tested for aliveness. This value must be less than the ``connectionTimeout``. Lowest acceptable validation timeout is 250 ms. *Default: 5000* ⌚``leakDetectionThreshold``
This property controls the amount of time that a connection can be out of the pool before a message is logged indicating a possible connection leak. A value of 0 means leak detection is disabled. Lowest acceptable value for enabling leak detection is 2000 (2 seconds). *Default: 0* ➡``dataSource``
This property is only available via programmatic configuration or IoC container. This property allows you to directly set the instance of the ``DataSource`` to be wrapped by the pool, rather than having HikariCP construct it via reflection. This can be useful in some dependency injection frameworks. When this property is specified, the ``dataSourceClassName`` property and all DataSource-specific properties will be ignored. *Default: none* ➡``threadFactory``
This property is only available via programmatic configuration or IoC container. This property allows you to set the instance of the ``java.util.concurrent.ThreadFactory`` that will be used for creating all threads used by the pool. It is needed in some restricted execution environments where threads can only be created through a ``ThreadFactory`` provided by the application container. *Default: none* ➡``scheduledExecutor``
This property is only available via programmatic configuration or IoC container. This property allows you to set the instance of the ``java.util.concurrent.ScheduledExecutorService`` that will be used for various internally scheduled tasks. If supplying HikariCP with a ``ScheduledThreadPoolExecutor`` instance, it is recommended that ``setRemoveOnCancelPolicy(true)`` is used. *Default: none* ---------------------------------------------------- #### Missing Knobs HikariCP has plenty of "knobs" to turn as you can see above, but comparatively less than some other pools. This is a design philosophy. The HikariCP design aesthetic is Minimalism. In keeping with the *simple is better* or *less is more* design philosophy, some configuration axis are intentionally left out. #### Statement Cache Many connection pools, including Apache DBCP, Vibur, c3p0 and others offer ``PreparedStatement`` caching. HikariCP does not. Why? At the connection pool layer ``PreparedStatements`` can only be cached *per connection*. If your application has 250 commonly executed queries and a pool of 20 connections you are asking your database to hold on to 5000 query execution plans -- and similarly the pool must cache this many ``PreparedStatements`` and their related graph of objects. Most major database JDBC drivers already have a Statement cache that can be configured, including PostgreSQL, Oracle, Derby, MySQL, DB2, and many others. JDBC drivers are in a unique position to exploit database specific features, and nearly all of the caching implementations are capable of sharing execution plans *across connections*. This means that instead of 5000 statements in memory and associated execution plans, your 250 commonly executed queries result in exactly 250 execution plans in the database. Clever implementations do not even retain ``PreparedStatement`` objects in memory at the driver-level but instead merely attach new instances to existing plan IDs. Using a statement cache at the pooling layer is an [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern), and will negatively impact your application performance compared to driver-provided caches. #### Log Statement Text / Slow Query Logging Like Statement caching, most major database vendors support statement logging through properties of their own driver. This includes Oracle, MySQL, Derby, MSSQL, and others. Some even support slow query logging. For those few databases that do not support it, [log4jdbc](https://github.com/arthurblake/log4jdbc) or [jdbcdslog-exp](https://code.google.com/p/jdbcdslog-exp/) are good options. ---------------------------------------------------- ### Initialization You can use the ``HikariConfig`` class like so1: ```java HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons"); config.setUsername("bart"); config.setPassword("51mp50n"); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); HikariDataSource ds = new HikariDataSource(config); ```  1 MySQL-specific example, DO NOT COPY VERBATIM. or directly instantiate a ``HikariDataSource`` like so: ```java HikariDataSource ds = new HikariDataSource(); ds.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons"); ds.setUsername("bart"); ds.setPassword("51mp50n"); ... ``` or property file based: ```java // Examines both filesystem and classpath for .properties file HikariConfig config = new HikariConfig("/some/path/hikari.properties"); HikariDataSource ds = new HikariDataSource(config); ``` Example property file: ```ini dataSourceClassName=org.postgresql.ds.PGSimpleDataSource dataSource.user=test dataSource.password=test dataSource.databaseName=mydb dataSource.portNumber=5432 dataSource.serverName=localhost ``` or ``java.util.Properties`` based: ```java Properties props = new Properties(); props.setProperty("dataSourceClassName", "org.postgresql.ds.PGSimpleDataSource"); props.setProperty("dataSource.user", "test"); props.setProperty("dataSource.password", "test"); props.setProperty("dataSource.databaseName", "mydb"); props.put("dataSource.logWriter", new PrintWriter(System.out)); HikariConfig config = new HikariConfig(props); HikariDataSource ds = new HikariDataSource(config); ``` There is also a System property available, ``hikaricp.configurationFile``, that can be used to specify the location of a properties file. If you intend to use this option, construct a ``HikariConfig`` or ``HikariDataSource`` instance using the default constructor and the properties file will be loaded. ### Performance Tips [MySQL Performnace Tips](https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration) ### Popular DataSource Class Names We recommended using ``dataSourceClassName`` instead of ``jdbcUrl``, but either is acceptable. We'll say that again, *either is acceptable*. ⚠ *Note: Spring Boot auto-configuration users, you need to use ``jdbcUrl``-based configuration.* ⚠ The MySQL DataSource is known to be broken with respect to network timeout support. Use ``jdbcUrl`` configuration instead. Here is a list of JDBC *DataSource* classes for popular databases: | Database | Driver | *DataSource* class | |:---------------- |:------------ |:-------------------| | Apache Derby | Derby | org.apache.derby.jdbc.ClientDataSource | | Firebird | Jaybird | org.firebirdsql.pool.FBSimpleDataSource | | H2 | H2 | org.h2.jdbcx.JdbcDataSource | | HSQLDB | HSQLDB | org.hsqldb.jdbc.JDBCDataSource | | IBM DB2 | IBM JCC | com.ibm.db2.jcc.DB2SimpleDataSource | | IBM Informix | IBM Informix | com.informix.jdbcx.IfxDataSource | | MS SQL Server | Microsoft | com.microsoft.sqlserver.jdbc.SQLServerDataSource | | ~~MySQL~~ | Connector/J | ~~com.mysql.jdbc.jdbc2.optional.MysqlDataSource~~ | | MySQL/MariaDB | MariaDB | org.mariadb.jdbc.MySQLDataSource | | Oracle | Oracle | oracle.jdbc.pool.OracleDataSource | | OrientDB | OrientDB | com.orientechnologies.orient.jdbc.OrientDataSource | | PostgreSQL | pgjdbc-ng | com.impossibl.postgres.jdbc.PGDataSource | | PostgreSQL | PostgreSQL | org.postgresql.ds.PGSimpleDataSource | | SAP MaxDB | SAP | com.sap.dbtech.jdbc.DriverSapDB | | SQLite | xerial | org.sqlite.SQLiteDataSource | | SyBase | jConnect | com.sybase.jdbc4.jdbc.SybDataSource | ### Play Framework Plugin Note Play 2.4 now uses HikariCP by default. A new plugin has come up for the the Play framework; [play-hikaricp](http://edulify.github.io/play-hikaricp.edulify.com/). If you're using the excellent Play framework, your application deserves HikariCP. Thanks Edulify Team! ### Clojure Wrapper A new Clojure wrapper has been created by [tomekw](https://github.com/tomekw) and can be [found here](https://github.com/tomekw/hikari-cp). ### JRuby Wrapper A new JRuby wrapper has been created by [tomekw](https://github.com/tomekw) and can be [found here](https://github.com/tomekw/hucpa). ---------------------------------------------------- ### Support 💬 Google discussion group [HikariCP here](https://groups.google.com/d/forum/hikari-cp), growing [FAQ](https://github.com/brettwooldridge/HikariCP/wiki/FAQ). [![](https://raw.github.com/wiki/brettwooldridge/HikariCP/twitter.png)](https://twitter.com/share?text=Interesting%20JDBC%20Connection%20Pool&hashtags=HikariCP&url=https%3A%2F%2Fgithub.com%2Fbrettwooldridge%2FHikariCP) [![](https://raw.github.com/wiki/brettwooldridge/HikariCP/facebook.png)](http://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fgithub.com%2Fbrettwooldridge%2FHikariCP&width&layout=standard&action=recommend&show_faces=true&share=false&height=80) ### Wiki Don't forget the [Wiki](https://github.com/brettwooldridge/HikariCP/wiki) for additional information such as: * [FAQ](https://github.com/brettwooldridge/HikariCP/wiki/FAQ) * [Hibernate 4.x Configuration](https://github.com/brettwooldridge/HikariCP/wiki/Hibernate4) * [MySQL Configuration Tips](https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration) * etc. ---------------------------------------------------- ### Requirements ⇒ Java 8+ (Java 6/7 artifacts are in maintenance mode)
⇒ slf4j library
### Sponsors YourKit supports open source projects with its full-featured Java Profiler. Click the YourKit logo below to learn more.
[![](https://github.com/brettwooldridge/HikariCP/wiki/yklogo.png)](http://www.yourkit.com/java/profiler/index.jsp)
### Contributions Please perform changes and submit pull requests from the ``dev`` branch instead of ``master``. Please set your editor to use spaces instead of tabs, and adhere to the apparent style of the code you are editing. The ``dev`` branch is always more "current" than the ``master`` if you are looking to live life on the edge. [Build Status]:https://travis-ci.org/brettwooldridge/HikariCP [Build Status img]:https://travis-ci.org/brettwooldridge/HikariCP.svg?branch=dev [Coverage Status]:https://coveralls.io/r/brettwooldridge/HikariCP?branch=dev [Coverage Status img]:https://coveralls.io/repos/brettwooldridge/HikariCP/badge.svg?branch=dev [Dependency Status]:https://www.versioneye.com/user/projects/551ce51c3661f1bee50004e0 [Dependency Status img]:https://www.versioneye.com/user/projects/551ce51c3661f1bee50004e0/badge.svg?style=flat [license]:LICENSE [license img]:https://img.shields.io/badge/license-Apache%202-blue.svg [Maven Central]:https://maven-badges.herokuapp.com/maven-central/com.zaxxer/HikariCP [Maven Central img]:https://maven-badges.herokuapp.com/maven-central/com.zaxxer/HikariCP/badge.svg [Javadocs]:http://javadoc.io/doc/com.zaxxer/HikariCP [Javadocs img]:http://javadoc.io/badge/com.zaxxer/HikariCP.svg HikariCP-HikariCP-2.7.1/TODO.md000066400000000000000000000000701315431642000156660ustar00rootroot00000000000000### TODO ### * More unit tests * Add metrics support HikariCP-HikariCP-2.7.1/documents/000077500000000000000000000000001315431642000166035ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/documents/Wall-of-Fame.md000066400000000000000000000047261315431642000213050ustar00rootroot00000000000000![][spacer]![][spacer] ![][spacer]![][spacer] ![][spacer]![][spacer] ![][spacer]![][spacer] ![][spacer]![][spacer] ------------------------------------------------------------------------------------- * Images on this page are Trademarked and Copyrighted by their respective rights holders. * Images on this page are used without express permission, and do not constitute an endorsement of HikariCP. If you are a trademark or copyright holder and wish an image to be removed from this page, please open a request in the issue tracker. [spacer]: https://github.com/brettwooldridge/HikariCP/wiki/space60x1.gif HikariCP-HikariCP-2.7.1/documents/Welcome-To-The-Jungle.md000066400000000000000000000201361315431642000230420ustar00rootroot00000000000000 Microbenchmarks are great at measuring performance "in the small"; for example, measuring the performance of individual methods. But good results do not necessarily translate into macro-scale performance. Real world access patterns and demand loads often run into deeper, systemic, architectural design issues that cannot be discerned at the micro level. HikariCP has over 100K users, so from time to time we are approached with challenges encountered "in the wild". Recently, one such challenge led to a deeper investigation: ***Spike Demand***. ### The Challenge The user has an environment where connection creation is expensive, on the order of 150ms; and yet queries typically execute in ~2ms. Long connection setup times can be the result of various factors, alone or in combination: DNS resolution times, encrypted connections with strong encryption (2048/4096 bit), external authentication, database server load, etc. *Generally speaking, for the best performance in response to spike demands, HikariCP recommends a fixed-size pool.* Unfortunately, the user's application is also in an environment where many other applications are connected to the same database, and therefore dynamically-sized pools are desirable -- where idle applications are allowed to give some of up their connections. The user is running the application with HikariCP configured as ``minimumIdle=5``. In this environment, the application has periods of quiet, as well as sudden spikes of requests, and periods of sustained activity. The combination of high connection setup times, a dynamically-sized pool requirement, and spike demands is just about the worst case scenario for a connection pool. The questions ultimately were these: > * If the pool is sitting idle with 5 connections, and is suddenly hit with 50 requests, what should happen? > * Given that a each new connection is going to take 150ms to establish, and given that each request can ultimately be satisfied in ~2ms, shouldn't even a single one of the idle connections be able to handle all the of the requests in ~100ms anyway? > * So, why is the pool size growing [so much]? We thought these were interesting questions, and HikariCP was indeed creating more connections than we expected... ### 3, 2, 1 ... Go! In order to explore these questions, we built a simulation and started measuring. The simulation harness [code is here](https://github.com/brettwooldridge/HikariCP-benchmark/blob/master/src/test/java/com/zaxxer/hikari/benchmark/SpikeLoadTest.java). The constraints are simple: * Connection establishment takes 150ms. * Query execution takes 2ms. * The maximum pool size is 50. * The minumum idle connections is 5. And the simulation is fairly simple: * Everything is quiet, and then ... Boom! ... 50 threads, at once, wanting a connection and to execute a query. * Take measurements every 250μs (microseconds). ### Results After running HikariCP through the simulation, tweaking the code (ultimately a one-line change), and satisfying ourselves that the behavior is as we would wish, we ran a few other pools through the simulation. The code was run as follows: ``` bash$ ./spiketest.sh 150 50 ``` Where ``150`` is the connection establishment time, ```` is one of [*hikari*, *dbcp2*, *vibur*, *tomcat*, *c3p0*], and ``50`` is the number of threads/requests. Note that *c3p0* was dropped from the analysis here, as its run time was ~120x that of HikariCP. #### HikariCP (v2.6.0) raw data -------------------- [![](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Hikari.png)](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Hikari.png) #### Apache DBCP (v2.1.1) raw data -------------------- [![](https://github.com/brettwooldridge/HikariCP/wiki/Spike-DBCP2.png)](https://github.com/brettwooldridge/HikariCP/wiki/Spike-DBCP2.png) #### Apache Tomcat (v8.0.24) raw data -------------------- [![](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Tomcat.png)](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Tomcat.png) #### Vibur DBCP (v16.1) raw data -------------------- [![](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Vibur.png)](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Vibur.png) * Note that the times provided in the raw data is the number of microseconds (μs) since the start of the test. For graphing purposes, raw data for each pool was trimmed such that the first entry has 0 requests enqueued, and the last entry has all connections completed. -------------------- #### Apache DBCP vs HikariCP In case you missed the *time-scale* in the graphs above, here is a properly scaled comparable; Apache DBCP on top, HikariCP on the bottom. [![](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Compare.png)](https://github.com/brettwooldridge/HikariCP/wiki/Spike-Compare.png) ### Commentary We'll start by saying that we are not going to comment on the implementation specifics of the other pools, but you may be able to draw inferences by our comments regarding HikariCP. Looking at the HikariCP graph, we couldn't have wished for a better profile; it's about as close to perfect efficiency as we could expect. It is interesting, though not surprising, that the other pool profiles are so similar to each other. Even though arrived at via different implementations, they are the result of a *conventional* or *obvious* approach to pool design. HikariCP's profile in this case, and the reason for the difference observed between other pools, is the result of our Prime Directive: 💡 **User threads should only ever block on the** ***pool itself***.1
1 to the greatest extent possible. Consider this hypothetical scenario: ``` There is a pool with five connections in-use, and zero idle (available) connections. Then, a new thread comes in requesting a connection. ``` "How the the prime directive apply in this case?" We'll answer with a question of our own: > If the thread is directed to create a new connection, and that connection takes 150ms to establish, what happens if one of the five in-use connections is returned to the pool? --------------------- Both Apache DBCP2 and Vibur ended the run with 45 connections, Apache Tomcat (inexplicably) with 40 connections, while HikariCP ended the run with 5 (technically six, see below). This has major and measurable effects for real world deployments. That is 35-40 additional connections that are not available to other applications, and 35-40 additional threads and associated memory structures in the database. We know what you are thinking, *"What if the load had been sustained?"*  The answer is: HikariCP also would have ramped up. In point of fact, as soon as the pool hit zero available connections, right around 800μs into the run, HikariCP began requesting connections to be added to the pool asynchronously. If the metrics had continued to be collected past the end of the spike -- out beyond 150ms -- you would observe that an additional connection is indeed added to the pool. But *only one*, because HikariCP employs *elision logic*; at that point HikariCP would also realize that there is actually no more pending demand, and the remaining connection acquisitions would be elided. ### Epilog This scenario represents only *one* of many access patterns. HikariCP will continue to research *and innovate* when presented with challenging problems encountered in real world deployments. As always, thank you for your patronage. HikariCP-HikariCP-2.7.1/eclipse.code.format.xml000066400000000000000000000750201315431642000211540ustar00rootroot00000000000000 HikariCP-HikariCP-2.7.1/logo.png000066400000000000000000000207711315431642000162570ustar00rootroot00000000000000PNG  IHDR>?7LiCCPICC ProfileX Yy8U_;p]Ey 9\K׬R($!TР&"CDRJ巯yw9kZkkIH Q8a`@chy GtYW8j؀(/e tĸ:;a<pk<Φ` Q(X ]$! a u0*lA@(Z BTT4O@,/9!_J_~,,6&YDEC]$Ҭ,"ږI;@q[7o14 pC)bf b|o,EAƏ1 viοc©`YA.uYXC s*%b'%!bb#\: kLyPRT,DkQڷx }}\ö]`9g>hhL ]?%&rm|C=тHK:] ?m{ht::NW36&Α>3 A8?{y@! (iVC HmgV _꯶ x6aE_a X;X[ =x3/֑𦁰BuA:,lGn 7{ĚߖhWF0 JJA5&X}?ˍc!MRxu_k-/YX4~k*ؓl材_s^h!Jʌ?om@ ]z0IƉU8HĚ }M輶V#BXsKZGM 'n~8[™ !mR@s`+> j40( gA @wcc3XA0#dF$yD F sqF?$"v$ه % 9\A:C2 oCpb1Re6cql`bR0 ?o?ď/AOp Pq,Qua ̠`@eHg(b8pa #$c c2c>c5c+c?$ (M'Éibb$ƴɉ)iS19[LcL_I$9)i3)G% =#-233K11{3111da^f!(Xd)eif`cedd5faMa-b:&fFaKe+e6ĶNfWew`be?~}!aȑQqcɦrMsJsZssEA!Ű𵑸QQcYp3s&*&4K&_LuLw0C,rsXYX[[jXna:h5d-h`]g=oeæ˖db[bNΎf׺f㡍/%!aGiǭWNNNSΪ۝{]..]>滾pqwtgu^̣cSs]/>0ow&M7Mn؜yp-}|"}}Y})p~~S(%k2Ӏ# g O 5 - 3 + [ /QuAvE E'E?Ɋݪy-& }2 J/$'Q&IH9 -`[viv8vߙsrSiĴ{*2<2Z33we]ŒE.߃^G ̹Oe_Ѿw/޿w?_3OxP0a÷!?2ZlWrT聣KBK6 -r,q ʿUU<=ayR _P5U^{Rd] _;SΧN ίϜ|Y- 'Ͻ=w~ɶ./4#C/x##Ң=3L3ve_bNž_О;Du/.-S8&p'.TWm?iUTYruݝKΤlpk4<'{|gG[.5b~Eujokk`1Y|e۽­)w|cte׃3> yDgP|yӱg;_4>8U1"ĉϦΞx,iv}\y™~$?~e~yoWƿOxZcQetہƻ0krI ̾,VZlL?ʜ>\}<(_( a!>a'<>qn2 6ryB/jG׏k*j%jw0E7|530ϰh|j5clc(d/& |5Xf(]݂!7BKÝ"" کGi1v[h\yL(tȰP08ⴣR2lu*'+ի_VSY~ʿX=Z?~ꆌsf%M/x٬E l듫]KqëòSL_7Kgw;wnO=Ϧyϣ__#SoͰwpٜ܇vW?7.b}gWBa.X\^@haHe" 発HE,欢?d9 \yv;-0"MSDE^,Zd_ݓ9G(Kq9pФ塺„æEE#GꋓZp]s1|ǧ˛+2OTJVT V;SXkx纁ӍgZ6H5b'<_Քq!%f-WxZ9s^.yCìflW~wc@"wɁ!O+8?q|ǔ xx)y{4{^jwqfX}82`v :"@rE f`VH8 f[|M^ "0JAH1rF0,EFL4 ")*Z1h1KŖa`d`\k}=yOF8Kx PW+Y(_,b?SyD!3 0og~bRJfMe}ݖ2=d;N W7/uy*xmx{ 0 t }n!j*F{*^#(i#%!Ht•.I!HE\YGEUUNMJ]rYI]q= }eC#&qf ߬mrl;~؛98;k쇻G7eSE"?*97(JqD_f|^TIS;r|v.#{^朡ʼF&_94ՊꆚSOǟn0=$|؂kŷ1_!iEɺt=~Ek:3za\l2)s-s"K6_b]ctm@ @| ̆$"† &f$ )D`Đ1Oṿ< E{E8 ;X W_ ea@:yFm4>"1x ere!aH!0`-m=}#L Tњun)\3{}gȍ.$^߲zA]=ܷ۳w߻#7O+{$_~0]s+1 ㋮n|R| YCg¿HLQ f0a+ 0# s@}< Ǵ`&Pv#,ŞƎl/ 9.gaB0 fQ &52"j3LLU$&Gp)ߘff]aegOf"rFss3;ǝWoHSIF\TXxDm!YDN@^WWq%)U5#_hJhh_a 60kho:h`g`=h`hOutuqu}`_? ֿ>#r5,&B:rZұ N]4Zf]Vў\#U?zÜ% L?.J\e?TKnDCg'*k]翯T 62 63 CJIDAThZOT/fqw@HV1(@p ^2"`U]LgpzLg_yyGG< -<[ [߃4fOLVԥ׬ql-qjeNo"q,' P H^)Q+сnjJma E[YYF0 Q6Ƌ4tW +OЦ@HcmLʭn?𱫫!?Wɠ2"Dnw&WxmE髚a>ߣ{[}f$E& -9}8$EueZ >rԄhqR_GqXJSgЋ4\9x1(G('̹ގō!ƠUY0ЁzǐVnVq趣j-Dqy2tl;%C(H`\] KfQ1F2CfHЗ lK1ZMe :^,xvN4EPso%v.}r̫"F}Mĺ|ƺtAPfxnH9`$|#3Ϥ-SGƏIӌ^$)R1Hƴj"t]'l.ƒubJq c*IA.nuٸ]tGM69?npbUQ92J ہƉyu Dw:Q}޳w)Ns/ls C]R& #q| rd"B/cuB\P_YSI]ba󦔦_Rh:؆w7y U)[2p㱡?\{?}מW/P(Eu]4Us )aFb?"<\i)_kkkõ5s`Yol33;gw<ܸlejjSSS OaU9үLU?z^s 2kIENDB`HikariCP-HikariCP-2.7.1/pom.xml000066400000000000000000000467461315431642000161400ustar00rootroot00000000000000 4.0.0 UTF-8 false 3.3.0 5.6.2 5.2.10.Final 3.22.0-CR1 0.11.4.1 2.5.3 3.2.2 0.10.0.RELEASE 0.0.22 2.8.9 4.11.0 2.5.2 1.7.25 2.8.2 1.4 1.4.195 4.12 com.zaxxer HikariCP 2.7.1 bundle HikariCP Ultimate JDBC Connection Pool https://github.com/brettwooldridge/HikariCP Zaxxer.com https://github.com/brettwooldridge scm:git:git@github.com:brettwooldridge/HikariCP.git scm:git:git@github.com:brettwooldridge/HikariCP.git git@github.com:brettwooldridge/HikariCP.git HikariCP-2.7.1 The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo Brett Wooldridge brett.wooldridge@gmail.com org.sonatype.oss oss-parent 9 3.3.9 org.slf4j slf4j-api ${slf4j.version} org.apache.logging.log4j log4j-slf4j-impl ${log4j.version} test org.apache.logging.log4j log4j-api ${log4j.version} test org.apache.logging.log4j log4j-core ${log4j.version} test org.apache.commons commons-csv ${commons.csv.version} test org.mockito mockito-core ${mockito.version} test org.hamcrest hamcrest-core junit junit ${junit.version} test org.javassist javassist ${javassist.version} true io.micrometer micrometer-core ${micrometer.version} true org.postgresql postgresql 42.1.4.jre7 test org.hibernate hibernate-core ${hibernate.version} provided true jboss-logging org.jboss.logging jboss-logging-annotations org.jboss.logging io.dropwizard.metrics metrics-core ${metrics.version} provided true io.dropwizard.metrics metrics-healthchecks ${metrics.version} provided true io.prometheus simpleclient ${simpleclient.version} provided true simple-jndi simple-jndi ${jndi.version} test javax.inject javax.inject 1 test org.apache.felix org.apache.felix.framework ${felix.version} test org.ops4j.pax.exam pax-exam-container-native ${pax.exam.version} test org.ops4j.pax.exam pax-exam-junit4 ${pax.exam.version} test org.ops4j.pax.exam pax-exam-link-assembly ${pax.exam.version} test org.ops4j.pax.exam pax-exam-link-mvn ${pax.exam.version} test org.ops4j.pax.url pax-url-aether ${pax.url.version} test org.ops4j.pax.url pax-url-reference ${pax.url.version} test com.h2database h2 ${h2.version} test org.codehaus.mojo exec-maven-plugin 1.6.0 compile java com.zaxxer.hikari.util.JavassistProxyFactory org.jacoco jacoco-maven-plugin 0.7.9 pre-unit-test prepare-agent ${project.build.directory}/coverage-reports/jacoco.exec surefireArgLine **/com/zaxxer/hikari/util/JavassistProxyFactory* **/com/zaxxer/hikari/pool/HikariProxy* **/com/zaxxer/hikari/metrics/** post-unit-test test report ${project.build.directory}/coverage-reports/jacoco.exec ${project.reporting.outputDirectory}/jacoco **/com/zaxxer/hikari/pool/HikariProxy* **/com/zaxxer/hikari/metrics/** org.apache.felix maven-bundle-plugin ${felix.bundle.plugin.version} true ${artifact.classifier} HikariCP com.zaxxer.hikari, com.zaxxer.hikari.hibernate, com.zaxxer.hikari.metrics com.zaxxer.hikari.* <_exportcontents> com.zaxxer.hikari.pool, com.zaxxer.hikari.util javax.management, javax.naming, javax.naming.spi, javax.sql, javax.sql.rowset, javax.sql.rowset.serial, javax.sql.rowset.spi, com.codahale.metrics;resolution:=optional, com.codahale.metrics.health;resolution:=optional, io.micrometer.core.instrument;resolution:=optional, org.slf4j;version="[1.6,2)", org.hibernate;resolution:=optional, org.hibernate.cfg;resolution:=optional, org.hibernate.engine.jdbc.connections.spi;resolution:=optional, org.hibernate.service;resolution:=optional, org.hibernate.service.spi;resolution:=optional ${project.groupId}.${project.artifactId} * manifest org.apache.maven.plugins maven-compiler-plugin 3.6.1 true 1.8 1.8 org.apache.maven.plugins maven-release-plugin ${maven.release.version} true HikariCP-@{project.version} org.apache.maven.plugins maven-surefire-plugin 2.20 ${surefireArgLine} ${sureFireOptions9} ${skip.unit.tests} ${sureFireForks9} org.apache.maven.plugins maven-source-plugin 3.0.1 true attach-sources jar org.apache.maven.plugins maven-javadoc-plugin 2.10.4 public com.zaxxer.hikari.hibernate:com.zaxxer.hikari.metrics.*:com.zaxxer.hikari.pool:com.zaxxer.hikari.util true 1024m bundle-sources package jar Java9 [9,) true java9 coverage org.eluder.coveralls coveralls-maven-plugin 4.3.0 coveralls verify jacoco false release-sign-artifacts performRelease true org.apache.maven.plugins maven-gpg-plugin 1.6 sign-artifacts verify sign felix true pax.exam.framework felix felix none org.apache.felix org.apache.felix.framework ${felix.version} test HikariCP-HikariCP-2.7.1/src/000077500000000000000000000000001315431642000153715ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/000077500000000000000000000000001315431642000163155ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/000077500000000000000000000000001315431642000172365ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/000077500000000000000000000000001315431642000200145ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/000077500000000000000000000000001315431642000213355ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/000077500000000000000000000000001315431642000226045ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/HikariConfig.java000066400000000000000000000772121315431642000260150ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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 com.codahale.metrics.health.HealthCheckRegistry; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.util.PropertyElf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import static com.zaxxer.hikari.util.UtilityElf.getNullIfEmpty; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; @SuppressWarnings({"SameParameterValue", "unused"}) public class HikariConfig implements HikariConfigMXBean { private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class); private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30); private static final long VALIDATION_TIMEOUT = SECONDS.toMillis(5); private static final long IDLE_TIMEOUT = MINUTES.toMillis(10); private static final long MAX_LIFETIME = MINUTES.toMillis(30); private static final int DEFAULT_POOL_SIZE = 10; private static boolean unitTest = false; // Properties changeable at runtime through the MBean // private volatile long connectionTimeout; private volatile long validationTimeout; private volatile long idleTimeout; private volatile long leakDetectionThreshold; private volatile long maxLifetime; private volatile int maxPoolSize; private volatile int minIdle; // Properties NOT changeable at runtime // private long initializationFailTimeout; private String catalog; private String connectionInitSql; private String connectionTestQuery; private String dataSourceClassName; private String dataSourceJndiName; private String driverClassName; private String jdbcUrl; private String password; private String poolName; private String schema; private String transactionIsolationName; private String username; private boolean isAutoCommit; private boolean isReadOnly; private boolean isIsolateInternalQueries; private boolean isRegisterMbeans; private boolean isAllowPoolSuspension; private DataSource dataSource; private Properties dataSourceProperties; private ThreadFactory threadFactory; private ScheduledExecutorService scheduledExecutor; private MetricsTrackerFactory metricsTrackerFactory; private Object metricRegistry; private Object healthCheckRegistry; private Properties healthCheckProperties; /** * Default constructor */ public HikariConfig() { dataSourceProperties = new Properties(); healthCheckProperties = new Properties(); minIdle = -1; maxPoolSize = -1; maxLifetime = MAX_LIFETIME; connectionTimeout = CONNECTION_TIMEOUT; validationTimeout = VALIDATION_TIMEOUT; idleTimeout = IDLE_TIMEOUT; initializationFailTimeout = 1; isAutoCommit = true; String systemProp = System.getProperty("hikaricp.configurationFile"); if (systemProp != null) { loadProperties(systemProp); } } /** * Construct a HikariConfig from the specified properties object. * * @param properties the name of the property file */ public HikariConfig(Properties properties) { this(); PropertyElf.setTargetFromProperties(this, properties); } /** * Construct a HikariConfig from the specified property file name. propertyFileName * will first be treated as a path in the file-system, and if that fails the * Class.getResourceAsStream(propertyFileName) will be tried. * * @param propertyFileName the name of the property file */ public HikariConfig(String propertyFileName) { this(); loadProperties(propertyFileName); } /** * Get the default catalog name to be set on connections. * * @return the default catalog name */ public String getCatalog() { return catalog; } /** * Set the default catalog name to be set on connections. * * @param catalog the catalog name, or null */ public void setCatalog(String catalog) { this.catalog = catalog; } /** * Get the SQL query to be executed to test the validity of connections. * * @return the SQL query string, or null */ public String getConnectionTestQuery() { return connectionTestQuery; } /** * Set the SQL query to be executed to test the validity of connections. Using * the JDBC4 Connection.isValid() method to test connection validity can * be more efficient on some databases and is recommended. * * @param connectionTestQuery a SQL query string */ public void setConnectionTestQuery(String connectionTestQuery) { this.connectionTestQuery = connectionTestQuery; } /** * Get the SQL string that will be executed on all new connections when they are * created, before they are added to the pool. * * @return the SQL to execute on new connections, or null */ public String getConnectionInitSql() { return connectionInitSql; } /** * Set the SQL string that will be executed on all new connections when they are * created, before they are added to the pool. If this query fails, it will be * treated as a failed connection attempt. * * @param connectionInitSql the SQL to execute on new connections */ public void setConnectionInitSql(String connectionInitSql) { this.connectionInitSql = connectionInitSql; } /** {@inheritDoc} */ @Override public long getConnectionTimeout() { return connectionTimeout; } /** {@inheritDoc} */ @Override public void setConnectionTimeout(long connectionTimeoutMs) { if (connectionTimeoutMs == 0) { this.connectionTimeout = Integer.MAX_VALUE; } else if (connectionTimeoutMs < 250) { throw new IllegalArgumentException("connectionTimeout cannot be less than 250ms"); } else { this.connectionTimeout = connectionTimeoutMs; } } /** {@inheritDoc} */ @Override public long getValidationTimeout() { return validationTimeout; } /** {@inheritDoc} */ @Override public void setValidationTimeout(long validationTimeoutMs) { if (validationTimeoutMs < 250) { throw new IllegalArgumentException("validationTimeout cannot be less than 250ms"); } this.validationTimeout = validationTimeoutMs; } /** * Get the {@link DataSource} that has been explicitly specified to be wrapped by the * pool. * * @return the {@link DataSource} instance, or null */ public DataSource getDataSource() { return dataSource; } /** * Set a {@link DataSource} for the pool to explicitly wrap. This setter is not * available through property file based initialization. * * @param dataSource a specific {@link DataSource} to be wrapped by the pool */ public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public String getDataSourceClassName() { return dataSourceClassName; } public void setDataSourceClassName(String className) { this.dataSourceClassName = className; } public void addDataSourceProperty(String propertyName, Object value) { dataSourceProperties.put(propertyName, value); } public String getDataSourceJNDI() { return this.dataSourceJndiName; } public void setDataSourceJNDI(String jndiDataSource) { this.dataSourceJndiName = jndiDataSource; } public Properties getDataSourceProperties() { return dataSourceProperties; } public void setDataSourceProperties(Properties dsProperties) { dataSourceProperties.putAll(dsProperties); } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { Class driverClass = null; try { driverClass = this.getClass().getClassLoader().loadClass(driverClassName); LOGGER.debug("Driver class found in the HikariConfig class classloader {}", this.getClass().getClassLoader()); } catch (ClassNotFoundException e) { ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader(); if (threadContextClassLoader != null && threadContextClassLoader != this.getClass().getClassLoader()) { try { driverClass = threadContextClassLoader.loadClass(driverClassName); LOGGER.debug("Driver class found in Thread context class loader {}", threadContextClassLoader); } catch (ClassNotFoundException e1) { LOGGER.error("Failed to load class of driverClassName {} in either of HikariConfig class classloader {} or Thread context classloader {}", driverClassName, this.getClass().getClassLoader(), threadContextClassLoader); } } else { LOGGER.error("Failed to load class of driverClassName {} in HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader()); } } if (driverClass == null) { throw new RuntimeException("Failed to load class of driverClassName [" + driverClassName + "] in either of HikariConfig class loader or Thread context classloader"); } try { driverClass.newInstance(); this.driverClassName = driverClassName; } catch (Exception e) { throw new RuntimeException("Failed to instantiate class " + driverClassName, e); } } /** {@inheritDoc} */ @Override public long getIdleTimeout() { return idleTimeout; } /** {@inheritDoc} */ @Override public void setIdleTimeout(long idleTimeoutMs) { if (idleTimeoutMs < 0) { throw new IllegalArgumentException("idleTimeout cannot be negative"); } this.idleTimeout = idleTimeoutMs; } public String getJdbcUrl() { return jdbcUrl; } public void setJdbcUrl(String jdbcUrl) { this.jdbcUrl = jdbcUrl; } /** * Get the default auto-commit behavior of connections in the pool. * * @return the default auto-commit behavior of connections */ public boolean isAutoCommit() { return isAutoCommit; } /** * Set the default auto-commit behavior of connections in the pool. * * @param isAutoCommit the desired auto-commit default for connections */ public void setAutoCommit(boolean isAutoCommit) { this.isAutoCommit = isAutoCommit; } /** * Get the pool suspension behavior (allowed or disallowed). * * @return the pool suspension behavior */ public boolean isAllowPoolSuspension() { return isAllowPoolSuspension; } /** * Set whether or not pool suspension is allowed. There is a performance * impact when pool suspension is enabled. Unless you need it (for a * redundancy system for example) do not enable it. * * @param isAllowPoolSuspension the desired pool suspension allowance */ public void setAllowPoolSuspension(boolean isAllowPoolSuspension) { this.isAllowPoolSuspension = isAllowPoolSuspension; } /** * Get the pool initialization failure timeout. See {@code #setInitializationFailTimeout(long)} * for details. * * @return the number of milliseconds before the pool initialization fails * @see HikariConfig#setInitializationFailTimeout(long) */ public long getInitializationFailTimeout() { return initializationFailTimeout; } /** * Set the pool initialization failure timeout. This setting applies to pool * initialization when {@link HikariDataSource} is constructed with a {@link HikariConfig}, * or when {@link HikariDataSource} is constructed using the no-arg constructor * and {@link HikariDataSource#getConnection()} is called. *
    *
  • Any value greater than zero will be treated as a timeout for pool initialization. * The calling thread will be blocked from continuing until a successful connection * to the database, or until the timeout is reached. If the timeout is reached, then * a {@code PoolInitializationException} will be thrown.
  • *
  • A value of zero will not prevent the pool from starting in the * case that a connection cannot be obtained. However, upon start the pool will * attempt to obtain a connection and validate that the {@code connectionTestQuery} * and {@code connectionInitSql} are valid. If those validations fail, an exception * will be thrown. If a connection cannot be obtained, the validation is skipped * and the the pool will start and continue to try to obtain connections in the * background. This can mean that callers to {@code DataSource#getConnection()} may * encounter exceptions.
  • *
  • A value less than zero will not bypass any connection attempt and * validation during startup, and therefore the pool will start immediately. The * pool will continue to try to obtain connections in the background. This can mean * that callers to {@code DataSource#getConnection()} may encounter exceptions.
  • *
* Note that if this timeout value is greater than or equal to zero (0), and therefore an * initial connection validation is performed, this timeout does not override the * {@code connectionTimeout} or {@code validationTimeout}; they will be honored before this * timeout is applied. The default value is one millisecond. * * @param initializationFailTimeout the number of milliseconds before the * pool initialization fails, or 0 to validate connection setup but continue with * pool start, or less than zero to skip all initialization checks and start the * pool without delay. */ public void setInitializationFailTimeout(long initializationFailTimeout) { this.initializationFailTimeout = initializationFailTimeout; } /** * Get whether or not the construction of the pool should throw an exception * if the minimum number of connections cannot be created. * * @return whether or not initialization should fail on error immediately * @deprecated */ @Deprecated public boolean isInitializationFailFast() { return initializationFailTimeout > 0; } /** * Set whether or not the construction of the pool should throw an exception * if the minimum number of connections cannot be created. * * @param failFast true if the pool should fail if the minimum connections cannot be created * @deprecated */ @Deprecated public void setInitializationFailFast(boolean failFast) { LOGGER.warn("The initializationFailFast propery is deprecated, see initializationFailTimeout"); initializationFailTimeout = (failFast ? 1 : -1); } public boolean isIsolateInternalQueries() { return isIsolateInternalQueries; } public void setIsolateInternalQueries(boolean isolate) { this.isIsolateInternalQueries = isolate; } @Deprecated public boolean isJdbc4ConnectionTest() { return false; } @Deprecated public void setJdbc4ConnectionTest(boolean useIsValid) { LOGGER.warn("The jdbcConnectionTest property is now deprecated, see the documentation for connectionTestQuery"); } public MetricsTrackerFactory getMetricsTrackerFactory() { return metricsTrackerFactory; } public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory) { if (metricRegistry != null) { throw new IllegalStateException("cannot use setMetricsTrackerFactory() and setMetricRegistry() together"); } this.metricsTrackerFactory = metricsTrackerFactory; } /** * Get the Codahale MetricRegistry, could be null. * * @return the codahale MetricRegistry instance */ public Object getMetricRegistry() { return metricRegistry; } /** * Set a Codahale MetricRegistry to use for HikariCP. * * @param metricRegistry the Codahale MetricRegistry to set */ public void setMetricRegistry(Object metricRegistry) { if (metricsTrackerFactory != null) { throw new IllegalStateException("cannot use setMetricRegistry() and setMetricsTrackerFactory() together"); } if (metricRegistry != null) { metricRegistry = getObjectOrPerformJndiLookup(metricRegistry); if (!(metricRegistry.getClass().getName().contains("MetricRegistry")) && !(metricRegistry.getClass().getName().contains("MeterRegistry"))) { throw new IllegalArgumentException("Class must be instance of com.codahale.metrics.MetricRegistry or io.micrometer.core.instrument.MeterRegistry"); } } this.metricRegistry = metricRegistry; } private Object getObjectOrPerformJndiLookup(Object object) { if (object instanceof String) { try { InitialContext initCtx = new InitialContext(); return initCtx.lookup((String) object); } catch (NamingException e) { throw new IllegalArgumentException(e); } } return object; } /** * Get the Codahale HealthCheckRegistry, could be null. * * @return the Codahale HealthCheckRegistry instance */ public Object getHealthCheckRegistry() { return healthCheckRegistry; } /** * Set a Codahale HealthCheckRegistry to use for HikariCP. * * @param healthCheckRegistry the Codahale HealthCheckRegistry to set */ public void setHealthCheckRegistry(Object healthCheckRegistry) { if (healthCheckRegistry != null) { healthCheckRegistry = getObjectOrPerformJndiLookup(healthCheckRegistry); if (!(healthCheckRegistry instanceof HealthCheckRegistry)) { throw new IllegalArgumentException("Class must be an instance of com.codahale.metrics.health.HealthCheckRegistry"); } } this.healthCheckRegistry = healthCheckRegistry; } public Properties getHealthCheckProperties() { return healthCheckProperties; } public void setHealthCheckProperties(Properties healthCheckProperties) { this.healthCheckProperties.putAll(healthCheckProperties); } public void addHealthCheckProperty(String key, String value) { healthCheckProperties.setProperty(key, value); } public boolean isReadOnly() { return isReadOnly; } public void setReadOnly(boolean readOnly) { this.isReadOnly = readOnly; } public boolean isRegisterMbeans() { return isRegisterMbeans; } public void setRegisterMbeans(boolean register) { this.isRegisterMbeans = register; } /** {@inheritDoc} */ @Override public long getLeakDetectionThreshold() { return leakDetectionThreshold; } /** {@inheritDoc} */ @Override public void setLeakDetectionThreshold(long leakDetectionThresholdMs) { this.leakDetectionThreshold = leakDetectionThresholdMs; } /** {@inheritDoc} */ @Override public long getMaxLifetime() { return maxLifetime; } /** {@inheritDoc} */ @Override public void setMaxLifetime(long maxLifetimeMs) { this.maxLifetime = maxLifetimeMs; } /** {@inheritDoc} */ @Override public int getMaximumPoolSize() { return maxPoolSize; } /** {@inheritDoc} */ @Override public void setMaximumPoolSize(int maxPoolSize) { if (maxPoolSize < 1) { throw new IllegalArgumentException("maxPoolSize cannot be less than 1"); } this.maxPoolSize = maxPoolSize; } /** {@inheritDoc} */ @Override public int getMinimumIdle() { return minIdle; } /** {@inheritDoc} */ @Override public void setMinimumIdle(int minIdle) { if (minIdle < 0) { throw new IllegalArgumentException("minimumIdle cannot be negative"); } this.minIdle = minIdle; } /** * Get the default password to use for DataSource.getConnection(username, password) calls. * @return the password */ public String getPassword() { return password; } /** * Set the default password to use for DataSource.getConnection(username, password) calls. * @param password the password */ @Override public void setPassword(String password) { this.password = password; } /** {@inheritDoc} */ @Override public String getPoolName() { return poolName; } /** * Set the name of the connection pool. This is primarily used for the MBean * to uniquely identify the pool configuration. * * @param poolName the name of the connection pool to use */ public void setPoolName(String poolName) { this.poolName = poolName; } /** * Get the ScheduledExecutorService used for housekeeping. * * @return the executor */ @Deprecated public ScheduledThreadPoolExecutor getScheduledExecutorService() { return (ScheduledThreadPoolExecutor) scheduledExecutor; } /** * Set the ScheduledExecutorService used for housekeeping. * * @param executor the ScheduledExecutorService */ @Deprecated public void setScheduledExecutorService(ScheduledThreadPoolExecutor executor) { this.scheduledExecutor = executor; } /** * Get the ScheduledExecutorService used for housekeeping. * * @return the executor */ public ScheduledExecutorService getScheduledExecutor() { return scheduledExecutor; } /** * Set the ScheduledExecutorService used for housekeeping. * * @param executor the ScheduledExecutorService */ public void setScheduledExecutor(ScheduledExecutorService executor) { this.scheduledExecutor = executor; } public String getTransactionIsolation() { return transactionIsolationName; } /** * Get the default schema name to be set on connections. * * @return the default schema name */ public String getSchema() { return schema; } /** * Set the default schema name to be set on connections. */ public void setSchema(String schema) { this.schema = schema; } /** * Set the default transaction isolation level. The specified value is the * constant name from the Connection class, eg. * TRANSACTION_REPEATABLE_READ. * * @param isolationLevel the name of the isolation level */ public void setTransactionIsolation(String isolationLevel) { this.transactionIsolationName = isolationLevel; } /** * Get the default username used for DataSource.getConnection(username, password) calls. * * @return the username */ public String getUsername() { return username; } /** * Set the default username used for DataSource.getConnection(username, password) calls. * * @param username the username */ @Override public void setUsername(String username) { this.username = username; } /** * Get the thread factory used to create threads. * * @return the thread factory (may be null, in which case the default thread factory is used) */ public ThreadFactory getThreadFactory() { return threadFactory; } /** * Set the thread factory to be used to create threads. * * @param threadFactory the thread factory (setting to null causes the default thread factory to be used) */ public void setThreadFactory(ThreadFactory threadFactory) { this.threadFactory = threadFactory; } @SuppressWarnings("StatementWithEmptyBody") public void validate() { if (poolName == null) { poolName = "HikariPool-" + generatePoolNumber(); } else if (isRegisterMbeans && poolName.contains(":")) { throw new IllegalArgumentException("poolName cannot contain ':' when used with JMX"); } // treat empty property as null catalog = getNullIfEmpty(catalog); connectionInitSql = getNullIfEmpty(connectionInitSql); connectionTestQuery = getNullIfEmpty(connectionTestQuery); transactionIsolationName = getNullIfEmpty(transactionIsolationName); dataSourceClassName = getNullIfEmpty(dataSourceClassName); dataSourceJndiName = getNullIfEmpty(dataSourceJndiName); driverClassName = getNullIfEmpty(driverClassName); jdbcUrl = getNullIfEmpty(jdbcUrl); // Check Data Source Options if (dataSource != null) { if (dataSourceClassName != null) { LOGGER.warn("{} - using dataSource and ignoring dataSourceClassName.", poolName); } } else if (dataSourceClassName != null) { if (driverClassName != null) { LOGGER.error("{} - cannot use driverClassName and dataSourceClassName together.", poolName); // NOTE: This exception text is referenced by a Spring Boot FailureAnalyzer, it should not be // changed without first notifying the Spring Boot developers. throw new IllegalStateException("cannot use driverClassName and dataSourceClassName together."); } else if (jdbcUrl != null) { LOGGER.warn("{} - using dataSourceClassName and ignoring jdbcUrl.", poolName); } } else if (jdbcUrl != null || dataSourceJndiName != null) { // ok } else if (driverClassName != null) { LOGGER.error("{} - jdbcUrl is required with driverClassName.", poolName); throw new IllegalArgumentException("jdbcUrl is required with driverClassName."); } else { LOGGER.error("{} - dataSource or dataSourceClassName or jdbcUrl is required.", poolName); throw new IllegalArgumentException("dataSource or dataSourceClassName or jdbcUrl is required."); } validateNumerics(); if (LOGGER.isDebugEnabled() || unitTest) { logConfiguration(); } } private void validateNumerics() { if (maxLifetime != 0 && maxLifetime < SECONDS.toMillis(30)) { LOGGER.warn("{} - maxLifetime is less than 30000ms, setting to default {}ms.", poolName, MAX_LIFETIME); maxLifetime = MAX_LIFETIME; } if (idleTimeout + SECONDS.toMillis(1) > maxLifetime && maxLifetime > 0) { LOGGER.warn("{} - idleTimeout is close to or more than maxLifetime, disabling it.", poolName); idleTimeout = 0; } if (idleTimeout != 0 && idleTimeout < SECONDS.toMillis(10)) { LOGGER.warn("{} - idleTimeout is less than 10000ms, setting to default {}ms.", poolName, IDLE_TIMEOUT); idleTimeout = IDLE_TIMEOUT; } if (leakDetectionThreshold > 0 && !unitTest) { if (leakDetectionThreshold < SECONDS.toMillis(2) || (leakDetectionThreshold > maxLifetime && maxLifetime > 0)) { LOGGER.warn("{} - leakDetectionThreshold is less than 2000ms or more than maxLifetime, disabling it.", poolName); leakDetectionThreshold = 0; } } if (connectionTimeout < 250) { LOGGER.warn("{} - connectionTimeout is less than 250ms, setting to {}ms.", poolName, CONNECTION_TIMEOUT); connectionTimeout = CONNECTION_TIMEOUT; } if (validationTimeout < 250) { LOGGER.warn("{} - validationTimeout is less than 250ms, setting to {}ms.", poolName, VALIDATION_TIMEOUT); validationTimeout = VALIDATION_TIMEOUT; } if (maxPoolSize < 1) { maxPoolSize = (minIdle <= 0) ? DEFAULT_POOL_SIZE : minIdle; } if (minIdle < 0 || minIdle > maxPoolSize) { minIdle = maxPoolSize; } } @SuppressWarnings("StatementWithEmptyBody") private void logConfiguration() { LOGGER.debug("{} - configuration:", poolName); final Set propertyNames = new TreeSet<>(PropertyElf.getPropertyNames(HikariConfig.class)); for (String prop : propertyNames) { try { Object value = PropertyElf.getProperty(prop, this); if ("dataSourceProperties".equals(prop)) { Properties dsProps = PropertyElf.copyProperties(dataSourceProperties); dsProps.setProperty("password", ""); value = dsProps; } if ("initializationFailTimeout".equals(prop) && initializationFailTimeout == Long.MAX_VALUE) { value = "infinite"; } else if ("transactionIsolation".equals(prop) && transactionIsolationName == null) { value = "default"; } else if (prop.matches("scheduledExecutorService|threadFactory") && value == null) { value = "internal"; } else if (prop.contains("jdbcUrl") && value instanceof String) { value = ((String)value).replaceAll("([?&;]password=)[^&#;]*(.*)", "$1$2"); } else if (prop.contains("password")) { value = ""; } else if (value instanceof String) { value = "\"" + value + "\""; // quote to see lead/trailing spaces is any } else if (value == null) { value = "none"; } LOGGER.debug((prop + "................................................").substring(0, 32) + value); } catch (Exception e) { // continue } } } private void loadProperties(String propertyFileName) { final File propFile = new File(propertyFileName); try (final InputStream is = propFile.isFile() ? new FileInputStream(propFile) : this.getClass().getResourceAsStream(propertyFileName)) { if (is != null) { Properties props = new Properties(); props.load(is); PropertyElf.setTargetFromProperties(this, props); } else { throw new IllegalArgumentException("Cannot find property file: " + propertyFileName); } } catch (IOException io) { throw new RuntimeException("Failed to read property file", io); } } private int generatePoolNumber() { // Pool number is global to the VM to avoid overlapping pool numbers in classloader scoped environments synchronized (System.getProperties()) { final int next = Integer.getInteger("com.zaxxer.hikari.pool_number", 0) + 1; System.setProperty("com.zaxxer.hikari.pool_number", String.valueOf(next)); return next; } } public void copyState(HikariConfig other) { for (Field field : HikariConfig.class.getDeclaredFields()) { if (!Modifier.isFinal(field.getModifiers())) { field.setAccessible(true); try { field.set(other, field.get(this)); } catch (Exception e) { throw new RuntimeException("Failed to copy HikariConfig state: " + e.getMessage(), e); } } } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/HikariConfigMXBean.java000066400000000000000000000160671315431642000270510ustar00rootroot00000000000000/* * 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; /** * The javax.management MBean for a Hikari pool configuration. * * @author Brett Wooldridge */ public interface HikariConfigMXBean { /** * Get the maximum number of milliseconds that a client will wait for a connection from the pool. If this * time is exceeded without a connection becoming available, a SQLException will be thrown from * {@link javax.sql.DataSource#getConnection()}. * * @return the connection timeout in milliseconds */ long getConnectionTimeout(); /** * Set the maximum number of milliseconds that a client will wait for a connection from the pool. If this * time is exceeded without a connection becoming available, a SQLException will be thrown from * {@link javax.sql.DataSource#getConnection()}. * * @param connectionTimeoutMs the connection timeout in milliseconds */ void setConnectionTimeout(long connectionTimeoutMs); /** * Get the maximum number of milliseconds that the pool will wait for a connection to be validated as * alive. * * @return the validation timeout in milliseconds */ long getValidationTimeout(); /** * Sets the maximum number of milliseconds that the pool will wait for a connection to be validated as * alive. * * @param validationTimeoutMs the validation timeout in milliseconds */ void setValidationTimeout(long validationTimeoutMs); /** * This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit * idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30 * seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout. * A value of 0 means that idle connections are never removed from the pool. * * @return the idle timeout in milliseconds */ long getIdleTimeout(); /** * This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit * idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30 * seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout. * A value of 0 means that idle connections are never removed from the pool. * * @param idleTimeoutMs the idle timeout in milliseconds */ void setIdleTimeout(long idleTimeoutMs); /** * This property controls the amount of time that a connection can be out of the pool before a message is * logged indicating a possible connection leak. A value of 0 means leak detection is disabled. * * @return the connection leak detection threshold in milliseconds */ long getLeakDetectionThreshold(); /** * This property controls the amount of time that a connection can be out of the pool before a message is * logged indicating a possible connection leak. A value of 0 means leak detection is disabled. * * @param leakDetectionThresholdMs the connection leak detection threshold in milliseconds */ void setLeakDetectionThreshold(long leakDetectionThresholdMs); /** * This property controls the maximum lifetime of a connection in the pool. When a connection reaches this * timeout, even if recently used, it will be retired from the pool. An in-use connection will never be * retired, only when it is idle will it be removed. * * @return the maximum connection lifetime in milliseconds */ long getMaxLifetime(); /** * This property controls the maximum lifetime of a connection in the pool. When a connection reaches this * timeout, even if recently used, it will be retired from the pool. An in-use connection will never be * retired, only when it is idle will it be removed. * * @param maxLifetimeMs the maximum connection lifetime in milliseconds */ void setMaxLifetime(long maxLifetimeMs); /** * The property controls the maximum size that the pool is allowed to reach, including both idle and in-use * connections. Basically this value will determine the maximum number of actual connections to the database * backend. *

* When the pool reaches this size, and no idle connections are available, calls to getConnection() will * block for up to connectionTimeout milliseconds before timing out. * * @return the minimum number of connections in the pool */ int getMinimumIdle(); /** * The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool, * including both idle and in-use connections. If the idle connections dip below this value, HikariCP will * make a best effort to restore them quickly and efficiently. * * @param minIdle the minimum number of idle connections in the pool to maintain */ void setMinimumIdle(int minIdle); /** * The property controls the maximum number of connections that HikariCP will keep in the pool, * including both idle and in-use connections. * * @return the maximum number of connections in the pool */ int getMaximumPoolSize(); /** * The property controls the maximum size that the pool is allowed to reach, including both idle and in-use * connections. Basically this value will determine the maximum number of actual connections to the database * backend. *

* When the pool reaches this size, and no idle connections are available, calls to getConnection() will * block for up to connectionTimeout milliseconds before timing out. * * @param maxPoolSize the maximum number of connections in the pool */ void setMaximumPoolSize(int maxPoolSize); /** * Set the password used for authentication. Changing this at runtime will apply to new connections only. * Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based * connections. * * @param password the database password */ void setPassword(String password); /** * Set the username used for authentication. Changing this at runtime will apply to new connections only. * Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based * connections. * * @param username the database username */ void setUsername(String username); /** * The name of the connection pool. * * @return the name of the connection pool */ String getPoolName(); }HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/HikariDataSource.java000066400000000000000000000254571315431642000266460ustar00rootroot00000000000000/* * 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 unwrap(Class 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()); } } } /** * Get the {@code HikariPoolMXBean} for this HikariDataSource instance. If this method is called on * a {@code HikariDataSource} that has been constructed without a {@code HikariConfig} instance, * and before an initial call to {@code #getConnection()}, the return value will be {@code null}. * * @return the {@code HikariPoolMXBean} instance, or {@code null}. */ public HikariPoolMXBean getHikariPoolMXBean() { return pool; } /** * Get the {@code HikariConfigMXBean} for this HikariDataSource instance. * * @return the {@code HikariConfigMXBean} instance. */ public HikariConfigMXBean getHikariConfigMXBean() { return this; } /** * 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 getConnection() * will block indefinitely until resumePool() is called. * * @deprecated Call the {@code HikariPoolMXBean#suspendPool()} method on the {@code HikariPoolMXBean} * obtained by {@code #getHikariPoolMXBean()} or JMX lookup. */ @Deprecated public void suspendPool() { HikariPool p; if (!isClosed() && (p = pool) != null) { p.suspendPool(); } } /** * Resume allocation of connections from the pool. * * @deprecated Call the {@code HikariPoolMXBean#resumePool()} method on the {@code HikariPoolMXBean} * obtained by {@code #getHikariPoolMXBean()} or JMX lookup. */ @Deprecated 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 + ")"; } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/HikariJNDIFactory.java000066400000000000000000000065411315431642000266610ustar00rootroot00000000000000/* * Copyright (C) 2013,2014 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.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.Set; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import javax.sql.DataSource; import com.zaxxer.hikari.util.PropertyElf; /** * A JNDI factory that produces HikariDataSource instances. * * @author Brett Wooldridge */ public class HikariJNDIFactory implements ObjectFactory { @Override synchronized public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { // We only know how to deal with javax.naming.Reference that specify a class name of "javax.sql.DataSource" if (!(obj instanceof Reference)) { return null; } Reference ref = (Reference) obj; if (!"javax.sql.DataSource".equals(ref.getClassName())) { throw new NamingException(ref.getClassName() + " is not a valid class name/type for this JNDI factory."); } Set hikariPropSet = PropertyElf.getPropertyNames(HikariConfig.class); Properties properties = new Properties(); Enumeration enumeration = ref.getAll(); while (enumeration.hasMoreElements()) { RefAddr element = enumeration.nextElement(); String type = element.getType(); if (type.startsWith("dataSource.") || hikariPropSet.contains(type)) { properties.setProperty(type, element.getContent().toString()); } } return createDataSource(properties, nameCtx); } private DataSource createDataSource(final Properties properties, final Context context) throws NamingException { String jndiName = properties.getProperty("dataSourceJNDI"); if (jndiName != null) { return lookupJndiDataSource(properties, context, jndiName); } return new HikariDataSource(new HikariConfig(properties)); } private DataSource lookupJndiDataSource(final Properties properties, final Context context, final String jndiName) throws NamingException { if (context == null) { throw new RuntimeException("JNDI context does not found for dataSourceJNDI : " + jndiName); } DataSource jndiDS = (DataSource) context.lookup(jndiName); if (jndiDS == null) { final Context ic = new InitialContext(); jndiDS = (DataSource) ic.lookup(jndiName); ic.close(); } if (jndiDS != null) { HikariConfig config = new HikariConfig(properties); config.setDataSource(jndiDS); return new HikariDataSource(config); } return null; } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/HikariPoolMXBean.java000066400000000000000000000017211315431642000265440ustar00rootroot00000000000000/* * 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; /** * The javax.management MBean for a Hikari pool instance. * * @author Brett Wooldridge */ public interface HikariPoolMXBean { int getIdleConnections(); int getActiveConnections(); int getTotalConnections(); int getThreadsAwaitingConnection(); void softEvictConnections(); void suspendPool(); void resumePool(); } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/hibernate/000077500000000000000000000000001315431642000245455ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/hibernate/HikariConfigurationUtil.java000066400000000000000000000046111315431642000322070ustar00rootroot00000000000000/* * 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.hibernate; import java.util.Map; import java.util.Properties; import org.hibernate.cfg.AvailableSettings; import com.zaxxer.hikari.HikariConfig; /** * Utility class to map Hibernate properties to HikariCP configuration properties. * * @author Brett Wooldridge, Luca Burgazzoli */ public class HikariConfigurationUtil { public static final String CONFIG_PREFIX = "hibernate.hikari."; public static final String CONFIG_PREFIX_DATASOURCE = "hibernate.hikari.dataSource."; /** * Create/load a HikariConfig from Hibernate properties. * * @param props a map of Hibernate properties * @return a HikariConfig */ @SuppressWarnings("rawtypes") public static HikariConfig loadConfiguration(Map props) { Properties hikariProps = new Properties(); copyProperty(AvailableSettings.ISOLATION, props, "transactionIsolation", hikariProps); copyProperty(AvailableSettings.AUTOCOMMIT, props, "autoCommit", hikariProps); copyProperty(AvailableSettings.DRIVER, props, "driverClassName", hikariProps); copyProperty(AvailableSettings.URL, props, "jdbcUrl", hikariProps); copyProperty(AvailableSettings.USER, props, "username", hikariProps); copyProperty(AvailableSettings.PASS, props, "password", hikariProps); for (Object keyo : props.keySet()) { String key = (String) keyo; if (key.startsWith(CONFIG_PREFIX)) { hikariProps.setProperty(key.substring(CONFIG_PREFIX.length()), (String) props.get(key)); } } return new HikariConfig(hikariProps); } @SuppressWarnings("rawtypes") private static void copyProperty(String srcKey, Map src, String dstKey, Properties dst) { if (src.containsKey(srcKey)) { dst.setProperty(dstKey, (String) src.get(srcKey)); } } }HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/hibernate/HikariConnectionProvider.java000066400000000000000000000106021315431642000323510ustar00rootroot00000000000000/* * 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.hibernate; import java.sql.Connection; import java.sql.SQLException; import java.util.Map; import org.hibernate.HibernateException; import org.hibernate.Version; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.service.UnknownUnwrapTypeException; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Stoppable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; /** * Connection provider for Hibernate 4.3. * * @author Brett Wooldridge, Luca Burgazzoli */ public class HikariConnectionProvider implements ConnectionProvider, Configurable, Stoppable { private static final long serialVersionUID = -9131625057941275711L; private static final Logger LOGGER = LoggerFactory.getLogger(HikariConnectionProvider.class); /** * HikariCP configuration. */ private HikariConfig hcfg; /** * HikariCP data source. */ private HikariDataSource hds; // ************************************************************************* // // ************************************************************************* /** * c-tor */ public HikariConnectionProvider() { this.hcfg = null; this.hds = null; if (Version.getVersionString().substring(0, 5).compareTo("4.3.6") >= 1) { LOGGER.warn("com.zaxxer.hikari.hibernate.HikariConnectionProvider has been deprecated for versions of " + "Hibernate 4.3.6 and newer. Please switch to org.hibernate.hikaricp.internal.HikariCPConnectionProvider."); } } // ************************************************************************* // Configurable // ************************************************************************* @SuppressWarnings("rawtypes") @Override public void configure(Map props) throws HibernateException { try { LOGGER.debug("Configuring HikariCP"); this.hcfg = HikariConfigurationUtil.loadConfiguration(props); this.hds = new HikariDataSource(this.hcfg); } catch (Exception e) { throw new HibernateException(e); } LOGGER.debug("HikariCP Configured"); } // ************************************************************************* // ConnectionProvider // ************************************************************************* @Override public Connection getConnection() throws SQLException { Connection conn = null; if (this.hds != null) { conn = this.hds.getConnection(); } return conn; } @Override public void closeConnection(Connection conn) throws SQLException { conn.close(); } @Override public boolean supportsAggressiveRelease() { return false; } @Override @SuppressWarnings("rawtypes") public boolean isUnwrappableAs(Class unwrapType) { return ConnectionProvider.class.equals(unwrapType) || HikariConnectionProvider.class.isAssignableFrom(unwrapType); } @Override @SuppressWarnings("unchecked") public T unwrap(Class unwrapType) { if ( ConnectionProvider.class.equals( unwrapType ) || HikariConnectionProvider.class.isAssignableFrom( unwrapType ) ) { return (T) this; } else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { return (T) this.hds; } else { throw new UnknownUnwrapTypeException( unwrapType ); } } // ************************************************************************* // Stoppable // ************************************************************************* @Override public void stop() { this.hds.close(); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/000077500000000000000000000000001315431642000242525ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/IMetricsTracker.java000066400000000000000000000020471315431642000301530ustar00rootroot00000000000000/* * Copyright (C) 2017 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.metrics; /** * @author Brett Wooldridge */ public interface IMetricsTracker extends AutoCloseable { default void recordConnectionCreatedMillis(long connectionCreatedMillis) {} default void recordConnectionAcquiredNanos(final long elapsedAcquiredNanos) {} default void recordConnectionUsageMillis(final long elapsedBorrowedMillis) {} default void recordConnectionTimeout() {} @Override default void close() {} } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/MetricsTracker.java000077500000000000000000000014561315431642000300500ustar00rootroot00000000000000/* * Copyright (C) 2013,2014 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.metrics; /** * This class only supports realtime, not historical metrics. * * @author Brett Wooldridge */ @Deprecated public class MetricsTracker implements IMetricsTracker { } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/MetricsTrackerFactory.java000066400000000000000000000017101315431642000313660ustar00rootroot00000000000000/* * Copyright (C) 2013,2014 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.metrics; public interface MetricsTrackerFactory { /** * Create an instance of an IMetricsTracker. * * @param poolName the name of the pool * @param poolStats a PoolStats instance to use * @return a IMetricsTracker implementation instance */ IMetricsTracker create(String poolName, PoolStats poolStats); } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/PoolStats.java000066400000000000000000000042051315431642000270460ustar00rootroot00000000000000/* * Copyright (C) 2015 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.metrics; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.plusMillis; import java.util.concurrent.atomic.AtomicLong; /** * * @author Brett Wooldridge */ public abstract class PoolStats { private final AtomicLong reloadAt; private final long timeoutMs; protected volatile int totalConnections; protected volatile int idleConnections; protected volatile int activeConnections; protected volatile int pendingThreads; public PoolStats(final long timeoutMs) { this.timeoutMs = timeoutMs; this.reloadAt = new AtomicLong(); } public int getTotalConnections() { if (shouldLoad()) { update(); } return totalConnections; } public int getIdleConnections() { if (shouldLoad()) { update(); } return idleConnections; } public int getActiveConnections() { if (shouldLoad()) { update(); } return activeConnections; } public int getPendingThreads() { if (shouldLoad()) { update(); } return pendingThreads; } protected abstract void update(); private boolean shouldLoad() { for (; ; ) { final long now = currentTime(); final long reloadTime = reloadAt.get(); if (reloadTime > now) { return false; } else if (reloadAt.compareAndSet(reloadTime, plusMillis(now, timeoutMs))) { return true; } } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/dropwizard/000077500000000000000000000000001315431642000264375ustar00rootroot00000000000000CodaHaleMetricsTracker.java000077500000000000000000000134211315431642000335320ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/dropwizard/* * Copyright (C) 2013,2014 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.metrics.dropwizard; import java.util.concurrent.TimeUnit; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.metrics.PoolStats; public final class CodaHaleMetricsTracker implements IMetricsTracker { private final String poolName; private final Timer connectionObtainTimer; private final Histogram connectionUsage; private final Histogram connectionCreation; private final Meter connectionTimeoutMeter; private final MetricRegistry registry; private static final String METRIC_CATEGORY = "pool"; private static final String METRIC_NAME_WAIT = "Wait"; private static final String METRIC_NAME_USAGE = "Usage"; private static final String METRIC_NAME_CONNECT = "ConnectionCreation"; private static final String METRIC_NAME_TIMEOUT_RATE = "ConnectionTimeoutRate"; private static final String METRIC_NAME_TOTAL_CONNECTIONS = "TotalConnections"; private static final String METRIC_NAME_IDLE_CONNECTIONS = "IdleConnections"; private static final String METRIC_NAME_ACTIVE_CONNECTIONS = "ActiveConnections"; private static final String METRIC_NAME_PENDING_CONNECTIONS = "PendingConnections"; public CodaHaleMetricsTracker(final String poolName, final PoolStats poolStats, final MetricRegistry registry) { this.poolName = poolName; this.registry = registry; this.connectionObtainTimer = registry.timer(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_WAIT)); this.connectionUsage = registry.histogram(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_USAGE)); this.connectionCreation = registry.histogram(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_CONNECT)); this.connectionTimeoutMeter = registry.meter(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_TIMEOUT_RATE)); registry.register(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_TOTAL_CONNECTIONS), new Gauge() { @Override public Integer getValue() { return poolStats.getTotalConnections(); } }); registry.register(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_IDLE_CONNECTIONS), new Gauge() { @Override public Integer getValue() { return poolStats.getIdleConnections(); } }); registry.register(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_ACTIVE_CONNECTIONS), new Gauge() { @Override public Integer getValue() { return poolStats.getActiveConnections(); } }); registry.register(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_PENDING_CONNECTIONS), new Gauge() { @Override public Integer getValue() { return poolStats.getPendingThreads(); } }); } /** {@inheritDoc} */ @Override public void close() { registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_WAIT)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_USAGE)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_CONNECT)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_TIMEOUT_RATE)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_TOTAL_CONNECTIONS)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_IDLE_CONNECTIONS)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_ACTIVE_CONNECTIONS)); registry.remove(MetricRegistry.name(poolName, METRIC_CATEGORY, METRIC_NAME_PENDING_CONNECTIONS)); } /** {@inheritDoc} */ @Override public void recordConnectionAcquiredNanos(final long elapsedAcquiredNanos) { connectionObtainTimer.update(elapsedAcquiredNanos, TimeUnit.NANOSECONDS); } /** {@inheritDoc} */ @Override public void recordConnectionUsageMillis(final long elapsedBorrowedMillis) { connectionUsage.update(elapsedBorrowedMillis); } @Override public void recordConnectionTimeout() { connectionTimeoutMeter.mark(); } @Override public void recordConnectionCreatedMillis(long connectionCreatedMillis) { connectionCreation.update(connectionCreatedMillis); } public Timer getConnectionAcquisitionTimer() { return connectionObtainTimer; } public Histogram getConnectionDurationHistogram() { return connectionUsage; } public Histogram getConnectionCreationHistogram() { return connectionCreation; } } CodahaleHealthChecker.java000066400000000000000000000121321315431642000333350ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/dropwizard/* * Copyright (C) 2014 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.metrics.dropwizard; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import java.util.SortedMap; import java.util.concurrent.TimeUnit; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.codahale.metrics.health.HealthCheck; import com.codahale.metrics.health.HealthCheckRegistry; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.pool.HikariPool; /** * Provides Dropwizard HealthChecks. Two health checks are provided: *

    *
  • ConnectivityCheck
  • *
  • Connection99Percent
  • *
* The ConnectivityCheck will use the connectionTimeout, unless the health check property * connectivityCheckTimeoutMs is defined. However, if either the connectionTimeout * or the connectivityCheckTimeoutMs is 0 (infinite), a timeout of 10 seconds will be used. *

* The Connection99Percent health check will only be registered if the health check property * expected99thPercentileMs is defined and greater than 0. * * @author Brett Wooldridge */ public final class CodahaleHealthChecker { /** * Register Dropwizard health checks. * * @param pool the pool to register health checks for * @param hikariConfig the pool configuration * @param registry the HealthCheckRegistry into which checks will be registered */ public static void registerHealthChecks(final HikariPool pool, final HikariConfig hikariConfig, final HealthCheckRegistry registry) { final Properties healthCheckProperties = hikariConfig.getHealthCheckProperties(); final MetricRegistry metricRegistry = (MetricRegistry) hikariConfig.getMetricRegistry(); final long checkTimeoutMs = Long.parseLong(healthCheckProperties.getProperty("connectivityCheckTimeoutMs", String.valueOf(hikariConfig.getConnectionTimeout()))); registry.register(MetricRegistry.name(hikariConfig.getPoolName(), "pool", "ConnectivityCheck"), new ConnectivityHealthCheck(pool, checkTimeoutMs)); final long expected99thPercentile = Long.parseLong(healthCheckProperties.getProperty("expected99thPercentileMs", "0")); if (metricRegistry != null && expected99thPercentile > 0) { SortedMap timers = metricRegistry.getTimers(new MetricFilter() { @Override public boolean matches(String name, Metric metric) { return name.equals(MetricRegistry.name(hikariConfig.getPoolName(), "pool", "Wait")); } }); if (!timers.isEmpty()) { final Timer timer = timers.entrySet().iterator().next().getValue(); registry.register(MetricRegistry.name(hikariConfig.getPoolName(), "pool", "Connection99Percent"), new Connection99Percent(timer, expected99thPercentile)); } } } private CodahaleHealthChecker() { // private constructor } private static class ConnectivityHealthCheck extends HealthCheck { private final HikariPool pool; private final long checkTimeoutMs; ConnectivityHealthCheck(final HikariPool pool, final long checkTimeoutMs) { this.pool = pool; this.checkTimeoutMs = (checkTimeoutMs > 0 && checkTimeoutMs != Integer.MAX_VALUE ? checkTimeoutMs : TimeUnit.SECONDS.toMillis(10)); } /** {@inheritDoc} */ @Override protected Result check() throws Exception { try (Connection connection = pool.getConnection(checkTimeoutMs)) { return Result.healthy(); } catch (SQLException e) { return Result.unhealthy(e); } } } private static class Connection99Percent extends HealthCheck { private final Timer waitTimer; private final long expected99thPercentile; Connection99Percent(final Timer waitTimer, final long expected99thPercentile) { this.waitTimer = waitTimer; this.expected99thPercentile = expected99thPercentile; } /** {@inheritDoc} */ @Override protected Result check() throws Exception { final long the99thPercentile = TimeUnit.NANOSECONDS.toMillis(Math.round(waitTimer.getSnapshot().get99thPercentile())); return the99thPercentile <= expected99thPercentile ? Result.healthy() : Result.unhealthy("99th percentile connection wait time of %dms exceeds the threshold %dms", the99thPercentile, expected99thPercentile); } } } CodahaleMetricsTrackerFactory.java000066400000000000000000000024471315431642000351250ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/dropwizard/* * 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.metrics.dropwizard; import com.codahale.metrics.MetricRegistry; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.metrics.PoolStats; public final class CodahaleMetricsTrackerFactory implements MetricsTrackerFactory { private final MetricRegistry registry; public CodahaleMetricsTrackerFactory(MetricRegistry registry) { this.registry = registry; } public MetricRegistry getRegistry() { return registry; } @Override public IMetricsTracker create(String poolName, PoolStats poolStats) { return new CodaHaleMetricsTracker(poolName, poolStats, registry); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/micrometer/000077500000000000000000000000001315431642000264205ustar00rootroot00000000000000MicrometerMetricsTracker.java000066400000000000000000000111001315431642000341460ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/micrometerpackage com.zaxxer.hikari.metrics.micrometer; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.metrics.PoolStats; import io.micrometer.core.instrument.DistributionSummary; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.stats.quantile.WindowSketchQuantiles; import java.util.concurrent.TimeUnit; import static io.micrometer.core.instrument.stats.hist.CumulativeHistogram.buckets; import static io.micrometer.core.instrument.stats.hist.CumulativeHistogram.linear; public class MicrometerMetricsTracker implements IMetricsTracker { private static final String METRIC_CATEGORY = "pool"; private static final String METRIC_NAME_WAIT = "Wait"; private static final String METRIC_NAME_USAGE = "Usage"; private static final String METRIC_NAME_CONNECT = "ConnectionCreation"; private static final String METRIC_NAME_TIMEOUT_RATE = "ConnectionTimeoutRate"; private static final String METRIC_NAME_TOTAL_CONNECTIONS = "TotalConnections"; private static final String METRIC_NAME_IDLE_CONNECTIONS = "IdleConnections"; private static final String METRIC_NAME_ACTIVE_CONNECTIONS = "ActiveConnections"; private static final String METRIC_NAME_PENDING_CONNECTIONS = "PendingConnections"; private final Timer connectionObtainTimer; private final DistributionSummary connectionTimeoutMeter; private final DistributionSummary connectionUsage; private final DistributionSummary connectionCreation; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final Gauge totalConnectionGauge; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final Gauge idleConnectionGauge; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final Gauge activeConnectionGauge; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final Gauge pendingConnectionGauge; MicrometerMetricsTracker(final String poolName, final PoolStats poolStats, final MeterRegistry meterRegistry) { this.connectionObtainTimer = meterRegistry .timerBuilder(METRIC_NAME_WAIT) .tags(METRIC_CATEGORY, poolName) .create(); this.connectionCreation = meterRegistry .summaryBuilder(METRIC_NAME_CONNECT) .tags(METRIC_CATEGORY, poolName) .quantiles(WindowSketchQuantiles.quantiles(0.5, 0.95).create()) .histogram(buckets(linear(0, 10, 20), TimeUnit.MILLISECONDS)) .create(); this.connectionUsage = meterRegistry .summaryBuilder(METRIC_NAME_USAGE) .tags(METRIC_CATEGORY, poolName) .quantiles(WindowSketchQuantiles.quantiles(0.5, 0.95).create()) .histogram(buckets(linear(0, 10, 20), TimeUnit.MILLISECONDS)) .create(); this.connectionTimeoutMeter = meterRegistry .summaryBuilder(METRIC_NAME_TIMEOUT_RATE) .tags(METRIC_CATEGORY, poolName) .quantiles(WindowSketchQuantiles.quantiles(0.5, 0.95).create()) .histogram(buckets(linear(0, 10, 20), TimeUnit.MILLISECONDS)) .create(); this.totalConnectionGauge = meterRegistry .gaugeBuilder(METRIC_NAME_TOTAL_CONNECTIONS, Integer.class, (i) -> poolStats.getTotalConnections()) .tags(METRIC_CATEGORY, poolName) .create(); this.idleConnectionGauge = meterRegistry .gaugeBuilder(METRIC_NAME_IDLE_CONNECTIONS, Integer.class, (i) -> poolStats.getIdleConnections()) .tags(METRIC_CATEGORY, poolName) .create(); this.activeConnectionGauge = meterRegistry .gaugeBuilder(METRIC_NAME_ACTIVE_CONNECTIONS, Integer.class, (i) -> poolStats.getActiveConnections()) .tags(METRIC_CATEGORY, poolName) .create(); this.pendingConnectionGauge = meterRegistry .gaugeBuilder(METRIC_NAME_PENDING_CONNECTIONS, Integer.class, (i) -> poolStats.getPendingThreads()) .tags(METRIC_CATEGORY, poolName) .create(); } /** {@inheritDoc} */ @Override public void recordConnectionAcquiredNanos(final long elapsedAcquiredNanos) { connectionObtainTimer.record(elapsedAcquiredNanos, TimeUnit.NANOSECONDS); } /** {@inheritDoc} */ @Override public void recordConnectionUsageMillis(final long elapsedBorrowedMillis) { connectionUsage.record(elapsedBorrowedMillis); } @Override public void recordConnectionTimeout() { connectionTimeoutMeter.count(); } @Override public void recordConnectionCreatedMillis(long connectionCreatedMillis) { connectionCreation.record(connectionCreatedMillis); } } MicrometerMetricsTrackerFactory.java000066400000000000000000000012141315431642000355030ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/micrometerpackage com.zaxxer.hikari.metrics.micrometer; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.metrics.PoolStats; import io.micrometer.core.instrument.MeterRegistry; public class MicrometerMetricsTrackerFactory implements MetricsTrackerFactory { private final MeterRegistry registry; public MicrometerMetricsTrackerFactory(MeterRegistry registry) { this.registry = registry; } @Override public IMetricsTracker create(String poolName, PoolStats poolStats) { return new MicrometerMetricsTracker(poolName, poolStats, registry); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/prometheus/000077500000000000000000000000001315431642000264455ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/prometheus/HikariCPCollector.java000066400000000000000000000043641315431642000326200ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.metrics.prometheus; import com.zaxxer.hikari.metrics.PoolStats; import io.prometheus.client.Collector; import io.prometheus.client.GaugeMetricFamily; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; class HikariCPCollector extends Collector { private static final List LABEL_NAMES = Collections.singletonList("pool"); private final Map poolStatsMap = new ConcurrentHashMap<>(); @Override public List collect() { return Arrays.asList( createGauge("hikaricp_active_connections", "Active connections", PoolStats::getActiveConnections), createGauge("hikaricp_idle_connections", "Idle connections", PoolStats::getIdleConnections), createGauge("hikaricp_pending_threads", "Pending threads", PoolStats::getPendingThreads), createGauge("hikaricp_connections", "The number of current connections", PoolStats::getTotalConnections) ); } protected HikariCPCollector add(String name, PoolStats poolStats) { poolStatsMap.put(name, poolStats); return this; } private GaugeMetricFamily createGauge(String metric, String help, Function metricValueFunction) { GaugeMetricFamily metricFamily = new GaugeMetricFamily(metric, help, LABEL_NAMES); poolStatsMap.forEach((k, v) -> metricFamily.addMetric( Collections.singletonList(k), metricValueFunction.apply(v) )); return metricFamily; } } PrometheusMetricsTracker.java000066400000000000000000000057371315431642000342430ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/prometheus/* * 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.metrics.prometheus; import com.zaxxer.hikari.metrics.IMetricsTracker; import io.prometheus.client.Collector; import io.prometheus.client.CollectorRegistry; import io.prometheus.client.Counter; import io.prometheus.client.Summary; import java.util.concurrent.TimeUnit; class PrometheusMetricsTracker implements IMetricsTracker { private static final Counter CONNECTION_TIMEOUT_COUNTER = Counter.build() .name("hikaricp_connection_timeout_total") .labelNames("pool") .help("Connection timeout total count") .register(); private static final Summary ELAPSED_ACQUIRED_SUMMARY = Summary.build() .name("hikaricp_connection_acquired_nanos") .labelNames("pool") .help("Connection acquired time (ns)") .register(); private static final Summary ELAPSED_BORROWED_SUMMARY = Summary.build() .name("hikaricp_connection_usage_millis") .labelNames("pool") .help("Connection usage (ms)") .register(); private static final Summary ELAPSED_CREATION_SUMMARY = Summary.build() .name("hikaricp_connection_creation_millis") .labelNames("pool") .help("Connection creation (ms)") .register(); private final Counter.Child connectionTimeoutCounterChild; private final Summary.Child elapsedAcquiredSummaryChild; private final Summary.Child elapsedBorrowedSummaryChild; private final Summary.Child elapsedCreationSummaryChild; PrometheusMetricsTracker(String poolName) { this.connectionTimeoutCounterChild = CONNECTION_TIMEOUT_COUNTER.labels(poolName); this.elapsedAcquiredSummaryChild = ELAPSED_ACQUIRED_SUMMARY.labels(poolName); this.elapsedBorrowedSummaryChild = ELAPSED_BORROWED_SUMMARY.labels(poolName); this.elapsedCreationSummaryChild = ELAPSED_CREATION_SUMMARY.labels(poolName); } @Override public void recordConnectionAcquiredNanos(long elapsedAcquiredNanos) { elapsedAcquiredSummaryChild.observe(elapsedAcquiredNanos); } @Override public void recordConnectionUsageMillis(long elapsedBorrowedMillis) { elapsedBorrowedSummaryChild.observe(elapsedBorrowedMillis); } @Override public void recordConnectionCreatedMillis(long connectionCreatedMillis) { elapsedCreationSummaryChild.observe(connectionCreatedMillis); } @Override public void recordConnectionTimeout() { connectionTimeoutCounterChild.inc(); } } PrometheusMetricsTrackerFactory.java000066400000000000000000000027701315431642000355650ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/metrics/prometheus/* * Copyright (C) 2016 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.metrics.prometheus; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.metrics.PoolStats; /** *

{@code
 * HikariConfig config = new HikariConfig();
 * config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
 * }
*/ public class PrometheusMetricsTrackerFactory implements MetricsTrackerFactory { private static HikariCPCollector collector; @Override public IMetricsTracker create(String poolName, PoolStats poolStats) { getCollector().add(poolName, poolStats); return new PrometheusMetricsTracker(poolName); } /** * initialize and register collector if it isn't initialized yet */ private HikariCPCollector getCollector() { if (collector == null) { collector = new HikariCPCollector().register(); } return collector; } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/000077500000000000000000000000001315431642000235555ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/HikariPool.java000077500000000000000000000643411315431642000264740ustar00rootroot00000000000000/* * Copyright (C) 2013,2014 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.pool; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedDisplayString; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.ClockSource.plusMillis; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_IN_USE; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_NOT_IN_USE; import static com.zaxxer.hikari.util.UtilityElf.createThreadPoolExecutor; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.Collections.unmodifiableCollection; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadPoolExecutor; import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory; import io.micrometer.core.instrument.MeterRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.health.HealthCheckRegistry; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariPoolMXBean; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.metrics.PoolStats; import com.zaxxer.hikari.metrics.dropwizard.CodahaleHealthChecker; import com.zaxxer.hikari.metrics.dropwizard.CodahaleMetricsTrackerFactory; import com.zaxxer.hikari.util.ConcurrentBag; import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener; import com.zaxxer.hikari.util.SuspendResumeLock; import com.zaxxer.hikari.util.UtilityElf.DefaultThreadFactory; /** * This is the primary connection pool class that provides the basic * pooling behavior for HikariCP. * * @author Brett Wooldridge */ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateListener { private final Logger LOGGER = LoggerFactory.getLogger(HikariPool.class); private static final int POOL_NORMAL = 0; private static final int POOL_SUSPENDED = 1; private static final int POOL_SHUTDOWN = 2; private volatile int poolState; private final long ALIVE_BYPASS_WINDOW_MS = Long.getLong("com.zaxxer.hikari.aliveBypassWindowMs", MILLISECONDS.toMillis(500)); private final long HOUSEKEEPING_PERIOD_MS = Long.getLong("com.zaxxer.hikari.housekeeping.periodMs", SECONDS.toMillis(30)); private final PoolEntryCreator POOL_ENTRY_CREATOR = new PoolEntryCreator(null); private final PoolEntryCreator POST_FILL_POOL_ENTRY_CREATOR = new PoolEntryCreator("After adding "); private final Collection addConnectionQueue; private final ThreadPoolExecutor addConnectionExecutor; private final ThreadPoolExecutor closeConnectionExecutor; private final ConcurrentBag connectionBag; private final ProxyLeakTaskFactory leakTaskFactory; private final SuspendResumeLock suspendResumeLock; private ScheduledExecutorService houseKeepingExecutorService; private ScheduledFuture houseKeeperTask; /** * Construct a HikariPool with the specified configuration. * * @param config a HikariConfig instance */ public HikariPool(final HikariConfig config) { super(config); this.connectionBag = new ConcurrentBag<>(this); this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK; this.houseKeepingExecutorService = initializeHouseKeepingExecutorService(); checkFailFast(); if (config.getMetricsTrackerFactory() != null) { setMetricsTrackerFactory(config.getMetricsTrackerFactory()); } else { setMetricRegistry(config.getMetricRegistry()); } setHealthCheckRegistry(config.getHealthCheckRegistry()); registerMBeans(this); ThreadFactory threadFactory = config.getThreadFactory(); LinkedBlockingQueue addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize()); this.addConnectionQueue = unmodifiableCollection(addConnectionQueue); this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy()); this.closeConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService); this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS); } /** * Get a connection from the pool, or timeout after connectionTimeout milliseconds. * * @return a java.sql.Connection instance * @throws SQLException thrown if a timeout occurs trying to obtain a connection */ public Connection getConnection() throws SQLException { return getConnection(connectionTimeout); } /** * Get a connection from the pool, or timeout after the specified number of milliseconds. * * @param hardTimeout the maximum time to wait for a connection from the pool * @return a java.sql.Connection instance * @throws SQLException thrown if a timeout occurs trying to obtain a connection */ public Connection getConnection(final long hardTimeout) throws SQLException { suspendResumeLock.acquire(); final long startTime = currentTime(); try { long timeout = hardTimeout; PoolEntry poolEntry = null; try { do { poolEntry = connectionBag.borrow(timeout, MILLISECONDS); if (poolEntry == null) { break; // We timed out... break and throw exception } final long now = currentTime(); if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { closeConnection(poolEntry, "(connection is evicted or dead)"); // Throw away the dead connection (passed max age or failed alive test) timeout = hardTimeout - elapsedMillis(startTime); } else { metricsTracker.recordBorrowStats(poolEntry, startTime); return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now); } } while (timeout > 0L); metricsTracker.recordBorrowTimeoutStats(startTime); } catch (InterruptedException e) { if (poolEntry != null) { poolEntry.recycle(startTime); } Thread.currentThread().interrupt(); throw new SQLException(poolName + " - Interrupted during connection acquisition", e); } } finally { suspendResumeLock.release(); } throw createTimeoutException(startTime); } /** * Shutdown the pool, closing all idle connections and aborting or closing * active connections. * * @throws InterruptedException thrown if the thread is interrupted during shutdown */ public synchronized void shutdown() throws InterruptedException { try { poolState = POOL_SHUTDOWN; if (addConnectionExecutor == null) { return; } logPoolState("Before shutdown "); if (houseKeeperTask != null) { houseKeeperTask.cancel(false); houseKeeperTask = null; } softEvictConnections(); addConnectionExecutor.shutdown(); addConnectionExecutor.awaitTermination(getLoginTimeout(), SECONDS); destroyHouseKeepingExecutorService(); connectionBag.close(); final ExecutorService assassinExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection assassinator", config.getThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); try { final long start = currentTime(); do { abortActiveConnections(assassinExecutor); softEvictConnections(); } while (getTotalConnections() > 0 && elapsedMillis(start) < SECONDS.toMillis(10)); } finally { assassinExecutor.shutdown(); assassinExecutor.awaitTermination(10L, SECONDS); } shutdownNetworkTimeoutExecutor(); closeConnectionExecutor.shutdown(); closeConnectionExecutor.awaitTermination(10L, SECONDS); } finally { logPoolState("After shutdown "); unregisterMBeans(); metricsTracker.close(); } } /** * Evict a connection from the pool. * * @param connection the connection to evict */ public void evictConnection(Connection connection) { ProxyConnection proxyConnection = (ProxyConnection) connection; proxyConnection.cancelLeakTask(); try { softEvictConnection(proxyConnection.getPoolEntry(), "(connection evicted by user)", !connection.isClosed() /* owner */); } catch (SQLException e) { // unreachable in HikariCP, but we're still forced to catch it } } public void setMetricRegistry(Object metricRegistry) { if (metricRegistry instanceof MetricRegistry) { setMetricsTrackerFactory(new CodahaleMetricsTrackerFactory((MetricRegistry) metricRegistry)); } else if (metricRegistry instanceof MeterRegistry) { setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory((MeterRegistry) metricRegistry)); } else { setMetricsTrackerFactory(null); } } public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory) { if (metricsTrackerFactory != null) { this.metricsTracker = new MetricsTrackerDelegate(metricsTrackerFactory.create(config.getPoolName(), getPoolStats())); } else { this.metricsTracker = new NopMetricsTrackerDelegate(); } } public void setHealthCheckRegistry(Object healthCheckRegistry) { if (healthCheckRegistry != null) { CodahaleHealthChecker.registerHealthChecks(this, config, (HealthCheckRegistry) healthCheckRegistry); } } // *********************************************************************** // IBagStateListener callback // *********************************************************************** /** {@inheritDoc} */ @Override public void addBagItem(final int waiting) { final boolean shouldAdd = waiting - addConnectionQueue.size() >= 0; // Yes, >= is intentional. if (shouldAdd) { addConnectionExecutor.submit(POOL_ENTRY_CREATOR); } CompletableFuture.completedFuture(Boolean.TRUE); } // *********************************************************************** // HikariPoolMBean methods // *********************************************************************** /** {@inheritDoc} */ @Override public int getActiveConnections() { return connectionBag.getCount(STATE_IN_USE); } /** {@inheritDoc} */ @Override public int getIdleConnections() { return connectionBag.getCount(STATE_NOT_IN_USE); } /** {@inheritDoc} */ @Override public int getTotalConnections() { return connectionBag.size(); } /** {@inheritDoc} */ @Override public int getThreadsAwaitingConnection() { return connectionBag.getWaitingThreadCount(); } /** {@inheritDoc} */ @Override public void softEvictConnections() { connectionBag.values().forEach(poolEntry -> softEvictConnection(poolEntry, "(connection evicted)", false /* not owner */)); } /** {@inheritDoc} */ @Override public synchronized void suspendPool() { if (suspendResumeLock == SuspendResumeLock.FAUX_LOCK) { throw new IllegalStateException(poolName + " - is not suspendable"); } else if (poolState != POOL_SUSPENDED) { suspendResumeLock.suspend(); poolState = POOL_SUSPENDED; } } /** {@inheritDoc} */ @Override public synchronized void resumePool() { if (poolState == POOL_SUSPENDED) { poolState = POOL_NORMAL; fillPool(); suspendResumeLock.resume(); } } // *********************************************************************** // Package methods // *********************************************************************** /** * Log the current pool state at debug level. * * @param prefix an optional prefix to prepend the log message */ void logPoolState(String... prefix) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("{} - {}stats (total={}, active={}, idle={}, waiting={})", poolName, (prefix.length > 0 ? prefix[0] : ""), getTotalConnections(), getActiveConnections(), getIdleConnections(), getThreadsAwaitingConnection()); } } /** * Recycle PoolEntry (add back to the pool) * * @param poolEntry the PoolEntry to recycle */ @Override void recycle(final PoolEntry poolEntry) { metricsTracker.recordConnectionUsage(poolEntry); connectionBag.requite(poolEntry); } /** * Permanently close the real (underlying) connection (eat any exception). * * @param poolEntry poolEntry having the connection to close * @param closureReason reason to close */ void closeConnection(final PoolEntry poolEntry, final String closureReason) { if (connectionBag.remove(poolEntry)) { final Connection connection = poolEntry.close(); closeConnectionExecutor.execute(() -> { quietlyCloseConnection(connection, closureReason); if (poolState == POOL_NORMAL) { fillPool(); } }); } } @SuppressWarnings("unused") int[] getPoolStateCounts() { return connectionBag.getStateCounts(); } // *********************************************************************** // Private methods // *********************************************************************** /** * Creating new poolEntry. */ private PoolEntry createPoolEntry() { try { final PoolEntry poolEntry = newPoolEntry(); final long maxLifetime = config.getMaxLifetime(); if (maxLifetime > 0) { // variance up to 2.5% of the maxlifetime final long variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0; final long lifetime = maxLifetime - variance; poolEntry.setFutureEol(houseKeepingExecutorService.schedule( () -> { if (softEvictConnection(poolEntry, "(connection has passed maxLifetime)", false /* not owner */)) { addBagItem(connectionBag.getWaitingThreadCount()); } }, lifetime, MILLISECONDS)); } return poolEntry; } catch (Exception e) { if (poolState == POOL_NORMAL) { LOGGER.debug("{} - Cannot acquire connection from data source", poolName, (e instanceof ConnectionSetupException ? e.getCause() : e)); } return null; } } /** * Fill pool up from current idle connections (as they are perceived at the point of execution) to minimumIdle connections. */ private synchronized void fillPool() { final int connectionsToAdd = Math.min(config.getMaximumPoolSize() - getTotalConnections(), config.getMinimumIdle() - getIdleConnections()) - addConnectionQueue.size(); for (int i = 0; i < connectionsToAdd; i++) { addConnectionExecutor.submit((i < connectionsToAdd - 1) ? POOL_ENTRY_CREATOR : POST_FILL_POOL_ENTRY_CREATOR); } } /** * Attempt to abort or close active connections. */ private void abortActiveConnections(final ExecutorService assassinExecutor) { for (PoolEntry poolEntry : connectionBag.values(STATE_IN_USE)) { Connection connection = poolEntry.close(); try { connection.abort(assassinExecutor); } catch (Throwable e) { quietlyCloseConnection(connection, "(connection aborted during shutdown)"); } finally { connectionBag.remove(poolEntry); } } } /** * If initializationFailFast is configured, check that we have DB connectivity. * * @throws PoolInitializationException if fails to create or validate connection */ private void checkFailFast() { final long initializationTimeout = config.getInitializationFailTimeout(); if (initializationTimeout < 0) { return; } final long startTime = currentTime(); do { final PoolEntry poolEntry = createPoolEntry(); if (poolEntry != null) { if (config.getMinimumIdle() > 0) { connectionBag.add(poolEntry); LOGGER.debug("{} - Added connection {}", poolName, poolEntry.connection); } else { quietlyCloseConnection(poolEntry.close(), "(initialization check complete and minimumIdle is zero)"); } return; } if (getLastConnectionFailure() instanceof ConnectionSetupException) { throwPoolInitializationException(getLastConnectionFailure().getCause()); } quietlySleep(1000L); } while (elapsedMillis(startTime) < initializationTimeout); if (initializationTimeout > 0) { throwPoolInitializationException(getLastConnectionFailure()); } } private void throwPoolInitializationException(Throwable t) { LOGGER.error("{} - Exception during pool initialization.", poolName, t); destroyHouseKeepingExecutorService(); throw new PoolInitializationException(t); } private boolean softEvictConnection(final PoolEntry poolEntry, final String reason, final boolean owner) { poolEntry.markEvicted(); if (owner || connectionBag.reserve(poolEntry)) { closeConnection(poolEntry, reason); return true; } return false; } private ScheduledExecutorService initializeHouseKeepingExecutorService() { if (config.getScheduledExecutor() == null) { final ThreadFactory threadFactory = Optional.ofNullable(config.getThreadFactory()).orElse(new DefaultThreadFactory(poolName + " housekeeper", true)); final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, threadFactory, new ThreadPoolExecutor.DiscardPolicy()); executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); executor.setRemoveOnCancelPolicy(true); return executor; } else { return config.getScheduledExecutor(); } } private void destroyHouseKeepingExecutorService() { if (config.getScheduledExecutor() == null) { houseKeepingExecutorService.shutdownNow(); } } private PoolStats getPoolStats() { return new PoolStats(SECONDS.toMillis(1)) { @Override protected void update() { this.pendingThreads = HikariPool.this.getThreadsAwaitingConnection(); this.idleConnections = HikariPool.this.getIdleConnections(); this.totalConnections = HikariPool.this.getTotalConnections(); this.activeConnections = HikariPool.this.getActiveConnections(); } }; } private SQLException createTimeoutException(long startTime) { logPoolState("Timeout failure "); metricsTracker.recordConnectionTimeout(); String sqlState = null; final Throwable originalException = getLastConnectionFailure(); if (originalException instanceof SQLException) { sqlState = ((SQLException) originalException).getSQLState(); } final SQLException connectionException = new SQLTransientConnectionException(poolName + " - Connection is not available, request timed out after " + elapsedMillis(startTime) + "ms.", sqlState, originalException); if (originalException instanceof SQLException) { connectionException.setNextException((SQLException) originalException); } return connectionException; } // *********************************************************************** // Non-anonymous Inner-classes // *********************************************************************** /** * Creating and adding poolEntries (connections) to the pool. */ private final class PoolEntryCreator implements Callable { private final String loggingPrefix; PoolEntryCreator(String loggingPrefix) { this.loggingPrefix = loggingPrefix; } @Override public Boolean call() throws Exception { long sleepBackoff = 250L; while (poolState == POOL_NORMAL && shouldCreateAnotherConnection()) { final PoolEntry poolEntry = createPoolEntry(); if (poolEntry != null) { connectionBag.add(poolEntry); LOGGER.debug("{} - Added connection {}", poolName, poolEntry.connection); if (loggingPrefix != null) { logPoolState(loggingPrefix); } return Boolean.TRUE; } // failed to get connection from db, sleep and retry quietlySleep(sleepBackoff); sleepBackoff = Math.min(SECONDS.toMillis(10), Math.min(connectionTimeout, (long) (sleepBackoff * 1.5))); } // Pool is suspended or shutdown or at max size return Boolean.FALSE; } private boolean shouldCreateAnotherConnection() { // only create connections if we need another idle connection or have threads still waiting // for a new connection, otherwise bail return getTotalConnections() < config.getMaximumPoolSize() && (connectionBag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle()); } } /** * The house keeping task to retire and maintain minimum idle connections. */ private final class HouseKeeper implements Runnable { private volatile long previous = plusMillis(currentTime(), -HOUSEKEEPING_PERIOD_MS); @Override public void run() { try { // refresh timeouts in case they changed via MBean connectionTimeout = config.getConnectionTimeout(); validationTimeout = config.getValidationTimeout(); leakTaskFactory.updateLeakDetectionThreshold(config.getLeakDetectionThreshold()); final long idleTimeout = config.getIdleTimeout(); final long now = currentTime(); // Detect retrograde time, allowing +128ms as per NTP spec. if (plusMillis(now, 128) < plusMillis(previous, HOUSEKEEPING_PERIOD_MS)) { LOGGER.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.", poolName, elapsedDisplayString(previous, now)); previous = now; softEvictConnections(); fillPool(); return; } else if (now > plusMillis(previous, (3 * HOUSEKEEPING_PERIOD_MS) / 2)) { // No point evicting for forward clock motion, this merely accelerates connection retirement anyway LOGGER.warn("{} - Thread starvation or clock leap detected (housekeeper delta={}).", poolName, elapsedDisplayString(previous, now)); } previous = now; String afterPrefix = "Pool "; if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) { logPoolState("Before cleanup "); afterPrefix = "After cleanup "; final List notInUse = connectionBag.values(STATE_NOT_IN_USE); int removed = 0; for (PoolEntry entry : notInUse) { if (elapsedMillis(entry.lastAccessed, now) > idleTimeout && connectionBag.reserve(entry)) { closeConnection(entry, "(connection has passed idleTimeout)"); if (++removed > config.getMinimumIdle()) { break; } } } } logPoolState(afterPrefix); fillPool(); // Try to maintain minimum connections } catch (Exception e) { LOGGER.error("Unexpected exception in housekeeping task", e); } } } public static class PoolInitializationException extends RuntimeException { private static final long serialVersionUID = 929872118275916520L; /** * Construct an exception, possibly wrapping the provided Throwable as the cause. * @param t the Throwable to wrap */ public PoolInitializationException(Throwable t) { super("Failed to initialize pool: " + t.getMessage(), t); } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/PoolBase.java000077500000000000000000000625501315431642000261370ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_SCHEMA; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import java.lang.management.ManagementFactory; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; import java.sql.Statement; import java.util.Properties; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.util.DriverDataSource; import com.zaxxer.hikari.util.PropertyElf; import com.zaxxer.hikari.util.UtilityElf; import com.zaxxer.hikari.util.UtilityElf.DefaultThreadFactory; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_AUTOCOMMIT; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_CATALOG; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_ISOLATION; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_NETTIMEOUT; import static com.zaxxer.hikari.pool.ProxyConnection.DIRTY_BIT_READONLY; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.ClockSource.elapsedNanos; import static com.zaxxer.hikari.util.UtilityElf.createInstance; abstract class PoolBase { private final Logger LOGGER = LoggerFactory.getLogger(PoolBase.class); protected final HikariConfig config; protected final String poolName; long connectionTimeout; long validationTimeout; IMetricsTrackerDelegate metricsTracker; private static final String[] RESET_STATES = {"readOnly", "autoCommit", "isolation", "catalog", "netTimeout", "schema"}; private static final int UNINITIALIZED = -1; private static final int TRUE = 1; private static final int FALSE = 0; private int networkTimeout; private int isNetworkTimeoutSupported; private int isQueryTimeoutSupported; private int defaultTransactionIsolation; private int transactionIsolation; private Executor netTimeoutExecutor; private DataSource dataSource; private final String catalog; private final String schema; private final boolean isReadOnly; private final boolean isAutoCommit; private final boolean isUseJdbc4Validation; private final boolean isIsolateInternalQueries; private final AtomicReference lastConnectionFailure; private volatile boolean isValidChecked; PoolBase(final HikariConfig config) { this.config = config; this.networkTimeout = UNINITIALIZED; this.catalog = config.getCatalog(); this.schema = config.getSchema(); this.isReadOnly = config.isReadOnly(); this.isAutoCommit = config.isAutoCommit(); this.transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation()); this.isQueryTimeoutSupported = UNINITIALIZED; this.isNetworkTimeoutSupported = UNINITIALIZED; this.isUseJdbc4Validation = config.getConnectionTestQuery() == null; this.isIsolateInternalQueries = config.isIsolateInternalQueries(); this.poolName = config.getPoolName(); this.connectionTimeout = config.getConnectionTimeout(); this.validationTimeout = config.getValidationTimeout(); this.lastConnectionFailure = new AtomicReference<>(); initializeDataSource(); } /** {@inheritDoc} */ @Override public String toString() { return poolName; } abstract void recycle(final PoolEntry poolEntry); // *********************************************************************** // JDBC methods // *********************************************************************** void quietlyCloseConnection(final Connection connection, final String closureReason) { if (connection != null) { try { LOGGER.debug("{} - Closing connection {}: {}", poolName, connection, closureReason); try { setNetworkTimeout(connection, SECONDS.toMillis(15)); } finally { connection.close(); // continue with the close even if setNetworkTimeout() throws } } catch (Throwable e) { LOGGER.debug("{} - Closing connection {} failed", poolName, connection, e); } } } boolean isConnectionAlive(final Connection connection) { try { try { setNetworkTimeout(connection, validationTimeout); final long validationSeconds = (int) Math.max(1000L, validationTimeout) / 1000; if (isUseJdbc4Validation) { return connection.isValid((int) validationSeconds); } try (Statement statement = connection.createStatement()) { if (isNetworkTimeoutSupported != TRUE) { setQueryTimeout(statement, (int) validationSeconds); } statement.execute(config.getConnectionTestQuery()); } } finally { setNetworkTimeout(connection, networkTimeout); if (isIsolateInternalQueries && !isAutoCommit) { connection.rollback(); } } return true; } catch (Exception e) { lastConnectionFailure.set(e); LOGGER.warn("{} - Failed to validate connection {} ({})", poolName, connection, e.getMessage()); return false; } } Throwable getLastConnectionFailure() { return lastConnectionFailure.get(); } public DataSource getUnwrappedDataSource() { return dataSource; } // *********************************************************************** // PoolEntry methods // *********************************************************************** PoolEntry newPoolEntry() throws Exception { return new PoolEntry(newConnection(), this, isReadOnly, isAutoCommit); } void resetConnectionState(final Connection connection, final ProxyConnection proxyConnection, final int dirtyBits) throws SQLException { int resetBits = 0; if ((dirtyBits & DIRTY_BIT_READONLY) != 0 && proxyConnection.getReadOnlyState() != isReadOnly) { connection.setReadOnly(isReadOnly); resetBits |= DIRTY_BIT_READONLY; } if ((dirtyBits & DIRTY_BIT_AUTOCOMMIT) != 0 && proxyConnection.getAutoCommitState() != isAutoCommit) { connection.setAutoCommit(isAutoCommit); resetBits |= DIRTY_BIT_AUTOCOMMIT; } if ((dirtyBits & DIRTY_BIT_ISOLATION) != 0 && proxyConnection.getTransactionIsolationState() != transactionIsolation) { connection.setTransactionIsolation(transactionIsolation); resetBits |= DIRTY_BIT_ISOLATION; } if ((dirtyBits & DIRTY_BIT_CATALOG) != 0 && catalog != null && !catalog.equals(proxyConnection.getCatalogState())) { connection.setCatalog(catalog); resetBits |= DIRTY_BIT_CATALOG; } if ((dirtyBits & DIRTY_BIT_NETTIMEOUT) != 0 && proxyConnection.getNetworkTimeoutState() != networkTimeout) { setNetworkTimeout(connection, networkTimeout); resetBits |= DIRTY_BIT_NETTIMEOUT; } if ((dirtyBits & DIRTY_BIT_SCHEMA) != 0 && schema != null && !schema.equals(proxyConnection.getSchemaState())) { connection.setSchema(schema); resetBits |= DIRTY_BIT_SCHEMA; } if (resetBits != 0 && LOGGER.isDebugEnabled()) { LOGGER.debug("{} - Reset ({}) on connection {}", poolName, stringFromResetBits(resetBits), connection); } } void shutdownNetworkTimeoutExecutor() { if (netTimeoutExecutor instanceof ThreadPoolExecutor) { ((ThreadPoolExecutor) netTimeoutExecutor).shutdownNow(); } } long getLoginTimeout() { try { return (dataSource != null) ? dataSource.getLoginTimeout() : SECONDS.toSeconds(5); } catch (SQLException e) { return SECONDS.toSeconds(5); } } // *********************************************************************** // JMX methods // *********************************************************************** /** * Register MBeans for HikariConfig and HikariPool. * * @param hikariPool a HikariPool instance */ void registerMBeans(final HikariPool hikariPool) { if (!config.isRegisterMbeans()) { return; } try { final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")"); final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")"); if (!mBeanServer.isRegistered(beanConfigName)) { mBeanServer.registerMBean(config, beanConfigName); mBeanServer.registerMBean(hikariPool, beanPoolName); } else { LOGGER.error("{} - JMX name ({}) is already registered.", poolName, poolName); } } catch (Exception e) { LOGGER.warn("{} - Failed to register management beans.", poolName, e); } } /** * Unregister MBeans for HikariConfig and HikariPool. */ void unregisterMBeans() { if (!config.isRegisterMbeans()) { return; } try { final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")"); final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")"); if (mBeanServer.isRegistered(beanConfigName)) { mBeanServer.unregisterMBean(beanConfigName); mBeanServer.unregisterMBean(beanPoolName); } } catch (Exception e) { LOGGER.warn("{} - Failed to unregister management beans.", poolName, e); } } // *********************************************************************** // Private methods // *********************************************************************** /** * Create/initialize the underlying DataSource. */ private void initializeDataSource() { final String jdbcUrl = config.getJdbcUrl(); final String username = config.getUsername(); final String password = config.getPassword(); final String dsClassName = config.getDataSourceClassName(); final String driverClassName = config.getDriverClassName(); final String dataSourceJNDI = config.getDataSourceJNDI(); final Properties dataSourceProperties = config.getDataSourceProperties(); DataSource dataSource = config.getDataSource(); if (dsClassName != null && dataSource == null) { dataSource = createInstance(dsClassName, DataSource.class); PropertyElf.setTargetFromProperties(dataSource, dataSourceProperties); } else if (jdbcUrl != null && dataSource == null) { dataSource = new DriverDataSource(jdbcUrl, driverClassName, dataSourceProperties, username, password); } else if (dataSourceJNDI != null && dataSource == null) { try { InitialContext ic = new InitialContext(); dataSource = (DataSource) ic.lookup(dataSourceJNDI); } catch (NamingException e) { throw new PoolInitializationException(e); } } if (dataSource != null) { setLoginTimeout(dataSource); createNetworkTimeoutExecutor(dataSource, dsClassName, jdbcUrl); } this.dataSource = dataSource; } /** * Obtain connection from data source. * * @return a Connection connection */ private Connection newConnection() throws Exception { final long start = currentTime(); Connection connection = null; try { String username = config.getUsername(); String password = config.getPassword(); connection = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password); if (connection == null) { throw new SQLTransientConnectionException("DataSource returned null unexpectedly"); } setupConnection(connection); lastConnectionFailure.set(null); return connection; } catch (Exception e) { if (connection != null) { quietlyCloseConnection(connection, "(Failed to create/setup connection)"); } else if (getLastConnectionFailure() == null) { LOGGER.debug("{} - Failed to create/setup connection: {}", poolName, e.getMessage()); } lastConnectionFailure.set(e); throw e; } finally { // tracker will be null during failFast check if (metricsTracker != null) { metricsTracker.recordConnectionCreated(elapsedMillis(start)); } } } /** * Setup a connection initial state. * * @param connection a Connection * @throws ConnectionSetupException thrown if any exception is encountered */ private void setupConnection(final Connection connection) throws ConnectionSetupException { try { if (networkTimeout == UNINITIALIZED) { networkTimeout = getAndSetNetworkTimeout(connection, validationTimeout); } else { setNetworkTimeout(connection, validationTimeout); } connection.setReadOnly(isReadOnly); connection.setAutoCommit(isAutoCommit); checkDriverSupport(connection); if (transactionIsolation != defaultTransactionIsolation) { connection.setTransactionIsolation(transactionIsolation); } if (catalog != null) { connection.setCatalog(catalog); } if (schema != null) { connection.setSchema(schema); } executeSql(connection, config.getConnectionInitSql(), true); setNetworkTimeout(connection, networkTimeout); } catch (SQLException e) { throw new ConnectionSetupException(e); } } /** * Execute isValid() or connection test query. * * @param connection a Connection to check */ private void checkDriverSupport(final Connection connection) throws SQLException { if (!isValidChecked) { try { if (isUseJdbc4Validation) { connection.isValid(1); } else { executeSql(connection, config.getConnectionTestQuery(), false); } } catch (Throwable e) { LOGGER.error("{} - Failed to execute" + (isUseJdbc4Validation ? " isValid() for connection, configure" : "") + " connection test query ({}).", poolName, e.getMessage()); throw e; } try { defaultTransactionIsolation = connection.getTransactionIsolation(); if (transactionIsolation == -1) { transactionIsolation = defaultTransactionIsolation; } } catch (SQLException e) { LOGGER.warn("{} - Default transaction isolation level detection failed ({}).", poolName, e.getMessage()); if (e.getSQLState() != null && !e.getSQLState().startsWith("08")) { throw e; } } isValidChecked = true; } } /** * Set the query timeout, if it is supported by the driver. * * @param statement a statement to set the query timeout on * @param timeoutSec the number of seconds before timeout */ private void setQueryTimeout(final Statement statement, final int timeoutSec) { if (isQueryTimeoutSupported != FALSE) { try { statement.setQueryTimeout(timeoutSec); isQueryTimeoutSupported = TRUE; } catch (Throwable e) { if (isQueryTimeoutSupported == UNINITIALIZED) { isQueryTimeoutSupported = FALSE; LOGGER.info("{} - Failed to set query timeout for statement. ({})", poolName, e.getMessage()); } } } } /** * Set the network timeout, if isUseNetworkTimeout is true and the * driver supports it. Return the pre-existing value of the network timeout. * * @param connection the connection to set the network timeout on * @param timeoutMs the number of milliseconds before timeout * @return the pre-existing network timeout value */ private int getAndSetNetworkTimeout(final Connection connection, final long timeoutMs) { if (isNetworkTimeoutSupported != FALSE) { try { final int originalTimeout = connection.getNetworkTimeout(); connection.setNetworkTimeout(netTimeoutExecutor, (int) timeoutMs); isNetworkTimeoutSupported = TRUE; return originalTimeout; } catch (Throwable e) { if (isNetworkTimeoutSupported == UNINITIALIZED) { isNetworkTimeoutSupported = FALSE; LOGGER.info("{} - Driver does not support get/set network timeout for connections. ({})", poolName, e.getMessage()); if (validationTimeout < SECONDS.toMillis(1)) { LOGGER.warn("{} - A validationTimeout of less than 1 second cannot be honored on drivers without setNetworkTimeout() support.", poolName); } else if (validationTimeout % SECONDS.toMillis(1) != 0) { LOGGER.warn("{} - A validationTimeout with fractional second granularity cannot be honored on drivers without setNetworkTimeout() support.", poolName); } } } } return 0; } /** * Set the network timeout, if isUseNetworkTimeout is true and the * driver supports it. * * @param connection the connection to set the network timeout on * @param timeoutMs the number of milliseconds before timeout * @throws SQLException throw if the connection.setNetworkTimeout() call throws */ private void setNetworkTimeout(final Connection connection, final long timeoutMs) throws SQLException { if (isNetworkTimeoutSupported == TRUE) { connection.setNetworkTimeout(netTimeoutExecutor, (int) timeoutMs); } } /** * Execute the user-specified init SQL. * * @param connection the connection to initialize * @param sql the SQL to execute * @param isCommit whether to commit the SQL after execution or not * @throws SQLException throws if the init SQL execution fails */ private void executeSql(final Connection connection, final String sql, final boolean isCommit) throws SQLException { if (sql != null) { try (Statement statement = connection.createStatement()) { // connection was created a few milliseconds before, so set query timeout is omitted (we assume it will succeed) statement.execute(sql); } if (isIsolateInternalQueries && !isAutoCommit) { if (isCommit) { connection.commit(); } else { connection.rollback(); } } } } private void createNetworkTimeoutExecutor(final DataSource dataSource, final String dsClassName, final String jdbcUrl) { // Temporary hack for MySQL issue: http://bugs.mysql.com/bug.php?id=75615 if ((dsClassName != null && dsClassName.contains("Mysql")) || (jdbcUrl != null && jdbcUrl.contains("mysql")) || (dataSource != null && dataSource.getClass().getName().contains("Mysql"))) { netTimeoutExecutor = new SynchronousExecutor(); } else { ThreadFactory threadFactory = config.getThreadFactory(); threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory(poolName + " network timeout executor", true); ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(threadFactory); executor.setKeepAliveTime(15, SECONDS); executor.allowCoreThreadTimeOut(true); netTimeoutExecutor = executor; } } /** * Set the loginTimeout on the specified DataSource. * * @param dataSource the DataSource */ private void setLoginTimeout(final DataSource dataSource) { if (connectionTimeout != Integer.MAX_VALUE) { try { dataSource.setLoginTimeout(Math.max(1, (int) MILLISECONDS.toSeconds(500L + connectionTimeout))); } catch (Throwable e) { LOGGER.info("{} - Failed to set login timeout for data source. ({})", poolName, e.getMessage()); } } } /** * This will create a string for debug logging. Given a set of "reset bits", this * method will return a concatenated string, for example: * * Input : 0b00110 * Output: "autoCommit, isolation" * * @param bits a set of "reset bits" * @return a string of which states were reset */ private String stringFromResetBits(final int bits) { final StringBuilder sb = new StringBuilder(); for (int ndx = 0; ndx < RESET_STATES.length; ndx++) { if ( (bits & (0b1 << ndx)) != 0) { sb.append(RESET_STATES[ndx]).append(", "); } } sb.setLength(sb.length() - 2); // trim trailing comma return sb.toString(); } // *********************************************************************** // Private Static Classes // *********************************************************************** static class ConnectionSetupException extends Exception { private static final long serialVersionUID = 929872118275916521L; ConnectionSetupException(Throwable t) { super(t); } } /** * Special executor used only to work around a MySQL issue that has not been addressed. * MySQL issue: http://bugs.mysql.com/bug.php?id=75615 */ private static class SynchronousExecutor implements Executor { /** {@inheritDoc} */ @Override public void execute(Runnable command) { try { command.run(); } catch (Throwable t) { LoggerFactory.getLogger(PoolBase.class).debug("Failed to execute: {}", command, t); } } } interface IMetricsTrackerDelegate extends AutoCloseable { default void recordConnectionUsage(PoolEntry poolEntry) {} default void recordConnectionCreated(long connectionCreatedMillis) {} default void recordBorrowTimeoutStats(long startTime) {} default void recordBorrowStats(final PoolEntry poolEntry, final long startTime) {} default void recordConnectionTimeout() {} @Override default void close() {} } /** * A class that delegates to a MetricsTracker implementation. The use of a delegate * allows us to use the NopMetricsTrackerDelegate when metrics are disabled, which in * turn allows the JIT to completely optimize away to callsites to record metrics. */ static class MetricsTrackerDelegate implements IMetricsTrackerDelegate { final IMetricsTracker tracker; MetricsTrackerDelegate(IMetricsTracker tracker) { this.tracker = tracker; } @Override public void recordConnectionUsage(final PoolEntry poolEntry) { tracker.recordConnectionUsageMillis(poolEntry.getMillisSinceBorrowed()); } @Override public void recordConnectionCreated(long connectionCreatedMillis) { tracker.recordConnectionCreatedMillis(connectionCreatedMillis); } @Override public void recordBorrowTimeoutStats(long startTime) { tracker.recordConnectionAcquiredNanos(elapsedNanos(startTime)); } @Override public void recordBorrowStats(final PoolEntry poolEntry, final long startTime) { final long now = currentTime(); poolEntry.lastBorrowed = now; tracker.recordConnectionAcquiredNanos(elapsedNanos(startTime, now)); } @Override public void recordConnectionTimeout() { tracker.recordConnectionTimeout(); } @Override public void close() { tracker.close(); } } /** * A no-op implementation of the IMetricsTrackerDelegate that is used when metrics capture is * disabled. */ static final class NopMetricsTrackerDelegate implements IMetricsTrackerDelegate {} } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/PoolEntry.java000066400000000000000000000121531315431642000263550ustar00rootroot00000000000000/* * Copyright (C) 2014 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.pool; import com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry; import com.zaxxer.hikari.util.FastList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import static com.zaxxer.hikari.util.ClockSource.*; /** * Entry used in the ConcurrentBag to track Connection instances. * * @author Brett Wooldridge */ final class PoolEntry implements IConcurrentBagEntry { private static final Logger LOGGER = LoggerFactory.getLogger(PoolEntry.class); private static final AtomicIntegerFieldUpdater stateUpdater; Connection connection; long lastAccessed; long lastBorrowed; @SuppressWarnings("FieldCanBeLocal") private volatile int state = 0; private volatile boolean evict; private volatile ScheduledFuture endOfLife; private final FastList openStatements; private final HikariPool hikariPool; private final boolean isReadOnly; private final boolean isAutoCommit; static { stateUpdater = AtomicIntegerFieldUpdater.newUpdater(PoolEntry.class, "state"); } PoolEntry(final Connection connection, final PoolBase pool, final boolean isReadOnly, final boolean isAutoCommit) { this.connection = connection; this.hikariPool = (HikariPool) pool; this.isReadOnly = isReadOnly; this.isAutoCommit = isAutoCommit; this.lastAccessed = currentTime(); this.openStatements = new FastList<>(Statement.class, 16); } /** * Release this entry back to the pool. * * @param lastAccessed last access time-stamp */ void recycle(final long lastAccessed) { if (connection != null) { this.lastAccessed = lastAccessed; hikariPool.recycle(this); } } /** * Set the end of life {@link ScheduledFuture}. * * @param endOfLife this PoolEntry/Connection's end of life {@link ScheduledFuture} */ void setFutureEol(final ScheduledFuture endOfLife) { this.endOfLife = endOfLife; } Connection createProxyConnection(final ProxyLeakTask leakTask, final long now) { return ProxyFactory.getProxyConnection(this, connection, openStatements, leakTask, now, isReadOnly, isAutoCommit); } void resetConnectionState(final ProxyConnection proxyConnection, final int dirtyBits) throws SQLException { hikariPool.resetConnectionState(connection, proxyConnection, dirtyBits); } String getPoolName() { return hikariPool.toString(); } boolean isMarkedEvicted() { return evict; } void markEvicted() { this.evict = true; } void evict(final String closureReason) { hikariPool.closeConnection(this, closureReason); } /** Returns millis since lastBorrowed */ long getMillisSinceBorrowed() { return elapsedMillis(lastBorrowed); } /** {@inheritDoc} */ @Override public String toString() { final long now = currentTime(); return connection + ", accessed " + elapsedDisplayString(lastAccessed, now) + " ago, " + stateToString(); } // *********************************************************************** // IConcurrentBagEntry methods // *********************************************************************** /** {@inheritDoc} */ @Override public int getState() { return stateUpdater.get(this); } /** {@inheritDoc} */ @Override public boolean compareAndSet(int expect, int update) { return stateUpdater.compareAndSet(this, expect, update); } /** {@inheritDoc} */ @Override public void setState(int update) { stateUpdater.set(this, update); } Connection close() { ScheduledFuture eol = endOfLife; if (eol != null && !eol.isDone() && !eol.cancel(false)) { LOGGER.warn("{} - maxLifeTime expiration task cancellation unexpectedly returned false for connection {}", getPoolName(), connection); } Connection con = connection; connection = null; endOfLife = null; return con; } private String stateToString() { switch (state) { case STATE_IN_USE: return "IN_USE"; case STATE_NOT_IN_USE: return "NOT_IN_USE"; case STATE_REMOVED: return "REMOVED"; case STATE_RESERVED: return "RESERVED"; default: return "Invalid"; } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyCallableStatement.java000066400000000000000000000023251315431642000310500ustar00rootroot00000000000000/* * 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.pool; import java.sql.CallableStatement; /** * This is the proxy class for java.sql.CallableStatement. * * @author Brett Wooldridge */ public abstract class ProxyCallableStatement extends ProxyPreparedStatement implements CallableStatement { protected ProxyCallableStatement(ProxyConnection connection, CallableStatement statement) { super(connection, statement); } // ********************************************************************** // Overridden java.sql.CallableStatement Methods // ********************************************************************** }HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java000066400000000000000000000362011315431642000275630ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.util.ClockSource.currentTime; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Wrapper; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Executor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.util.FastList; /** * This is the proxy class for java.sql.Connection. * * @author Brett Wooldridge */ public abstract class ProxyConnection implements Connection { static final int DIRTY_BIT_READONLY = 0b000001; static final int DIRTY_BIT_AUTOCOMMIT = 0b000010; static final int DIRTY_BIT_ISOLATION = 0b000100; static final int DIRTY_BIT_CATALOG = 0b001000; static final int DIRTY_BIT_NETTIMEOUT = 0b010000; static final int DIRTY_BIT_SCHEMA = 0b100000; private static final Logger LOGGER; private static final Set ERROR_STATES; private static final Set ERROR_CODES; @SuppressWarnings("WeakerAccess") protected Connection delegate; private final PoolEntry poolEntry; private final ProxyLeakTask leakTask; private final FastList openStatements; private int dirtyBits; private long lastAccess; private boolean isCommitStateDirty; private boolean isReadOnly; private boolean isAutoCommit; private int networkTimeout; private int transactionIsolation; private String dbcatalog; private String dbschema; // static initializer static { LOGGER = LoggerFactory.getLogger(ProxyConnection.class); ERROR_STATES = new HashSet<>(); ERROR_STATES.add("57P01"); // ADMIN SHUTDOWN ERROR_STATES.add("57P02"); // CRASH SHUTDOWN ERROR_STATES.add("57P03"); // CANNOT CONNECT NOW ERROR_STATES.add("01002"); // SQL92 disconnect error ERROR_STATES.add("JZ0C0"); // Sybase disconnect error ERROR_STATES.add("JZ0C1"); // Sybase disconnect error ERROR_CODES = new HashSet<>(); ERROR_CODES.add(500150); ERROR_CODES.add(2399); } protected ProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList openStatements, final ProxyLeakTask leakTask, final long now, final boolean isReadOnly, final boolean isAutoCommit) { this.poolEntry = poolEntry; this.delegate = connection; this.openStatements = openStatements; this.leakTask = leakTask; this.lastAccess = now; this.isReadOnly = isReadOnly; this.isAutoCommit = isAutoCommit; } /** {@inheritDoc} */ @Override public final String toString() { return this.getClass().getSimpleName() + '@' + System.identityHashCode(this) + " wrapping " + delegate; } // *********************************************************************** // Connection State Accessors // *********************************************************************** final boolean getAutoCommitState() { return isAutoCommit; } final String getCatalogState() { return dbcatalog; } final String getSchemaState() { return dbschema; } final int getTransactionIsolationState() { return transactionIsolation; } final boolean getReadOnlyState() { return isReadOnly; } final int getNetworkTimeoutState() { return networkTimeout; } // *********************************************************************** // Internal methods // *********************************************************************** final PoolEntry getPoolEntry() { return poolEntry; } final SQLException checkException(SQLException sqle) { SQLException nse = sqle; for (int depth = 0; delegate != ClosedConnection.CLOSED_CONNECTION && nse != null && depth < 10; depth++) { final String sqlState = nse.getSQLState(); if (sqlState != null && sqlState.startsWith("08") || ERROR_STATES.contains(sqlState) || ERROR_CODES.contains(nse.getErrorCode())) { // broken connection LOGGER.warn("{} - Connection {} marked as broken because of SQLSTATE({}), ErrorCode({})", poolEntry.getPoolName(), delegate, sqlState, nse.getErrorCode(), nse); leakTask.cancel(); poolEntry.evict("(connection is broken)"); delegate = ClosedConnection.CLOSED_CONNECTION; } else { nse = nse.getNextException(); } } return sqle; } final synchronized void untrackStatement(final Statement statement) { openStatements.remove(statement); } final void markCommitStateDirty() { if (isAutoCommit) { lastAccess = currentTime(); } else { isCommitStateDirty = true; } } void cancelLeakTask() { leakTask.cancel(); } private synchronized T trackStatement(final T statement) { openStatements.add(statement); return statement; } @SuppressWarnings("EmptyTryBlock") private synchronized void closeStatements() { final int size = openStatements.size(); if (size > 0) { for (int i = 0; i < size && delegate != ClosedConnection.CLOSED_CONNECTION; i++) { try (Statement ignored = openStatements.get(i)) { // automatic resource cleanup } catch (SQLException e) { LOGGER.warn("{} - Connection {} marked as broken because of an exception closing open statements during Connection.close()", poolEntry.getPoolName(), delegate); leakTask.cancel(); poolEntry.evict("(exception closing Statements during Connection.close())"); delegate = ClosedConnection.CLOSED_CONNECTION; } } openStatements.clear(); } } // ********************************************************************** // "Overridden" java.sql.Connection Methods // ********************************************************************** /** {@inheritDoc} */ @Override public final void close() throws SQLException { // Closing statements can cause connection eviction, so this must run before the conditional below closeStatements(); if (delegate != ClosedConnection.CLOSED_CONNECTION) { leakTask.cancel(); try { if (isCommitStateDirty && !isAutoCommit) { delegate.rollback(); lastAccess = currentTime(); LOGGER.debug("{} - Executed rollback on connection {} due to dirty commit state on close().", poolEntry.getPoolName(), delegate); } if (dirtyBits != 0) { poolEntry.resetConnectionState(this, dirtyBits); lastAccess = currentTime(); } delegate.clearWarnings(); } catch (SQLException e) { // when connections are aborted, exceptions are often thrown that should not reach the application if (!poolEntry.isMarkedEvicted()) { throw checkException(e); } } finally { delegate = ClosedConnection.CLOSED_CONNECTION; poolEntry.recycle(lastAccess); } } } /** {@inheritDoc} */ @Override public boolean isClosed() throws SQLException { return (delegate == ClosedConnection.CLOSED_CONNECTION); } /** {@inheritDoc} */ @Override public Statement createStatement() throws SQLException { return ProxyFactory.getProxyStatement(this, trackStatement(delegate.createStatement())); } /** {@inheritDoc} */ @Override public Statement createStatement(int resultSetType, int concurrency) throws SQLException { return ProxyFactory.getProxyStatement(this, trackStatement(delegate.createStatement(resultSetType, concurrency))); } /** {@inheritDoc} */ @Override public Statement createStatement(int resultSetType, int concurrency, int holdability) throws SQLException { return ProxyFactory.getProxyStatement(this, trackStatement(delegate.createStatement(resultSetType, concurrency, holdability))); } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql) throws SQLException { return ProxyFactory.getProxyCallableStatement(this, trackStatement(delegate.prepareCall(sql))); } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql, int resultSetType, int concurrency) throws SQLException { return ProxyFactory.getProxyCallableStatement(this, trackStatement(delegate.prepareCall(sql, resultSetType, concurrency))); } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql, int resultSetType, int concurrency, int holdability) throws SQLException { return ProxyFactory.getProxyCallableStatement(this, trackStatement(delegate.prepareCall(sql, resultSetType, concurrency, holdability))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql, autoGeneratedKeys))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql, resultSetType, concurrency))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency, int holdability) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql, resultSetType, concurrency, holdability))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql, columnIndexes))); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return ProxyFactory.getProxyPreparedStatement(this, trackStatement(delegate.prepareStatement(sql, columnNames))); } /** {@inheritDoc} */ @Override public DatabaseMetaData getMetaData() throws SQLException { markCommitStateDirty(); return delegate.getMetaData(); } /** {@inheritDoc} */ @Override public void commit() throws SQLException { delegate.commit(); isCommitStateDirty = false; lastAccess = currentTime(); } /** {@inheritDoc} */ @Override public void rollback() throws SQLException { delegate.rollback(); isCommitStateDirty = false; lastAccess = currentTime(); } /** {@inheritDoc} */ @Override public void rollback(Savepoint savepoint) throws SQLException { delegate.rollback(savepoint); isCommitStateDirty = false; lastAccess = currentTime(); } /** {@inheritDoc} */ @Override public void setAutoCommit(boolean autoCommit) throws SQLException { delegate.setAutoCommit(autoCommit); isAutoCommit = autoCommit; dirtyBits |= DIRTY_BIT_AUTOCOMMIT; } /** {@inheritDoc} */ @Override public void setReadOnly(boolean readOnly) throws SQLException { delegate.setReadOnly(readOnly); isReadOnly = readOnly; isCommitStateDirty = false; dirtyBits |= DIRTY_BIT_READONLY; } /** {@inheritDoc} */ @Override public void setTransactionIsolation(int level) throws SQLException { delegate.setTransactionIsolation(level); transactionIsolation = level; dirtyBits |= DIRTY_BIT_ISOLATION; } /** {@inheritDoc} */ @Override public void setCatalog(String catalog) throws SQLException { delegate.setCatalog(catalog); dbcatalog = catalog; dirtyBits |= DIRTY_BIT_CATALOG; } /** {@inheritDoc} */ @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { delegate.setNetworkTimeout(executor, milliseconds); networkTimeout = milliseconds; dirtyBits |= DIRTY_BIT_NETTIMEOUT; } /** {@inheritDoc} */ @Override public void setSchema(String schema) throws SQLException { delegate.setSchema(schema); dbschema = schema; dirtyBits |= DIRTY_BIT_SCHEMA; } /** {@inheritDoc} */ @Override public final boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(delegate) || (delegate instanceof Wrapper && delegate.isWrapperFor(iface)); } /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public final T unwrap(Class iface) throws SQLException { if (iface.isInstance(delegate)) { return (T) delegate; } else if (delegate instanceof Wrapper) { return delegate.unwrap(iface); } throw new SQLException("Wrapped connection is not an instance of " + iface); } // ********************************************************************** // Private classes // ********************************************************************** private static final class ClosedConnection { static final Connection CLOSED_CONNECTION = getClosedConnection(); private static Connection getClosedConnection() { InvocationHandler handler = (proxy, method, args) -> { final String methodName = method.getName(); if ("abort".equals(methodName)) { return Void.TYPE; } else if ("isValid".equals(methodName)) { return Boolean.FALSE; } else if ("toString".equals(methodName)) { return ClosedConnection.class.getCanonicalName(); } throw new SQLException("Connection is closed"); }; return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[] { Connection.class }, handler); } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyFactory.java000066400000000000000000000064651315431642000271040ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import com.zaxxer.hikari.util.FastList; /** * A factory class that produces proxies around instances of the standard * JDBC interfaces. * * @author Brett Wooldridge */ @SuppressWarnings("unused") public final class ProxyFactory { private ProxyFactory() { // unconstructable } /** * Create a proxy for the specified {@link Connection} instance. * @param poolEntry the PoolEntry holding pool state * @param connection the raw database Connection * @param openStatements a reusable list to track open Statement instances * @param leakTask the ProxyLeakTask for this connection * @param now the current timestamp * @param isReadOnly the default readOnly state of the connection * @param isAutoCommit the default autoCommit state of the connection * @return a proxy that wraps the specified {@link Connection} */ static ProxyConnection getProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList openStatements, final ProxyLeakTask leakTask, final long now, final boolean isReadOnly, final boolean isAutoCommit) { // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } static Statement getProxyStatement(final ProxyConnection connection, final Statement statement) { // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } static CallableStatement getProxyCallableStatement(final ProxyConnection connection, final CallableStatement statement) { // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } static PreparedStatement getProxyPreparedStatement(final ProxyConnection connection, final PreparedStatement statement) { // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } static ResultSet getProxyResultSet(final ProxyConnection connection, final ProxyStatement statement, final ResultSet resultSet) { // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyLeakTask.java000066400000000000000000000052671315431642000271730ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Runnable that is scheduled in the future to report leaks. The ScheduledFuture is * cancelled if the connection is closed before the leak time expires. * * @author Brett Wooldridge */ class ProxyLeakTask implements Runnable { private static final Logger LOGGER = LoggerFactory.getLogger(ProxyLeakTask.class); static final ProxyLeakTask NO_LEAK; private ScheduledFuture scheduledFuture; private String connectionName; private Exception exception; private boolean isLeaked; static { NO_LEAK = new ProxyLeakTask() { @Override void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold) {} @Override public void run() {} @Override public void cancel() {} }; } ProxyLeakTask(final PoolEntry poolEntry) { this.exception = new Exception("Apparent connection leak detected"); this.connectionName = poolEntry.connection.toString(); } private ProxyLeakTask() { } void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold) { scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS); } /** {@inheritDoc} */ @Override public void run() { isLeaked = true; final StackTraceElement[] stackTrace = exception.getStackTrace(); final StackTraceElement[] trace = new StackTraceElement[stackTrace.length - 5]; System.arraycopy(stackTrace, 5, trace, 0, trace.length); exception.setStackTrace(trace); LOGGER.warn("Connection leak detection triggered for {}, stack trace follows", connectionName, exception); } void cancel() { scheduledFuture.cancel(false); if (isLeaked) { LOGGER.info("Previously reported leaked connection {} was returned to the pool (unleaked)", connectionName); } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyLeakTaskFactory.java000066400000000000000000000032671315431642000305210ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import java.util.concurrent.ScheduledExecutorService; /** * A factory for {@link ProxyLeakTask} Runnables that are scheduled in the future to report leaks. * * @author Brett Wooldridge * @author Andreas Brenk */ class ProxyLeakTaskFactory { private ScheduledExecutorService executorService; private long leakDetectionThreshold; ProxyLeakTaskFactory(final long leakDetectionThreshold, final ScheduledExecutorService executorService) { this.executorService = executorService; this.leakDetectionThreshold = leakDetectionThreshold; } ProxyLeakTask schedule(final PoolEntry poolEntry) { return (leakDetectionThreshold == 0) ? ProxyLeakTask.NO_LEAK : scheduleNewTask(poolEntry); } void updateLeakDetectionThreshold(final long leakDetectionThreshold) { this.leakDetectionThreshold = leakDetectionThreshold; } private ProxyLeakTask scheduleNewTask(PoolEntry poolEntry) { ProxyLeakTask task = new ProxyLeakTask(poolEntry); task.schedule(executorService, leakDetectionThreshold); return task; } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyPreparedStatement.java000066400000000000000000000041731315431642000311160ustar00rootroot00000000000000/* * 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.pool; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * This is the proxy class for java.sql.PreparedStatement. * * @author Brett Wooldridge */ public abstract class ProxyPreparedStatement extends ProxyStatement implements PreparedStatement { ProxyPreparedStatement(ProxyConnection connection, PreparedStatement statement) { super(connection, statement); } // ********************************************************************** // Overridden java.sql.PreparedStatement Methods // ********************************************************************** /** {@inheritDoc} */ @Override public boolean execute() throws SQLException { connection.markCommitStateDirty(); return ((PreparedStatement) delegate).execute(); } /** {@inheritDoc} */ @Override public ResultSet executeQuery() throws SQLException { connection.markCommitStateDirty(); ResultSet resultSet = ((PreparedStatement) delegate).executeQuery(); return ProxyFactory.getProxyResultSet(connection, this, resultSet); } /** {@inheritDoc} */ @Override public int executeUpdate() throws SQLException { connection.markCommitStateDirty(); return ((PreparedStatement) delegate).executeUpdate(); } /** {@inheritDoc} */ @Override public long executeLargeUpdate() throws SQLException { connection.markCommitStateDirty(); return ((PreparedStatement) delegate).executeLargeUpdate(); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyResultSet.java000066400000000000000000000053231315431642000274170ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * This is the proxy class for java.sql.ResultSet. * * @author Brett Wooldridge */ public abstract class ProxyResultSet implements ResultSet { protected final ProxyConnection connection; protected final ProxyStatement statement; final ResultSet delegate; protected ProxyResultSet(ProxyConnection connection, ProxyStatement statement, ResultSet resultSet) { this.connection = connection; this.statement = statement; this.delegate = resultSet; } @SuppressWarnings("unused") final SQLException checkException(SQLException e) { return connection.checkException(e); } /** {@inheritDoc} */ @Override public String toString() { return this.getClass().getSimpleName() + '@' + System.identityHashCode(this) + " wrapping " + delegate; } // ********************************************************************** // Overridden java.sql.ResultSet Methods // ********************************************************************** /** {@inheritDoc} */ @Override public final Statement getStatement() throws SQLException { return statement; } /** {@inheritDoc} */ @Override public void updateRow() throws SQLException { connection.markCommitStateDirty(); delegate.updateRow(); } /** {@inheritDoc} */ @Override public void insertRow() throws SQLException { connection.markCommitStateDirty(); delegate.insertRow(); } /** {@inheritDoc} */ @Override public void deleteRow() throws SQLException { connection.markCommitStateDirty(); delegate.deleteRow(); } /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public final T unwrap(Class iface) throws SQLException { if (iface.isInstance(delegate)) { return (T) delegate; } else if (delegate != null) { return delegate.unwrap(iface); } throw new SQLException("Wrapped ResultSet is not an instance of " + iface); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/pool/ProxyStatement.java000066400000000000000000000145321315431642000274330ustar00rootroot00000000000000/* * 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.pool; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * This is the proxy class for java.sql.Statement. * * @author Brett Wooldridge */ public abstract class ProxyStatement implements Statement { protected final ProxyConnection connection; final Statement delegate; private boolean isClosed; private ResultSet proxyResultSet; ProxyStatement(ProxyConnection connection, Statement statement) { this.connection = connection; this.delegate = statement; } @SuppressWarnings("unused") final SQLException checkException(SQLException e) { return connection.checkException(e); } /** {@inheritDoc} */ @Override public final String toString() { final String delegateToString = delegate.toString(); return this.getClass().getSimpleName() + '@' + System.identityHashCode(this) + " wrapping " + delegateToString; } // ********************************************************************** // Overridden java.sql.Statement Methods // ********************************************************************** /** {@inheritDoc} */ @Override public final void close() throws SQLException { synchronized (this) { if (isClosed) { return; } isClosed = true; } connection.untrackStatement(delegate); try { delegate.close(); } catch (SQLException e) { throw connection.checkException(e); } } /** {@inheritDoc} */ @Override public Connection getConnection() throws SQLException { return connection; } /** {@inheritDoc} */ @Override public boolean execute(String sql) throws SQLException { connection.markCommitStateDirty(); return delegate.execute(sql); } /** {@inheritDoc} */ @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { connection.markCommitStateDirty(); return delegate.execute(sql, autoGeneratedKeys); } /** {@inheritDoc} */ @Override public ResultSet executeQuery(String sql) throws SQLException { connection.markCommitStateDirty(); ResultSet resultSet = delegate.executeQuery(sql); return ProxyFactory.getProxyResultSet(connection, this, resultSet); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { connection.markCommitStateDirty(); return delegate.executeUpdate(sql); } /** {@inheritDoc} */ @Override public int[] executeBatch() throws SQLException { connection.markCommitStateDirty(); return delegate.executeBatch(); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { connection.markCommitStateDirty(); return delegate.executeUpdate(sql, autoGeneratedKeys); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { connection.markCommitStateDirty(); return delegate.executeUpdate(sql, columnIndexes); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { connection.markCommitStateDirty(); return delegate.executeUpdate(sql, columnNames); } /** {@inheritDoc} */ @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { connection.markCommitStateDirty(); return delegate.execute(sql, columnIndexes); } /** {@inheritDoc} */ @Override public boolean execute(String sql, String[] columnNames) throws SQLException { connection.markCommitStateDirty(); return delegate.execute(sql, columnNames); } /** {@inheritDoc} */ @Override public long[] executeLargeBatch() throws SQLException { connection.markCommitStateDirty(); return delegate.executeLargeBatch(); } /** {@inheritDoc} */ @Override public long executeLargeUpdate(String sql) throws SQLException { connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql); } /** {@inheritDoc} */ @Override public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException { connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, autoGeneratedKeys); } /** {@inheritDoc} */ @Override public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException { connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, columnIndexes); } /** {@inheritDoc} */ @Override public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException { connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, columnNames); } /** {@inheritDoc} */ @Override public ResultSet getResultSet() throws SQLException { final ResultSet resultSet = delegate.getResultSet(); if (resultSet != null) { if (proxyResultSet == null || ((ProxyResultSet) proxyResultSet).delegate != resultSet) { proxyResultSet = ProxyFactory.getProxyResultSet(connection, this, resultSet); } } else { proxyResultSet = null; } return proxyResultSet; } /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public final T unwrap(Class iface) throws SQLException { if (iface.isInstance(delegate)) { return (T) delegate; } else if (delegate != null) { return delegate.unwrap(iface); } throw new SQLException("Wrapped statement is not an instance of " + iface); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/000077500000000000000000000000001315431642000235615ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/ClockSource.java000066400000000000000000000217111315431642000266420ustar00rootroot00000000000000/* * Copyright (C) 2015 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.util; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import java.util.concurrent.TimeUnit; /** * A resolution-independent provider of current time-stamps and elapsed time * calculations. * * @author Brett Wooldridge */ public interface ClockSource { static ClockSource CLOCK = Factory.create(); /** * Get the current time-stamp (resolution is opaque). * * @return the current time-stamp */ static long currentTime() { return CLOCK.currentTime0(); } long currentTime0(); /** * Convert an opaque time-stamp returned by currentTime() into * milliseconds. * * @param time an opaque time-stamp returned by an instance of this class * @return the time-stamp in milliseconds */ static long toMillis(long time) { return CLOCK.toMillis0(time); } long toMillis0(long time); /** * Convert an opaque time-stamp returned by currentTime() into * nanoseconds. * * @param time an opaque time-stamp returned by an instance of this class * @return the time-stamp in nanoseconds */ static long toNanos(long time) { return CLOCK.toNanos0(time); } long toNanos0(long time); /** * Convert an opaque time-stamp returned by currentTime() into an * elapsed time in milliseconds, based on the current instant in time. * * @param startTime an opaque time-stamp returned by an instance of this class * @return the elapsed time between startTime and now in milliseconds */ static long elapsedMillis(long startTime) { return CLOCK.elapsedMillis0(startTime); } long elapsedMillis0(long startTime); /** * Get the difference in milliseconds between two opaque time-stamps returned * by currentTime(). * * @param startTime an opaque time-stamp returned by an instance of this class * @param endTime an opaque time-stamp returned by an instance of this class * @return the elapsed time between startTime and endTime in milliseconds */ static long elapsedMillis(long startTime, long endTime) { return CLOCK.elapsedMillis0(startTime, endTime); } long elapsedMillis0(long startTime, long endTime); /** * Convert an opaque time-stamp returned by currentTime() into an * elapsed time in milliseconds, based on the current instant in time. * * @param startTime an opaque time-stamp returned by an instance of this class * @return the elapsed time between startTime and now in milliseconds */ static long elapsedNanos(long startTime) { return CLOCK.elapsedNanos0(startTime); } long elapsedNanos0(long startTime); /** * Get the difference in nanoseconds between two opaque time-stamps returned * by currentTime(). * * @param startTime an opaque time-stamp returned by an instance of this class * @param endTime an opaque time-stamp returned by an instance of this class * @return the elapsed time between startTime and endTime in nanoseconds */ static long elapsedNanos(long startTime, long endTime) { return CLOCK.elapsedNanos0(startTime, endTime); } long elapsedNanos0(long startTime, long endTime); /** * Return the specified opaque time-stamp plus the specified number of milliseconds. * * @param time an opaque time-stamp * @param millis milliseconds to add * @return a new opaque time-stamp */ static long plusMillis(long time, long millis) { return CLOCK.plusMillis0(time, millis); } long plusMillis0(long time, long millis); /** * Get the TimeUnit the ClockSource is denominated in. * @return */ static TimeUnit getSourceTimeUnit() { return CLOCK.getSourceTimeUnit0(); } TimeUnit getSourceTimeUnit0(); /** * Get a String representation of the elapsed time in appropriate magnitude terminology. * * @param startTime an opaque time-stamp * @param endTime an opaque time-stamp * @return a string representation of the elapsed time interval */ static String elapsedDisplayString(long startTime, long endTime) { return CLOCK.elapsedDisplayString0(startTime, endTime); } default String elapsedDisplayString0(long startTime, long endTime) { long elapsedNanos = elapsedNanos0(startTime, endTime); StringBuilder sb = new StringBuilder(elapsedNanos < 0 ? "-" : ""); elapsedNanos = Math.abs(elapsedNanos); for (TimeUnit unit : TIMEUNITS_DESCENDING) { long converted = unit.convert(elapsedNanos, NANOSECONDS); if (converted > 0) { sb.append(converted).append(TIMEUNIT_DISPLAY_VALUES[unit.ordinal()]); elapsedNanos -= NANOSECONDS.convert(converted, unit); } } return sb.toString(); } TimeUnit[] TIMEUNITS_DESCENDING = {DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS}; String[] TIMEUNIT_DISPLAY_VALUES = {"ns", "µs", "ms", "s", "m", "h", "d"}; /** * Factory class used to create a platform-specific ClockSource. */ class Factory { private static ClockSource create() { String os = System.getProperty("os.name"); if ("Mac OS X".equals(os)) { return new MillisecondClockSource(); } return new NanosecondClockSource(); } } final class MillisecondClockSource implements ClockSource { /** {@inheritDoc} */ @Override public long currentTime0() { return System.currentTimeMillis(); } /** {@inheritDoc} */ @Override public long elapsedMillis0(final long startTime) { return System.currentTimeMillis() - startTime; } /** {@inheritDoc} */ @Override public long elapsedMillis0(final long startTime, final long endTime) { return endTime - startTime; } /** {@inheritDoc} */ @Override public long elapsedNanos0(final long startTime) { return MILLISECONDS.toNanos(System.currentTimeMillis() - startTime); } /** {@inheritDoc} */ @Override public long elapsedNanos0(final long startTime, final long endTime) { return MILLISECONDS.toNanos(endTime - startTime); } /** {@inheritDoc} */ @Override public long toMillis0(final long time) { return time; } /** {@inheritDoc} */ @Override public long toNanos0(final long time) { return MILLISECONDS.toNanos(time); } /** {@inheritDoc} */ @Override public long plusMillis0(final long time, final long millis) { return time + millis; } /** {@inheritDoc} */ @Override public TimeUnit getSourceTimeUnit0() { return MILLISECONDS; } } class NanosecondClockSource implements ClockSource { /** {@inheritDoc} */ @Override public long currentTime0() { return System.nanoTime(); } /** {@inheritDoc} */ @Override public long toMillis0(final long time) { return NANOSECONDS.toMillis(time); } /** {@inheritDoc} */ @Override public long toNanos0(final long time) { return time; } /** {@inheritDoc} */ @Override public long elapsedMillis0(final long startTime) { return NANOSECONDS.toMillis(System.nanoTime() - startTime); } /** {@inheritDoc} */ @Override public long elapsedMillis0(final long startTime, final long endTime) { return NANOSECONDS.toMillis(endTime - startTime); } /** {@inheritDoc} */ @Override public long elapsedNanos0(final long startTime) { return System.nanoTime() - startTime; } /** {@inheritDoc} */ @Override public long elapsedNanos0(final long startTime, final long endTime) { return endTime - startTime; } /** {@inheritDoc} */ @Override public long plusMillis0(final long time, final long millis) { return time + MILLISECONDS.toNanos(millis); } /** {@inheritDoc} */ @Override public TimeUnit getSourceTimeUnit0() { return NANOSECONDS; } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java000077500000000000000000000322271315431642000271710ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import static java.lang.Thread.yield; import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.locks.LockSupport.parkNanos; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedNanos; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_IN_USE; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_NOT_IN_USE; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_REMOVED; import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_RESERVED; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry; /** * This is a specialized concurrent bag that achieves superior performance * to LinkedBlockingQueue and LinkedTransferQueue for the purposes of a * connection pool. It uses ThreadLocal storage when possible to avoid * locks, but resorts to scanning a common collection if there are no * available items in the ThreadLocal list. Not-in-use items in the * ThreadLocal lists can be "stolen" when the borrowing thread has none * of its own. It is a "lock-less" implementation using a specialized * AbstractQueuedLongSynchronizer to manage cross-thread signaling. * * Note that items that are "borrowed" from the bag are not actually * removed from any collection, so garbage collection will not occur * even if the reference is abandoned. Thus care must be taken to * "requite" borrowed objects otherwise a memory leak will result. Only * the "remove" method can completely remove an object from the bag. * * @author Brett Wooldridge * * @param the templated type to store in the bag */ public class ConcurrentBag implements AutoCloseable { private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrentBag.class); private final CopyOnWriteArrayList sharedList; private final boolean weakThreadLocals; private final ThreadLocal> threadList; private final IBagStateListener listener; private final AtomicInteger waiters; private volatile boolean closed; private final SynchronousQueue handoffQueue; public interface IConcurrentBagEntry { int STATE_NOT_IN_USE = 0; int STATE_IN_USE = 1; int STATE_REMOVED = -1; int STATE_RESERVED = -2; boolean compareAndSet(int expectState, int newState); void setState(int newState); int getState(); } public interface IBagStateListener { void addBagItem(int waiting); } /** * Construct a ConcurrentBag with the specified listener. * * @param listener the IBagStateListener to attach to this bag */ public ConcurrentBag(final IBagStateListener listener) { this.listener = listener; this.weakThreadLocals = useWeakThreadLocals(); this.handoffQueue = new SynchronousQueue<>(true); this.waiters = new AtomicInteger(); this.sharedList = new CopyOnWriteArrayList<>(); if (weakThreadLocals) { this.threadList = ThreadLocal.withInitial(() -> new ArrayList<>(16)); } else { this.threadList = ThreadLocal.withInitial(() -> new FastList<>(IConcurrentBagEntry.class, 16)); } } /** * The method will borrow a BagEntry from the bag, blocking for the * specified timeout if none are available. * * @param timeout how long to wait before giving up, in units of unit * @param timeUnit a TimeUnit determining how to interpret the timeout parameter * @return a borrowed instance from the bag or null if a timeout occurs * @throws InterruptedException if interrupted while waiting */ public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException { // Try the thread-local list first final List list = threadList.get(); for (int i = list.size() - 1; i >= 0; i--) { final Object entry = list.remove(i); @SuppressWarnings("unchecked") final T bagEntry = weakThreadLocals ? ((WeakReference) entry).get() : (T) entry; if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { return bagEntry; } } // Otherwise, scan the shared list ... then poll the handoff queue final int waiting = waiters.incrementAndGet(); try { for (T bagEntry : sharedList) { if (bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { // If we may have stolen another waiter's connection, request another bag add. if (waiting > 1) { listener.addBagItem(waiting - 1); } return bagEntry; } } listener.addBagItem(waiting); timeout = timeUnit.toNanos(timeout); do { final long start = currentTime(); final T bagEntry = handoffQueue.poll(timeout, NANOSECONDS); if (bagEntry == null || bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { return bagEntry; } timeout -= elapsedNanos(start); } while (timeout > 10_000); return null; } finally { waiters.decrementAndGet(); } } /** * This method will return a borrowed object to the bag. Objects * that are borrowed from the bag but never "requited" will result * in a memory leak. * * @param bagEntry the value to return to the bag * @throws NullPointerException if value is null * @throws IllegalStateException if the bagEntry was not borrowed from the bag */ public void requite(final T bagEntry) { bagEntry.setState(STATE_NOT_IN_USE); for (int i = 0; waiters.get() > 0; i++) { if (bagEntry.getState() != STATE_NOT_IN_USE || handoffQueue.offer(bagEntry)) { return; } else if ((i & 0xff) == 0xff) { parkNanos(MICROSECONDS.toNanos(10)); } else { yield(); } } final List threadLocalList = threadList.get(); threadLocalList.add(weakThreadLocals ? new WeakReference<>(bagEntry) : bagEntry); } /** * Add a new object to the bag for others to borrow. * * @param bagEntry an object to add to the bag */ public void add(final T bagEntry) { if (closed) { LOGGER.info("ConcurrentBag has been closed, ignoring add()"); throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()"); } sharedList.add(bagEntry); // spin until a thread takes it or none are waiting while (waiters.get() > 0 && !handoffQueue.offer(bagEntry)) { yield(); } } /** * Remove a value from the bag. This method should only be called * with objects obtained by borrow(long, TimeUnit) or reserve(T) * * @param bagEntry the value to remove * @return true if the entry was removed, false otherwise * @throws IllegalStateException if an attempt is made to remove an object * from the bag that was not borrowed or reserved first */ public boolean remove(final T bagEntry) { if (!bagEntry.compareAndSet(STATE_IN_USE, STATE_REMOVED) && !bagEntry.compareAndSet(STATE_RESERVED, STATE_REMOVED) && !closed) { LOGGER.warn("Attempt to remove an object from the bag that was not borrowed or reserved: {}", bagEntry); return false; } final boolean removed = sharedList.remove(bagEntry); if (!removed && !closed) { LOGGER.warn("Attempt to remove an object from the bag that does not exist: {}", bagEntry); } return removed; } /** * Close the bag to further adds. */ @Override public void close() { closed = true; } /** * This method provides a "snapshot" in time of the BagEntry * items in the bag in the specified state. It does not "lock" * or reserve items in any way. Call reserve(T) * on items in list before performing any action on them. * * @param state one of the {@link IConcurrentBagEntry} states * @return a possibly empty list of objects having the state specified */ public List values(final int state) { final List list = sharedList.stream().filter(e -> e.getState() == state).collect(Collectors.toList()); Collections.reverse(list); return list; } /** * This method provides a "snapshot" in time of the bag items. It * does not "lock" or reserve items in any way. Call reserve(T) * on items in the list, or understand the concurrency implications of * modifying items, before performing any action on them. * * @return a possibly empty list of (all) bag items */ @SuppressWarnings("unchecked") public List values() { return (List) sharedList.clone(); } /** * The method is used to make an item in the bag "unavailable" for * borrowing. It is primarily used when wanting to operate on items * returned by the values(int) method. Items that are * reserved can be removed from the bag via remove(T) * without the need to unreserve them. Items that are not removed * from the bag can be make available for borrowing again by calling * the unreserve(T) method. * * @param bagEntry the item to reserve * @return true if the item was able to be reserved, false otherwise */ public boolean reserve(final T bagEntry) { return bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_RESERVED); } /** * This method is used to make an item reserved via reserve(T) * available again for borrowing. * * @param bagEntry the item to unreserve */ public void unreserve(final T bagEntry) { if (bagEntry.compareAndSet(STATE_RESERVED, STATE_NOT_IN_USE)) { // spin until a thread takes it or none are waiting while (waiters.get() > 0 && !handoffQueue.offer(bagEntry)) { yield(); } } else { LOGGER.warn("Attempt to relinquish an object to the bag that was not reserved: {}", bagEntry); } } /** * Get the number of threads pending (waiting) for an item from the * bag to become available. * * @return the number of threads waiting for items from the bag */ public int getWaitingThreadCount() { return waiters.get(); } /** * Get a count of the number of items in the specified state at the time of this call. * * @param state the state of the items to count * @return a count of how many items in the bag are in the specified state */ public int getCount(final int state) { int count = 0; for (IConcurrentBagEntry e : sharedList) { if (e.getState() == state) { count++; } } return count; } public int[] getStateCounts() { final int[] states = new int[6]; for (IConcurrentBagEntry e : sharedList) { ++states[e.getState()]; } states[4] = sharedList.size(); states[5] = waiters.get(); return states; } /** * Get the total number of items in the bag. * * @return the number of items in the bag */ public int size() { return sharedList.size(); } public void dumpState() { sharedList.forEach(entry -> LOGGER.info(entry.toString())); } /** * Determine whether to use WeakReferences based on whether there is a * custom ClassLoader implementation sitting between this class and the * System ClassLoader. * * @return true if we should use WeakReferences in our ThreadLocals, false otherwise */ private boolean useWeakThreadLocals() { try { if (System.getProperty("com.zaxxer.hikari.useWeakReferences") != null) { // undocumented manual override of WeakReference behavior return Boolean.getBoolean("com.zaxxer.hikari.useWeakReferences"); } return getClass().getClassLoader() != ClassLoader.getSystemClassLoader(); } catch (SecurityException se) { return true; } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/DriverDataSource.java000066400000000000000000000130721315431642000276350ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import java.io.PrintWriter; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Enumeration; import java.util.Map.Entry; import java.util.Properties; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class DriverDataSource implements DataSource { private static final Logger LOGGER = LoggerFactory.getLogger(DriverDataSource.class); private final String jdbcUrl; private final Properties driverProperties; private Driver driver; public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password) { this.jdbcUrl = jdbcUrl; this.driverProperties = new Properties(); for (Entry entry : properties.entrySet()) { driverProperties.setProperty(entry.getKey().toString(), entry.getValue().toString()); } if (username != null) { driverProperties.put("user", driverProperties.getProperty("user", username)); } if (password != null) { driverProperties.put("password", driverProperties.getProperty("password", password)); } if (driverClassName != null) { Enumeration drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver d = drivers.nextElement(); if (d.getClass().getName().equals(driverClassName)) { driver = d; break; } } if (driver == null) { LOGGER.warn("Registered driver with driverClassName={} was not found, trying direct instantiation.", driverClassName); Class driverClass = null; try { driverClass = this.getClass().getClassLoader().loadClass(driverClassName); LOGGER.debug("Driver class found in the HikariConfig class classloader {}", this.getClass().getClassLoader()); } catch (ClassNotFoundException e) { ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader(); if (threadContextClassLoader != null && threadContextClassLoader != this.getClass().getClassLoader()) { try { driverClass = threadContextClassLoader.loadClass(driverClassName); LOGGER.debug("Driver class found in Thread context class loader {}", threadContextClassLoader); } catch (ClassNotFoundException e1) { LOGGER.warn("Failed to load class of driverClassName {} in either of HikariConfig class classloader {} or Thread context classloader {}", driverClassName, this.getClass().getClassLoader(), threadContextClassLoader); } } else { LOGGER.warn("Failed to load class of driverClassName {} in HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader()); } } if (driverClass != null) { try { driver = (Driver) driverClass.newInstance(); } catch (Exception e) { LOGGER.warn("Failed to create instance of driver class {}, trying jdbcUrl resolution", driverClassName, e); } } } } try { if (driver == null) { driver = DriverManager.getDriver(jdbcUrl); } else if (!driver.acceptsURL(jdbcUrl)) { throw new RuntimeException("Driver " + driverClassName + " claims to not accept jdbcUrl, " + jdbcUrl); } } catch (SQLException e) { throw new RuntimeException("Failed to get driver instance for jdbcUrl=" + jdbcUrl, e); } } @Override public Connection getConnection() throws SQLException { return driver.connect(jdbcUrl, driverProperties); } @Override public Connection getConnection(String username, String password) throws SQLException { return getConnection(); } @Override public PrintWriter getLogWriter() throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void setLogWriter(PrintWriter logWriter) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void setLoginTimeout(int seconds) throws SQLException { DriverManager.setLoginTimeout(seconds); } @Override public int getLoginTimeout() throws SQLException { return DriverManager.getLoginTimeout(); } @Override public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { return driver.getParentLogger(); } @Override public T unwrap(Class iface) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/FastList.java000066400000000000000000000204071315431642000261600ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import java.io.Serializable; import java.lang.reflect.Array; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; import java.util.Spliterator; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; /** * Fast list without range checking. * * @author Brett Wooldridge */ public final class FastList implements List, RandomAccess, Serializable { private static final long serialVersionUID = -4598088075242913858L; private final Class clazz; private T[] elementData; private int size; /** * Construct a FastList with a default size of 32. * @param clazz the Class stored in the collection */ @SuppressWarnings("unchecked") public FastList(Class clazz) { this.elementData = (T[]) Array.newInstance(clazz, 32); this.clazz = clazz; } /** * Construct a FastList with a specified size. * @param clazz the Class stored in the collection * @param capacity the initial size of the FastList */ @SuppressWarnings("unchecked") public FastList(Class clazz, int capacity) { this.elementData = (T[]) Array.newInstance(clazz, capacity); this.clazz = clazz; } /** * Add an element to the tail of the FastList. * * @param element the element to add */ @Override public boolean add(T element) { if (size < elementData.length) { elementData[size++] = element; } else { // overflow-conscious code final int oldCapacity = elementData.length; final int newCapacity = oldCapacity << 1; @SuppressWarnings("unchecked") final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity); System.arraycopy(elementData, 0, newElementData, 0, oldCapacity); newElementData[size++] = element; elementData = newElementData; } return true; } /** * Get the element at the specified index. * * @param index the index of the element to get * @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid */ @Override public T get(int index) { return elementData[index]; } /** * Remove the last element from the list. No bound check is performed, so if this * method is called on an empty list and ArrayIndexOutOfBounds exception will be * thrown. * * @return the last element of the list */ public T removeLast() { T element = elementData[--size]; elementData[size] = null; return element; } /** * This remove method is most efficient when the element being removed * is the last element. Equality is identity based, not equals() based. * Only the first matching element is removed. * * @param element the element to remove */ @Override public boolean remove(Object element) { for (int index = size - 1; index >= 0; index--) { if (element == elementData[index]) { final int numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index + 1, elementData, index, numMoved); } elementData[--size] = null; return true; } } return false; } /** * Clear the FastList. */ @Override public void clear() { for (int i = 0; i < size; i++) { elementData[i] = null; } size = 0; } /** * Get the current number of elements in the FastList. * * @return the number of current elements */ @Override public int size() { return size; } /** {@inheritDoc} */ @Override public boolean isEmpty() { return size == 0; } /** {@inheritDoc} */ @Override public T set(int index, T element) { T old = elementData[index]; elementData[index] = element; return old; } /** {@inheritDoc} */ @Override public T remove(int index) { if (size == 0) { return null; } final T old = elementData[index]; final int numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index + 1, elementData, index, numMoved); } elementData[--size] = null; return old; } /** {@inheritDoc} */ @Override public boolean contains(Object o) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Iterator iterator() { return new Iterator() { private int index; @Override public boolean hasNext() { return index < size; } @Override public T next() { if (index < size) { return elementData[index++]; } throw new NoSuchElementException("No more elements in FastList"); } }; } /** {@inheritDoc} */ @Override public Object[] toArray() { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public E[] toArray(E[] a) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean containsAll(Collection c) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean addAll(int index, Collection c) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public void add(int index, T element) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public ListIterator listIterator() { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public ListIterator listIterator(int index) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Object clone() { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public void forEach(Consumer action) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Spliterator spliterator() { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public void replaceAll(UnaryOperator operator) { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public void sort(Comparator c) { throw new UnsupportedOperationException(); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/JavassistProxyFactory.java000066400000000000000000000234271315431642000307750ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import java.lang.reflect.Array; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import com.zaxxer.hikari.pool.ProxyCallableStatement; import com.zaxxer.hikari.pool.ProxyConnection; import com.zaxxer.hikari.pool.ProxyFactory; import com.zaxxer.hikari.pool.ProxyPreparedStatement; import com.zaxxer.hikari.pool.ProxyResultSet; import com.zaxxer.hikari.pool.ProxyStatement; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.LoaderClassPath; import javassist.Modifier; import javassist.NotFoundException; import javassist.bytecode.ClassFile; /** * This class generates the proxy objects for {@link Connection}, {@link Statement}, * {@link PreparedStatement}, and {@link CallableStatement}. Additionally it injects * method bodies into the {@link ProxyFactory} class methods that can instantiate * instances of the generated proxies. * * @author Brett Wooldridge */ public final class JavassistProxyFactory { private static ClassPool classPool; public static void main(String... args) { classPool = new ClassPool(); classPool.importPackage("java.sql"); classPool.appendClassPath(new LoaderClassPath(JavassistProxyFactory.class.getClassLoader())); try { // Cast is not needed for these String methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }"; generateProxyClass(Connection.class, ProxyConnection.class.getName(), methodBody); generateProxyClass(Statement.class, ProxyStatement.class.getName(), methodBody); generateProxyClass(ResultSet.class, ProxyResultSet.class.getName(), methodBody); // For these we have to cast the delegate methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; generateProxyClass(PreparedStatement.class, ProxyPreparedStatement.class.getName(), methodBody); generateProxyClass(CallableStatement.class, ProxyCallableStatement.class.getName(), methodBody); modifyProxyFactory(); } catch (Exception e) { throw new RuntimeException(e); } } private static void modifyProxyFactory() throws Exception { System.out.println("Generating method bodies for com.zaxxer.hikari.proxy.ProxyFactory"); String packageName = ProxyConnection.class.getPackage().getName(); CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.pool.ProxyFactory"); for (CtMethod method : proxyCt.getMethods()) { switch (method.getName()) { case "getProxyConnection": method.setBody("{return new " + packageName + ".HikariProxyConnection($$);}"); break; case "getProxyStatement": method.setBody("{return new " + packageName + ".HikariProxyStatement($$);}"); break; case "getProxyPreparedStatement": method.setBody("{return new " + packageName + ".HikariProxyPreparedStatement($$);}"); break; case "getProxyCallableStatement": method.setBody("{return new " + packageName + ".HikariProxyCallableStatement($$);}"); break; case "getProxyResultSet": method.setBody("{return new " + packageName + ".HikariProxyResultSet($$);}"); break; default: // unhandled method break; } } proxyCt.writeFile("target/classes"); } /** * Generate Javassist Proxy Classes */ private static void generateProxyClass(Class primaryInterface, String superClassName, String methodBody) throws Exception { String newClassName = superClassName.replaceAll("(.+)\\.(\\w+)", "$1.Hikari$2"); CtClass superCt = classPool.getCtClass(superClassName); CtClass targetCt = classPool.makeClass(newClassName, superCt); targetCt.setModifiers(Modifier.FINAL); System.out.println("Generating " + newClassName); targetCt.setModifiers(Modifier.PUBLIC); // Make a set of method signatures we inherit implementation for, so we don't generate delegates for these Set superSigs = new HashSet<>(); for (CtMethod method : superCt.getMethods()) { if ((method.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { superSigs.add(method.getName() + method.getSignature()); } } Set methods = new HashSet<>(); Set> interfaces = getAllInterfaces(primaryInterface); for (Class intf : interfaces) { CtClass intfCt = classPool.getCtClass(intf.getName()); targetCt.addInterface(intfCt); for (CtMethod intfMethod : intfCt.getDeclaredMethods()) { final String signature = intfMethod.getName() + intfMethod.getSignature(); // don't generate delegates for methods we override if (superSigs.contains(signature)) { continue; } // Ignore already added methods that come from other interfaces if (methods.contains(signature)) { continue; } // Track what methods we've added methods.add(signature); // Clone the method we want to inject into CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null); String modifiedBody = methodBody; // If the super-Proxy has concrete methods (non-abstract), transform the call into a simple super.method() call CtMethod superMethod = superCt.getMethod(intfMethod.getName(), intfMethod.getSignature()); if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT && !isDefaultMethod(intf, intfCt, intfMethod)) { modifiedBody = modifiedBody.replace("((cast) ", ""); modifiedBody = modifiedBody.replace("delegate", "super"); modifiedBody = modifiedBody.replace("super)", "super"); } modifiedBody = modifiedBody.replace("cast", primaryInterface.getName()); // Generate a method that simply invokes the same method on the delegate if (isThrowsSqlException(intfMethod)) { modifiedBody = modifiedBody.replace("method", method.getName()); } else { modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName()); } if (method.getReturnType() == CtClass.voidType) { modifiedBody = modifiedBody.replace("return", ""); } method.setBody(modifiedBody); targetCt.addMethod(method); } } targetCt.getClassFile().setMajorVersion(ClassFile.JAVA_7); targetCt.writeFile("target/classes"); } private static boolean isThrowsSqlException(CtMethod method) { try { for (CtClass clazz : method.getExceptionTypes()) { if (clazz.getSimpleName().equals("SQLException")) { return true; } } } catch (NotFoundException e) { // fall thru } return false; } private static boolean isDefaultMethod(Class intf, CtClass intfCt, CtMethod intfMethod) throws Exception { List> paramTypes = new ArrayList<>(); for (CtClass pt : intfMethod.getParameterTypes()) { paramTypes.add(toJavaClass(pt)); } return intf.getDeclaredMethod(intfMethod.getName(), paramTypes.toArray(new Class[paramTypes.size()])).toString().contains("default "); } private static Set> getAllInterfaces(Class clazz) { Set> interfaces = new HashSet<>(); for (Class intf : Arrays.asList(clazz.getInterfaces())) { if (intf.getInterfaces().length > 0) { interfaces.addAll(getAllInterfaces(intf)); } interfaces.add(intf); } if (clazz.getSuperclass() != null) { interfaces.addAll(getAllInterfaces(clazz.getSuperclass())); } if (clazz.isInterface()) { interfaces.add(clazz); } return interfaces; } private static Class toJavaClass(CtClass cls) throws Exception { if (cls.getName().endsWith("[]")) { return Array.newInstance(toJavaClass(cls.getName().replace("[]", "")), 0).getClass(); } else { return toJavaClass(cls.getName()); } } private static Class toJavaClass(String cn) throws Exception { switch (cn) { case "int": return int.class; case "long": return long.class; case "short": return short.class; case "byte": return byte.class; case "float": return float.class; case "double": return double.class; case "boolean": return boolean.class; case "char": return char.class; case "void": return void.class; default: return Class.forName(cn); } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/PropertyElf.java000066400000000000000000000131771315431642000267100ustar00rootroot00000000000000/* * 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.util; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; /** * A class that reflectively sets bean properties on a target object. * * @author Brett Wooldridge */ public final class PropertyElf { private static final Logger LOGGER = LoggerFactory.getLogger(PropertyElf.class); private static final Pattern GETTER_PATTERN = Pattern.compile("(get|is)[A-Z].+"); public static void setTargetFromProperties(final Object target, final Properties properties) { if (target == null || properties == null) { return; } List methods = Arrays.asList(target.getClass().getMethods()); properties.forEach((key, value) -> { if (target instanceof HikariConfig && key.toString().startsWith("dataSource.")) { ((HikariConfig) target).addDataSourceProperty(key.toString().substring("dataSource.".length()), value); } else { setProperty(target, key.toString(), value, methods); } }); } /** * Get the bean-style property names for the specified object. * * @param targetClass the target object * @return a set of property names */ public static Set getPropertyNames(final Class targetClass) { HashSet set = new HashSet<>(); Matcher matcher = GETTER_PATTERN.matcher(""); for (Method method : targetClass.getMethods()) { String name = method.getName(); if (method.getParameterTypes().length == 0 && matcher.reset(name).matches()) { name = name.replaceFirst("(get|is)", ""); try { if (targetClass.getMethod("set" + name, method.getReturnType()) != null) { name = Character.toLowerCase(name.charAt(0)) + name.substring(1); set.add(name); } } catch (Exception e) { continue; } } } return set; } public static Object getProperty(final String propName, final Object target) { try { // use the english locale to avoid the infamous turkish locale bug String capitalized = "get" + propName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propName.substring(1); Method method = target.getClass().getMethod(capitalized); return method.invoke(target); } catch (Exception e) { try { String capitalized = "is" + propName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propName.substring(1); Method method = target.getClass().getMethod(capitalized); return method.invoke(target); } catch (Exception e2) { return null; } } } public static Properties copyProperties(final Properties props) { Properties copy = new Properties(); props.forEach((key, value) -> copy.setProperty(key.toString(), value.toString())); return copy; } private static void setProperty(final Object target, final String propName, final Object propValue, final List methods) { // use the english locale to avoid the infamous turkish locale bug String methodName = "set" + propName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propName.substring(1); Method writeMethod = methods.stream().filter(m -> m.getName().equals(methodName) && m.getParameterCount() == 1).findFirst().orElse(null); if (writeMethod == null) { String methodName2 = "set" + propName.toUpperCase(Locale.ENGLISH); writeMethod = methods.stream().filter(m -> m.getName().equals(methodName2) && m.getParameterCount() == 1).findFirst().orElse(null); } if (writeMethod == null) { LOGGER.error("Property {} does not exist on target {}", propName, target.getClass()); throw new RuntimeException(String.format("Property %s does not exist on target %s", propName, target.getClass())); } try { Class paramClass = writeMethod.getParameterTypes()[0]; if (paramClass == int.class) { writeMethod.invoke(target, Integer.parseInt(propValue.toString())); } else if (paramClass == long.class) { writeMethod.invoke(target, Long.parseLong(propValue.toString())); } else if (paramClass == boolean.class || paramClass == Boolean.class) { writeMethod.invoke(target, Boolean.parseBoolean(propValue.toString())); } else if (paramClass == String.class) { writeMethod.invoke(target, propValue.toString()); } else { writeMethod.invoke(target, propValue); } } catch (Exception e) { LOGGER.error("Failed to set property {} on target {}", propName, target.getClass(), e); throw new RuntimeException(e); } } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/SuspendResumeLock.java000066400000000000000000000036621315431642000300460ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import java.util.concurrent.Semaphore; /** * This class implements a lock that can be used to suspend and resume the pool. It * also provides a faux implementation that is used when the feature is disabled that * hopefully gets fully "optimized away" by the JIT. * * @author Brett Wooldridge */ public class SuspendResumeLock { public static final SuspendResumeLock FAUX_LOCK = new SuspendResumeLock(false) { @Override public void acquire() {} @Override public void release() {} @Override public void suspend() {} @Override public void resume() {} }; private static final int MAX_PERMITS = 10000; private final Semaphore acquisitionSemaphore; /** * Default constructor */ public SuspendResumeLock() { this(true); } private SuspendResumeLock(final boolean createSemaphore) { acquisitionSemaphore = (createSemaphore ? new Semaphore(MAX_PERMITS, true) : null); } public void acquire() { acquisitionSemaphore.acquireUninterruptibly(); } public void release() { acquisitionSemaphore.release(); } public void suspend() { acquisitionSemaphore.acquireUninterruptibly(MAX_PERMITS); } public void resume() { acquisitionSemaphore.release(MAX_PERMITS); } } HikariCP-HikariCP-2.7.1/src/main/java/com/zaxxer/hikari/util/UtilityElf.java000066400000000000000000000150301315431642000265150ustar00rootroot00000000000000/* * 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.util; import static java.lang.Thread.currentThread; import static java.util.concurrent.TimeUnit.SECONDS; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.sql.Connection; import java.util.Locale; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; /** * * @author Brett Wooldridge */ public final class UtilityElf { /** * * @return null if string is null or empty */ public static String getNullIfEmpty(final String text) { return text == null ? null : text.trim().isEmpty() ? null : text.trim(); } /** * Sleep and suppress InterruptedException (but re-signal it). * * @param millis the number of milliseconds to sleep */ public static void quietlySleep(final long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { // I said be quiet! currentThread().interrupt(); } } /** * Create and instance of the specified class using the constructor matching the specified * arguments. * * @param the class type * @param className the name of the class to instantiate * @param clazz a class to cast the result as * @param args arguments to a constructor * @return an instance of the specified class */ public static T createInstance(final String className, final Class clazz, final Object... args) { if (className == null) { return null; } try { Class loaded = UtilityElf.class.getClassLoader().loadClass(className); if (args.length == 0) { return clazz.cast(loaded.newInstance()); } Class[] argClasses = new Class[args.length]; for (int i = 0; i < args.length; i++) { argClasses[i] = args[i].getClass(); } Constructor constructor = loaded.getConstructor(argClasses); return clazz.cast(constructor.newInstance(args)); } catch (Exception e) { throw new RuntimeException(e); } } /** * Create a ThreadPoolExecutor. * * @param queueSize the queue size * @param threadName the thread name * @param threadFactory an optional ThreadFactory * @param policy the RejectedExecutionHandler policy * @return a ThreadPoolExecutor */ public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName, ThreadFactory threadFactory, final RejectedExecutionHandler policy) { if (threadFactory == null) { threadFactory = new DefaultThreadFactory(threadName, true); } LinkedBlockingQueue queue = new LinkedBlockingQueue<>(queueSize); ThreadPoolExecutor executor = new ThreadPoolExecutor(1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, queue, threadFactory, policy); executor.allowCoreThreadTimeOut(true); return executor; } /** * Create a ThreadPoolExecutor. * * @param queue the BlockingQueue to use * @param threadName the thread name * @param threadFactory an optional ThreadFactory * @param policy the RejectedExecutionHandler policy * @return a ThreadPoolExecutor */ public static ThreadPoolExecutor createThreadPoolExecutor(final BlockingQueue queue, final String threadName, ThreadFactory threadFactory, final RejectedExecutionHandler policy) { if (threadFactory == null) { threadFactory = new DefaultThreadFactory(threadName, true); } ThreadPoolExecutor executor = new ThreadPoolExecutor(1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, queue, threadFactory, policy); executor.allowCoreThreadTimeOut(true); return executor; } // *********************************************************************** // Misc. public methods // *********************************************************************** /** * Get the int value of a transaction isolation level by name. * * @param transactionIsolationName the name of the transaction isolation level * @return the int value of the isolation level or -1 */ public static int getTransactionIsolation(final String transactionIsolationName) { if (transactionIsolationName != null) { try { // use the english locale to avoid the infamous turkish locale bug final String upperName = transactionIsolationName.toUpperCase(Locale.ENGLISH); if (upperName.startsWith("TRANSACTION_")) { Field field = Connection.class.getField(upperName); return field.getInt(null); } final int level = Integer.parseInt(transactionIsolationName); switch (level) { case Connection.TRANSACTION_READ_UNCOMMITTED: case Connection.TRANSACTION_READ_COMMITTED: case Connection.TRANSACTION_REPEATABLE_READ: case Connection.TRANSACTION_SERIALIZABLE: case Connection.TRANSACTION_NONE: return level; default: throw new IllegalArgumentException(); } } catch (Exception e) { throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName); } } return -1; } public static final class DefaultThreadFactory implements ThreadFactory { private final String threadName; private final boolean daemon; public DefaultThreadFactory(String threadName, boolean daemon) { this.threadName = threadName; this.daemon = daemon; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r, threadName); thread.setDaemon(daemon); return thread; } } } HikariCP-HikariCP-2.7.1/src/test/000077500000000000000000000000001315431642000163505ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/000077500000000000000000000000001315431642000172715ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/000077500000000000000000000000001315431642000200475ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/000077500000000000000000000000001315431642000213705ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/000077500000000000000000000000001315431642000226375ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/db/000077500000000000000000000000001315431642000232245ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/db/BasicPoolTest.java000066400000000000000000000124641315431642000266110ustar00rootroot00000000000000/* * Copyright (C) 2016 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.db; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool; /** * @author brettw * */ public class BasicPoolTest { @Before public void setup() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(2); config.setConnectionTestQuery("SELECT 1"); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.addDataSourceProperty("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); try (HikariDataSource ds = new HikariDataSource(config); Connection conn = ds.getConnection(); Statement stmt = conn.createStatement()) { stmt.executeUpdate("DROP TABLE IF EXISTS basic_pool_test"); stmt.executeUpdate("CREATE TABLE basic_pool_test (" + "id INTEGER NOT NULL IDENTITY PRIMARY KEY, " + "timestamp TIMESTAMP, " + "string VARCHAR(128), " + "string_from_number NUMERIC " + ")"); } } @Test public void testIdleTimeout() throws InterruptedException, SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(10); config.setConnectionTestQuery("SELECT 1"); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.addDataSourceProperty("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "1000"); try (HikariDataSource ds = new HikariDataSource(config)) { System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); SECONDS.sleep(1); HikariPool pool = getPool(ds); ds.setIdleTimeout(3000); assertEquals("Total connections not as expected", 5, pool.getTotalConnections()); assertEquals("Idle connections not as expected", 5, pool.getIdleConnections()); try (Connection connection = ds.getConnection()) { Assert.assertNotNull(connection); MILLISECONDS.sleep(1500); assertEquals("Second total connections not as expected", 6, pool.getTotalConnections()); assertEquals("Second idle connections not as expected", 5, pool.getIdleConnections()); } assertEquals("Idle connections not as expected", 6, pool.getIdleConnections()); SECONDS.sleep(2); assertEquals("Third total connections not as expected", 5, pool.getTotalConnections()); assertEquals("Third idle connections not as expected", 5, pool.getIdleConnections()); } } @Test public void testIdleTimeout2() throws InterruptedException, SQLException { HikariConfig config = newHikariConfig(); config.setMaximumPoolSize(50); config.setConnectionTestQuery("SELECT 1"); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.addDataSourceProperty("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "1000"); try (HikariDataSource ds = new HikariDataSource(config)) { System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); SECONDS.sleep(1); HikariPool pool = getPool(ds); ds.setIdleTimeout(3000); assertEquals("Total connections not as expected", 50, pool.getTotalConnections()); assertEquals("Idle connections not as expected", 50, pool.getIdleConnections()); try (Connection connection = ds.getConnection()) { assertNotNull(connection); MILLISECONDS.sleep(1500); assertEquals("Second total connections not as expected", 50, pool.getTotalConnections()); assertEquals("Second idle connections not as expected", 49, pool.getIdleConnections()); } assertEquals("Idle connections not as expected", 50, pool.getIdleConnections()); SECONDS.sleep(3); assertEquals("Third total connections not as expected", 50, pool.getTotalConnections()); assertEquals("Third idle connections not as expected", 50, pool.getIdleConnections()); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/000077500000000000000000000000001315431642000243055ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/dropwizard/000077500000000000000000000000001315431642000264725ustar00rootroot00000000000000CodaHaleMetricsTrackerTest.java000077500000000000000000000023221315431642000344230ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/dropwizardpackage com.zaxxer.hikari.metrics.dropwizard; import static org.mockito.Mockito.verify; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import com.codahale.metrics.MetricRegistry; @RunWith(MockitoJUnitRunner.class) public class CodaHaleMetricsTrackerTest { @Mock public MetricRegistry mockMetricRegistry; private CodaHaleMetricsTracker testee; @Before public void setup(){ testee = new CodaHaleMetricsTracker("mypool", null, mockMetricRegistry); } @Test public void close() throws Exception { testee.close(); verify(mockMetricRegistry).remove("mypool.pool.Wait"); verify(mockMetricRegistry).remove("mypool.pool.Usage"); verify(mockMetricRegistry).remove("mypool.pool.ConnectionCreation"); verify(mockMetricRegistry).remove("mypool.pool.ConnectionTimeoutRate"); verify(mockMetricRegistry).remove("mypool.pool.TotalConnections"); verify(mockMetricRegistry).remove("mypool.pool.IdleConnections"); verify(mockMetricRegistry).remove("mypool.pool.ActiveConnections"); verify(mockMetricRegistry).remove("mypool.pool.PendingConnections"); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/micrometer/000077500000000000000000000000001315431642000264535ustar00rootroot00000000000000MicrometerMetricsTrackerTest.java000077500000000000000000000024531315431642000350570ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/micrometerpackage com.zaxxer.hikari.metrics.micrometer; import com.zaxxer.hikari.metrics.PoolStats; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class MicrometerMetricsTrackerTest { private MeterRegistry mockMeterRegistry = new SimpleMeterRegistry(); private MicrometerMetricsTracker testee; @Before public void setup(){ testee = new MicrometerMetricsTracker("mypool", new PoolStats(1000L) { @Override protected void update() { // nothing } }, mockMeterRegistry); } @Test public void close() throws Exception { Assert.assertNotNull(mockMeterRegistry.find("Wait")); Assert.assertNotNull(mockMeterRegistry.find("Usage")); Assert.assertNotNull(mockMeterRegistry.find("ConnectionCreation")); Assert.assertNotNull(mockMeterRegistry.find("ConnectionTimeoutRate")); Assert.assertNotNull(mockMeterRegistry.find("TotalConnections")); Assert.assertNotNull(mockMeterRegistry.find("IdleConnections")); Assert.assertNotNull(mockMeterRegistry.find("ActiveConnections")); Assert.assertNotNull(mockMeterRegistry.find("PendingConnections")); testee.close(); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/prometheus/000077500000000000000000000000001315431642000265005ustar00rootroot00000000000000HikariCPCollectorTest.java000066400000000000000000000114701315431642000334300ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/prometheus/* * Copyright (C) 2013, 2014 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.metrics.prometheus; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.sql.Connection; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import io.prometheus.client.CollectorRegistry; public class HikariCPCollectorTest { @Test public void noConnection() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config)) { assertThat(getValue("hikaricp_active_connections", "noConnection"), is(0.0)); assertThat(getValue("hikaricp_idle_connections", "noConnection"), is(0.0)); assertThat(getValue("hikaricp_pending_threads", "noConnection"), is(0.0)); assertThat(getValue("hikaricp_connections", "noConnection"), is(0.0)); } finally { StubConnection.slowCreate = false; } } @Test public void noConnectionWithoutPoolName() throws Exception { HikariConfig config = new HikariConfig(); config.setMinimumIdle(0); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config)) { String poolName = ds.getHikariConfigMXBean().getPoolName(); assertThat(getValue("hikaricp_active_connections", poolName), is(0.0)); assertThat(getValue("hikaricp_idle_connections", poolName), is(0.0)); assertThat(getValue("hikaricp_pending_threads", poolName), is(0.0)); assertThat(getValue("hikaricp_connections", poolName), is(0.0)); } finally { StubConnection.slowCreate = false; } } @Test public void connection1() throws Exception { HikariConfig config = newHikariConfig(); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setMaximumPoolSize(1); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config); Connection connection1 = ds.getConnection()) { quietlySleep(1000); assertThat(getValue("hikaricp_active_connections", "connection1"), is(1.0)); assertThat(getValue("hikaricp_idle_connections", "connection1"), is(0.0)); assertThat(getValue("hikaricp_pending_threads", "connection1"), is(0.0)); assertThat(getValue("hikaricp_connections", "connection1"), is(1.0)); } finally { StubConnection.slowCreate = false; } } @Test public void connectionClosed() throws Exception { HikariConfig config = newHikariConfig(); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setMaximumPoolSize(1); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config)) { try (Connection connection1 = ds.getConnection()) { // close immediately } assertThat(getValue("hikaricp_active_connections", "connectionClosed"), is(0.0)); assertThat(getValue("hikaricp_idle_connections", "connectionClosed"), is(1.0)); assertThat(getValue("hikaricp_pending_threads", "connectionClosed"), is(0.0)); assertThat(getValue("hikaricp_connections", "connectionClosed"), is(1.0)); } finally { StubConnection.slowCreate = false; } } private double getValue(String name, String poolName) { String[] labelNames = {"pool"}; String[] labelValues = {poolName}; return CollectorRegistry.defaultRegistry.getSampleValue(name, labelNames, labelValues); } } PrometheusMetricsTrackerTest.java000066400000000000000000000102511315431642000351210ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/metrics/prometheus/* * Copyright (C) 2013, 2014 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.metrics.prometheus; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.SQLTransientConnectionException; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import io.prometheus.client.CollectorRegistry; public class PrometheusMetricsTrackerTest { @Test public void recordConnectionTimeout() throws Exception { HikariConfig config = newHikariConfig(); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setJdbcUrl("jdbc:h2:mem:"); config.setMaximumPoolSize(2); config.setConnectionTimeout(250); String[] labelNames = {"pool"}; String[] labelValues = {config.getPoolName()}; try (HikariDataSource hikariDataSource = new HikariDataSource(config)) { try (Connection connection1 = hikariDataSource.getConnection(); Connection connection2 = hikariDataSource.getConnection()) { try (Connection connection3 = hikariDataSource.getConnection()) { } catch (SQLTransientConnectionException ignored) { } } assertThat(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_timeout_total", labelNames, labelValues), is(1.0)); assertThat(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_acquired_nanos_count", labelNames, labelValues), is(equalTo(3.0))); assertTrue(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_acquired_nanos_sum", labelNames, labelValues) > 0.0); assertThat(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_usage_millis_count", labelNames, labelValues), is(equalTo(2.0))); assertTrue(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_usage_millis_sum", labelNames, labelValues) > 0.0); } } @Test public void testMultiplePoolName() throws Exception { String[] labelNames = {"pool"}; HikariConfig config = newHikariConfig(); config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config.setPoolName("first"); config.setJdbcUrl("jdbc:h2:mem:"); config.setMaximumPoolSize(2); config.setConnectionTimeout(250); String[] labelValues1 = {config.getPoolName()}; try (HikariDataSource ignored = new HikariDataSource(config)) { assertThat(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_timeout_total", labelNames, labelValues1), is(0.0)); HikariConfig config2 = newHikariConfig(); config2.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory()); config2.setPoolName("second"); config2.setJdbcUrl("jdbc:h2:mem:"); config2.setMaximumPoolSize(4); config2.setConnectionTimeout(250); String[] labelValues2 = {config2.getPoolName()}; try (HikariDataSource ignored2 = new HikariDataSource(config2)) { assertThat(CollectorRegistry.defaultRegistry.getSampleValue( "hikaricp_connection_timeout_total", labelNames, labelValues2), is(0.0)); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/000077500000000000000000000000001315431642000237535ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/MockDataSource.java000066400000000000000000000133361315431642000274700ustar00rootroot00000000000000/* * 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.mocks; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.PrintWriter; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; import java.util.logging.Logger; import javax.sql.DataSource; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; /** * * @author Brett Wooldridge */ public class MockDataSource implements DataSource { @Override public Connection getConnection() throws SQLException { return createMockConnection(); } @Override public Connection getConnection(String username, String password) throws SQLException { return getConnection(); } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } @Override public T unwrap(Class iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } public static Connection createMockConnection() throws SQLException { // Setup mock connection final Connection mockConnection = mock(Connection.class); // Autocommit is always true by default when(mockConnection.getAutoCommit()).thenReturn(true); // Handle Connection.createStatement() Statement statement = mock(Statement.class); when(mockConnection.createStatement()).thenReturn(statement); when(mockConnection.createStatement(anyInt(), anyInt())).thenReturn(statement); when(mockConnection.createStatement(anyInt(), anyInt(), anyInt())).thenReturn(statement); when(mockConnection.isValid(anyInt())).thenReturn(true); // Handle Connection.prepareStatement() PreparedStatement mockPreparedStatement = mock(PreparedStatement.class); when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement); when(mockConnection.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStatement); when(mockConnection.prepareStatement(anyString(), any(int[].class))).thenReturn(mockPreparedStatement); when(mockConnection.prepareStatement(anyString(), any(String[].class))).thenReturn(mockPreparedStatement); when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockPreparedStatement); when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockPreparedStatement); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { return null; } }).doNothing().when(mockPreparedStatement).setInt(anyInt(), anyInt()); ResultSet mockResultSet = mock(ResultSet.class); when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet); when(mockResultSet.getString(anyInt())).thenReturn("aString"); when(mockResultSet.next()).thenReturn(true); // Handle Connection.prepareCall() CallableStatement mockCallableStatement = mock(CallableStatement.class); when(mockConnection.prepareCall(anyString())).thenReturn(mockCallableStatement); when(mockConnection.prepareCall(anyString(), anyInt(), anyInt())).thenReturn(mockCallableStatement); when(mockConnection.prepareCall(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockCallableStatement); // Handle Connection.close() // doAnswer(new Answer() { // public Void answer(InvocationOnMock invocation) throws Throwable { // return null; // } // }).doThrow(new SQLException("Connection is already closed")).when(mockConnection).close(); // Handle Connection.commit() // doAnswer(new Answer() { // public Void answer(InvocationOnMock invocation) throws Throwable { // return null; // } // }).doThrow(new SQLException("Transaction already commited")).when(mockConnection).commit(); // Handle Connection.rollback() // doAnswer(new Answer() { // public Void answer(InvocationOnMock invocation) throws Throwable { // return null; // } // }).doThrow(new SQLException("Transaction already rolledback")).when(mockConnection).rollback(); return mockConnection; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubBaseConnection.java000066400000000000000000000024601315431642000303500ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.mocks; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; public abstract class StubBaseConnection implements Connection { public volatile boolean throwException; /** {@inheritDoc} */ @Override public Statement createStatement() throws SQLException { if (throwException) { throw new SQLException(); } return new StubStatement(this); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubConnection.java000066400000000000000000000246161315431642000275640ustar00rootroot00000000000000/* * 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.mocks; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import com.zaxxer.hikari.util.UtilityElf; /** * * @author Brett Wooldridge */ public class StubConnection extends StubBaseConnection implements Connection { public static final AtomicInteger count = new AtomicInteger(); public static volatile boolean slowCreate; public static volatile boolean oldDriver; private static long foo; private boolean autoCommit; private int isolation = Connection.TRANSACTION_READ_COMMITTED; private String catalog; static { foo = System.currentTimeMillis(); } public StubConnection() { count.incrementAndGet(); if (slowCreate) { UtilityElf.quietlySleep(1000); } } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { if (throwException) { throw new SQLException(); } if (iface.isInstance(this)) { return (T) this; } throw new SQLException("Wrapped connection is not an instance of " + iface); } /** {@inheritDoc} */ @Override public boolean isWrapperFor(Class iface) throws SQLException { if (throwException) { throw new SQLException(); } return false; } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql) throws SQLException { if (throwException) { throw new SQLException(); } return null; } /** {@inheritDoc} */ @Override public String nativeSQL(String sql) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void setAutoCommit(boolean autoCommit) throws SQLException { if (throwException) { throw new SQLException(); } this.autoCommit = autoCommit; } /** {@inheritDoc} */ @Override public boolean getAutoCommit() throws SQLException { return autoCommit; } /** {@inheritDoc} */ @Override public void commit() throws SQLException { } /** {@inheritDoc} */ @Override public void rollback() throws SQLException { } /** {@inheritDoc} */ @Override public void close() throws SQLException { } /** {@inheritDoc} */ @Override public boolean isClosed() throws SQLException { if (throwException) { throw new SQLException(); } return false; } /** {@inheritDoc} */ @Override public DatabaseMetaData getMetaData() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void setReadOnly(boolean readOnly) throws SQLException { if (throwException) { throw new SQLException(); } } /** {@inheritDoc} */ @Override public boolean isReadOnly() throws SQLException { if (throwException) { throw new SQLException(); } return false; } /** {@inheritDoc} */ @Override public void setCatalog(String catalog) throws SQLException { if (throwException) { throw new SQLException(); } this.catalog = catalog; } /** {@inheritDoc} */ @Override public String getCatalog() throws SQLException { return catalog; } /** {@inheritDoc} */ @Override public void setTransactionIsolation(int level) throws SQLException { if (throwException) { throw new SQLException(); } this.isolation = level; } /** {@inheritDoc} */ @Override public int getTransactionIsolation() throws SQLException { return isolation; } /** {@inheritDoc} */ @Override public SQLWarning getWarnings() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void clearWarnings() throws SQLException { if (throwException) { throw new SQLException(); } } /** {@inheritDoc} */ @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { if (throwException) { throw new SQLException(); } return null; } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { if (throwException) { throw new SQLException(); } return null; } /** {@inheritDoc} */ @Override public Map> getTypeMap() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void setTypeMap(Map> map) throws SQLException { } /** {@inheritDoc} */ @Override public void setHoldability(int holdability) throws SQLException { } /** {@inheritDoc} */ @Override public int getHoldability() throws SQLException { return (int) foo; } /** {@inheritDoc} */ @Override public Savepoint setSavepoint() throws SQLException { return null; } /** {@inheritDoc} */ @Override public Savepoint setSavepoint(String name) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void rollback(Savepoint savepoint) throws SQLException { } /** {@inheritDoc} */ @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { } /** {@inheritDoc} */ @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if (throwException) { throw new SQLException(); } return null; } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if (throwException) { throw new SQLException(); } return null; } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } /** {@inheritDoc} */ @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { if (throwException) { throw new SQLException(); } return new StubPreparedStatement(this); } /** {@inheritDoc} */ @Override public Clob createClob() throws SQLException { return null; } /** {@inheritDoc} */ @Override public Blob createBlob() throws SQLException { return null; } /** {@inheritDoc} */ @Override public NClob createNClob() throws SQLException { return null; } /** {@inheritDoc} */ @Override public SQLXML createSQLXML() throws SQLException { return null; } /** {@inheritDoc} */ @Override public boolean isValid(int timeout) throws SQLException { if (throwException) { throw new SQLException(); } return true; } /** {@inheritDoc} */ @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { } /** {@inheritDoc} */ @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { } /** {@inheritDoc} */ @Override public String getClientInfo(String name) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Properties getClientInfo() throws SQLException { return null; } /** {@inheritDoc} */ @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return null; } /** {@inheritDoc} */ public void setSchema(String schema) throws SQLException { } /** {@inheritDoc} */ public String getSchema() throws SQLException { return null; } /** {@inheritDoc} */ public void abort(Executor executor) throws SQLException { throw new SQLException("Intentional exception during abort"); } /** {@inheritDoc} */ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { } /** {@inheritDoc} */ public int getNetworkTimeout() throws SQLException { if (oldDriver) { throw new AbstractMethodError(); } return 0; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubDataSource.java000077500000000000000000000064361315431642000275220ustar00rootroot00000000000000/* * 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.mocks; import com.zaxxer.hikari.util.UtilityElf; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; import javax.sql.DataSource; /** * * @author Brett Wooldridge */ public class StubDataSource implements DataSource { private String user; private String password; private PrintWriter logWriter; private SQLException throwException; private long connectionAcquistionTime = 0; private int loginTimeout; public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void setURL(String url) { // we don't care } /** {@inheritDoc} */ @Override public PrintWriter getLogWriter() throws SQLException { return logWriter; } /** {@inheritDoc} */ @Override public void setLogWriter(PrintWriter out) throws SQLException { this.logWriter = out; } /** {@inheritDoc} */ @Override public void setLoginTimeout(int seconds) throws SQLException { this.loginTimeout = seconds; } /** {@inheritDoc} */ @Override public int getLoginTimeout() throws SQLException { return loginTimeout; } /** {@inheritDoc} */ public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return (T) this; } throw new SQLException("Wrapped DataSource is not an instance of " + iface); } /** {@inheritDoc} */ @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } /** {@inheritDoc} */ @Override public Connection getConnection() throws SQLException { if (throwException != null) { throw throwException; } if (connectionAcquistionTime > 0) { UtilityElf.quietlySleep(connectionAcquistionTime); } return new StubConnection(); } /** {@inheritDoc} */ @Override public Connection getConnection(String username, String password) throws SQLException { return new StubConnection(); } public void setThrowException(SQLException e) { this.throwException = e; } public void setConnectionAcquistionTime(long connectionAcquisitionTime) { this.connectionAcquistionTime = connectionAcquisitionTime; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubDriver.java000066400000000000000000000042121315431642000267060ustar00rootroot00000000000000/* * 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.mocks; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; /** * * @author Brett Wooldridge */ public class StubDriver implements Driver { private static final Driver driver; static { driver = new StubDriver(); try { DriverManager.registerDriver(driver); } catch (SQLException e) { e.printStackTrace(); } } /** {@inheritDoc} */ @Override public Connection connect(String url, Properties info) throws SQLException { return new StubConnection(); } /** {@inheritDoc} */ @Override public boolean acceptsURL(String url) throws SQLException { return "jdbc:stub".equals(url); } /** {@inheritDoc} */ @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return null; } /** {@inheritDoc} */ @Override public int getMajorVersion() { return 0; } /** {@inheritDoc} */ @Override public int getMinorVersion() { return 0; } /** {@inheritDoc} */ @Override public boolean jdbcCompliant() { return true; } /** {@inheritDoc} */ public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubPreparedStatement.java000066400000000000000000000341711315431642000311110ustar00rootroot00000000000000/* * 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.mocks; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.NClob; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; /** * * @author Brett Wooldridge */ public class StubPreparedStatement extends StubStatement implements PreparedStatement { StubPreparedStatement(Connection connection) { super(connection); } /** {@inheritDoc} */ @Override public ResultSet executeQuery(String sql) throws SQLException { return new StubResultSet(); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getMaxFieldSize() throws SQLException { throw new SQLException("Simulated disconnection error", "08999"); } /** {@inheritDoc} */ @Override public void setMaxFieldSize(int max) throws SQLException { } /** {@inheritDoc} */ @Override public int getMaxRows() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setMaxRows(int max) throws SQLException { } /** {@inheritDoc} */ @Override public void setEscapeProcessing(boolean enable) throws SQLException { } /** {@inheritDoc} */ @Override public int getQueryTimeout() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setQueryTimeout(int seconds) throws SQLException { } /** {@inheritDoc} */ @Override public void cancel() throws SQLException { } /** {@inheritDoc} */ @Override public SQLWarning getWarnings() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void clearWarnings() throws SQLException { } /** {@inheritDoc} */ @Override public void setCursorName(String name) throws SQLException { } /** {@inheritDoc} */ @Override public boolean execute(String sql) throws SQLException { return false; } /** {@inheritDoc} */ @Override public ResultSet getResultSet() throws SQLException { return new StubResultSet(); } /** {@inheritDoc} */ @Override public int getUpdateCount() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public boolean getMoreResults() throws SQLException { if (isClosed()) { throw new SQLException("Connection is closed"); } return false; } /** {@inheritDoc} */ @Override public void setFetchDirection(int direction) throws SQLException { } /** {@inheritDoc} */ @Override public int getFetchDirection() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setFetchSize(int rows) throws SQLException { } /** {@inheritDoc} */ @Override public int getFetchSize() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getResultSetConcurrency() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getResultSetType() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void addBatch(String sql) throws SQLException { } /** {@inheritDoc} */ @Override public void clearBatch() throws SQLException { } /** {@inheritDoc} */ @Override public int[] executeBatch() throws SQLException { return null; } /** {@inheritDoc} */ @Override public boolean getMoreResults(int current) throws SQLException { return false; } /** {@inheritDoc} */ @Override public ResultSet getGeneratedKeys() throws SQLException { return new StubResultSet(); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean execute(String sql, String[] columnNames) throws SQLException { return false; } /** {@inheritDoc} */ @Override public int getResultSetHoldability() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setPoolable(boolean poolable) throws SQLException { } /** {@inheritDoc} */ @Override public boolean isPoolable() throws SQLException { return false; } /** {@inheritDoc} */ @Override public void closeOnCompletion() throws SQLException { } /** {@inheritDoc} */ @Override public boolean isCloseOnCompletion() throws SQLException { return false; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return (T) this; } throw new SQLException("Wrapped connection is not an instance of " + iface); } /** {@inheritDoc} */ @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } /** {@inheritDoc} */ @Override public ResultSet executeQuery() throws SQLException { return new StubResultSet(); } /** {@inheritDoc} */ @Override public int executeUpdate() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setNull(int parameterIndex, int sqlType) throws SQLException { } /** {@inheritDoc} */ @Override public void setBoolean(int parameterIndex, boolean x) throws SQLException { } /** {@inheritDoc} */ @Override public void setByte(int parameterIndex, byte x) throws SQLException { } /** {@inheritDoc} */ @Override public void setShort(int parameterIndex, short x) throws SQLException { } /** {@inheritDoc} */ @Override public void setInt(int parameterIndex, int x) throws SQLException { } /** {@inheritDoc} */ @Override public void setLong(int parameterIndex, long x) throws SQLException { } /** {@inheritDoc} */ @Override public void setFloat(int parameterIndex, float x) throws SQLException { } /** {@inheritDoc} */ @Override public void setDouble(int parameterIndex, double x) throws SQLException { } /** {@inheritDoc} */ @Override public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { } /** {@inheritDoc} */ @Override public void setString(int parameterIndex, String x) throws SQLException { } /** {@inheritDoc} */ @Override public void setBytes(int parameterIndex, byte[] x) throws SQLException { } /** {@inheritDoc} */ @Override public void setDate(int parameterIndex, Date x) throws SQLException { } /** {@inheritDoc} */ @Override public void setTime(int parameterIndex, Time x) throws SQLException { } /** {@inheritDoc} */ @Override public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { } /** {@inheritDoc} */ @Override public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void clearParameters() throws SQLException { } /** {@inheritDoc} */ @Override public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { } /** {@inheritDoc} */ @Override public void setObject(int parameterIndex, Object x) throws SQLException { } /** {@inheritDoc} */ @Override public boolean execute() throws SQLException { return false; } /** {@inheritDoc} */ @Override public void addBatch() throws SQLException { } /** {@inheritDoc} */ @Override public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void setRef(int parameterIndex, Ref x) throws SQLException { } /** {@inheritDoc} */ @Override public void setBlob(int parameterIndex, Blob x) throws SQLException { } /** {@inheritDoc} */ @Override public void setClob(int parameterIndex, Clob x) throws SQLException { } /** {@inheritDoc} */ @Override public void setArray(int parameterIndex, Array x) throws SQLException { } /** {@inheritDoc} */ @Override public ResultSetMetaData getMetaData() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { } /** {@inheritDoc} */ @Override public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { } /** {@inheritDoc} */ @Override public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { } /** {@inheritDoc} */ @Override public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { } /** {@inheritDoc} */ @Override public void setURL(int parameterIndex, URL x) throws SQLException { } /** {@inheritDoc} */ @Override public ParameterMetaData getParameterMetaData() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void setRowId(int parameterIndex, RowId x) throws SQLException { } /** {@inheritDoc} */ @Override public void setNString(int parameterIndex, String value) throws SQLException { } /** {@inheritDoc} */ @Override public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setNClob(int parameterIndex, NClob value) throws SQLException { } /** {@inheritDoc} */ @Override public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { } /** {@inheritDoc} */ @Override public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { } /** {@inheritDoc} */ @Override public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { } /** {@inheritDoc} */ @Override public void setClob(int parameterIndex, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { } /** {@inheritDoc} */ @Override public void setNClob(int parameterIndex, Reader reader) throws SQLException { } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubResultSet.java000066400000000000000000000650121315431642000274120ustar00rootroot00000000000000/* * 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.mocks; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; /** * * @author Brett Wooldridge */ public class StubResultSet implements ResultSet { private int counter; private boolean closed; /** {@inheritDoc} */ @Override public T unwrap(Class iface) throws SQLException { return null; } /** {@inheritDoc} */ @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean next() throws SQLException { return (counter > 100000); } /** {@inheritDoc} */ @Override public void close() throws SQLException { closed = true; } /** {@inheritDoc} */ @Override public boolean wasNull() throws SQLException { return false; } /** {@inheritDoc} */ @Override public String getString(int columnIndex) throws SQLException { return "aString"; } /** {@inheritDoc} */ @Override public boolean getBoolean(int columnIndex) throws SQLException { return false; } /** {@inheritDoc} */ @Override public byte getByte(int columnIndex) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public short getShort(int columnIndex) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getInt(int columnIndex) throws SQLException { return ++counter; } /** {@inheritDoc} */ @Override public long getLong(int columnIndex) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public float getFloat(int columnIndex) throws SQLException { throw new SQLException("Simulated disconnection error", "08999"); } /** {@inheritDoc} */ @Override public double getDouble(int columnIndex) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { return null; } /** {@inheritDoc} */ @Override public byte[] getBytes(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Date getDate(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Time getTime(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getAsciiStream(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getUnicodeStream(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getBinaryStream(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public String getString(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public boolean getBoolean(String columnLabel) throws SQLException { return false; } /** {@inheritDoc} */ @Override public byte getByte(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public short getShort(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getInt(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public long getLong(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public float getFloat(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public double getDouble(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { return null; } /** {@inheritDoc} */ @Override public byte[] getBytes(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Date getDate(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Time getTime(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getAsciiStream(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getUnicodeStream(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public InputStream getBinaryStream(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public SQLWarning getWarnings() throws SQLException { return null; } /** {@inheritDoc} */ @Override public void clearWarnings() throws SQLException { } /** {@inheritDoc} */ @Override public String getCursorName() throws SQLException { return null; } /** {@inheritDoc} */ @Override public ResultSetMetaData getMetaData() throws SQLException { return null; } /** {@inheritDoc} */ @Override public Object getObject(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Object getObject(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public int findColumn(String columnLabel) throws SQLException { return 0; } /** {@inheritDoc} */ @Override public Reader getCharacterStream(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Reader getCharacterStream(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public boolean isBeforeFirst() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean isAfterLast() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean isFirst() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean isLast() throws SQLException { return false; } /** {@inheritDoc} */ @Override public void beforeFirst() throws SQLException { } /** {@inheritDoc} */ @Override public void afterLast() throws SQLException { } /** {@inheritDoc} */ @Override public boolean first() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean last() throws SQLException { return false; } /** {@inheritDoc} */ @Override public int getRow() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public boolean absolute(int row) throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean relative(int rows) throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean previous() throws SQLException { return false; } /** {@inheritDoc} */ @Override public void setFetchDirection(int direction) throws SQLException { } /** {@inheritDoc} */ @Override public int getFetchDirection() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public void setFetchSize(int rows) throws SQLException { } /** {@inheritDoc} */ @Override public int getFetchSize() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getType() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public int getConcurrency() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public boolean rowUpdated() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean rowInserted() throws SQLException { return false; } /** {@inheritDoc} */ @Override public boolean rowDeleted() throws SQLException { return false; } /** {@inheritDoc} */ @Override public void updateNull(int columnIndex) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBoolean(int columnIndex, boolean x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateByte(int columnIndex, byte x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateShort(int columnIndex, short x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateInt(int columnIndex, int x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateLong(int columnIndex, long x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateFloat(int columnIndex, float x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateDouble(int columnIndex, double x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateString(int columnIndex, String x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBytes(int columnIndex, byte[] x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateDate(int columnIndex, Date x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateTime(int columnIndex, Time x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { } /** {@inheritDoc} */ @Override public void updateObject(int columnIndex, Object x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNull(String columnLabel) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBoolean(String columnLabel, boolean x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateByte(String columnLabel, byte x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateShort(String columnLabel, short x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateInt(String columnLabel, int x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateLong(String columnLabel, long x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateFloat(String columnLabel, float x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateDouble(String columnLabel, double x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateString(String columnLabel, String x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBytes(String columnLabel, byte[] x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateDate(String columnLabel, Date x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateTime(String columnLabel, Time x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { } /** {@inheritDoc} */ @Override public void updateObject(String columnLabel, Object x) throws SQLException { } /** {@inheritDoc} */ @Override public void insertRow() throws SQLException { } /** {@inheritDoc} */ @Override public void updateRow() throws SQLException { } /** {@inheritDoc} */ @Override public void deleteRow() throws SQLException { } /** {@inheritDoc} */ @Override public void refreshRow() throws SQLException { } /** {@inheritDoc} */ @Override public void cancelRowUpdates() throws SQLException { } /** {@inheritDoc} */ @Override public void moveToInsertRow() throws SQLException { } /** {@inheritDoc} */ @Override public void moveToCurrentRow() throws SQLException { } /** {@inheritDoc} */ @Override public Statement getStatement() throws SQLException { return null; } /** {@inheritDoc} */ @Override public Object getObject(int columnIndex, Map> map) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Ref getRef(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Blob getBlob(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Clob getClob(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Array getArray(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Object getObject(String columnLabel, Map> map) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Ref getRef(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Blob getBlob(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Clob getClob(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Array getArray(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Date getDate(int columnIndex, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Date getDate(String columnLabel, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Time getTime(int columnIndex, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Time getTime(String columnLabel, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { return null; } /** {@inheritDoc} */ @Override public URL getURL(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public URL getURL(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void updateRef(int columnIndex, Ref x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateRef(String columnLabel, Ref x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(int columnIndex, Blob x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(String columnLabel, Blob x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(int columnIndex, Clob x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(String columnLabel, Clob x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateArray(int columnIndex, Array x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateArray(String columnLabel, Array x) throws SQLException { } /** {@inheritDoc} */ @Override public RowId getRowId(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public RowId getRowId(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void updateRowId(int columnIndex, RowId x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateRowId(String columnLabel, RowId x) throws SQLException { } /** {@inheritDoc} */ @Override public int getHoldability() throws SQLException { return 0; } /** {@inheritDoc} */ @Override public boolean isClosed() throws SQLException { return closed; } /** {@inheritDoc} */ @Override public void updateNString(int columnIndex, String nString) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNString(String columnLabel, String nString) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(int columnIndex, NClob nClob) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(String columnLabel, NClob nClob) throws SQLException { } /** {@inheritDoc} */ @Override public NClob getNClob(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public NClob getNClob(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public SQLXML getSQLXML(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public SQLXML getSQLXML(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { } /** {@inheritDoc} */ @Override public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { } /** {@inheritDoc} */ @Override public String getNString(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public String getNString(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Reader getNCharacterStream(int columnIndex) throws SQLException { return null; } /** {@inheritDoc} */ @Override public Reader getNCharacterStream(String columnLabel) throws SQLException { return null; } /** {@inheritDoc} */ @Override public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { } /** {@inheritDoc} */ @Override public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { } /** {@inheritDoc} */ @Override public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(int columnIndex, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void updateClob(String columnLabel, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(int columnIndex, Reader reader) throws SQLException { } /** {@inheritDoc} */ @Override public void updateNClob(String columnLabel, Reader reader) throws SQLException { } /** {@inheritDoc} */ public T getObject(int columnIndex, Class type) throws SQLException { return null; } /** {@inheritDoc} */ public T getObject(String columnLabel, Class type) throws SQLException { return null; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/mocks/StubStatement.java000066400000000000000000000174011315431642000274230ustar00rootroot00000000000000/* * 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.mocks; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.Statement; /** * * @author Brett Wooldridge */ public class StubStatement implements Statement { public static volatile boolean oldDriver; private static volatile long simulatedQueryTime; private boolean closed; private Connection connection; public StubStatement(Connection connection) { this.connection = connection; } public static void setSimulatedQueryTime(long time) { simulatedQueryTime = time; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { checkClosed(); return (T) this; } /** {@inheritDoc} */ @Override public boolean isWrapperFor(Class iface) throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public ResultSet executeQuery(String sql) throws SQLException { checkClosed(); StubResultSet resultSet = new StubResultSet(); return resultSet; } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void close() throws SQLException { closed = true; } /** {@inheritDoc} */ @Override public int getMaxFieldSize() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void setMaxFieldSize(int max) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public int getMaxRows() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void setMaxRows(int max) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public void setEscapeProcessing(boolean enable) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public int getQueryTimeout() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void setQueryTimeout(int seconds) throws SQLException { if (oldDriver) { throw new SQLFeatureNotSupportedException(); } checkClosed(); } /** {@inheritDoc} */ @Override public void cancel() throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public SQLWarning getWarnings() throws SQLException { checkClosed(); return null; } /** {@inheritDoc} */ @Override public void clearWarnings() throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public void setCursorName(String name) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public boolean execute(String sql) throws SQLException { checkClosed(); if (simulatedQueryTime > 0) { quietlySleep(simulatedQueryTime); } return false; } /** {@inheritDoc} */ @Override public ResultSet getResultSet() throws SQLException { checkClosed(); return new StubResultSet(); } /** {@inheritDoc} */ @Override public int getUpdateCount() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public boolean getMoreResults() throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public void setFetchDirection(int direction) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public int getFetchDirection() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void setFetchSize(int rows) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public int getFetchSize() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public int getResultSetConcurrency() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public int getResultSetType() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public void addBatch(String sql) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public void clearBatch() throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public int[] executeBatch() throws SQLException { checkClosed(); return null; } /** {@inheritDoc} */ @Override public Connection getConnection() throws SQLException { checkClosed(); return connection; } /** {@inheritDoc} */ @Override public boolean getMoreResults(int current) throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public ResultSet getGeneratedKeys() throws SQLException { checkClosed(); return new StubResultSet(); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public boolean execute(String sql, String[] columnNames) throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ @Override public int getResultSetHoldability() throws SQLException { checkClosed(); return 0; } /** {@inheritDoc} */ @Override public boolean isClosed() throws SQLException { return closed; } /** {@inheritDoc} */ @Override public void setPoolable(boolean poolable) throws SQLException { checkClosed(); } /** {@inheritDoc} */ @Override public boolean isPoolable() throws SQLException { checkClosed(); return false; } /** {@inheritDoc} */ public void closeOnCompletion() throws SQLException { checkClosed(); } /** {@inheritDoc} */ public boolean isCloseOnCompletion() throws SQLException { checkClosed(); return false; } private void checkClosed() throws SQLException { if (closed) { throw new SQLException("Statement is closed"); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/osgi/000077500000000000000000000000001315431642000236005ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/osgi/OSGiBundleTest.java000066400000000000000000000062401315431642000272400ustar00rootroot00000000000000/* * 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.osgi; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.InitializationError; import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import javax.inject.Inject; import java.io.File; import static com.zaxxer.hikari.pool.TestElf.isJava9; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.ops4j.pax.exam.CoreOptions.*; /** * @author lburgazzoli */ @RunWith(OSGiBundleTest.ConditionalPaxExam.class) public class OSGiBundleTest { @Test public void checkInject() { assertNotNull(context); } @Test public void checkBundle() { Boolean bundleFound = false; Boolean bundleActive = false; Bundle[] bundles = context.getBundles(); for (Bundle bundle : bundles) { if (bundle != null) { if (bundle.getSymbolicName().equals("com.zaxxer.HikariCP")) { bundleFound = true; if (bundle.getState() == Bundle.ACTIVE) { bundleActive = true; } } } } assertTrue(bundleFound); assertTrue(bundleActive); } @Inject BundleContext context; @Configuration public Option[] config() { return options( systemProperty("org.osgi.framework.storage.clean").value("true"), systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"), mavenBundle("org.slf4j", "slf4j-api", "1.7.5"), mavenBundle("org.slf4j", "slf4j-simple", "1.7.5").noStart(), new File("target/classes").exists() ? bundle("reference:file:target/classes") : bundle("reference:file:../target/classes"), junitBundles(), cleanCaches() ); } public static class ConditionalPaxExam extends PaxExam { public ConditionalPaxExam(Class klass) throws InitializationError { super(klass); } @Override public void run(RunNotifier notifier) { if (!isJava9()) { super.run(notifier); } } @Override public void filter(Filter filter) throws NoTestsRemainException { if (isJava9()) { throw new NoTestsRemainException(); } super.filter(filter); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/000077500000000000000000000000001315431642000236105ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ConcurrentCloseConnectionTest.java000066400000000000000000000040221315431642000324410ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; /** * @author Matthew Tambara (matthew.tambara@liferay.com) */ public class ConcurrentCloseConnectionTest { @Test public void testConcurrentClose() throws Exception { HikariConfig config = newHikariConfig(); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config); final Connection connection = ds.getConnection()) { ExecutorService executorService = Executors.newFixedThreadPool(10); List> futures = new ArrayList<>(); for (int i = 0; i < 500; i++) { final PreparedStatement preparedStatement = connection.prepareStatement(""); futures.add(executorService.submit(new Callable() { @Override public Void call() throws Exception { preparedStatement.close(); return null; } })); } executorService.shutdown(); for (Future future : futures) { future.get(); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ConnectionPoolSizeVsThreadsTest.java000077500000000000000000000203501315431642000327260ustar00rootroot00000000000000/* * Copyright (C) 2013, 2017 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.pool; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubDataSource; /** * @author Matthew Tambara (matthew.tambara@liferay.com) */ public class ConnectionPoolSizeVsThreadsTest { private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionPoolSizeVsThreadsTest.class); private static final int ITERATIONS = 50_000; @Test public void testPoolSizeAboutSameSizeAsThreadCount() throws Exception { final int threadCount = 50; final Counts counts = testPoolSize(2 /*minIdle*/, 100 /*maxPoolSize*/, threadCount, 1 /*workTimeMs*/, 0 /*restTimeMs*/, 20 /*connectionAcquisitionTimeMs*/, ITERATIONS, SECONDS.toMillis(2) /*postTestTimeMs*/); // maxActive may never make it to threadCount but it shouldn't be any higher assertEquals(threadCount, counts.maxActive, 15 /*delta*/); assertEquals(threadCount, counts.maxTotal, 5 /*delta*/); } @Test public void testSlowConnectionTimeBurstyWork() throws Exception { // setup a bursty work load, 50 threads all needing to do around 100 units of work. // Using a more realistic time for connection startup of 250 ms and only 5 seconds worth of work will mean that we end up finishing // all of the work before we actually have setup 50 connections even though we have requested 50 connections final int threadCount = 50; final int workItems = threadCount * 100; final int workTimeMs = 0; final int connectionAcquisitionTimeMs = 250; final Counts counts = testPoolSize(2 /*minIdle*/, 100 /*maxPoolSize*/, threadCount, workTimeMs, 0 /*restTimeMs*/, connectionAcquisitionTimeMs, workItems /*iterations*/, SECONDS.toMillis(3) /*postTestTimeMs*/); // hard to put exact bounds on how many thread we will use but we can put an upper bound on usage (if there was only one thread) final long totalWorkTime = workItems * workTimeMs; final long connectionMax = totalWorkTime / connectionAcquisitionTimeMs; assertTrue(connectionMax <= counts.maxActive); assertEquals(connectionMax, counts.maxTotal, 2 + 2 /*delta*/); } private Counts testPoolSize(final int minIdle, final int maxPoolSize, final int threadCount, final long workTimeMs, final long restTimeMs, final long connectionAcquisitionTimeMs, final int iterations, final long postTestTimeMs) throws Exception { LOGGER.info("Starting test (minIdle={}, maxPoolSize={}, threadCount={}, workTimeMs={}, restTimeMs={}, connectionAcquisitionTimeMs={}, iterations={}, postTestTimeMs={})", minIdle, maxPoolSize, threadCount, workTimeMs, restTimeMs, connectionAcquisitionTimeMs, iterations, postTestTimeMs); final HikariConfig config = newHikariConfig(); config.setMinimumIdle(minIdle); config.setMaximumPoolSize(maxPoolSize); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTimeout(2500); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); final AtomicReference ref = new AtomicReference<>(null); // Initialize HikariPool with no initial connections and room to grow try (final HikariDataSource ds = new HikariDataSource(config)) { final StubDataSource stubDataSource = ds.unwrap(StubDataSource.class); // connection acquisition takes more than 0 ms in a real system stubDataSource.setConnectionAcquistionTime(connectionAcquisitionTimeMs); final ExecutorService threadPool = newFixedThreadPool(threadCount); final CountDownLatch allThreadsDone = new CountDownLatch(iterations); for (int i = 0; i < iterations; i++) { threadPool.submit(() -> { if (ref.get() == null) { quietlySleep(restTimeMs); try (Connection c2 = ds.getConnection()) { quietlySleep(workTimeMs); } catch (Exception e) { ref.set(e); } } allThreadsDone.countDown(); }); } final HikariPool pool = getPool(ds); // collect pool usage data while work is still being done final Counts underLoad = new Counts(); while (allThreadsDone.getCount() > 0 || pool.getTotalConnections() < minIdle) { quietlySleep(50); underLoad.updateMaxCounts(pool); } // wait for long enough any pending acquisitions have already been done LOGGER.info("Test Over, waiting for post delay time {}ms ", postTestTimeMs); quietlySleep(connectionAcquisitionTimeMs + workTimeMs + restTimeMs); // collect pool data while there is no work to do. final Counts postLoad = new Counts(); final long start = currentTime(); while (elapsedMillis(start) < postTestTimeMs) { quietlySleep(50); postLoad.updateMaxCounts(pool); } allThreadsDone.await(); threadPool.shutdown(); threadPool.awaitTermination(30, SECONDS); if (ref.get() != null) { LOGGER.error("Task failed", ref.get()); fail("Task failed"); } LOGGER.info("Under Load... {}", underLoad); LOGGER.info("Post Load.... {}", postLoad); // verify that the no connections created after the work has stopped if (postTestTimeMs > 0) { if (postLoad.maxActive != 0) { fail("Max Active was greater than 0 after test was done"); } final int createdAfterWorkAllFinished = postLoad.maxTotal - underLoad.maxTotal; assertEquals("Connections were created when there was no waiting consumers", 0, createdAfterWorkAllFinished, 1 /*delta*/); } return underLoad; } } private static class Counts { int maxTotal = 0; int maxActive = 0; void updateMaxCounts(final HikariPool pool) { maxTotal = Math.max(pool.getTotalConnections(), maxTotal); maxActive = Math.max(pool.getActiveConnections(), maxActive); } @Override public String toString() { return "Counts{" + "maxTotal=" + maxTotal + ", maxActive=" + maxActive + '}'; } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ConnectionRaceConditionTest.java000077500000000000000000000065151315431642000320660ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static org.junit.Assert.fail; import java.sql.Connection; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.Test; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.ConcurrentBag; /** * @author Matthew Tambara (matthew.tambara@liferay.com) */ public class ConnectionRaceConditionTest { public static final int ITERATIONS = 10_000; @Test public void testRaceCondition() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(10); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTimeout(5000); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); setSlf4jLogLevel(ConcurrentBag.class, Level.INFO); final AtomicReference ref = new AtomicReference<>(null); // Initialize HikariPool with no initial connections and room to grow try (final HikariDataSource ds = new HikariDataSource(config)) { ExecutorService threadPool = Executors.newFixedThreadPool(2); for (int i = 0; i < ITERATIONS; i++) { threadPool.submit(new Callable() { /** {@inheritDoc} */ @Override public Exception call() throws Exception { if (ref.get() == null) { Connection c2; try { c2 = ds.getConnection(); ds.evictConnection(c2); } catch (Exception e) { ref.set(e); } } return null; } }); } threadPool.shutdown(); threadPool.awaitTermination(30, TimeUnit.SECONDS); if (ref.get() != null) { LoggerFactory.getLogger(ConnectionRaceConditionTest.class).error("Task failed", ref.get()); fail("Task failed"); } } catch (Exception e) { throw e; } } @After public void after() { System.getProperties().remove("com.zaxxer.hikari.housekeeping.periodMs"); setSlf4jLogLevel(HikariPool.class, Level.WARN); setSlf4jLogLevel(ConcurrentBag.class, Level.WARN); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ConnectionStateTest.java000066400000000000000000000135151315431642000304200ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.UtilityElf; public class ConnectionStateTest { @Test public void testAutoCommit() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setAutoCommit(true); ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); ds.addDataSourceProperty("user", "bar"); ds.addDataSourceProperty("password", "secret"); ds.addDataSourceProperty("url", "baf"); ds.addDataSourceProperty("loginTimeout", "10"); try (Connection connection = ds.getConnection()) { Connection unwrap = connection.unwrap(Connection.class); connection.setAutoCommit(false); connection.close(); assertTrue(unwrap.getAutoCommit()); } } } @Test public void testTransactionIsolation() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setTransactionIsolation("TRANSACTION_READ_COMMITTED"); ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { Connection unwrap = connection.unwrap(Connection.class); connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); connection.close(); assertEquals(Connection.TRANSACTION_READ_COMMITTED, unwrap.getTransactionIsolation()); } } } @Test public void testIsolation() throws Exception { HikariConfig config = newHikariConfig(); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ"); config.validate(); int transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation()); assertSame(Connection.TRANSACTION_REPEATABLE_READ, transactionIsolation); } @Test public void testReadOnly() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setCatalog("test"); ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { Connection unwrap = connection.unwrap(Connection.class); connection.setReadOnly(true); connection.close(); assertFalse(unwrap.isReadOnly()); } } } @Test public void testCatalog() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setCatalog("test"); ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { Connection unwrap = connection.unwrap(Connection.class); connection.setCatalog("other"); connection.close(); assertEquals("test", unwrap.getCatalog()); } } } @Test public void testCommitTracking() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setAutoCommit(false); ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { Statement statement = connection.createStatement(); statement.execute("SELECT something"); assertTrue(TestElf.getConnectionCommitDirtyState(connection)); connection.commit(); assertFalse(TestElf.getConnectionCommitDirtyState(connection)); statement.execute("SELECT something", Statement.NO_GENERATED_KEYS); assertTrue(TestElf.getConnectionCommitDirtyState(connection)); connection.rollback(); assertFalse(TestElf.getConnectionCommitDirtyState(connection)); ResultSet resultSet = statement.executeQuery("SELECT something"); assertTrue(TestElf.getConnectionCommitDirtyState(connection)); connection.rollback(null); assertFalse(TestElf.getConnectionCommitDirtyState(connection)); resultSet.updateRow(); assertTrue(TestElf.getConnectionCommitDirtyState(connection)); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ExceptionTest.java000066400000000000000000000066121315431642000272560ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; public class ExceptionTest { private HikariDataSource ds; @Before public void setup() { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(2); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); ds = new HikariDataSource(config); } @After public void teardown() { ds.close(); } @Test public void testException1() throws SQLException { try (Connection connection = ds.getConnection()) { assertNotNull(connection); PreparedStatement statement = connection.prepareStatement("SELECT some, thing FROM somewhere WHERE something=?"); assertNotNull(statement); ResultSet resultSet = statement.executeQuery(); assertNotNull(resultSet); try { statement.getMaxFieldSize(); fail(); } catch (Exception e) { assertSame(SQLException.class, e.getClass()); } } HikariPool pool = getPool(ds); assertTrue("Total (3) connections not as expected", pool.getTotalConnections() >= 0); assertTrue("Idle (3) connections not as expected", pool.getIdleConnections() >= 0); } @Test public void testUseAfterStatementClose() throws SQLException { Connection connection = ds.getConnection(); assertNotNull(connection); try (Statement statement = connection.prepareStatement("SELECT some, thing FROM somewhere WHERE something=?")) { statement.close(); statement.getMoreResults(); fail(); } catch (SQLException e) { assertSame("Connection is closed", e.getMessage()); } } @Test public void testUseAfterClose() throws SQLException { try (Connection connection = ds.getConnection()) { assertNotNull(connection); connection.close(); try (Statement statement = connection.prepareStatement("SELECT some, thing FROM somewhere WHERE something=?")) { fail(); } catch (SQLException e) { assertSame("Connection is closed", e.getMessage()); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/HouseKeeperCleanupTest.java000066400000000000000000000051761315431642000310530ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.junit.Assert.assertEquals; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.UtilityElf; /** * @author Martin Stříž (striz@raynet.cz) */ public class HouseKeeperCleanupTest { private ScheduledThreadPoolExecutor executor; @Before public void before() throws Exception { ThreadFactory threadFactory = new UtilityElf.DefaultThreadFactory("global housekeeper", true); executor = new ScheduledThreadPoolExecutor(1, threadFactory, new ThreadPoolExecutor.DiscardPolicy()); executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); executor.setRemoveOnCancelPolicy(true); } @Test public void testHouseKeeperCleanupWithCustomExecutor() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(10); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTimeout(2500); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setScheduledExecutor(executor); HikariConfig config2 = newHikariConfig(); config.copyState(config2); try ( final HikariDataSource ds1 = new HikariDataSource(config); final HikariDataSource ds2 = new HikariDataSource(config2) ) { assertEquals("Scheduled tasks count not as expected, ", 2, executor.getQueue().size()); } assertEquals("Scheduled tasks count not as expected, ", 0, executor.getQueue().size()); } @After public void after() throws Exception { executor.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/IsolationTest.java000066400000000000000000000044031315431642000272550ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import java.sql.Connection; import java.sql.SQLException; import org.junit.Test; import com.zaxxer.hikari.HikariDataSource; public class IsolationTest { @Test public void testIsolation() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setIsolateInternalQueries(true); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { connection.close(); try (Connection connection2 = ds.getConnection()) { connection2.close(); assertNotSame(connection, connection2); assertSame(connection.unwrap(Connection.class), connection2.unwrap(Connection.class)); } } } } @Test public void testNonIsolation() throws SQLException { try (HikariDataSource ds = newHikariDataSource()) { ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setIsolateInternalQueries(false); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (Connection connection = ds.getConnection()) { connection.close(); try (Connection connection2 = ds.getConnection()) { connection2.close(); assertSame(connection.unwrap(Connection.class), connection2.unwrap(Connection.class)); } } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/JdbcDriverTest.java000066400000000000000000000046541315431642000273420ustar00rootroot00000000000000/* * Copyright (C) 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.SQLException; import org.junit.After; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.DriverDataSource; public class JdbcDriverTest { private HikariDataSource ds; @After public void teardown() { if (ds != null) { ds.close(); } } @Test public void driverTest1() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setDriverClassName("com.zaxxer.hikari.mocks.StubDriver"); config.setJdbcUrl("jdbc:stub"); config.addDataSourceProperty("user", "bart"); config.addDataSourceProperty("password", "simpson"); ds = new HikariDataSource(config); assertTrue(ds.isWrapperFor(DriverDataSource.class)); DriverDataSource unwrap = ds.unwrap(DriverDataSource.class); assertNotNull(unwrap); try (Connection connection = ds.getConnection()) { // test that getConnection() succeeds } } @Test public void driverTest2() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setDriverClassName("com.zaxxer.hikari.mocks.StubDriver"); config.setJdbcUrl("jdbc:invalid"); try { ds = new HikariDataSource(config); } catch (RuntimeException e) { assertTrue(e.getMessage().contains("claims to not accept")); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/MetricsTrackerTest.java000066400000000000000000000055321315431642000302420ustar00rootroot00000000000000package com.zaxxer.hikari.pool; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.metrics.IMetricsTracker; import com.zaxxer.hikari.mocks.StubDataSource; import org.junit.Test; import java.sql.Connection; import java.sql.SQLTransientConnectionException; import java.util.concurrent.TimeUnit; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static junit.framework.TestCase.fail; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** * @author wvuong@chariotsolutions.com on 2/16/17. */ public class MetricsTrackerTest { @Test(expected = SQLTransientConnectionException.class) public void connectionTimeoutIsRecorded() throws Exception { int timeoutMillis = 1000; int timeToCreateNewConnectionMillis = timeoutMillis * 2; StubDataSource stubDataSource = new StubDataSource(); stubDataSource.setConnectionAcquistionTime(timeToCreateNewConnectionMillis); StubMetricsTracker metricsTracker = new StubMetricsTracker(); try (HikariDataSource ds = newHikariDataSource()) { ds.setMinimumIdle(0); ds.setMaximumPoolSize(1); ds.setConnectionTimeout(timeoutMillis); ds.setDataSource(stubDataSource); ds.setMetricsTrackerFactory((poolName, poolStats) -> metricsTracker); try (Connection c = ds.getConnection()) { fail("Connection shouldn't have been successfully created due to configured connection timeout"); } finally { // assert that connection timeout was measured assertThat(metricsTracker.connectionTimeoutRecorded, is(true)); // assert that measured time to acquire connection should be roughly equal or greater than the configured connection timeout time assertTrue(metricsTracker.connectionAcquiredNanos >= TimeUnit.NANOSECONDS.convert(timeoutMillis, TimeUnit.MILLISECONDS)); } } } private static class StubMetricsTracker implements IMetricsTracker { private Long connectionCreatedMillis; private Long connectionAcquiredNanos; private Long connectionBorrowedMillis; private boolean connectionTimeoutRecorded; @Override public void recordConnectionCreatedMillis(long connectionCreatedMillis) { this.connectionCreatedMillis = connectionCreatedMillis; } @Override public void recordConnectionAcquiredNanos(long elapsedAcquiredNanos) { this.connectionAcquiredNanos = elapsedAcquiredNanos; } @Override public void recordConnectionUsageMillis(long elapsedBorrowedMillis) { this.connectionBorrowedMillis = elapsedBorrowedMillis; } @Override public void recordConnectionTimeout() { this.connectionTimeoutRecorded = true; } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/MiscTest.java000066400000000000000000000106451315431642000262140ustar00rootroot00000000000000/* * 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.setConfigUnitTest; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static com.zaxxer.hikari.pool.TestElf.setSlf4jTargetStream; import static com.zaxxer.hikari.util.UtilityElf.createInstance; import static com.zaxxer.hikari.util.UtilityElf.getTransactionIsolation; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Level; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; /** * @author Brett Wooldridge */ public class MiscTest { @Test public void testLogWriter() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(4); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); setConfigUnitTest(true); try (HikariDataSource ds = new HikariDataSource(config)) { PrintWriter writer = new PrintWriter(System.out); ds.setLogWriter(writer); assertSame(writer, ds.getLogWriter()); assertEquals("testLogWriter", config.getPoolName()); } finally { setConfigUnitTest(false); } } @Test public void testInvalidIsolation() { try { getTransactionIsolation("INVALID"); fail(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } @Test public void testCreateInstance() { try { createInstance("invalid", null); fail(); } catch (RuntimeException e) { assertTrue(e.getCause() instanceof ClassNotFoundException); } } @Test public void testLeakDetection() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (PrintStream ps = new PrintStream(baos, true)) { setSlf4jTargetStream(Class.forName("com.zaxxer.hikari.pool.ProxyLeakTask"), ps); setConfigUnitTest(true); HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(4); config.setThreadFactory(Executors.defaultThreadFactory()); config.setMetricRegistry(null); config.setLeakDetectionThreshold(TimeUnit.SECONDS.toMillis(1)); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { setSlf4jLogLevel(HikariPool.class, Level.DEBUG); getPool(ds).logPoolState(); try (Connection connection = ds.getConnection()) { quietlySleep(SECONDS.toMillis(4)); connection.close(); quietlySleep(SECONDS.toMillis(1)); ps.close(); String s = new String(baos.toByteArray()); assertNotNull("Exception string was null", s); assertTrue("Expected exception to contain 'Connection leak detection' but contains *" + s + "*", s.contains("Connection leak detection")); } } finally { setConfigUnitTest(false); setSlf4jLogLevel(HikariPool.class, Level.INFO); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/PostgresTest.java000066400000000000000000000173261315431642000271320ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.TimeUnit.MINUTES; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.Before; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.UtilityElf; /** * This test is meant to be run manually and interactively and was * build for issue #159. * * @author Brett Wooldridge */ public class PostgresTest { //@Test public void testCase1() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(3); config.setMaximumPoolSize(10); config.setConnectionTimeout(3000); config.setIdleTimeout(TimeUnit.SECONDS.toMillis(10)); config.setValidationTimeout(TimeUnit.SECONDS.toMillis(2)); config.setJdbcUrl("jdbc:pgsql://localhost:5432/test"); config.setUsername("brettw"); try (final HikariDataSource ds = new HikariDataSource(config)) { final long start = currentTime(); do { Thread t = new Thread() { public void run() { try (Connection connection = ds.getConnection()) { System.err.println("Obtained connection " + connection); quietlySleep(TimeUnit.SECONDS.toMillis((long)(10 + (Math.random() * 20)))); } catch (SQLException e) { e.printStackTrace(); } } }; t.setDaemon(true); t.start(); quietlySleep(TimeUnit.SECONDS.toMillis((long)((Math.random() * 20)))); } while (elapsedMillis(start) < MINUTES.toMillis(15)); } } //@Test public void testCase2() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(3); config.setMaximumPoolSize(10); config.setConnectionTimeout(1000); config.setIdleTimeout(TimeUnit.SECONDS.toMillis(60)); config.setJdbcUrl("jdbc:pgsql://localhost:5432/test"); config.setUsername("brettw"); try (HikariDataSource ds = new HikariDataSource(config)) { try (Connection conn = ds.getConnection()) { System.err.println("\nGot a connection, and released it. Now, enable the firewall."); } getPool(ds).logPoolState(); quietlySleep(5000L); System.err.println("\nNow attempting another getConnection(), expecting a timeout..."); long start = currentTime(); try (Connection conn = ds.getConnection()) { System.err.println("\nOpps, got a connection. Did you enable the firewall? " + conn); fail("Opps, got a connection. Did you enable the firewall?"); } catch (SQLException e) { assertTrue("Timeout less than expected " + elapsedMillis(start) + "ms", elapsedMillis(start) > 5000); } System.err.println("\nOk, so far so good. Now, disable the firewall again. Attempting connection in 5 seconds..."); quietlySleep(5000L); getPool(ds).logPoolState(); try (Connection conn = ds.getConnection()) { System.err.println("\nGot a connection, and released it."); } } System.err.println("\nPassed."); } //@Test public void testCase3() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(3); config.setMaximumPoolSize(10); config.setConnectionTimeout(1000); config.setIdleTimeout(TimeUnit.SECONDS.toMillis(60)); config.setJdbcUrl("jdbc:pgsql://localhost:5432/test"); config.setUsername("brettw"); try (final HikariDataSource ds = new HikariDataSource(config)) { for (int i = 0; i < 10; i++) { new Thread() { public void run() { try (Connection conn = ds.getConnection()) { System.err.println("ERROR: should not have acquired connection."); } catch (SQLException e) { // expected } } }.start(); } quietlySleep(5000L); System.err.println("Now, bring the DB online. Checking pool in 15 seconds."); quietlySleep(15000L); getPool(ds).logPoolState(); } } // @Test public void testCase4() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(15); config.setConnectionTimeout(10000); config.setIdleTimeout(TimeUnit.MINUTES.toMillis(1)); config.setMaxLifetime(TimeUnit.MINUTES.toMillis(2)); config.setRegisterMbeans(true); config.setJdbcUrl("jdbc:postgresql://localhost:5432/netld"); config.setUsername("brettw"); try (final HikariDataSource ds = new HikariDataSource(config)) { countdown(20); List threads = new ArrayList<>(); for (int i = 0; i < 20; i++) { threads.add(new Thread() { public void run() { UtilityElf.quietlySleep((long)(Math.random() * 2500L)); final long start = currentTime(); do { try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SELECT * FROM device WHERE device_id=0 ORDER BY device_id LIMIT 1 OFFSET 0")) { rs.next(); } UtilityElf.quietlySleep(100L); //Math.max(50L, (long)(Math.random() * 250L))); } catch (SQLException e) { e.printStackTrace(); // throw new RuntimeException(e); } // UtilityElf.quietlySleep(10L); //Math.max(50L, (long)(Math.random() * 250L))); } while (elapsedMillis(start) < TimeUnit.MINUTES.toMillis(5)); } }); } // threads.forEach(t -> t.start()); // threads.forEach(t -> { try { t.join(); } catch (InterruptedException e) {} }); } } @Before public void before() { System.err.println("\n"); } private void countdown(int seconds) { do { System.out.printf("Starting in %d seconds...\n", seconds); if (seconds > 10) { UtilityElf.quietlySleep(TimeUnit.SECONDS.toMillis(10)); seconds -= 10; } else { UtilityElf.quietlySleep(TimeUnit.SECONDS.toMillis(1)); seconds -= 1; } } while (seconds > 0); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/RampUpDown.java000077500000000000000000000046431315431642000265210ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static org.junit.Assert.assertSame; import java.sql.Connection; import java.sql.SQLException; import org.junit.Assert; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; public class RampUpDown { @Test public void rampUpDownTest() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(60); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "250"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.setIdleTimeout(1000); HikariPool pool = getPool(ds); // wait two housekeeping periods so we don't fail if this part of test runs too quickly quietlySleep(500); Assert.assertSame("Total connections not as expected", 5, pool.getTotalConnections()); Connection[] connections = new Connection[ds.getMaximumPoolSize()]; for (int i = 0; i < connections.length; i++) { connections[i] = ds.getConnection(); } assertSame("Total connections not as expected", 60, pool.getTotalConnections()); for (Connection connection : connections) { connection.close(); } quietlySleep(500); assertSame("Total connections not as expected", 5, pool.getTotalConnections()); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/SaturatedPoolTest830.java000066400000000000000000000136371315431642000303460ustar00rootroot00000000000000/* * Copyright (C) 2017 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.pool; import static com.zaxxer.hikari.pool.TestElf.getConcurrentBag; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.lang.Math.round; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.logging.log4j.Level; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.mocks.StubStatement; /** * @author Brett Wooldridge */ public class SaturatedPoolTest830 { private static final Logger LOGGER = LoggerFactory.getLogger(SaturatedPoolTest830.class); private static final int MAX_POOL_SIZE = 10; @Test public void saturatedPoolTest() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(MAX_POOL_SIZE); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTimeout(1000); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); StubConnection.slowCreate = true; StubStatement.setSimulatedQueryTime(1000); setSlf4jLogLevel(HikariPool.class, Level.DEBUG); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "5000"); final long start = currentTime(); try (final HikariDataSource ds = new HikariDataSource(config)) { LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 50 /*core*/, 50 /*max*/, 2 /*keepalive*/, SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy()); threadPool.allowCoreThreadTimeOut(true); AtomicInteger windowIndex = new AtomicInteger(); boolean[] failureWindow = new boolean[100]; Arrays.fill(failureWindow, true); // Initial saturation for (int i = 0; i < 50; i++) { threadPool.execute(() -> { try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement()) { stmt.execute("SELECT bogus FROM imaginary"); } catch (SQLException e) { LOGGER.info(e.getMessage()); } }); } long sleep = 80; outer: while (true) { quietlySleep(sleep); if (elapsedMillis(start) > SECONDS.toMillis(12) && sleep < 100) { sleep = 100; LOGGER.warn("Switching to 100ms sleep"); } else if (elapsedMillis(start) > SECONDS.toMillis(6) && sleep < 90) { sleep = 90; LOGGER.warn("Switching to 90ms sleep"); } threadPool.execute(() -> { int ndx = windowIndex.incrementAndGet() % failureWindow.length; try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement()) { stmt.execute("SELECT bogus FROM imaginary"); failureWindow[ndx] = false; } catch (SQLException e) { LOGGER.info(e.getMessage()); failureWindow[ndx] = true; } }); for (int i = 0; i < failureWindow.length; i++) { if (failureWindow[i]) { if (elapsedMillis(start) % (SECONDS.toMillis(1) - sleep) < sleep) { LOGGER.info("Active threads {}, submissions per second {}, waiting threads {}", threadPool.getActiveCount(), SECONDS.toMillis(1) / sleep, getPool(ds).getThreadsAwaitingConnection()); } continue outer; } } LOGGER.info("Timeouts have subsided."); LOGGER.info("Active threads {}, submissions per second {}, waiting threads {}", threadPool.getActiveCount(), SECONDS.toMillis(1) / sleep, getPool(ds).getThreadsAwaitingConnection()); break; } LOGGER.info("Waiting for completion of {} active tasks.", threadPool.getActiveCount()); while (getPool(ds).getActiveConnections() > 0) { quietlySleep(50); } assertEquals("Rate not in balance at 10req/s", SECONDS.toMillis(1) / sleep, 10L); } finally { StubStatement.setSimulatedQueryTime(0); StubConnection.slowCreate = false; System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); setSlf4jLogLevel(HikariPool.class, Level.INFO); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/ShutdownTest.java000066400000000000000000000272601315431642000271350ustar00rootroot00000000000000/* * Copyright (C) 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.util.UtilityElf; /** * @author Brett Wooldridge */ public class ShutdownTest { @Before public void beforeTest() { setSlf4jLogLevel(PoolBase.class, Level.DEBUG); setSlf4jLogLevel(HikariPool.class, Level.DEBUG); StubConnection.count.set(0); } @After public void afterTest() { setSlf4jLogLevel(PoolBase.class, Level.WARN); setSlf4jLogLevel(HikariPool.class, Level.WARN); StubConnection.slowCreate = false; } @Test public void testShutdown1() throws SQLException { Assert.assertSame("StubConnection count not as expected", 0, StubConnection.count.get()); StubConnection.slowCreate = true; HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(10); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { threads[i] = new Thread() { @Override public void run() { try { if (ds.getConnection() != null) { quietlySleep(SECONDS.toMillis(1)); } } catch (SQLException e) { } } }; threads[i].setDaemon(true); } for (int i = 0; i < 10; i++) { threads[i].start(); } quietlySleep(1800L); assertTrue("Total connection count not as expected, ", pool.getTotalConnections() > 0); ds.close(); assertSame("Active connection count not as expected, ", 0, pool.getActiveConnections()); assertSame("Idle connection count not as expected, ", 0, pool.getIdleConnections()); assertSame("Total connection count not as expected, ", 0, pool.getTotalConnections()); assertTrue(ds.isClosed()); } } @Test public void testShutdown2() throws SQLException { assertSame("StubConnection count not as expected", 0, StubConnection.count.get()); StubConnection.slowCreate = true; HikariConfig config = newHikariConfig(); config.setMinimumIdle(10); config.setMaximumPoolSize(10); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); quietlySleep(1200L); assertTrue("Total connection count not as expected, ", pool.getTotalConnections() > 0); ds.close(); assertSame("Active connection count not as expected, ", 0, pool.getActiveConnections()); assertSame("Idle connection count not as expected, ", 0, pool.getIdleConnections()); assertSame("Total connection count not as expected, ", 0, pool.getTotalConnections()); assertTrue(ds.toString().startsWith("HikariDataSource (") && ds.toString().endsWith(")")); } } @Test public void testShutdown3() throws SQLException { assertSame("StubConnection count not as expected", 0, StubConnection.count.get()); StubConnection.slowCreate = false; HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(5); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); quietlySleep(1200L); assertTrue("Total connection count not as expected, ", pool.getTotalConnections() == 5); ds.close(); assertSame("Active connection count not as expected, ", 0, pool.getActiveConnections()); assertSame("Idle connection count not as expected, ", 0, pool.getIdleConnections()); assertSame("Total connection count not as expected, ", 0, pool.getTotalConnections()); } } @Test public void testShutdown4() throws SQLException { StubConnection.slowCreate = true; HikariConfig config = newHikariConfig(); config.setMinimumIdle(10); config.setMaximumPoolSize(10); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { quietlySleep(500L); ds.close(); long startTime = currentTime(); while (elapsedMillis(startTime) < SECONDS.toMillis(5) && threadCount() > 0) { quietlySleep(250); } assertSame("Unreleased connections after shutdown", 0, getPool(ds).getTotalConnections()); } } @Test public void testShutdown5() throws SQLException { Assert.assertSame("StubConnection count not as expected", 0, StubConnection.count.get()); HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(5); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); Connection[] connections = new Connection[5]; for (int i = 0; i < 5; i++) { connections[i] = ds.getConnection(); } Assert.assertTrue("Total connection count not as expected, ", pool.getTotalConnections() == 5); ds.close(); Assert.assertSame("Active connection count not as expected, ", 0, pool.getActiveConnections()); Assert.assertSame("Idle connection count not as expected, ", 0, pool.getIdleConnections()); Assert.assertSame("Total connection count not as expected, ", 0, pool.getTotalConnections()); } } @Test public void testAfterShutdown() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(5); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.close(); try { ds.getConnection(); } catch (SQLException e) { Assert.assertTrue(e.getMessage().contains("has been closed.")); } } } @Test public void testShutdownDuringInit() throws Exception { final HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(5); config.setConnectionTimeout(1000); config.setValidationTimeout(1000); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { StubConnection.slowCreate = true; UtilityElf.quietlySleep(3000L); } } @Test public void testThreadedShutdown() throws Exception { final HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(5); config.setConnectionTimeout(1000); config.setValidationTimeout(1000); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); for (int i = 0; i < 4; i++) { try (final HikariDataSource ds = new HikariDataSource(config)) { Thread t = new Thread() { @Override public void run() { try (Connection connection = ds.getConnection()) { for (int i = 0; i < 10; i++) { Connection connection2 = null; try { connection2 = ds.getConnection(); PreparedStatement stmt = connection2.prepareStatement("SOMETHING"); UtilityElf.quietlySleep(20); stmt.getMaxFieldSize(); } catch (SQLException e) { try { if (connection2 != null) { connection2.close(); } } catch (SQLException e2) { if (e2.getMessage().contains("shutdown") || e2.getMessage().contains("evicted")) { break; } } } } } catch (Exception e) { Assert.fail(e.getMessage()); } finally { ds.close(); } } }; t.start(); Thread t2 = new Thread() { @Override public void run() { UtilityElf.quietlySleep(100); try { ds.close(); } catch (IllegalStateException e) { Assert.fail(e.getMessage()); } } }; t2.start(); t.join(); t2.join(); ds.close(); } } } private int threadCount() { Thread[] threads = new Thread[Thread.activeCount() * 2]; Thread.enumerate(threads); int count = 0; for (Thread thread : threads) { count += (thread != null && thread.getName().startsWith("Hikari")) ? 1 : 0; } return count; } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/StatementTest.java000066400000000000000000000065431315431642000272670ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; public class StatementTest { private HikariDataSource ds; @Before public void setup() { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(2); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); ds = new HikariDataSource(config); } @After public void teardown() { ds.close(); } @Test public void testStatementClose() throws SQLException { ds.getConnection().close(); HikariPool pool = getPool(ds); assertTrue("Total connections not as expected", pool.getTotalConnections() >= 1); assertTrue("Idle connections not as expected", pool.getIdleConnections() >= 1); try (Connection connection = ds.getConnection()) { assertNotNull(connection); assertTrue("Total connections not as expected", pool.getTotalConnections() >= 1); assertTrue("Idle connections not as expected", pool.getIdleConnections() >= 0); Statement statement = connection.createStatement(); assertNotNull(statement); connection.close(); assertTrue(statement.isClosed()); } } @Test public void testAutoStatementClose() throws SQLException { try (Connection connection = ds.getConnection()) { assertNotNull(connection); Statement statement1 = connection.createStatement(); assertNotNull(statement1); Statement statement2 = connection.createStatement(); assertNotNull(statement2); connection.close(); assertTrue(statement1.isClosed()); assertTrue(statement2.isClosed()); } } @Test public void testDoubleStatementClose() throws SQLException { try (Connection connection = ds.getConnection(); Statement statement1 = connection.createStatement()) { statement1.close(); statement1.close(); } } @Test public void testOutOfOrderStatementClose() throws SQLException { try (Connection connection = ds.getConnection(); Statement statement1 = connection.createStatement(); Statement statement2 = connection.createStatement()) { statement1.close(); statement2.close(); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestConcurrentBag.java000066400000000000000000000071151315431642000300530ustar00rootroot00000000000000/* * 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.pool; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jTargetStream; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.concurrent.CompletableFuture; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.ConcurrentBag; /** * * @author Brett Wooldridge */ public class TestConcurrentBag { private static HikariDataSource ds; private static HikariPool pool; @BeforeClass public static void setup() { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(2); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); ds = new HikariDataSource(config); pool = getPool(ds); } @AfterClass public static void teardown() { ds.close(); } @Test public void testConcurrentBag() throws Exception { try (ConcurrentBag bag = new ConcurrentBag<>((x) -> CompletableFuture.completedFuture(Boolean.TRUE))) { assertEquals(0, bag.values(8).size()); PoolEntry reserved = pool.newPoolEntry(); bag.add(reserved); bag.reserve(reserved); // reserved PoolEntry inuse = pool.newPoolEntry(); bag.add(inuse); bag.borrow(2, MILLISECONDS); // in use PoolEntry notinuse = pool.newPoolEntry(); bag.add(notinuse); // not in use bag.dumpState(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos, true); setSlf4jTargetStream(ConcurrentBag.class, ps); bag.requite(reserved); bag.remove(notinuse); assertTrue(new String(baos.toByteArray()).contains("not borrowed or reserved")); bag.unreserve(notinuse); assertTrue(new String(baos.toByteArray()).contains("was not reserved")); bag.remove(inuse); bag.remove(inuse); assertTrue(new String(baos.toByteArray()).contains("not borrowed or reserved")); bag.close(); try { PoolEntry bagEntry = pool.newPoolEntry(); bag.add(bagEntry); assertNotEquals(bagEntry, bag.borrow(100, MILLISECONDS)); } catch (IllegalStateException e) { assertTrue(new String(baos.toByteArray()).contains("ignoring add()")); } assertNotNull(notinuse.toString()); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestConnectionCloseBlocking.java000066400000000000000000000071561315431642000320620ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; import java.sql.Connection; import java.sql.SQLException; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.MockDataSource; /** * Test for cases when db network connectivity goes down and close is called on existing connections. By default Hikari * blocks longer than getMaximumTimeout (it can hang for a lot of time depending on driver timeout settings). Closing * async the connections fixes this issue. * */ public class TestConnectionCloseBlocking { private static volatile boolean shouldFail = false; // @Test public void testConnectionCloseBlocking() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(1500); config.setDataSource(new CustomMockDataSource()); long start = currentTime(); try (HikariDataSource ds = new HikariDataSource(config); Connection connection = ds.getConnection()) { connection.close(); // Hikari only checks for validity for connections with lastAccess > 1000 ms so we sleep for 1001 ms to force // Hikari to do a connection validation which will fail and will trigger the connection to be closed quietlySleep(1100L); shouldFail = true; // on physical connection close we sleep 2 seconds try (Connection connection2 = ds.getConnection()) { assertTrue("Waited longer than timeout", (elapsedMillis(start) < config.getConnectionTimeout())); } } catch (SQLException e) { assertTrue("getConnection failed because close connection took longer than timeout", (elapsedMillis(start) < config.getConnectionTimeout())); } } private static class CustomMockDataSource extends MockDataSource { @Override public Connection getConnection() throws SQLException { Connection mockConnection = super.getConnection(); when(mockConnection.isValid(anyInt())).thenReturn(!shouldFail); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { if (shouldFail) { SECONDS.sleep(2); } return null; } }).when(mockConnection).close(); return mockConnection; } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestConnectionTimeoutRetry.java000066400000000000000000000227651315431642000320230ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static com.zaxxer.hikari.pool.TestElf.setSlf4jTargetStream; import static com.zaxxer.hikari.util.ClockSource.currentTime; import static com.zaxxer.hikari.util.ClockSource.elapsedMillis; import static java.lang.Thread.sleep; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.mocks.StubDataSource; public class TestConnectionTimeoutRetry { @Test public void testConnectionRetries() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(2800); config.setValidationTimeout(2800); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { StubDataSource stubDataSource = ds.unwrap(StubDataSource.class); stubDataSource.setThrowException(new SQLException("Connection refused")); long start = currentTime(); try (Connection connection = ds.getConnection()) { connection.close(); fail("Should not have been able to get a connection."); } catch (SQLException e) { long elapsed = elapsedMillis(start); long timeout = config.getConnectionTimeout(); assertTrue("Didn't wait long enough for timeout", (elapsed >= timeout)); } } } @Test public void testConnectionRetries2() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(2800); config.setValidationTimeout(2800); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { final StubDataSource stubDataSource = ds.unwrap(StubDataSource.class); stubDataSource.setThrowException(new SQLException("Connection refused")); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.schedule(new Runnable() { @Override public void run() { stubDataSource.setThrowException(null); } }, 300, TimeUnit.MILLISECONDS); long start = currentTime(); try { try (Connection connection = ds.getConnection()) { // close immediately } long elapsed = elapsedMillis(start); assertTrue("Connection returned too quickly, something is wrong.", elapsed > 250); assertTrue("Waited too long to get a connection.", elapsed < config.getConnectionTimeout()); } catch (SQLException e) { fail("Should not have timed out: " + e.getMessage()); } finally { scheduler.shutdownNow(); } } } @Test public void testConnectionRetries3() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(2); config.setConnectionTimeout(2800); config.setValidationTimeout(2800); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { final Connection connection1 = ds.getConnection(); final Connection connection2 = ds.getConnection(); assertNotNull(connection1); assertNotNull(connection2); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); scheduler.schedule(new Runnable() { @Override public void run() { try { connection1.close(); } catch (Exception e) { e.printStackTrace(System.err); } } }, 800, MILLISECONDS); long start = currentTime(); try { try (Connection connection3 = ds.getConnection()) { // close immediately } long elapsed = elapsedMillis(start); assertTrue("Waited too long to get a connection.", (elapsed >= 700) && (elapsed < 950)); } catch (SQLException e) { fail("Should not have timed out."); } finally { scheduler.shutdownNow(); } } } @Test public void testConnectionRetries5() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(2); config.setConnectionTimeout(1000); config.setValidationTimeout(1000); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { final Connection connection1 = ds.getConnection(); long start = currentTime(); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); scheduler.schedule(new Runnable() { @Override public void run() { try { connection1.close(); } catch (Exception e) { e.printStackTrace(System.err); } } }, 250, MILLISECONDS); StubDataSource stubDataSource = ds.unwrap(StubDataSource.class); stubDataSource.setThrowException(new SQLException("Connection refused")); try { try (Connection connection2 = ds.getConnection()) { // close immediately } long elapsed = elapsedMillis(start); assertTrue("Waited too long to get a connection.", (elapsed >= 250) && (elapsed < config.getConnectionTimeout())); } catch (SQLException e) { fail("Should not have timed out."); } finally { scheduler.shutdownNow(); } } } @Test public void testConnectionIdleFill() throws Exception { StubConnection.slowCreate = false; HikariConfig config = newHikariConfig(); config.setMinimumIdle(5); config.setMaximumPoolSize(10); config.setConnectionTimeout(2000); config.setValidationTimeout(2000); config.setConnectionTestQuery("VALUES 2"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "400"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos, true); setSlf4jTargetStream(HikariPool.class, ps); try (HikariDataSource ds = new HikariDataSource(config)) { setSlf4jLogLevel(HikariPool.class, Level.DEBUG); HikariPool pool = getPool(ds); try ( Connection connection1 = ds.getConnection(); Connection connection2 = ds.getConnection(); Connection connection3 = ds.getConnection(); Connection connection4 = ds.getConnection(); Connection connection5 = ds.getConnection(); Connection connection6 = ds.getConnection(); Connection connection7 = ds.getConnection()) { sleep(1300); assertSame("Total connections not as expected", 10, pool.getTotalConnections()); assertSame("Idle connections not as expected", 3, pool.getIdleConnections()); } assertSame("Total connections not as expected", 10, pool.getTotalConnections()); assertSame("Idle connections not as expected", 10, pool.getIdleConnections()); } } @Before public void before() { setSlf4jLogLevel(HikariPool.class, Level.INFO); } @After public void after() { System.getProperties().remove("com.zaxxer.hikari.housekeeping.periodMs"); setSlf4jLogLevel(HikariPool.class, Level.INFO); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestConnections.java000066400000000000000000000523441315431642000276050ustar00rootroot00000000000000/* * 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static com.zaxxer.hikari.pool.TestElf.getPool; import static com.zaxxer.hikari.pool.TestElf.setConfigUnitTest; import static com.zaxxer.hikari.pool.TestElf.setSlf4jLogLevel; import static com.zaxxer.hikari.pool.TestElf.setSlf4jTargetStream; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; import java.sql.Statement; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.mocks.StubDataSource; import com.zaxxer.hikari.mocks.StubStatement; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; /** * @author Brett Wooldridge */ public class TestConnections { @Before public void before() { setSlf4jTargetStream(HikariPool.class, System.err); setSlf4jLogLevel(HikariPool.class, Level.DEBUG); setSlf4jLogLevel(PoolBase.class, Level.DEBUG); } @After public void after() { System.getProperties().remove("com.zaxxer.hikari.housekeeping.periodMs"); setSlf4jLogLevel(HikariPool.class, Level.WARN); setSlf4jLogLevel(PoolBase.class, Level.WARN); } @Test public void testCreate() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setConnectionInitSql("SELECT 1"); config.setReadOnly(true); config.setConnectionTimeout(2500); config.setLeakDetectionThreshold(TimeUnit.SECONDS.toMillis(30)); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.setLoginTimeout(10); assertSame(10, ds.getLoginTimeout()); HikariPool pool = getPool(ds); ds.getConnection().close(); assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); try (Connection connection = ds.getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT * FROM device WHERE device_id=?")) { assertNotNull(connection); assertNotNull(statement); assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 0, pool.getIdleConnections()); statement.setInt(1, 0); try (ResultSet resultSet = statement.executeQuery()) { assertNotNull(resultSet); assertFalse(resultSet.next()); } } assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); } } @Test public void testMaxLifetime() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(2500); config.setConnectionTestQuery("VALUES 1"); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "100"); setConfigUnitTest(true); try (HikariDataSource ds = new HikariDataSource(config)) { System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); ds.setMaxLifetime(700); HikariPool pool = getPool(ds); assertSame("Total connections not as expected", 0, pool.getTotalConnections()); assertSame("Idle connections not as expected", 0, pool.getIdleConnections()); Connection unwrap; Connection unwrap2; try (Connection connection = ds.getConnection()) { unwrap = connection.unwrap(Connection.class); assertNotNull(connection); assertSame("Second total connections not as expected", 1, pool.getTotalConnections()); assertSame("Second idle connections not as expected", 0, pool.getIdleConnections()); } assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); try (Connection connection = ds.getConnection()) { unwrap2 = connection.unwrap(Connection.class); assertSame(unwrap, unwrap2); assertSame("Second total connections not as expected", 1, pool.getTotalConnections()); assertSame("Second idle connections not as expected", 0, pool.getIdleConnections()); } quietlySleep(TimeUnit.SECONDS.toMillis(2)); try (Connection connection = ds.getConnection()) { unwrap2 = connection.unwrap(Connection.class); assertNotSame("Expected a different connection", unwrap, unwrap2); } assertSame("Post total connections not as expected", 1, pool.getTotalConnections()); assertSame("Post idle connections not as expected", 1, pool.getIdleConnections()); } finally { setConfigUnitTest(false); } } @Test public void testMaxLifetime2() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(2500); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "100"); setConfigUnitTest(true); try (HikariDataSource ds = new HikariDataSource(config)) { ds.setMaxLifetime(700); HikariPool pool = getPool(ds); assertSame("Total connections not as expected", 0, pool.getTotalConnections()); assertSame("Idle connections not as expected", 0, pool.getIdleConnections()); Connection unwrap; Connection unwrap2; try (Connection connection = ds.getConnection()) { unwrap = connection.unwrap(Connection.class); assertNotNull(connection); assertSame("Second total connections not as expected", 1, pool.getTotalConnections()); assertSame("Second idle connections not as expected", 0, pool.getIdleConnections()); } assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); try (Connection connection = ds.getConnection()) { unwrap2 = connection.unwrap(Connection.class); assertSame(unwrap, unwrap2); assertSame("Second total connections not as expected", 1, pool.getTotalConnections()); assertSame("Second idle connections not as expected", 0, pool.getIdleConnections()); } quietlySleep(800); try (Connection connection = ds.getConnection()) { unwrap2 = connection.unwrap(Connection.class); assertNotSame("Expected a different connection", unwrap, unwrap2); } assertSame("Post total connections not as expected", 1, pool.getTotalConnections()); assertSame("Post idle connections not as expected", 1, pool.getIdleConnections()); } finally { setConfigUnitTest(false); } } @Test public void testDoubleClose() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setConnectionTimeout(2500); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config); Connection connection = ds.getConnection()) { connection.close(); // should no-op connection.abort(null); assertTrue("Connection should have closed", connection.isClosed()); assertFalse("Connection should have closed", connection.isValid(5)); assertTrue("Expected to contain ClosedConnection, but was " + connection, connection.toString().contains("ClosedConnection")); } } @Test public void testEviction() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(5); config.setConnectionTimeout(2500); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { Connection connection = ds.getConnection(); HikariPool pool = getPool(ds); assertEquals(1, pool.getTotalConnections()); ds.evictConnection(connection); assertEquals(0, pool.getTotalConnections()); } } @Test public void testBackfill() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(4); config.setConnectionTimeout(1000); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); quietlySleep(1250); assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); // This will take the pool down to zero try (Connection connection = ds.getConnection()) { assertNotNull(connection); assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 0, pool.getIdleConnections()); PreparedStatement statement = connection.prepareStatement("SELECT some, thing FROM somewhere WHERE something=?"); assertNotNull(statement); ResultSet resultSet = statement.executeQuery(); assertNotNull(resultSet); try { statement.getMaxFieldSize(); fail(); } catch (Exception e) { assertSame(SQLException.class, e.getClass()); } pool.logPoolState("testBackfill() before close..."); // The connection will be ejected from the pool here } assertSame("Total connections not as expected", 0, pool.getTotalConnections()); pool.logPoolState("testBackfill() after close..."); quietlySleep(1250); assertSame("Total connections not as expected", 1, pool.getTotalConnections()); assertSame("Idle connections not as expected", 1, pool.getIdleConnections()); } finally { StubConnection.slowCreate = false; } } @Test public void testMaximumPoolLimit() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(4); config.setConnectionTimeout(20000); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); final AtomicReference ref = new AtomicReference<>(); StubConnection.count.set(0); // reset counter try (final HikariDataSource ds = new HikariDataSource(config)) { final HikariPool pool = getPool(ds); Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { try { pool.logPoolState("Before acquire "); try (Connection connection = ds.getConnection()) { pool.logPoolState("After acquire "); quietlySleep(500); } } catch (Exception e) { ref.set(e); } } }); } for (int i = 0; i < threads.length; i++) { threads[i].start(); } for (int i = 0; i < threads.length; i++) { threads[i].join(); } pool.logPoolState("before check "); assertNull((ref.get() != null ? ref.get().toString() : ""), ref.get()); assertSame("StubConnection count not as expected", 4, StubConnection.count.get()); } } @Test public void testOldDriver() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setConnectionTimeout(2500); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); StubConnection.oldDriver = true; StubStatement.oldDriver = true; try (HikariDataSource ds = new HikariDataSource(config)) { quietlySleep(500); try (Connection connection = ds.getConnection()) { // close } quietlySleep(500); try (Connection connection = ds.getConnection()) { // close } } finally { StubConnection.oldDriver = false; StubStatement.oldDriver = false; } } @Test public void testSuspendResume() throws Exception { HikariConfig config = newHikariConfig(); config.setMinimumIdle(3); config.setMaximumPoolSize(3); config.setConnectionTimeout(2500); config.setAllowPoolSuspension(true); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (final HikariDataSource ds = new HikariDataSource(config)) { HikariPool pool = getPool(ds); while (pool.getTotalConnections() < 3) { quietlySleep(50); } Thread t = new Thread(new Runnable() { @Override public void run() { try { ds.getConnection(); ds.getConnection(); } catch (Exception e) { fail(); } } }); try (Connection c3 = ds.getConnection()) { assertEquals(2, pool.getIdleConnections()); pool.suspendPool(); t.start(); quietlySleep(500); assertEquals(2, pool.getIdleConnections()); } assertEquals(3, pool.getIdleConnections()); pool.resumePool(); quietlySleep(500); assertEquals(1, pool.getIdleConnections()); } } @Test public void testInitializationFailure1() throws SQLException { StubDataSource stubDataSource = new StubDataSource(); stubDataSource.setThrowException(new SQLException("Connection refused")); try (HikariDataSource ds = newHikariDataSource()) { ds.setMinimumIdle(1); ds.setMaximumPoolSize(1); ds.setConnectionTimeout(2500); ds.setConnectionTestQuery("VALUES 1"); ds.setDataSource(stubDataSource); try (Connection c = ds.getConnection()) { fail("Initialization should have failed"); } catch (SQLException e) { // passed } } } @Test public void testInitializationFailure2() throws SQLException { StubDataSource stubDataSource = new StubDataSource(); stubDataSource.setThrowException(new SQLException("Connection refused")); HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setConnectionTestQuery("VALUES 1"); config.setDataSource(stubDataSource); try (HikariDataSource ds = new HikariDataSource(config); Connection c = ds.getConnection()) { fail("Initialization should have failed"); } catch (PoolInitializationException e) { // passed } } @Test public void testInvalidConnectionTestQuery() { class BadConnection extends StubConnection { /** {@inheritDoc} */ @Override public Statement createStatement() throws SQLException { throw new SQLException("Simulated exception in createStatement()"); } } StubDataSource stubDataSource = new StubDataSource() { /** {@inheritDoc} */ @Override public Connection getConnection() throws SQLException { return new BadConnection(); } }; HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(2); config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3)); config.setConnectionTestQuery("VALUES 1"); config.setInitializationFailTimeout(TimeUnit.SECONDS.toMillis(2)); config.setDataSource(stubDataSource); try (HikariDataSource ds = new HikariDataSource(config)) { try (Connection c = ds.getConnection()) { fail("getConnection() should have failed"); } catch (SQLException e) { assertSame("Simulated exception in createStatement()", e.getNextException().getMessage()); } } catch (PoolInitializationException e) { assertSame("Simulated exception in createStatement()", e.getCause().getMessage()); } config.setInitializationFailTimeout(0); try (HikariDataSource ds = new HikariDataSource(config)) { fail("Initialization should have failed"); } catch (PoolInitializationException e) { // passed } } @Test public void testPopulationSlowAcquisition() throws InterruptedException, SQLException { HikariConfig config = newHikariConfig(); config.setMaximumPoolSize(20); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "1000"); StubConnection.slowCreate = true; try (HikariDataSource ds = new HikariDataSource(config)) { System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); ds.setIdleTimeout(3000); SECONDS.sleep(2); HikariPool pool = getPool(ds); assertSame("Total connections not as expected", 2, pool.getTotalConnections()); assertSame("Idle connections not as expected", 2, pool.getIdleConnections()); try (Connection connection = ds.getConnection()) { assertNotNull(connection); SECONDS.sleep(20); assertSame("Second total connections not as expected", 20, pool.getTotalConnections()); assertSame("Second idle connections not as expected", 19, pool.getIdleConnections()); } assertSame("Idle connections not as expected", 20, pool.getIdleConnections()); SECONDS.sleep(5); assertSame("Third total connections not as expected", 20, pool.getTotalConnections()); assertSame("Third idle connections not as expected", 20, pool.getIdleConnections()); } finally { StubConnection.slowCreate = false; } } @Test public void testMinimumIdleZero() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(5); config.setConnectionTimeout(1000L); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config); Connection connection = ds.getConnection()) { // passed } catch (SQLTransientConnectionException sqle) { fail("Failed to obtain connection"); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestElf.java000066400000000000000000000122711315431642000260240ustar00rootroot00000000000000/* * 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.pool; import java.io.PrintStream; import java.lang.reflect.Field; import java.sql.Connection; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.layout.CsvLogEventLayout; import org.apache.logging.slf4j.Log4jLogger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.util.ConcurrentBag; /** * Utility methods for testing. * * @author Brett Wooldridge */ public final class TestElf { private TestElf() { // default constructor } public static boolean isJava9() { return System.getProperty("java.version").startsWith("9"); } public static HikariPool getPool(HikariDataSource ds) { try { Field field = ds.getClass().getDeclaredField("pool"); field.setAccessible(true); return (HikariPool) field.get(ds); } catch (Exception e) { throw new RuntimeException(e); } } static ConcurrentBag getConcurrentBag(HikariDataSource ds) { try { Field field = HikariPool.class.getDeclaredField("connectionBag"); field.setAccessible(true); return (ConcurrentBag) field.get(getPool(ds)); } catch (Exception e) { throw new RuntimeException(e); } } static boolean getConnectionCommitDirtyState(Connection connection) { try { Field field = ProxyConnection.class.getDeclaredField("isCommitStateDirty"); field.setAccessible(true); return field.getBoolean(connection); } catch (Exception e) { throw new RuntimeException(e); } } static void setConfigUnitTest(boolean unitTest) { try { Field field = HikariConfig.class.getDeclaredField("unitTest"); field.setAccessible(true); field.setBoolean(null, unitTest); } catch (Exception e) { throw new RuntimeException(e); } } static void setSlf4jTargetStream(Class clazz, PrintStream stream) { try { Log4jLogger log4Jlogger = (Log4jLogger) LoggerFactory.getLogger(clazz); Field field = clazz.getClassLoader().loadClass("org.apache.logging.slf4j.Log4jLogger").getDeclaredField("logger"); field.setAccessible(true); Logger logger = (Logger) field.get(log4Jlogger); if (logger.getAppenders().containsKey("string")) { Appender appender = logger.getAppenders().get("string"); logger.removeAppender(appender); } logger.addAppender(new StringAppender("string", stream)); } catch (Exception e) { throw new RuntimeException(e); } } static void setSlf4jLogLevel(Class clazz, Level logLevel) { try { Log4jLogger log4Jlogger = (Log4jLogger) LoggerFactory.getLogger(clazz); Field field = clazz.getClassLoader().loadClass("org.apache.logging.slf4j.Log4jLogger").getDeclaredField("logger"); field.setAccessible(true); Logger logger = (Logger) field.get(log4Jlogger); logger.setLevel(logLevel); } catch (Exception e) { throw new RuntimeException(e); } } public static HikariConfig newHikariConfig() { final StackTraceElement callerStackTrace = Thread.currentThread().getStackTrace()[2]; String poolName = callerStackTrace.getMethodName(); if ("setup".equals(poolName)) { poolName = callerStackTrace.getClassName(); } final HikariConfig config = new HikariConfig(); config.setPoolName(poolName); return config; } static HikariDataSource newHikariDataSource() { final StackTraceElement callerStackTrace = Thread.currentThread().getStackTrace()[2]; String poolName = callerStackTrace.getMethodName(); if ("setup".equals(poolName)) { poolName = callerStackTrace.getClassName(); } final HikariDataSource ds = new HikariDataSource(); ds.setPoolName(poolName); return ds; } private static class StringAppender extends AbstractAppender { private PrintStream stream; StringAppender(String name, PrintStream stream) { super(name, null, CsvLogEventLayout.createDefaultLayout()); this.stream = stream; } @Override public void append(LogEvent event) { stream.println(event.getMessage().getFormattedMessage()); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestHibernate.java000066400000000000000000000032601315431642000272150ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.sql.Connection; import java.util.Properties; import org.hibernate.service.UnknownUnwrapTypeException; import org.junit.Test; import com.zaxxer.hikari.hibernate.HikariConnectionProvider; public class TestHibernate { @Test public void testConnectionProvider() throws Exception { HikariConnectionProvider provider = new HikariConnectionProvider(); Properties props = new Properties(); props.load(getClass().getResourceAsStream("/hibernate.properties")); provider.configure(props); Connection connection = provider.getConnection(); provider.closeConnection(connection); assertNotNull(provider.unwrap(HikariConnectionProvider.class)); assertFalse(provider.supportsAggressiveRelease()); try { provider.unwrap(TestHibernate.class); fail("Expected exception"); } catch (UnknownUnwrapTypeException e) { } provider.stop(); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestJNDI.java000066400000000000000000000126071315431642000260450ustar00rootroot00000000000000/* * Copyright (C) 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import com.zaxxer.hikari.HikariConfig; import org.junit.Test; import org.osjava.sj.jndi.AbstractContext; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariJNDIFactory; import com.zaxxer.hikari.mocks.StubDataSource; import java.sql.Connection; public class TestJNDI { @Test public void testJndiLookup1() throws Exception { HikariJNDIFactory jndi = new HikariJNDIFactory(); Reference ref = new Reference("javax.sql.DataSource"); ref.add(new BogusRef("driverClassName", "com.zaxxer.hikari.mocks.StubDriver")); ref.add(new BogusRef("jdbcUrl", "jdbc:stub")); ref.add(new BogusRef("username", "foo")); ref.add(new BogusRef("password", "foo")); ref.add(new BogusRef("minimumIdle", "0")); ref.add(new BogusRef("maxLifetime", "30000")); ref.add(new BogusRef("maximumPoolSize", "10")); ref.add(new BogusRef("dataSource.loginTimeout", "10")); Context nameCtx = new BogusContext(); try (HikariDataSource ds = (HikariDataSource) jndi.getObjectInstance(ref, null, nameCtx, null)) { assertNotNull(ds); assertEquals("foo", ds.getUsername()); } } @Test public void testJndiLookup2() throws Exception { HikariJNDIFactory jndi = new HikariJNDIFactory(); Reference ref = new Reference("javax.sql.DataSource"); ref.add(new BogusRef("dataSourceJNDI", "java:comp/env/HikariDS")); ref.add(new BogusRef("driverClassName", "com.zaxxer.hikari.mocks.StubDriver")); ref.add(new BogusRef("jdbcUrl", "jdbc:stub")); ref.add(new BogusRef("username", "foo")); ref.add(new BogusRef("password", "foo")); ref.add(new BogusRef("minimumIdle", "0")); ref.add(new BogusRef("maxLifetime", "30000")); ref.add(new BogusRef("maximumPoolSize", "10")); ref.add(new BogusRef("dataSource.loginTimeout", "10")); Context nameCtx = new BogusContext2(); try (HikariDataSource ds = (HikariDataSource) jndi.getObjectInstance(ref, null, nameCtx, null)) { assertNotNull(ds); assertEquals("foo", ds.getUsername()); } } @Test public void testJndiLookup3() throws Exception { HikariJNDIFactory jndi = new HikariJNDIFactory(); Reference ref = new Reference("javax.sql.DataSource"); ref.add(new BogusRef("dataSourceJNDI", "java:comp/env/HikariDS")); try { jndi.getObjectInstance(ref, null, null, null); fail(); } catch (RuntimeException e) { assertTrue(e.getMessage().contains("JNDI context does not found")); } } @Test public void testJndiLookup4() throws Exception { System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.osjava.sj.memory.MemoryContextFactory"); System.setProperty("org.osjava.sj.jndi.shared", "true"); InitialContext ic = new InitialContext(); StubDataSource ds = new StubDataSource(); Context subcontext = ic.createSubcontext("java:/comp/env/jdbc"); subcontext.bind("java:/comp/env/jdbc/myDS", ds); HikariConfig config = newHikariConfig(); config.setDataSourceJNDI("java:/comp/env/jdbc/myDS"); try (HikariDataSource hds = new HikariDataSource(config); Connection conn = hds.getConnection()) { assertNotNull(conn); } } private class BogusContext extends AbstractContext { @Override public Context createSubcontext(Name name) throws NamingException { return null; } @Override public Object lookup(String name) throws NamingException { final HikariDataSource ds = new HikariDataSource(); ds.setPoolName("TestJNDI"); return ds; } } private class BogusContext2 extends AbstractContext { @Override public Context createSubcontext(Name name) throws NamingException { return null; } @Override public Object lookup(String name) throws NamingException { return new StubDataSource(); } } private class BogusRef extends RefAddr { private static final long serialVersionUID = 1L; private String content; BogusRef(String type, String content) { super(type); this.content = content; } @Override public Object getContent() { return content; } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestMBean.java000066400000000000000000000066211315431642000263020ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariPoolMXBean; import org.junit.Test; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import java.lang.management.ManagementFactory; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.TimeUnit; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.junit.Assert.assertEquals; public class TestMBean { @Test public void testMBeanRegistration() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setRegisterMbeans(true); config.setConnectionTimeout(2800); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { // Close immediately } } @Test public void testMBeanReporting() throws SQLException, InterruptedException, MalformedObjectNameException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(3); config.setMaximumPoolSize(5); config.setRegisterMbeans(true); config.setConnectionTimeout(2800); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "100"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.setIdleTimeout(3000); TimeUnit.SECONDS.sleep(1); MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (testMBeanReporting)"); HikariPoolMXBean hikariPoolMXBean = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class); assertEquals(0, hikariPoolMXBean.getActiveConnections()); assertEquals(3, hikariPoolMXBean.getIdleConnections()); try (Connection connection = ds.getConnection()) { assertEquals(1, hikariPoolMXBean.getActiveConnections()); TimeUnit.SECONDS.sleep(1); assertEquals(3, hikariPoolMXBean.getIdleConnections()); assertEquals(4, hikariPoolMXBean.getTotalConnections()); } TimeUnit.SECONDS.sleep(2); assertEquals(0, hikariPoolMXBean.getActiveConnections()); assertEquals(3, hikariPoolMXBean.getIdleConnections()); assertEquals(3, hikariPoolMXBean.getTotalConnections()); } finally { System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs"); } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestMetrics.java000066400000000000000000000251141315431642000267240ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.newHikariDataSource; import static com.zaxxer.hikari.util.UtilityElf.quietlySleep; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import java.sql.Connection; import java.sql.SQLException; import java.util.SortedMap; import java.util.concurrent.TimeUnit; import org.junit.Test; import com.codahale.metrics.Histogram; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.codahale.metrics.health.HealthCheck.Result; import com.codahale.metrics.health.HealthCheckRegistry; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.metrics.MetricsTrackerFactory; import com.zaxxer.hikari.metrics.dropwizard.CodahaleMetricsTrackerFactory; import com.zaxxer.hikari.util.UtilityElf; /** * Test HikariCP/CodaHale metrics integration. * * @author Brett Wooldridge */ public class TestMetrics { @Test public void testMetricWait() throws SQLException { MetricRegistry metricRegistry = new MetricRegistry(); HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setMetricRegistry(metricRegistry); config.setInitializationFailTimeout(Long.MAX_VALUE); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.getConnection().close(); Timer timer = metricRegistry.getTimers(new MetricFilter() { /** {@inheritDoc} */ @Override public boolean matches(String name, Metric metric) { return "testMetricWait.pool.Wait".equals(MetricRegistry.name("testMetricWait", "pool", "Wait")); } }).values().iterator().next(); assertEquals(1, timer.getCount()); assertTrue(timer.getMeanRate() > 0.0); } } @Test public void testMetricUsage() throws SQLException { assumeFalse(System.getProperty("os.name").contains("Windows")); MetricRegistry metricRegistry = new MetricRegistry(); HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setMetricRegistry(metricRegistry); config.setInitializationFailTimeout(0); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { try (Connection connection = ds.getConnection()) { UtilityElf.quietlySleep(250L); } Histogram histo = metricRegistry.getHistograms(new MetricFilter() { /** {@inheritDoc} */ @Override public boolean matches(String name, Metric metric) { return name.equals(MetricRegistry.name("testMetricUsage", "pool", "Usage")); } }).values().iterator().next(); assertEquals(1, histo.getCount()); double seventyFifth = histo.getSnapshot().get75thPercentile(); assertTrue("Seventy-fith percentile less than 250ms: " + seventyFifth, seventyFifth >= 250.0); } } @Test public void testHealthChecks() throws Exception { MetricRegistry metricRegistry = new MetricRegistry(); HealthCheckRegistry healthRegistry = new HealthCheckRegistry(); HikariConfig config = newHikariConfig(); config.setMaximumPoolSize(10); config.setMetricRegistry(metricRegistry); config.setHealthCheckRegistry(healthRegistry); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.addHealthCheckProperty("connectivityCheckTimeoutMs", "1000"); config.addHealthCheckProperty("expected99thPercentileMs", "100"); try (HikariDataSource ds = new HikariDataSource(config)) { quietlySleep(TimeUnit.SECONDS.toMillis(2)); try (Connection connection = ds.getConnection()) { // close immediately } try (Connection connection = ds.getConnection()) { // close immediately } SortedMap healthChecks = healthRegistry.runHealthChecks(); Result connectivityResult = healthChecks.get("testHealthChecks.pool.ConnectivityCheck"); assertTrue(connectivityResult.isHealthy()); Result slaResult = healthChecks.get("testHealthChecks.pool.Connection99Percent"); assertTrue(slaResult.isHealthy()); } } @Test public void testSetters1() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setMaximumPoolSize(1); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); MetricRegistry metricRegistry = new MetricRegistry(); HealthCheckRegistry healthRegistry = new HealthCheckRegistry(); try { try (Connection connection = ds.getConnection()) { // close immediately } // After the pool as started, we can only set them once... ds.setMetricRegistry(metricRegistry); ds.setHealthCheckRegistry(healthRegistry); // and never again... ds.setMetricRegistry(metricRegistry); fail("Should not have been allowed to set registry after pool started"); } catch (IllegalStateException ise) { // pass try { ds.setHealthCheckRegistry(healthRegistry); fail("Should not have been allowed to set registry after pool started"); } catch (IllegalStateException ise2) { // pass } } } } @Test public void testSetters2() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setMaximumPoolSize(1); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); MetricRegistry metricRegistry = new MetricRegistry(); HealthCheckRegistry healthRegistry = new HealthCheckRegistry(); ds.setMetricRegistry(metricRegistry); ds.setHealthCheckRegistry(healthRegistry); // before the pool is started, we can set it any number of times... ds.setMetricRegistry(metricRegistry); ds.setHealthCheckRegistry(healthRegistry); try (Connection connection = ds.getConnection()) { // after the pool is started, we cannot set it any more ds.setMetricRegistry(metricRegistry); fail("Should not have been allowed to set registry after pool started"); } catch (IllegalStateException ise) { // pass } } } @Test public void testSetters3() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setMaximumPoolSize(1); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); MetricRegistry metricRegistry = new MetricRegistry(); MetricsTrackerFactory metricsTrackerFactory = new CodahaleMetricsTrackerFactory(metricRegistry); try (Connection connection = ds.getConnection()) { // After the pool as started, we can only set them once... ds.setMetricsTrackerFactory(metricsTrackerFactory); // and never again... ds.setMetricsTrackerFactory(metricsTrackerFactory); fail("Should not have been allowed to set metricsTrackerFactory after pool started"); } catch (IllegalStateException ise) { // pass try { // and never again... (even when calling another method) ds.setMetricRegistry(metricRegistry); fail("Should not have been allowed to set registry after pool started"); } catch (IllegalStateException ise2) { // pass } } } } @Test public void testSetters4() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setMaximumPoolSize(1); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); MetricRegistry metricRegistry = new MetricRegistry(); // before the pool is started, we can set it any number of times using either setter ds.setMetricRegistry(metricRegistry); ds.setMetricRegistry(metricRegistry); ds.setMetricRegistry(metricRegistry); try (Connection connection = ds.getConnection()) { // after the pool is started, we cannot set it any more ds.setMetricRegistry(metricRegistry); fail("Should not have been allowed to set registry after pool started"); } catch (IllegalStateException ise) { // pass } } } @Test public void testSetters5() throws Exception { try (HikariDataSource ds = newHikariDataSource()) { ds.setMaximumPoolSize(1); ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); MetricRegistry metricRegistry = new MetricRegistry(); MetricsTrackerFactory metricsTrackerFactory = new CodahaleMetricsTrackerFactory(metricRegistry); // before the pool is started, we can set it any number of times using either setter ds.setMetricsTrackerFactory(metricsTrackerFactory); ds.setMetricsTrackerFactory(metricsTrackerFactory); ds.setMetricsTrackerFactory(metricsTrackerFactory); try (Connection connection = ds.getConnection()) { // after the pool is started, we cannot set it any more ds.setMetricsTrackerFactory(metricsTrackerFactory); fail("Should not have been allowed to set registry factory after pool started"); } catch (IllegalStateException ise) { // pass } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestPropertySetter.java000066400000000000000000000074331315431642000303350ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.util.Properties; import java.util.Set; import javax.sql.DataSource; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.util.PropertyElf; public class TestPropertySetter { @Test public void testProperty1() throws Exception { Properties propfile1 = new Properties(); propfile1.load(TestPropertySetter.class.getResourceAsStream("/propfile1.properties")); HikariConfig config = new HikariConfig(propfile1); config.validate(); assertEquals(5, config.getMinimumIdle()); assertEquals("SELECT 1", config.getConnectionTestQuery()); } @Test public void testProperty2() throws Exception { Properties propfile2 = new Properties(); propfile2.load(TestPropertySetter.class.getResourceAsStream("/propfile2.properties")); HikariConfig config = new HikariConfig(propfile2); config.validate(); Class clazz = this.getClass().getClassLoader().loadClass(config.getDataSourceClassName()); DataSource dataSource = (DataSource) clazz.newInstance(); PropertyElf.setTargetFromProperties(dataSource, config.getDataSourceProperties()); } @Test public void testObjectProperty() throws Exception { HikariConfig config = newHikariConfig(); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); PrintWriter writer = new PrintWriter(new ByteArrayOutputStream()); config.addDataSourceProperty("logWriter", writer); Class clazz = this.getClass().getClassLoader().loadClass(config.getDataSourceClassName()); DataSource dataSource = (DataSource) clazz.newInstance(); PropertyElf.setTargetFromProperties(dataSource, config.getDataSourceProperties()); assertSame(PrintWriter.class, dataSource.getLogWriter().getClass()); } @Test public void testPropertyUpperCase() throws Exception { Properties propfile3 = new Properties(); propfile3.load(TestPropertySetter.class.getResourceAsStream("/propfile3.properties")); HikariConfig config = new HikariConfig(propfile3); config.validate(); Class clazz = this.getClass().getClassLoader().loadClass(config.getDataSourceClassName()); DataSource dataSource = (DataSource) clazz.newInstance(); PropertyElf.setTargetFromProperties(dataSource, config.getDataSourceProperties()); } @Test public void testGetPropertyNames() throws Exception { Set propertyNames = PropertyElf.getPropertyNames(HikariConfig.class); assertTrue(propertyNames.contains("dataSourceClassName")); } @Test public void testSetNonExistantPropertyName() throws Exception { try { Properties props = new Properties(); props.put("what", "happened"); PropertyElf.setTargetFromProperties(new HikariConfig(), props); fail(); } catch (RuntimeException e) { } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestProxies.java000066400000000000000000000217141315431642000267510ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.concurrent.TimeUnit; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.mocks.StubStatement; public class TestProxies { @Test public void testProxyCreation() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { Connection conn = ds.getConnection(); assertNotNull(conn.createStatement(ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE)); assertNotNull(conn.createStatement(ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.HOLD_CURSORS_OVER_COMMIT)); assertNotNull(conn.prepareCall("some sql")); assertNotNull(conn.prepareCall("some sql", ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE)); assertNotNull(conn.prepareCall("some sql", ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.HOLD_CURSORS_OVER_COMMIT)); assertNotNull(conn.prepareStatement("some sql", PreparedStatement.NO_GENERATED_KEYS)); assertNotNull(conn.prepareStatement("some sql", new int[3])); assertNotNull(conn.prepareStatement("some sql", new String[3])); assertNotNull(conn.prepareStatement("some sql", ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE)); assertNotNull(conn.prepareStatement("some sql", ResultSet.FETCH_FORWARD, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.HOLD_CURSORS_OVER_COMMIT)); assertNotNull(conn.toString()); assertTrue(conn.isWrapperFor(Connection.class)); assertTrue(conn.isValid(10)); assertFalse(conn.isClosed()); assertTrue(conn.unwrap(StubConnection.class) instanceof StubConnection); try { conn.unwrap(TestProxies.class); fail(); } catch (SQLException e) { // pass } } } @Test public void testStatementProxy() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { Connection conn = ds.getConnection(); PreparedStatement stmt = conn.prepareStatement("some sql"); stmt.executeQuery(); stmt.executeQuery("some sql"); assertFalse(stmt.isClosed()); assertNotNull(stmt.getGeneratedKeys()); assertNotNull(stmt.getResultSet()); assertNotNull(stmt.getConnection()); assertTrue(stmt.unwrap(StubStatement.class) instanceof StubStatement); try { stmt.unwrap(TestProxies.class); fail(); } catch (SQLException e) { // pass } } } @Test public void testStatementExceptions() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(1)); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { Connection conn = ds.getConnection(); StubConnection stubConnection = conn.unwrap(StubConnection.class); stubConnection.throwException = true; try { conn.createStatement(); fail(); } catch (SQLException e) { // pass } try { conn.createStatement(0, 0); fail(); } catch (SQLException e) { // pass } try { conn.createStatement(0, 0, 0); fail(); } catch (SQLException e) { // pass } try { conn.prepareCall(""); fail(); } catch (SQLException e) { // pass } try { conn.prepareCall("", 0, 0); fail(); } catch (SQLException e) { // pass } try { conn.prepareCall("", 0, 0, 0); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement(""); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement("", 0); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement("", new int[0]); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement("", new String[0]); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement("", 0, 0); fail(); } catch (SQLException e) { // pass } try { conn.prepareStatement("", 0, 0, 0); fail(); } catch (SQLException e) { // pass } } } @Test public void testOtherExceptions() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { try (Connection conn = ds.getConnection()) { StubConnection stubConnection = conn.unwrap(StubConnection.class); stubConnection.throwException = true; try { conn.setTransactionIsolation(Connection.TRANSACTION_NONE); fail(); } catch (SQLException e) { // pass } try { conn.isReadOnly(); fail(); } catch (SQLException e) { // pass } try { conn.setReadOnly(false); fail(); } catch (SQLException e) { // pass } try { conn.setCatalog(""); fail(); } catch (SQLException e) { // pass } try { conn.setAutoCommit(false); fail(); } catch (SQLException e) { // pass } try { conn.clearWarnings(); fail(); } catch (SQLException e) { // pass } try { conn.isValid(0); fail(); } catch (SQLException e) { // pass } try { conn.isWrapperFor(getClass()); fail(); } catch (SQLException e) { // pass } try { conn.unwrap(getClass()); fail(); } catch (SQLException e) { // pass } try { conn.close(); fail(); } catch (SQLException e) { // pass } try { assertFalse(conn.isValid(0)); } catch (SQLException e) { fail(); } } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/TestValidation.java000066400000000000000000000157071315431642000274170ustar00rootroot00000000000000/* * Copyright (C) 2014 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.setSlf4jTargetStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.concurrent.TimeUnit; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; /** * @author Brett Wooldridge */ public class TestValidation { @Test public void validateLoadProperties() { System.setProperty("hikaricp.configurationFile", "/propfile1.properties"); HikariConfig config = newHikariConfig(); System.clearProperty("hikaricp.configurationFile"); assertEquals(5, config.getMinimumIdle()); } @Test public void validateMissingProperties() { try { HikariConfig config = new HikariConfig("missing"); config.validate(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("property file")); } } @Test public void validateMissingDS() { try { HikariConfig config = newHikariConfig(); config.validate(); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("dataSource or dataSourceClassName or jdbcUrl is required.")); } } @Test public void validateMissingUrl() { try { HikariConfig config = newHikariConfig(); config.setDriverClassName("com.zaxxer.hikari.mocks.StubDriver"); config.validate(); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("jdbcUrl is required with driverClassName")); } } @Test public void validateDriverAndUrl() { try { HikariConfig config = newHikariConfig(); config.setDriverClassName("com.zaxxer.hikari.mocks.StubDriver"); config.setJdbcUrl("jdbc:stub"); config.validate(); } catch (Throwable t) { fail(t.getMessage()); } } @Test public void validateBadDriver() { try { HikariConfig config = newHikariConfig(); config.setDriverClassName("invalid"); config.validate(); fail(); } catch (RuntimeException ise) { assertTrue(ise.getMessage().contains("class of driverClassName ")); } } @Test public void validateInvalidConnectionTimeout() { try { HikariConfig config = newHikariConfig(); config.setConnectionTimeout(10L); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("connectionTimeout cannot be less than 250ms")); } } @Test public void validateInvalidValidationTimeout() { try { HikariConfig config = newHikariConfig(); config.setValidationTimeout(10L); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("validationTimeout cannot be less than 250ms")); } } @Test public void validateInvalidIdleTimeout() { try { HikariConfig config = newHikariConfig(); config.setIdleTimeout(-1L); fail("negative idle timeout accepted"); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("idleTimeout cannot be negative")); } } @Test public void validateIdleTimeoutTooSmall() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos, true); setSlf4jTargetStream(HikariConfig.class, ps); HikariConfig config = newHikariConfig(); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setIdleTimeout(TimeUnit.SECONDS.toMillis(5)); config.validate(); assertTrue(new String(baos.toByteArray()).contains("less than 10000ms")); } @Test public void validateIdleTimeoutExceedsLifetime() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos, true); setSlf4jTargetStream(HikariConfig.class, ps); HikariConfig config = newHikariConfig(); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); config.setMaxLifetime(TimeUnit.MINUTES.toMillis(2)); config.setIdleTimeout(TimeUnit.MINUTES.toMillis(3)); config.validate(); String s = new String(baos.toByteArray()); assertTrue("idleTimeout is close to or more than maxLifetime, disabling it." + s + "*", s.contains("is close to or more than maxLifetime")); } @Test public void validateInvalidMinIdle() { try { HikariConfig config = newHikariConfig(); config.setMinimumIdle(-1); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("minimumIdle cannot be negative")); } } @Test public void validateInvalidMaxPoolSize() { try { HikariConfig config = newHikariConfig(); config.setMaximumPoolSize(0); fail(); } catch (IllegalArgumentException ise) { assertTrue(ise.getMessage().contains("maxPoolSize cannot be less than 1")); } } @Test public void validateInvalidLifetime() { try { HikariConfig config = newHikariConfig(); config.setConnectionTimeout(Integer.MAX_VALUE); config.setIdleTimeout(1000L); config.setMaxLifetime(-1L); config.setLeakDetectionThreshold(1000L); config.validate(); fail(); } catch (IllegalArgumentException ise) { // pass } } @Test public void validateInvalidLeakDetection() { try { HikariConfig config = newHikariConfig(); config.setLeakDetectionThreshold(1000L); config.validate(); fail(); } catch (IllegalArgumentException ise) { // pass } } @Test public void validateZeroConnectionTimeout() { try { HikariConfig config = newHikariConfig(); config.setConnectionTimeout(0); config.validate(); assertEquals(Integer.MAX_VALUE, config.getConnectionTimeout()); } catch (IllegalArgumentException ise) { // pass } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/pool/UnwrapTest.java000066400000000000000000000061311315431642000265700ustar00rootroot00000000000000/* * 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.pool; import static com.zaxxer.hikari.pool.TestElf.newHikariConfig; import static com.zaxxer.hikari.pool.TestElf.getPool; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.SQLException; import org.junit.Test; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; import com.zaxxer.hikari.mocks.StubDataSource; /** * @author Brett Wooldridge */ public class UnwrapTest { @Test public void testUnwrapConnection() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { ds.getConnection().close(); assertSame("Idle connections not as expected", 1, getPool(ds).getIdleConnections()); Connection connection = ds.getConnection(); assertNotNull(connection); StubConnection unwrapped = connection.unwrap(StubConnection.class); assertTrue("unwrapped connection is not instance of StubConnection: " + unwrapped, (unwrapped != null && unwrapped instanceof StubConnection)); } } @Test public void testUnwrapDataSource() throws SQLException { HikariConfig config = newHikariConfig(); config.setMinimumIdle(1); config.setMaximumPoolSize(1); config.setInitializationFailTimeout(0); config.setConnectionTestQuery("VALUES 1"); config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); try (HikariDataSource ds = new HikariDataSource(config)) { StubDataSource unwrap = ds.unwrap(StubDataSource.class); assertNotNull(unwrap); assertTrue(unwrap instanceof StubDataSource); assertTrue(ds.isWrapperFor(HikariDataSource.class)); assertTrue(ds.unwrap(HikariDataSource.class) instanceof HikariDataSource); assertFalse(ds.isWrapperFor(getClass())); try { ds.unwrap(getClass()); } catch (SQLException e) { assertTrue(e.getMessage().contains("Wrapped DataSource")); } } } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/util/000077500000000000000000000000001315431642000236145ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/util/ClockSourceTest.java000066400000000000000000000047011315431642000275350ustar00rootroot00000000000000/* * Copyright (C) 2016 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.util; import org.junit.Assert; import org.junit.Test; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; /** * * @author Brett Wooldridge */ public class ClockSourceTest { @Test public void testClockSourceDisplay() { ClockSource msSource = new ClockSource.MillisecondClockSource(); final long sTime = DAYS.toMillis(3) + HOURS.toMillis(9) + MINUTES.toMillis(24) + SECONDS.toMillis(18) + MILLISECONDS.toMillis(572); final long eTime = DAYS.toMillis(4) + HOURS.toMillis(9) + MINUTES.toMillis(55) + SECONDS.toMillis(23) + MILLISECONDS.toMillis(777); String ds1 = msSource.elapsedDisplayString0(sTime, eTime); Assert.assertEquals("1d31m5s205ms", ds1); final long eTime2 = DAYS.toMillis(3) + HOURS.toMillis(8) + MINUTES.toMillis(24) + SECONDS.toMillis(23) + MILLISECONDS.toMillis(777); String ds2 = msSource.elapsedDisplayString0(sTime, eTime2); Assert.assertEquals("-59m54s795ms", ds2); ClockSource nsSource = new ClockSource.NanosecondClockSource(); final long sTime2 = DAYS.toNanos(3) + HOURS.toNanos(9) + MINUTES.toNanos(24) + SECONDS.toNanos(18) + MILLISECONDS.toNanos(572) + MICROSECONDS.toNanos(324) + NANOSECONDS.toNanos(823); final long eTime3 = DAYS.toNanos(4) + HOURS.toNanos(19) + MINUTES.toNanos(55) + SECONDS.toNanos(23) + MILLISECONDS.toNanos(777) + MICROSECONDS.toNanos(0) + NANOSECONDS.toNanos(982); String ds3 = nsSource.elapsedDisplayString0(sTime2, eTime3); Assert.assertEquals("1d10h31m5s204ms676µs159ns", ds3); } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/util/TestFastList.java000066400000000000000000000105111315431642000270460ustar00rootroot00000000000000/* * Copyright (C) 2013, 2014 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.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import java.sql.Statement; import java.util.ArrayList; import java.util.Iterator; import org.junit.Test; import com.zaxxer.hikari.mocks.StubStatement; public class TestFastList { @Test public void testAddRemove() { ArrayList verifyList = new ArrayList<>(); FastList list = new FastList<>(Statement.class); for (int i = 0; i < 32; i++) { StubStatement statement = new StubStatement(null); list.add(statement); verifyList.add(statement); } for (int i = 0; i < 32; i++) { assertNotNull("Element " + i + " was null but should be " + verifyList.get(i), list.get(0)); int size = list.size(); list.remove(verifyList.get(i)); assertSame(size - 1, list.size()); } } @Test public void testAddRemoveTail() { ArrayList verifyList = new ArrayList<>(); FastList list = new FastList<>(Statement.class); for (int i = 0; i < 32; i++) { StubStatement statement = new StubStatement(null); list.add(statement); verifyList.add(statement); } for (int i = 31; i >= 0; i--) { assertNotNull("Element " + i, list.get(i)); int size = list.size(); list.remove(verifyList.get(i)); assertSame(size - 1, list.size()); } } @Test public void testOverflow() { ArrayList verifyList = new ArrayList<>(); FastList list = new FastList<>(Statement.class); for (int i = 0; i < 100; i++) { StubStatement statement = new StubStatement(null); list.add(statement); verifyList.add(statement); } for (int i = 0; i < 100; i++) { assertNotNull("Element " + i, list.get(i)); assertSame(verifyList.get(i), list.get(i)); } } @Test public void testIterator() { FastList list = new FastList<>(Statement.class); for (int i = 0; i < 100; i++) { StubStatement statement = new StubStatement(null); list.add(statement); } Iterator iter = list.iterator(); for (int i = 0; i < list.size(); i++) { assertSame(list.get(i), iter.next()); } } @Test public void testClear() { FastList list = new FastList<>(Statement.class); for (int i = 0; i < 100; i++) { StubStatement statement = new StubStatement(null); list.add(statement); } assertNotEquals(0, list.size()); list.clear(); assertEquals(0, list.size()); } @Test public void testRemoveLast() { FastList list = new FastList<>(Statement.class); Statement last = null; for (int i = 0; i < 100; i++) { StubStatement statement = new StubStatement(null); list.add(statement); last = statement; } assertEquals(last, list.removeLast()); assertEquals(99, list.size()); } @Test public void testPolyMorphism1() { class Foo implements Base2 { } class Bar extends Foo { } FastList list = new FastList<>(Base.class, 2); list.add(new Foo()); list.add(new Foo()); list.add(new Bar()); } interface Base { } interface Base2 extends Base { } } HikariCP-HikariCP-2.7.1/src/test/java/com/zaxxer/hikari/util/TomcatConcurrentBagLeakTest.java000066400000000000000000000327101315431642000320230ustar00rootroot00000000000000/* * Copyright (C) 2017 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.util; import com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.DataInputStream; import java.io.IOException; import java.lang.ref.Reference; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.concurrent.CompletableFuture; import static com.zaxxer.hikari.pool.TestElf.isJava9; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assume.assumeTrue; /** * @author Brett Wooldridge */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TomcatConcurrentBagLeakTest { @Test public void testConcurrentBagForLeaks() throws Exception { assumeTrue(!isJava9()); ClassLoader cl = new FauxWebClassLoader(); Class clazz = cl.loadClass(this.getClass().getName() + "$FauxWebContext"); Object fauxWebContext = clazz.newInstance(); Method createConcurrentBag = clazz.getDeclaredMethod("createConcurrentBag"); createConcurrentBag.invoke(fauxWebContext); Field failureException = clazz.getDeclaredField("failureException"); Exception ex = (Exception) failureException.get(fauxWebContext); assertNull(ex); } @Test public void testConcurrentBagForLeaks2() throws Exception { assumeTrue(!isJava9()); ClassLoader cl = this.getClass().getClassLoader(); Class clazz = cl.loadClass(this.getClass().getName() + "$FauxWebContext"); Object fauxWebContext = clazz.newInstance(); Method createConcurrentBag = clazz.getDeclaredMethod("createConcurrentBag"); createConcurrentBag.invoke(fauxWebContext); Field failureException = clazz.getDeclaredField("failureException"); Exception ex = (Exception) failureException.get(fauxWebContext); assertNotNull(ex); } static class FauxWebClassLoader extends ClassLoader { static final byte[] classBytes = new byte[16_000]; @Override public Class loadClass(String name) throws ClassNotFoundException { if (name.startsWith("java") || name.startsWith("org")) { return super.loadClass(name, true); } final String resourceName = "/" + name.replace('.', '/') + ".class"; final URL resource = this.getClass().getResource(resourceName); try (DataInputStream is = new DataInputStream(resource.openStream())) { int read = 0; while (read < classBytes.length) { final int rc = is.read(classBytes, read, classBytes.length - read); if (rc == -1) { break; } read += rc; } return defineClass(name, classBytes, 0, read); } catch (IOException e) { throw new ClassNotFoundException(name); } } } public static class PoolEntry implements IConcurrentBagEntry { private int state; @Override public boolean compareAndSet(int expectState, int newState) { this.state = newState; return true; } @Override public void setState(int newState) { this.state = newState; } @Override public int getState() { return state; } } @SuppressWarnings("unused") public static class FauxWebContext { private static final Logger log = LoggerFactory.getLogger(FauxWebContext.class); @SuppressWarnings("WeakerAccess") public Exception failureException; @SuppressWarnings("unused") public void createConcurrentBag() throws InterruptedException { try (ConcurrentBag bag = new ConcurrentBag<>((x) -> CompletableFuture.completedFuture(Boolean.TRUE))) { PoolEntry entry = new PoolEntry(); bag.add(entry); PoolEntry borrowed = bag.borrow(100, MILLISECONDS); bag.requite(borrowed); PoolEntry removed = bag.borrow(100, MILLISECONDS); bag.remove(removed); } checkThreadLocalsForLeaks(); } private void checkThreadLocalsForLeaks() { Thread[] threads = getThreads(); try { // Make the fields in the Thread class that store ThreadLocals // accessible Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals"); inheritableThreadLocalsField.setAccessible(true); // Make the underlying array of ThreadLoad.ThreadLocalMap.Entry objects // accessible Class tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap"); Field tableField = tlmClass.getDeclaredField("table"); tableField.setAccessible(true); Method expungeStaleEntriesMethod = tlmClass.getDeclaredMethod("expungeStaleEntries"); expungeStaleEntriesMethod.setAccessible(true); for (Thread thread : threads) { Object threadLocalMap; if (thread != null) { // Clear the first map threadLocalMap = threadLocalsField.get(thread); if (null != threadLocalMap) { expungeStaleEntriesMethod.invoke(threadLocalMap); checkThreadLocalMapForLeaks(threadLocalMap, tableField); } // Clear the second map threadLocalMap = inheritableThreadLocalsField.get(thread); if (null != threadLocalMap) { expungeStaleEntriesMethod.invoke(threadLocalMap); checkThreadLocalMapForLeaks(threadLocalMap, tableField); } } } } catch (Throwable t) { log.warn("Failed to check for ThreadLocal references for web application [{}]", getContextName(), t); failureException = new Exception(); } } private Object getContextName() { return this.getClass().getName(); } // THE FOLLOWING CODE COPIED FROM APACHE TOMCAT (2017/01/08) /** * Analyzes the given thread local map object. Also pass in the field that * points to the internal table to save re-calculating it on every * call to this method. */ private void checkThreadLocalMapForLeaks(Object map, Field internalTableField) throws IllegalAccessException, NoSuchFieldException { if (map != null) { Object[] table = (Object[]) internalTableField.get(map); if (table != null) { for (Object obj : table) { if (obj != null) { boolean keyLoadedByWebapp = false; boolean valueLoadedByWebapp = false; // Check the key Object key = ((Reference) obj).get(); if (this.equals(key) || loadedByThisOrChild(key)) { keyLoadedByWebapp = true; } // Check the value Field valueField = obj.getClass().getDeclaredField("value"); valueField.setAccessible(true); Object value = valueField.get(obj); if (this.equals(value) || loadedByThisOrChild(value)) { valueLoadedByWebapp = true; } if (keyLoadedByWebapp || valueLoadedByWebapp) { Object[] args = new Object[5]; args[0] = getContextName(); if (key != null) { args[1] = getPrettyClassName(key.getClass()); try { args[2] = key.toString(); } catch (Exception e) { log.warn("Unable to determine string representation of key of type [{}]", args[1], e); args[2] = "Unknown"; } } if (value != null) { args[3] = getPrettyClassName(value.getClass()); try { args[4] = value.toString(); } catch (Exception e) { log.warn("webappClassLoader.checkThreadLocalsForLeaks.badValue {}", args[3], e); args[4] = "Unknown"; } } if (valueLoadedByWebapp) { log.error("The web application [{}] created a ThreadLocal with key " + "(value [{}]) and a value of type [{}] (value [{}]) but failed to remove " + "it when the web application was stopped. Threads are going to be renewed " + "over time to try and avoid a probable memory leak.", args); failureException = new Exception(); } else if (value == null) { log.debug("The web application [{}] created a ThreadLocal with key of type [{}] " + "(value [{}]). The ThreadLocal has been correctly set to null and the " + "key will be removed by GC.", args); failureException = new Exception(); } else { log.debug("The web application [{}] created a ThreadLocal with key of type [{}] " + "(value [{}]) and a value of type [{}] (value [{}]). Since keys are only " + "weakly held by the ThreadLocal Map this is not a memory leak.", args); failureException = new Exception(); } } } } } } } /** * @param o object to test, may be null * @return true if o has been loaded by the current classloader * or one of its descendants. */ private boolean loadedByThisOrChild(Object o) { if (o == null) { return false; } Class clazz; if (o instanceof Class) { clazz = (Class) o; } else { clazz = o.getClass(); } ClassLoader cl = clazz.getClassLoader(); while (cl != null) { if (cl == this.getClass().getClassLoader()) { return true; } cl = cl.getParent(); } if (o instanceof Collection) { Iterator iter = ((Collection) o).iterator(); try { while (iter.hasNext()) { Object entry = iter.next(); if (loadedByThisOrChild(entry)) { return true; } } } catch (ConcurrentModificationException e) { log.warn("Failed to check for ThreadLocal references for web application [{}]", getContextName(), e); } } return false; } /* * Get the set of current threads as an array. */ private Thread[] getThreads() { // Get the current thread group ThreadGroup tg = Thread.currentThread().getThreadGroup(); // Find the root thread group try { while (tg.getParent() != null) { tg = tg.getParent(); } } catch (SecurityException se) { log.warn("Unable to obtain the parent for ThreadGroup [{}]. It will not be possible to check all threads for potential memory leaks", tg.getName(), se); } int threadCountGuess = tg.activeCount() + 50; Thread[] threads = new Thread[threadCountGuess]; int threadCountActual = tg.enumerate(threads); // Make sure we don't miss any threads while (threadCountActual == threadCountGuess) { threadCountGuess *= 2; threads = new Thread[threadCountGuess]; // Note tg.enumerate(Thread[]) silently ignores any threads that // can't fit into the array threadCountActual = tg.enumerate(threads); } return threads; } private String getPrettyClassName(Class clazz) { String name = clazz.getCanonicalName(); if (name == null) { name = clazz.getName(); } return name; } } } HikariCP-HikariCP-2.7.1/src/test/resources/000077500000000000000000000000001315431642000203625ustar00rootroot00000000000000HikariCP-HikariCP-2.7.1/src/test/resources/hibernate.properties000066400000000000000000000002771315431642000244470ustar00rootroot00000000000000hibernate.hikari.minimumIdle=5 hibernate.hikari.connectionTestQuery=SELECT 1 hibernate.hikari.dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource hibernate.connection.autocommit=false HikariCP-HikariCP-2.7.1/src/test/resources/log4j2-test.xml000066400000000000000000000005511315431642000231630ustar00rootroot00000000000000 HikariCP-HikariCP-2.7.1/src/test/resources/propfile1.properties000066400000000000000000000001671315431642000244050ustar00rootroot00000000000000minimumIdle=5 connectionTestQuery=SELECT 1 autoCommit=false dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource HikariCP-HikariCP-2.7.1/src/test/resources/propfile2.properties000066400000000000000000000002261315431642000244020ustar00rootroot00000000000000connectionTestQuery=SELECT 1 autoCommit=false dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource dataSource.user=test dataSource.password=testHikariCP-HikariCP-2.7.1/src/test/resources/propfile3.properties000066400000000000000000000002641315431642000244050ustar00rootroot00000000000000connectionTestQuery=SELECT 1 autoCommit=false dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource dataSource.user=test dataSource.password=test dataSource.url=jdbc:stub:foo