/****************************************************************************** * Copyright © 2013-2016 The Nxt Core Developers. * * * * See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * Nxt software, including this file, may be copied, modified, propagated, * * or distributed except according to the terms contained in the LICENSE.txt * * file. * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ package nxt.db; import nxt.Nxt; import nxt.util.Logger; import org.h2.jdbcx.JdbcConnectionPool; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; public class BasicDb { public static final class DbProperties { private long maxCacheSize; private String dbUrl; private String dbType; private String dbDir; private String dbParams; private String dbUsername; private String dbPassword; private int maxConnections; private int loginTimeout; private int defaultLockTimeout; public DbProperties maxCacheSize(int maxCacheSize) { this.maxCacheSize = maxCacheSize; return this; } public DbProperties dbUrl(String dbUrl) { this.dbUrl = dbUrl; return this; } public DbProperties dbType(String dbType) { this.dbType = dbType; return this; } public DbProperties dbDir(String dbDir) { this.dbDir = dbDir; return this; } public DbProperties dbParams(String dbParams) { this.dbParams = dbParams; return this; } public DbProperties dbUsername(String dbUsername) { this.dbUsername = dbUsername; return this; } public DbProperties dbPassword(String dbPassword) { this.dbPassword = dbPassword; return this; } public DbProperties maxConnections(int maxConnections) { this.maxConnections = maxConnections; return this; } public DbProperties loginTimeout(int loginTimeout) { this.loginTimeout = loginTimeout; return this; } public DbProperties defaultLockTimeout(int defaultLockTimeout) { this.defaultLockTimeout = defaultLockTimeout; return this; } } private JdbcConnectionPool cp; private volatile int maxActiveConnections; private final String dbUrl; private final String dbUsername; private final String dbPassword; private final int maxConnections; private final int loginTimeout; private final int defaultLockTimeout; private volatile boolean initialized = false; public BasicDb(DbProperties dbProperties) { long maxCacheSize = dbProperties.maxCacheSize; if (maxCacheSize == 0) { maxCacheSize = Math.min(256, Math.max(16, (Runtime.getRuntime().maxMemory() / (1024 * 1024) - 128)/2)) * 1024; } String dbUrl = dbProperties.dbUrl; if (dbUrl == null) { String dbDir = Nxt.getDbDir(dbProperties.dbDir); dbUrl = String.format("jdbc:%s:%s;%s", dbProperties.dbType, dbDir, dbProperties.dbParams); } if (!dbUrl.contains("CACHE_SIZE=")) { dbUrl += ";CACHE_SIZE=" + maxCacheSize; } this.dbUrl = dbUrl; this.dbUsername = dbProperties.dbUsername; this.dbPassword = dbProperties.dbPassword; this.maxConnections = dbProperties.maxConnections; this.loginTimeout = dbProperties.loginTimeout; this.defaultLockTimeout = dbProperties.defaultLockTimeout; } public void init(DbVersion dbVersion) { Logger.logDebugMessage("Database jdbc url set to %s username %s", dbUrl, dbUsername); FullTextTrigger.setActive(true); cp = JdbcConnectionPool.create(dbUrl, dbUsername, dbPassword); cp.setMaxConnections(maxConnections); cp.setLoginTimeout(loginTimeout); try (Connection con = cp.getConnection(); Statement stmt = con.createStatement()) { stmt.executeUpdate("SET DEFAULT_LOCK_TIMEOUT " + defaultLockTimeout); } catch (SQLException e) { throw new RuntimeException(e.toString(), e); } dbVersion.init(this); initialized = true; } public void shutdown() { if (!initialized) { return; } try { FullTextTrigger.setActive(false); Connection con = cp.getConnection(); Statement stmt = con.createStatement(); stmt.execute("SHUTDOWN COMPACT"); Logger.logShutdownMessage("Database shutdown completed"); } catch (SQLException e) { Logger.logShutdownMessage(e.toString(), e); } } public void analyzeTables() { try (Connection con = cp.getConnection(); Statement stmt = con.createStatement()) { stmt.execute("ANALYZE SAMPLE_SIZE 0"); } catch (SQLException e) { throw new RuntimeException(e.toString(), e); } } public Connection getConnection() throws SQLException { Connection con = getPooledConnection(); con.setAutoCommit(true); return con; } protected Connection getPooledConnection() throws SQLException { Connection con = cp.getConnection(); int activeConnections = cp.getActiveConnections(); if (activeConnections > maxActiveConnections) { maxActiveConnections = activeConnections; Logger.logDebugMessage("Database connection pool current size: " + activeConnections); } return con; } public String getUrl() { return dbUrl; } }