/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.constant.ErrorCode;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.tools.CreateCluster;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server;
import org.h2.util.JdbcUtils;
/**
* Test for the cluster feature.
*/
public class TestCluster extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
public void test() throws Exception {
testClob();
testRecover();
testRollback();
testCase();
testCreateClusterAtRuntime();
testStartStopCluster();
}
private void testClob() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9191, port2 = 9192;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
org.h2.Driver.load();
String user = getUser(), password = getPassword();
Connection conn;
Statement stat;
String url1 = "jdbc:h2:tcp://localhost:" + port1 + "/test";
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
conn = DriverManager.getConnection(url1, user, password);
stat = conn.createStatement();
stat.execute("create table t1(id int, name clob)");
stat.execute("insert into t1 values(1, repeat('Hello', 50))");
conn.close();
String url2 = "jdbc:h2:tcp://localhost:" + port2 + "/test";
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
String urlCluster = "jdbc:h2:tcp://" + serverList + "/test";
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
conn = DriverManager.getConnection(urlCluster, user, password);
conn.close();
n1.stop();
n2.stop();
deleteFiles();
}
private void testRecover() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9191, port2 = 9192;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
org.h2.Driver.load();
String user = getUser(), password = getPassword();
Connection conn;
Statement stat;
ResultSet rs;
String url1 = "jdbc:h2:tcp://localhost:" + port1 + "/test";
String url2 = "jdbc:h2:tcp://localhost:" + port2 + "/test";
String urlCluster = "jdbc:h2:tcp://" + serverList + "/test";
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
conn = DriverManager.getConnection(urlCluster, user, password);
stat = conn.createStatement();
stat.execute("create table t1(id int, name varchar(30))");
stat.execute("insert into t1 values(1, 'a'), (2, 'b'), (3, 'c')");
rs = stat.executeQuery("select count(*) from t1");
rs.next();
assertEquals(3, rs.getInt(1));
n2.stop();
DeleteDbFiles.main("-dir", getBaseDir() + "/node2", "-quiet");
stat.execute("insert into t1 values(4, 'd'), (5, 'e')");
rs = stat.executeQuery("select count(*) from t1");
rs.next();
assertEquals(5, rs.getInt(1));
n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
conn.close();
conn = DriverManager.getConnection(urlCluster, user, password);
stat = conn.createStatement();
rs = stat.executeQuery("select count(*) from t1");
rs.next();
assertEquals(5, rs.getInt(1));
n1.stop();
n2.stop();
deleteFiles();
}
private void testRollback() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9191, port2 = 9192;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
org.h2.Driver.load();
String user = getUser(), password = getPassword();
Connection conn;
Statement stat;
ResultSet rs;
String url1 = "jdbc:h2:tcp://localhost:" + port1 + "/test";
String url2 = "jdbc:h2:tcp://localhost:" + port2 + "/test";
String urlCluster = "jdbc:h2:tcp://" + serverList + "/test";
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
conn = DriverManager.getConnection(urlCluster, user, password);
stat = conn.createStatement();
assertTrue(conn.getAutoCommit());
stat.execute("create table test(id int, name varchar)");
assertTrue(conn.getAutoCommit());
stat.execute("set autocommit false");
// issue 259
// assertFalse(conn.getAutoCommit());
conn.setAutoCommit(false);
assertFalse(conn.getAutoCommit());
stat.execute("insert into test values(1, 'Hello')");
stat.execute("rollback");
rs = stat.executeQuery("select * from test order by id");
assertFalse(rs.next());
conn.close();
n1.stop();
n2.stop();
deleteFiles();
}
private void testCase() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9191, port2 = 9192;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
org.h2.Driver.load();
String user = getUser(), password = getPassword();
Connection conn;
Statement stat;
ResultSet rs;
String url1 = "jdbc:h2:tcp://localhost:" + port1 + "/test";
String url2 = "jdbc:h2:tcp://localhost:" + port2 + "/test";
String urlCluster = "jdbc:h2:tcp://" + serverList + "/test";
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
conn = DriverManager.getConnection(urlCluster, user, password);
stat = conn.createStatement();
assertTrue(conn.getAutoCommit());
stat.execute("create table test(name int)");
assertTrue(conn.getAutoCommit());
stat.execute("insert into test values(1)");
conn.setAutoCommit(false);
assertFalse(conn.getAutoCommit());
stat.execute("insert into test values(2)");
assertFalse(conn.getAutoCommit());
conn.rollback();
rs = stat.executeQuery("select * from test order by name");
assertTrue(rs.next());
assertFalse(rs.next());
conn.close();
// stop server 2, and test if only one server is available
n2.stop();
conn = DriverManager.getConnection(urlCluster, user, password);
stat = conn.createStatement();
rs = stat.executeQuery("select * from test");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
conn.close();
n1.stop();
deleteFiles();
}
private void testCreateClusterAtRuntime() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9191, port2 = 9192;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
org.h2.Driver.load();
String user = getUser(), password = getPassword();
Connection conn;
Statement stat;
String url1 = "jdbc:h2:tcp://localhost:" + port1 + "/test";
String url2 = "jdbc:h2:tcp://localhost:" + port2 + "/test";
String urlCluster = "jdbc:h2:tcp://" + serverList + "/test";
int len = 10;
// initialize the database
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
conn = DriverManager.getConnection(url1, user, password);
stat = conn.createStatement();
stat.execute("create table test(id int primary key, name varchar) as " +
"select x, 'Data' || x from system_range(0, " + (len - 1) + ")");
stat.execute("create user test password 'test'");
stat.execute("grant all on test to test");
// start the second server
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2 , "-baseDir", getBaseDir() + "/node2").start();
// copy the database and initialize the cluster
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
// check the original connection is closed
assertThrows(ErrorCode.CONNECTION_BROKEN_1, stat).
execute("select * from test");
JdbcUtils.closeSilently(conn);
// test the cluster connection
Connection connApp = DriverManager.getConnection(urlCluster + ";AUTO_RECONNECT=TRUE", user, password);
check(connApp, len, "'" + serverList + "'");
// delete the rows, but don't commit
connApp.setAutoCommit(false);
connApp.createStatement().execute("delete from test");
// stop server 2, and test if only one server is available
n2.stop();
// rollback the transaction
connApp.createStatement().executeQuery("select count(*) from test");
connApp.rollback();
check(connApp, len, "''");
connApp.setAutoCommit(true);
// re-create the cluster
n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2, "-baseDir", getBaseDir() + "/node2").start();
CreateCluster.main("-urlSource", url1, "-urlTarget", url2, "-user", user, "-password", password, "-serverList",
serverList);
// test the cluster connection
check(connApp, len, "'" + serverList + "'");
// test a non-admin user
String user2 = "test", password2 = getPassword("test");
connApp = DriverManager.getConnection(urlCluster, user2, password2);
check(connApp, len, "'" + serverList + "'");
n1.stop();
// test non-admin cluster connection if only one server runs
Connection connApp2 = DriverManager.getConnection(urlCluster + ";AUTO_RECONNECT=TRUE", user2, password2);
check(connApp2, len, "''");
connApp2.close();
// test non-admin cluster connection if only one server runs
connApp2 = DriverManager.getConnection(urlCluster + ";AUTO_RECONNECT=TRUE", user2, password2);
check(connApp2, len, "''");
connApp2.close();
n2.stop();
deleteFiles();
}
private void testStartStopCluster() throws SQLException {
if (config.memory || config.networked || config.cipher != null) {
return;
}
int port1 = 9193, port2 = 9194;
String serverList = "localhost:" + port1 + ",localhost:" + port2;
deleteFiles();
// initialize the database
Connection conn;
org.h2.Driver.load();
String urlNode1 = getURL("node1/test", true);
String urlNode2 = getURL("node2/test", true);
String user = getUser(), password = getPassword();
conn = DriverManager.getConnection(urlNode1, user, password);
Statement stat;
stat = conn.createStatement();
stat.execute("DROP TABLE IF EXISTS TEST");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?)");
int len = getSize(10, 1000);
for (int i = 0; i < len; i++) {
prep.setInt(1, i);
prep.setString(2, "Data" + i);
prep.executeUpdate();
}
check(conn, len, "''");
conn.close();
// copy the database and initialize the cluster
CreateCluster.main("-urlSource", urlNode1, "-urlTarget",
urlNode2, "-user", user, "-password", password, "-serverList",
serverList);
// start both servers
Server n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
Server n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2, "-baseDir", getBaseDir() + "/node2").start();
// try to connect in standalone mode - should fail
// should not be able to connect in standalone mode
assertThrows(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_CLUSTERED_1, this).
getConnection("jdbc:h2:tcp://localhost:"+port1+"/test", user, password);
assertThrows(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_CLUSTERED_1, this).
getConnection("jdbc:h2:tcp://localhost:"+port2+"/test", user, password);
// test a cluster connection
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
check(conn, len, "'"+serverList+"'");
conn.close();
// stop server 2, and test if only one server is available
n2.stop();
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
check(conn, len, "''");
conn.close();
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
check(conn, len, "''");
conn.close();
// disable the cluster
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:"+port1+"/test;CLUSTER=''", user, password);
conn.close();
n1.stop();
// re-create the cluster
DeleteDbFiles.main("-dir", getBaseDir() + "/node2", "-quiet");
CreateCluster.main("-urlSource", urlNode1, "-urlTarget",
urlNode2, "-user", user, "-password", password, "-serverList",
serverList);
n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2, "-baseDir", getBaseDir() + "/node2").start();
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
stat = conn.createStatement();
stat.execute("CREATE TABLE BOTH(ID INT)");
n1.stop();
stat.execute("CREATE TABLE A(ID INT)");
conn.close();
n2.stop();
n1 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port1, "-baseDir", getBaseDir() + "/node1").start();
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:"+port1+"/test;CLUSTER=''", user, password);
check(conn, len, "''");
conn.close();
n1.stop();
n2 = org.h2.tools.Server.createTcpServer("-tcpPort", "" + port2, "-baseDir", getBaseDir() + "/node2").start();
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:" + port2 + "/test;CLUSTER=''", user, password);
check(conn, len, "''");
conn.createStatement().execute("SELECT * FROM A");
conn.close();
n2.stop();
deleteFiles();
}
private void deleteFiles() throws SQLException {
DeleteDbFiles.main("-dir", getBaseDir() + "/node1", "-quiet");
DeleteDbFiles.main("-dir", getBaseDir() + "/node2", "-quiet");
FileUtils.delete(getBaseDir() + "/node1");
FileUtils.delete(getBaseDir() + "/node2");
}
private void check(Connection conn, int len, String expectedCluster) throws SQLException {
PreparedStatement prep = conn.prepareStatement("SELECT * FROM TEST WHERE ID=?");
for (int i = 0; i < len; i++) {
prep.setInt(1, i);
ResultSet rs = prep.executeQuery();
rs.next();
assertEquals("Data" + i, rs.getString(2));
assertFalse(rs.next());
}
ResultSet rs = conn.createStatement().executeQuery(
"SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME='CLUSTER'");
String cluster = rs.next() ? rs.getString(1) : "''";
assertEquals(expectedCluster, cluster);
}
}