From 4c8dac6d7551c627a478f70356b93002e9c942dc Mon Sep 17 00:00:00 2001 From: Martin Bielmann Date: Fri, 6 Sep 2019 13:25:07 +0200 Subject: [PATCH] #43: Lazy datasource creation + aligned open/closed/recreate operations to allow multiple gateway open and close --- .../storage/jooqdb/JooqClusterStorage.java | 49 +++++----------- .../storage/jooqdb/JooqHandler.java | 58 +++++++++++++++---- .../jooqdb/lookup/JooqLookupManager.java | 2 +- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqClusterStorage.java b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqClusterStorage.java index d31f90d0b..fbc8b0ce7 100644 --- a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqClusterStorage.java +++ b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqClusterStorage.java @@ -123,29 +123,10 @@ public void dropHandlers() throws PersistencyException { } - private void recreateDS(boolean autoCommit) { - HikariConfig config = new HikariConfig(); - JooqHandler.ds.copyStateTo(config); - config.setAutoCommit(autoCommit); - config.addDataSourceProperty("autoCommit", autoCommit); - HikariDataSource newDs = new HikariDataSource(config); - JooqHandler.ds = newDs; - } - @Override public void close() throws PersistencyException { Logger.msg(1, "JooqClusterStorage.close()"); - try { - HikariPoolMXBean poolBean = JooqHandler.ds.getHikariPoolMXBean(); - while (poolBean.getActiveConnections() > 0) { - poolBean.softEvictConnections(); - } - JooqHandler.ds.close(); - } - catch (Exception e) { - Logger.error(e); - throw new PersistencyException(e.getMessage()); - } + JooqHandler.closeDataSource(); } @Override @@ -156,9 +137,8 @@ public void postBoostrap() throws PersistencyException { // after the the bootstrap the DataSOurce needs to be reset to its original config if (!JooqHandler.autoCommit) { - //Close current DS and create a new one - close(); - recreateDS(JooqHandler.autoCommit); + //Create a new data source with original autocommit setting + JooqHandler.recreateDataSource(JooqHandler.autoCommit); } } @@ -173,9 +153,8 @@ public void postStartServer() throws PersistencyException { public void postConnect() throws PersistencyException { // the DataSource need to be set to autocommit for the the bootstrap to work if (!JooqHandler.autoCommit) { - //Close current DS and create a new one - close(); - recreateDS(true); + //recreate a new DS with auto-commit forced to true + JooqHandler.recreateDataSource(true); } JooqHandler.connect().transaction(nested -> { @@ -186,7 +165,7 @@ public void postConnect() throws PersistencyException { @Override public void begin(Object locker) throws PersistencyException { - if (!JooqHandler.ds.isAutoCommit() && locker == null) { + if (!JooqHandler.getDataSource().isAutoCommit() && locker == null) { throw new PersistencyException("locker cannot be null when autoCommit is false"); } Connection conn = JooqHandler.connect().configuration().connectionProvider().acquire(); @@ -195,13 +174,13 @@ public void begin(Object locker) throws PersistencyException { } private DSLContext retrieveContext(Object locker) throws PersistencyException { - if (JooqHandler.ds.isAutoCommit()) return JooqHandler.connect(); - else return JooqHandler.connect(connectionMap.get(locker)); + if (JooqHandler.getDataSource().isAutoCommit()) return JooqHandler.connect(); + else return JooqHandler.connect(connectionMap.get(locker)); } @Override public void commit(Object locker) throws PersistencyException { - if (!JooqHandler.ds.isAutoCommit() && locker == null) { + if (!JooqHandler.getDataSource().isAutoCommit() && locker == null) { throw new PersistencyException("locker cannot be null when autoCommit is false"); } @@ -218,7 +197,7 @@ public void commit(Object locker) throws PersistencyException { try { Connection conn = connectionMap.remove(locker); - if (!JooqHandler.ds.isAutoCommit()) { + if (!JooqHandler.getDataSource().isAutoCommit()) { conn.commit(); } conn.close(); @@ -231,7 +210,7 @@ public void commit(Object locker) throws PersistencyException { @Override public void abort(Object locker) throws PersistencyException { - if (!JooqHandler.ds.isAutoCommit() && locker == null) { + if (!JooqHandler.getDataSource().isAutoCommit() && locker == null) { throw new PersistencyException("locker cannot be null when autoCommit is false"); } @@ -247,7 +226,7 @@ public void abort(Object locker) throws PersistencyException { Logger.msg(1, "JooqClusterStorage.abort()"); try { Connection conn = connectionMap.remove(locker); - if (!JooqHandler.ds.isAutoCommit()) { + if (!JooqHandler.getDataSource().isAutoCommit()) { conn.rollback(); } conn.close(); @@ -362,7 +341,7 @@ public void put(ItemPath itemPath, C2KLocalObject obj) throws PersistencyExcepti @Override public void put(ItemPath itemPath, C2KLocalObject obj, Object locker) throws PersistencyException { - if (!JooqHandler.ds.isAutoCommit() && locker == null) { + if (!JooqHandler.getDataSource().isAutoCommit() && locker == null) { throw new PersistencyException("locker cannot be null when autoCommit is false"); } @@ -394,7 +373,7 @@ public void delete(ItemPath itemPath, String path) throws PersistencyException { @Override public void delete(ItemPath itemPath, String path, Object locker) throws PersistencyException { - if (!JooqHandler.ds.isAutoCommit() && locker == null) { + if (!JooqHandler.getDataSource().isAutoCommit() && locker == null) { throw new PersistencyException("locker cannot be null when autoCommit is false"); } diff --git a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqHandler.java b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqHandler.java index d5d963682..816daf17d 100644 --- a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqHandler.java +++ b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/JooqHandler.java @@ -25,6 +25,7 @@ import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.using; +import com.zaxxer.hikari.HikariPoolMXBean; import java.sql.Connection; import java.sql.Timestamp; import java.util.Arrays; @@ -165,18 +166,15 @@ public abstract class JooqHandler { public static final Boolean autoCommit = Gateway.getProperties().getBoolean(JooqHandler.JOOQ_AUTOCOMMIT, false); public static final SQLDialect dialect = SQLDialect.valueOf(Gateway.getProperties().getString(JooqHandler.JOOQ_DIALECT, "POSTGRES")); - public static HikariDataSource ds; - - static { - if (StringUtils.isAnyBlank(uri, user, pwd)) { - throw new IllegalArgumentException("JOOQ (uri, user, password) config values must not be blank"); - } - - HikariConfig config = new HikariConfig(); + private static HikariDataSource ds = null; + private static HikariConfig config; + public static synchronized HikariDataSource getDataSource(){ + if (StringUtils.isAnyBlank(uri, user, pwd)) + throw new IllegalArgumentException("JOOQ (uri, user, password) config values must not be blank"); + config = new HikariConfig(); config.setPoolName("CRISTAL-iSE-HikariCP"); config.setRegisterMbeans(true); - config.setJdbcUrl(uri); config.setUsername(user); config.setPassword(pwd); @@ -191,14 +189,50 @@ public abstract class JooqHandler { config.addDataSourceProperty( "prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty( "autoCommit", autoCommit); - ds = new HikariDataSource(config); - Logger.msg(8, "JooqHandler.static() - uri:'"+uri+"' user:'"+user+"' dialect:'"+dialect+"'"); + + if (ds == null){ + config.setAutoCommit(autoCommit); + ds = new HikariDataSource(config); + Logger.msg(3, "JooqHandler.getDataSource() create datasource %s", ds); + } + return ds; + } + + public static synchronized void recreateDataSource(boolean forcedAutoCommit) throws PersistencyException { + if (ds == null) + throw new PersistencyException("Cannot recreate a null data source"); + Logger.msg(3, "JooqHandler.recreateDataSource() autocomit=%b", forcedAutoCommit); + HikariConfig config = new HikariConfig(); + ds.copyStateTo(config); + config.setAutoCommit(forcedAutoCommit); + config.addDataSourceProperty("autoCommit", forcedAutoCommit); + closeDataSource(); + HikariDataSource newDs = new HikariDataSource(config); + ds = newDs; + } + + public static synchronized void closeDataSource() throws PersistencyException { + try { + if (ds != null){ + HikariPoolMXBean poolBean = ds.getHikariPoolMXBean(); + Logger.msg(3, "JooqHandler.closeDataSource() active connections=%d", poolBean.getActiveConnections()); + while (poolBean.getActiveConnections() > 0) { + poolBean.softEvictConnections(); + } + ds.close(); + ds = null; + } + } + catch (Exception e) { + Logger.error(e); + throw new PersistencyException(e.getMessage()); + } } public static DSLContext connect() throws PersistencyException { try { - return using(ds, dialect); + return using(getDataSource(), dialect); } catch (Exception ex) { Logger.error("JooqHandler could not connect to URI '"+uri+"' with user '"+user+"'"); diff --git a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/lookup/JooqLookupManager.java b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/lookup/JooqLookupManager.java index 3af8593e9..90f511e63 100644 --- a/jooqdb/src/main/java/org/cristalise/storage/jooqdb/lookup/JooqLookupManager.java +++ b/jooqdb/src/main/java/org/cristalise/storage/jooqdb/lookup/JooqLookupManager.java @@ -124,7 +124,7 @@ public void initializeDirectory() throws ObjectNotFoundException { @Override public void close() { try { - JooqHandler.connect().close(); + JooqHandler.closeDataSource(); } catch (DataAccessException | PersistencyException e) { Logger.error(e);