Skip to content

Commit 1f67ab4

Browse files
committed
Add addition dbcp2 configs
1 parent 6f6c82f commit 1f67ab4

4 files changed

Lines changed: 212 additions & 25 deletions

File tree

document-store/src/main/java/org/hypertrace/core/documentstore/model/config/ConnectionPoolConfig.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
package org.hypertrace.core.documentstore.model.config;
22

33
import java.time.Duration;
4+
import java.util.List;
45
import javax.annotation.Nonnegative;
6+
import javax.annotation.Nullable;
57
import lombok.AccessLevel;
68
import lombok.AllArgsConstructor;
79
import lombok.Builder;
810
import lombok.NonNull;
11+
import lombok.Singular;
912
import lombok.Value;
1013
import lombok.experimental.Accessors;
1114

15+
/**
16+
* See <a href="https://commons.apache.org/proper/commons-dbcp/configuration.html">DBCP2
17+
* Configuration</a> for details
18+
*/
1219
@Value
1320
@Builder
1421
@Accessors(fluent = true)
@@ -29,6 +36,31 @@ public class ConnectionPoolConfig {
2936
// Time duration to wait for surrendering an idle connection back to the pool
3037
@NonNull @Builder.Default Duration connectionSurrenderTimeout = Duration.ofMinutes(5);
3138

32-
// Whether to validate connections when borrowing from the pool
33-
@NonNull @Builder.Default Boolean testOnBorrow = true;
39+
@Nullable String validationQuery;
40+
41+
@Nullable Duration validationQueryTimeout;
42+
43+
@Nullable Boolean testOnCreate;
44+
45+
@Nullable Boolean testOnBorrow;
46+
47+
@Nullable Boolean testOnReturn;
48+
49+
@Nullable Boolean testWhileIdle;
50+
51+
@Nullable Duration timeBetweenEvictionRuns;
52+
53+
@Nullable Integer numTestsPerEvictionRun;
54+
55+
@Nullable Duration minEvictableIdleTime;
56+
57+
@Nullable Duration softMinEvictableIdleTime;
58+
59+
@Nullable Duration maxConnLifetime;
60+
61+
@NonNull
62+
@Singular("connectionInitSql")
63+
List<String> connectionInitSqls;
64+
65+
@Nullable Boolean lifo;
3466
}

document-store/src/main/java/org/hypertrace/core/documentstore/model/config/TypesafeConfigDatastoreConfigExtractor.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public class TypesafeConfigDatastoreConfigExtractor {
3535
private static final String DEFAULT_MAX_IDLE_PERCENT_KEY = "maxIdlePercent";
3636
private static final String DEFAULT_MIN_IDLE_PERCENT_KEY = "minIdlePercent";
3737
private static final String DEFAULT_TEST_ON_BORROW_KEY = "testOnBorrow";
38+
private static final String DEFAULT_VALIDATION_QUERY_KEY = "validationQuery";
39+
private static final String DEFAULT_VALIDATION_QUERY_TIMEOUT_KEY = "validationQueryTimeout";
40+
private static final String DEFAULT_TEST_ON_CREATE_KEY = "testOnCreate";
41+
private static final String DEFAULT_TEST_ON_RETURN_KEY = "testOnReturn";
42+
private static final String DEFAULT_TEST_WHILE_IDLE_KEY = "testWhileIdle";
43+
private static final String DEFAULT_TIME_BETWEEN_EVICTION_RUNS_KEY = "timeBetweenEvictionRuns";
44+
private static final String DEFAULT_NUM_TESTS_PER_EVICTION_RUN_KEY = "numTestsPerEvictionRun";
45+
private static final String DEFAULT_MIN_EVICTABLE_IDLE_TIME_KEY = "minEvictableIdleTime";
46+
private static final String DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_KEY = "softMinEvictableIdleTime";
47+
private static final String DEFAULT_MAX_CONN_LIFETIME_KEY = "maxConnLifetime";
48+
private static final String DEFAULT_CONNECTION_INIT_SQLS_KEY = "connectionInitSqls";
49+
private static final String DEFAULT_LIFO_KEY = "lifo";
3850
private static final String DEFAULT_AGGREGATION_PIPELINE_MODE_KEY = "aggregationPipelineMode";
3951
private static final String DEFAULT_DATA_FRESHNESS_KEY = "dataFreshness";
4052
private static final String DEFAULT_QUERY_TIMEOUT_KEY = "queryTimeout";
@@ -90,6 +102,18 @@ private TypesafeConfigDatastoreConfigExtractor(
90102
.poolMaxIdlePercentKey(DEFAULT_MAX_IDLE_PERCENT_KEY)
91103
.poolMinIdlePercentKey(DEFAULT_MIN_IDLE_PERCENT_KEY)
92104
.poolTestOnBorrowKey(DEFAULT_TEST_ON_BORROW_KEY)
105+
.poolValidationQueryKey(DEFAULT_VALIDATION_QUERY_KEY)
106+
.poolValidationQueryTimeoutKey(DEFAULT_VALIDATION_QUERY_TIMEOUT_KEY)
107+
.poolTestOnCreateKey(DEFAULT_TEST_ON_CREATE_KEY)
108+
.poolTestOnReturnKey(DEFAULT_TEST_ON_RETURN_KEY)
109+
.poolTestWhileIdleKey(DEFAULT_TEST_WHILE_IDLE_KEY)
110+
.poolTimeBetweenEvictionRunsKey(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_KEY)
111+
.poolNumTestsPerEvictionRunKey(DEFAULT_NUM_TESTS_PER_EVICTION_RUN_KEY)
112+
.poolMinEvictableIdleTimeKey(DEFAULT_MIN_EVICTABLE_IDLE_TIME_KEY)
113+
.poolSoftMinEvictableIdleTimeKey(DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_KEY)
114+
.poolMaxConnLifetimeKey(DEFAULT_MAX_CONN_LIFETIME_KEY)
115+
.poolConnectionInitSqlsKey(DEFAULT_CONNECTION_INIT_SQLS_KEY)
116+
.poolLifoKey(DEFAULT_LIFO_KEY)
93117
.aggregationPipelineMode(DEFAULT_AGGREGATION_PIPELINE_MODE_KEY)
94118
.dataFreshnessKey(DEFAULT_DATA_FRESHNESS_KEY)
95119
.queryTimeoutKey(DEFAULT_QUERY_TIMEOUT_KEY)
@@ -255,6 +279,96 @@ public TypesafeConfigDatastoreConfigExtractor poolTestOnBorrowKey(@NonNull final
255279
return this;
256280
}
257281

282+
public TypesafeConfigDatastoreConfigExtractor poolValidationQueryKey(@NonNull final String key) {
283+
if (config.hasPath(key)) {
284+
connectionPoolConfigBuilder.validationQuery(config.getString(key));
285+
}
286+
return this;
287+
}
288+
289+
public TypesafeConfigDatastoreConfigExtractor poolValidationQueryTimeoutKey(
290+
@NonNull final String key) {
291+
if (config.hasPath(key)) {
292+
connectionPoolConfigBuilder.validationQueryTimeout(config.getDuration(key));
293+
}
294+
return this;
295+
}
296+
297+
public TypesafeConfigDatastoreConfigExtractor poolTestOnCreateKey(@NonNull final String key) {
298+
if (config.hasPath(key)) {
299+
connectionPoolConfigBuilder.testOnCreate(config.getBoolean(key));
300+
}
301+
return this;
302+
}
303+
304+
public TypesafeConfigDatastoreConfigExtractor poolTestOnReturnKey(@NonNull final String key) {
305+
if (config.hasPath(key)) {
306+
connectionPoolConfigBuilder.testOnReturn(config.getBoolean(key));
307+
}
308+
return this;
309+
}
310+
311+
public TypesafeConfigDatastoreConfigExtractor poolTestWhileIdleKey(@NonNull final String key) {
312+
if (config.hasPath(key)) {
313+
connectionPoolConfigBuilder.testWhileIdle(config.getBoolean(key));
314+
}
315+
return this;
316+
}
317+
318+
public TypesafeConfigDatastoreConfigExtractor poolTimeBetweenEvictionRunsKey(
319+
@NonNull final String key) {
320+
if (config.hasPath(key)) {
321+
connectionPoolConfigBuilder.timeBetweenEvictionRuns(config.getDuration(key));
322+
}
323+
return this;
324+
}
325+
326+
public TypesafeConfigDatastoreConfigExtractor poolNumTestsPerEvictionRunKey(
327+
@NonNull final String key) {
328+
if (config.hasPath(key)) {
329+
connectionPoolConfigBuilder.numTestsPerEvictionRun(config.getInt(key));
330+
}
331+
return this;
332+
}
333+
334+
public TypesafeConfigDatastoreConfigExtractor poolMinEvictableIdleTimeKey(
335+
@NonNull final String key) {
336+
if (config.hasPath(key)) {
337+
connectionPoolConfigBuilder.minEvictableIdleTime(config.getDuration(key));
338+
}
339+
return this;
340+
}
341+
342+
public TypesafeConfigDatastoreConfigExtractor poolSoftMinEvictableIdleTimeKey(
343+
@NonNull final String key) {
344+
if (config.hasPath(key)) {
345+
connectionPoolConfigBuilder.softMinEvictableIdleTime(config.getDuration(key));
346+
}
347+
return this;
348+
}
349+
350+
public TypesafeConfigDatastoreConfigExtractor poolMaxConnLifetimeKey(@NonNull final String key) {
351+
if (config.hasPath(key)) {
352+
connectionPoolConfigBuilder.maxConnLifetime(config.getDuration(key));
353+
}
354+
return this;
355+
}
356+
357+
public TypesafeConfigDatastoreConfigExtractor poolConnectionInitSqlsKey(
358+
@NonNull final String key) {
359+
if (config.hasPath(key)) {
360+
config.getStringList(key).forEach(connectionPoolConfigBuilder::connectionInitSql);
361+
}
362+
return this;
363+
}
364+
365+
public TypesafeConfigDatastoreConfigExtractor poolLifoKey(@NonNull final String key) {
366+
if (config.hasPath(key)) {
367+
connectionPoolConfigBuilder.lifo(config.getBoolean(key));
368+
}
369+
return this;
370+
}
371+
258372
public TypesafeConfigDatastoreConfigExtractor aggregationPipelineMode(@NonNull final String key) {
259373
if (config.hasPath(key)) {
260374
connectionConfigBuilder.aggregationPipelineMode(

document-store/src/main/java/org/hypertrace/core/documentstore/model/config/postgres/PostgresConnectionConfig.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@
1717
import lombok.Value;
1818
import lombok.experimental.Accessors;
1919
import lombok.experimental.NonFinal;
20+
import lombok.extern.slf4j.Slf4j;
2021
import org.hypertrace.core.documentstore.model.config.ConnectionConfig;
2122
import org.hypertrace.core.documentstore.model.config.ConnectionCredentials;
2223
import org.hypertrace.core.documentstore.model.config.ConnectionPoolConfig;
2324
import org.hypertrace.core.documentstore.model.config.DatabaseType;
2425
import org.hypertrace.core.documentstore.model.config.Endpoint;
2526
import org.postgresql.PGProperty;
2627

28+
@Slf4j
2729
@Value
2830
@NonFinal
2931
@Accessors(fluent = true)
3032
@ToString(callSuper = true)
3133
@EqualsAndHashCode(callSuper = true)
3234
public class PostgresConnectionConfig extends ConnectionConfig {
35+
3336
private static final ConnectionCredentials DEFAULT_CREDENTIALS =
3437
ConnectionCredentials.builder()
3538
.username(PostgresDefaults.DEFAULT_USER)
@@ -99,6 +102,15 @@ public Properties buildProperties() {
99102
version ->
100103
properties.setProperty(PGProperty.ASSUME_MIN_SERVER_VERSION.getName(), version));
101104

105+
log.debug(
106+
"Postgres JDBC properties - {}={}, {}={}, {}={}",
107+
PGProperty.USER.getName(),
108+
properties.getProperty(PGProperty.USER.getName()),
109+
PGProperty.APPLICATION_NAME.getName(),
110+
properties.getProperty(PGProperty.APPLICATION_NAME.getName()),
111+
PGProperty.ASSUME_MIN_SERVER_VERSION.getName(),
112+
properties.getProperty(PGProperty.ASSUME_MIN_SERVER_VERSION.getName()));
113+
102114
return properties;
103115
}
104116

document-store/src/main/java/org/hypertrace/core/documentstore/postgres/PostgresConnectionPool.java

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@
99
import org.apache.commons.dbcp2.PoolableConnection;
1010
import org.apache.commons.dbcp2.PoolableConnectionFactory;
1111
import org.apache.commons.dbcp2.PoolingDataSource;
12-
import org.apache.commons.pool2.impl.AbandonedConfig;
1312
import org.apache.commons.pool2.impl.GenericObjectPool;
1413
import org.hypertrace.core.documentstore.model.config.ConnectionPoolConfig;
1514
import org.hypertrace.core.documentstore.model.config.postgres.PostgresConnectionConfig;
1615

1716
@Slf4j
1817
class PostgresConnectionPool {
1918

20-
private static final String VALIDATION_QUERY = "SELECT 1";
21-
private static final Duration VALIDATION_QUERY_TIMEOUT = Duration.ofSeconds(5);
22-
2319
// Single pool with autoCommit=true by default. Transactional connections flip autoCommit
2420
// to false on borrow; DBCP2 resets it back when the connection is returned to the pool.
2521
private final PoolingDataSource<PoolableConnection> dataSource;
@@ -66,57 +62,90 @@ private PoolingDataSource<PoolableConnection> createPooledDataSource(
6662

6763
final ConnectionPoolConfig poolConfig = config.connectionPoolConfig();
6864
setPoolProperties(connectionPool, poolConfig);
69-
setFactoryProperties(poolableConnectionFactory, connectionPool);
65+
setFactoryProperties(poolableConnectionFactory, connectionPool, poolConfig);
7066

7167
return new PoolingDataSource<>(connectionPool);
7268
}
7369

7470
private void setPoolProperties(
7571
final GenericObjectPool<PoolableConnection> connectionPool,
7672
final ConnectionPoolConfig poolConfig) {
77-
final AbandonedConfig abandonedConfig = getAbandonedConfig(poolConfig);
7873
final int maxConnections = poolConfig.maxConnections();
7974
connectionPool.setMaxTotal(maxConnections);
8075
connectionPool.setMaxIdle(getIdleCount(poolConfig.maxIdlePercent(), maxConnections));
8176
connectionPool.setMinIdle(getIdleCount(poolConfig.minIdlePercent(), maxConnections));
8277
connectionPool.setBlockWhenExhausted(true);
8378
connectionPool.setMaxWaitMillis(poolConfig.connectionAccessTimeout().toMillis());
84-
connectionPool.setTestOnBorrow(poolConfig.testOnBorrow());
85-
connectionPool.setAbandonedConfig(abandonedConfig);
79+
if (poolConfig.testOnCreate() != null) {
80+
connectionPool.setTestOnCreate(poolConfig.testOnCreate());
81+
}
82+
if (poolConfig.testOnBorrow() != null) {
83+
connectionPool.setTestOnBorrow(poolConfig.testOnBorrow());
84+
}
85+
if (poolConfig.testOnReturn() != null) {
86+
connectionPool.setTestOnReturn(poolConfig.testOnReturn());
87+
}
88+
if (poolConfig.testWhileIdle() != null) {
89+
connectionPool.setTestWhileIdle(poolConfig.testWhileIdle());
90+
}
91+
if (poolConfig.timeBetweenEvictionRuns() != null) {
92+
connectionPool.setTimeBetweenEvictionRuns(poolConfig.timeBetweenEvictionRuns());
93+
}
94+
if (poolConfig.numTestsPerEvictionRun() != null) {
95+
connectionPool.setNumTestsPerEvictionRun(poolConfig.numTestsPerEvictionRun());
96+
}
97+
if (poolConfig.minEvictableIdleTime() != null) {
98+
connectionPool.setMinEvictableIdleTime(poolConfig.minEvictableIdleTime());
99+
}
100+
if (poolConfig.softMinEvictableIdleTime() != null) {
101+
connectionPool.setSoftMinEvictableIdleTime(poolConfig.softMinEvictableIdleTime());
102+
}
103+
if (poolConfig.lifo() != null) {
104+
connectionPool.setLifo(poolConfig.lifo());
105+
}
86106
log.debug(
87-
"Postgres connection pool properties - maxTotal: {}, maxIdle: {}, minIdle: {}, maxWaitMillis: {}, connectionSurrenderTimeout: {}, testOnBorrow: {}",
107+
"Postgres connection pool properties - maxTotal: {}, maxIdle: {}, minIdle: {}, maxWaitMillis: {}, testOnBorrow: {}, testWhileIdle: {}, timeBetweenEvictionRunsMillis: {}, minEvictableIdleTimeMillis: {}, maxConnLifetimeMillis: {}, lifo: {}",
88108
connectionPool.getMaxTotal(),
89109
connectionPool.getMaxIdle(),
90110
connectionPool.getMinIdle(),
91111
connectionPool.getMaxWaitMillis(),
92-
poolConfig.connectionSurrenderTimeout(),
93-
poolConfig.testOnBorrow());
112+
poolConfig.testOnBorrow(),
113+
poolConfig.testWhileIdle(),
114+
toMillisOrNull(poolConfig.timeBetweenEvictionRuns()),
115+
toMillisOrNull(poolConfig.minEvictableIdleTime()),
116+
toMillisOrNull(poolConfig.maxConnLifetime()),
117+
poolConfig.lifo());
118+
}
119+
120+
private static Long toMillisOrNull(final Duration duration) {
121+
return duration == null ? null : duration.toMillis();
94122
}
95123

96124
private void setFactoryProperties(
97125
PoolableConnectionFactory poolableConnectionFactory,
98-
GenericObjectPool<PoolableConnection> connectionPool) {
126+
GenericObjectPool<PoolableConnection> connectionPool,
127+
ConnectionPoolConfig poolConfig) {
99128
poolableConnectionFactory.setPool(connectionPool);
100-
poolableConnectionFactory.setValidationQuery(VALIDATION_QUERY);
101-
poolableConnectionFactory.setValidationQueryTimeout((int) VALIDATION_QUERY_TIMEOUT.toSeconds());
129+
if (poolConfig.validationQuery() != null) {
130+
poolableConnectionFactory.setValidationQuery(poolConfig.validationQuery());
131+
}
132+
if (poolConfig.validationQueryTimeout() != null) {
133+
poolableConnectionFactory.setValidationQueryTimeout(
134+
(int) poolConfig.validationQueryTimeout().toSeconds());
135+
}
102136
poolableConnectionFactory.setDefaultReadOnly(false);
103137
poolableConnectionFactory.setDefaultAutoCommit(true);
138+
if (poolConfig.maxConnLifetime() != null) {
139+
poolableConnectionFactory.setMaxConnLifetimeMillis(poolConfig.maxConnLifetime().toMillis());
140+
}
141+
poolableConnectionFactory.setConnectionInitSql(poolConfig.connectionInitSqls());
104142
// Note: We intentionally do NOT call setDefaultTransactionIsolation() here.
105143
// PostgreSQL defaults to READ_COMMITTED, which is what we want. Setting it explicitly
106144
// causes DBCP2 to execute "SHOW TRANSACTION ISOLATION LEVEL" on every connection borrow
107145
// (via PgConnection.getTransactionIsolation()), adding unnecessary overhead.
108146
poolableConnectionFactory.setPoolStatements(false);
109147
}
110148

111-
private AbandonedConfig getAbandonedConfig(final ConnectionPoolConfig poolConfig) {
112-
final AbandonedConfig abandonedConfig = new AbandonedConfig();
113-
abandonedConfig.setLogAbandoned(true);
114-
abandonedConfig.setRemoveAbandonedOnBorrow(true);
115-
abandonedConfig.setRequireFullStackTrace(true);
116-
abandonedConfig.setRemoveAbandonedTimeout(poolConfig.connectionSurrenderTimeout());
117-
return abandonedConfig;
118-
}
119-
120149
private int getIdleCount(final int percent, final int maxConnections) {
121150
if (percent < 0) {
122151
return maxConnections;

0 commit comments

Comments
 (0)