All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.h2.tools.CreateCluster Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2004-2023 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (https://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.tools;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.h2.jdbc.JdbcConnection;
import org.h2.util.Tool;

/**
 * Creates a cluster from a stand-alone database.
 *
 * Copies a database to another location if required.
 */
public class CreateCluster extends Tool {

    /**
     * Options are case sensitive.
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
Supported options
[-help] or [-?]Print the list of options
[-urlSource "<url>"]The database URL of the source database (jdbc:h2:...)
[-urlTarget "<url>"]The database URL of the target database (jdbc:h2:...)
[-user <user>]The user name (default: sa)
[-password <pwd>]The password
[-serverList <list>]The comma separated list of host names or IP addresses
* * @param args the command line arguments * @throws SQLException on failure */ public static void main(String... args) throws SQLException { new CreateCluster().runTool(args); } @Override public void runTool(String... args) throws SQLException { String urlSource = null; String urlTarget = null; String user = ""; String password = ""; String serverList = null; for (int i = 0; args != null && i < args.length; i++) { String arg = args[i]; if (arg.equals("-urlSource")) { urlSource = args[++i]; } else if (arg.equals("-urlTarget")) { urlTarget = args[++i]; } else if (arg.equals("-user")) { user = args[++i]; } else if (arg.equals("-password")) { password = args[++i]; } else if (arg.equals("-serverList")) { serverList = args[++i]; } else if (arg.equals("-help") || arg.equals("-?")) { showUsage(); return; } else { showUsageAndThrowUnsupportedOption(arg); } } if (urlSource == null || urlTarget == null || serverList == null) { showUsage(); throw new SQLException("Source URL, target URL, or server list not set"); } process(urlSource, urlTarget, user, password, serverList); } /** * Creates a cluster. * * @param urlSource the database URL of the original database * @param urlTarget the database URL of the copy * @param user the user name * @param password the password * @param serverList the server list * @throws SQLException on failure */ public void execute(String urlSource, String urlTarget, String user, String password, String serverList) throws SQLException { process(urlSource, urlTarget, user, password, serverList); } private static void process(String urlSource, String urlTarget, String user, String password, String serverList) throws SQLException { // use cluster='' so connecting is possible // even if the cluster is enabled try (JdbcConnection connSource = new JdbcConnection(urlSource + ";CLUSTER=''", null, user, password, false); Statement statSource = connSource.createStatement()) { // enable the exclusive mode and close other connections, // so that data can't change while restoring the second database statSource.execute("SET EXCLUSIVE 2"); try { performTransfer(statSource, urlTarget, user, password, serverList); } finally { // switch back to the regular mode statSource.execute("SET EXCLUSIVE FALSE"); } } } private static void performTransfer(Statement statSource, String urlTarget, String user, String password, String serverList) throws SQLException { // Delete the target database first. try (JdbcConnection connTarget = new JdbcConnection(urlTarget + ";CLUSTER=''", null, user, password, false); Statement statTarget = connTarget.createStatement()) { statTarget.execute("DROP ALL OBJECTS DELETE FILES"); } try (PipedReader pipeReader = new PipedReader()) { Future threadFuture = startWriter(pipeReader, statSource); // Read data from pipe reader, restore on target. try (JdbcConnection connTarget = new JdbcConnection(urlTarget, null, user, password, false); Statement statTarget = connTarget.createStatement()) { RunScript.execute(connTarget, pipeReader); // Check if the writer encountered any exception try { threadFuture.get(); } catch (ExecutionException ex) { throw new SQLException(ex.getCause()); } catch (InterruptedException ex) { throw new SQLException(ex); } // set the cluster to the serverList on both databases statSource.executeUpdate("SET CLUSTER '" + serverList + "'"); statTarget.executeUpdate("SET CLUSTER '" + serverList + "'"); } } catch (IOException ex) { throw new SQLException(ex); } } private static Future startWriter(final PipedReader pipeReader, final Statement statSource) throws IOException { final ExecutorService thread = Executors.newFixedThreadPool(1); final PipedWriter pipeWriter = new PipedWriter(pipeReader); // Since exceptions cannot be thrown across thread boundaries, return // the task's future so we can check manually Future threadFuture = thread.submit(() -> { // If the creation of the piped writer fails, the reader will // throw an IOException as soon as read() is called: IOException // - if the pipe is broken, unconnected, closed, or an I/O error // occurs. The reader's IOException will then trigger the // finally{} that releases exclusive mode on the source DB. try (PipedWriter writer = pipeWriter; final ResultSet rs = statSource.executeQuery("SCRIPT")) { while (rs.next()) { writer.write(rs.getString(1) + "\n"); } } catch (SQLException | IOException ex) { throw new IllegalStateException("Producing script from the source DB is failing.", ex); } }); thread.shutdown(); return threadFuture; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy