/******************************************************************************
* 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;
}
}