Hi I am using H2 in a clustered configuration where we need some control/detection of which servers are currently in the cluster. I have added functionality to the jdbc connection to get the number of servers currently in the cluster and which servers that are available. Have a look at my patch and tell me what you think.
Best regards Nikolaj Fogh -- You received this message because you are subscribed to the Google Groups "H2 Database" group. To unsubscribe from this group and stop receiving emails from it, send an email to h2-database+unsubscr...@googlegroups.com. To post to this group, send email to h2-database@googlegroups.com. Visit this group at http://groups.google.com/group/h2-database. For more options, visit https://groups.google.com/d/optout.
Index: src/docsrc/html/advanced.html =================================================================== --- src/docsrc/html/advanced.html (revision 5747) +++ src/docsrc/html/advanced.html (working copy) @@ -390,6 +390,15 @@ servers is returned, enclosed in single quote. Example: <code>'server1:9191,server2:9191'</code>. </p> +<p>It is also possible to get the list of servers by using Connection.getClientInfo().</p> + +<p>The property list returned from <code>getClientInfo()</code> contains a <code>numServers</code> property that returns the +number of servers that are in the connection list. To get the actual servers, <code>getClientInfo()</code> also has +properties <code>server0</code>..<code>serverX</code>, where serverX is the number of servers minus 1. + +<p>Example: To get the 2nd server in the connection list one uses <code>getClientInfo('server1')<code>. <b>Note:</b> The +<code>serverX</code> property only returns IP addresses and ports and not hostnames.</p> + <h3>Clustering Algorithm and Limitations</h3> <p> Read-only queries are only executed against the first cluster node, but all other statements are Index: src/main/org/h2/engine/Session.java =================================================================== --- src/main/org/h2/engine/Session.java (revision 5747) +++ src/main/org/h2/engine/Session.java (working copy) @@ -127,6 +127,10 @@ this.currentSchemaName = Constants.SCHEMA_MAIN; } + public ArrayList<String> getServers() { + return new ArrayList<String>(); + } + public boolean setCommitOrRollbackDisabled(boolean x) { boolean old = commitOrRollbackDisabled; commitOrRollbackDisabled = x; Index: src/main/org/h2/engine/SessionInterface.java =================================================================== --- src/main/org/h2/engine/SessionInterface.java (revision 5747) +++ src/main/org/h2/engine/SessionInterface.java (working copy) @@ -6,6 +6,8 @@ package org.h2.engine; import java.io.Closeable; +import java.util.ArrayList; + import org.h2.command.CommandInterface; import org.h2.message.Trace; import org.h2.store.DataHandler; @@ -17,6 +19,13 @@ public interface SessionInterface extends Closeable { /** + * Get the list of servers for this session. + * + * @return A list of "IP:PORT" strings for the servers in this session. + */ + ArrayList<String> getServers(); + + /** * Parse a command and prepare it for execution. * * @param sql the SQL statement Index: src/main/org/h2/engine/SessionRemote.java =================================================================== --- src/main/org/h2/engine/SessionRemote.java (revision 5747) +++ src/main/org/h2/engine/SessionRemote.java (working copy) @@ -8,6 +8,7 @@ import java.io.IOException; import java.net.Socket; import java.util.ArrayList; +import java.util.List; import org.h2.api.DatabaseEventListener; import org.h2.api.ErrorCode; @@ -95,6 +96,17 @@ this.connectionInfo = ci; } + public ArrayList<String> getServers() { + ArrayList<String> serverList = new ArrayList<String>(); + + for (int i = 0; i < transferList.size(); i++) { + Transfer transfer = transferList.get(i); + serverList.add(transfer.getSocket().getInetAddress().getHostAddress().toString() + ":" + String.valueOf(transfer.getSocket().getPort())); + } + + return serverList; + } + private Transfer initTransfer(ConnectionInfo ci, String db, String server) throws IOException { Socket socket = NetUtils.createSocket(server, Index: src/main/org/h2/jdbc/JdbcConnection.java =================================================================== --- src/main/org/h2/jdbc/JdbcConnection.java (revision 5747) +++ src/main/org/h2/jdbc/JdbcConnection.java (working copy) @@ -25,6 +25,7 @@ import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; +import java.util.ArrayList; import java.util.Map; import java.util.Properties; @@ -47,7 +48,7 @@ import org.h2.value.ValueNull; import org.h2.value.ValueString; -/*## Java 1.7 ## +//## Java 1.7 ## import java.util.concurrent.Executor; //*/ @@ -1715,35 +1716,37 @@ /** * Get the client properties. - * This method always returns null. * - * @return always null + * @return the property list */ @Override public Properties getClientInfo() throws SQLException { try { - debugCode("getClientInfo();"); - // we don't have any client properties, so return null - return null; + ArrayList<String> serverList = session.getServers(); + Properties p = new Properties(); + + p.setProperty("numServers", String.valueOf(serverList.size())); + for (int i = 0; i < serverList.size(); i++) + p.setProperty("server" + String.valueOf(i), serverList.get(i)); + return p; } catch (Exception e) { throw logAndConvert(e); } } /** - * Set a client property. - * This method always throws a SQLClientInfoException. + * Get a client property. * * @param name the client info name (ignored) - * @return this method never returns normally + * @return the property value */ @Override public String getClientInfo(String name) throws SQLException { try { + Properties p = getClientInfo(); debugCodeCall("getClientInfo", name); checkClosed(); - // we don't have any client properties, so just throw - throw new SQLClientInfoException(); + return p.getProperty(name); } catch (Exception e) { throw logAndConvert(e); } @@ -1814,7 +1817,7 @@ * * @param schema the schema */ -/*## Java 1.7 ## +//## Java 1.7 ## @Override public void setSchema(String schema) { // not supported @@ -1824,7 +1827,7 @@ /** * [Not supported] */ -/*## Java 1.7 ## +//## Java 1.7 ## @Override public String getSchema() { return null; @@ -1836,7 +1839,7 @@ * * @param executor the executor used by this method */ -/*## Java 1.7 ## +//## Java 1.7 ## @Override public void abort(Executor executor) { // not supported @@ -1849,7 +1852,7 @@ * @param executor the executor used by this method * @param milliseconds the TCP connection timeout */ -/*## Java 1.7 ## +//## Java 1.7 ## @Override public void setNetworkTimeout(Executor executor, int milliseconds) { // not supported @@ -1859,7 +1862,7 @@ /** * [Not supported] */ -/*## Java 1.7 ## +//## Java 1.7 ## @Override public int getNetworkTimeout() { return 0; Index: src/test/org/h2/test/db/TestCluster.java =================================================================== --- src/test/org/h2/test/db/TestCluster.java (revision 5747) +++ src/test/org/h2/test/db/TestCluster.java (working copy) @@ -10,6 +10,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.Properties; import org.h2.api.ErrorCode; import org.h2.store.fs.FileUtils; @@ -39,6 +40,7 @@ testRecover(); testRollback(); testCase(); + testClientInfo(); testCreateClusterAtRuntime(); testStartStopCluster(); } @@ -250,6 +252,60 @@ n1.stop(); deleteFiles(); } + + private void testClientInfo() 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; + + String url1 = getURL("jdbc:h2:tcp://localhost:" + port1 + "/test", true); + String url2 = getURL("jdbc:h2:tcp://localhost:" + port2 + "/test", true); + String urlCluster = getURL("jdbc:h2:tcp://" + serverList + "/test", true); + + 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 = getConnection(urlCluster, user, password); + Properties p = conn.getClientInfo(); + + assertEquals("2", p.getProperty("numServers")); + assertEquals("127.0.0.1:" + port1, p.getProperty("server0")); + assertEquals("127.0.0.1:" + port2, p.getProperty("server1")); + + assertEquals("2", conn.getClientInfo("numServers")); + assertEquals("127.0.0.1:" + port1, conn.getClientInfo("server0")); + assertEquals("127.0.0.1:" + port2, conn.getClientInfo("server1")); + conn.close(); + + // stop server 2, and test if only one server is available + n2.stop(); + + conn = getConnection(urlCluster, user, password); + p = conn.getClientInfo(); + + assertEquals("1", p.getProperty("numServers")); + assertEquals("127.0.0.1:" + port1, p.getProperty("server0")); + assertEquals("1", conn.getClientInfo("numServers")); + assertEquals("127.0.0.1:" + port1, conn.getClientInfo("server0")); + conn.close(); + + n1.stop(); + deleteFiles(); + } + private void testCreateClusterAtRuntime() throws SQLException { if (config.memory || config.networked || config.cipher != null) { return;