/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ /* * Copyright 2004-2010 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 com.thoughtworks.go.server.database; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.h2.tools.RunScript; /** * Migrate a H2 database version 1.1.x (page store not enabled) to 1.2.x (page * store format). This will download the H2 jar file version 1.2.127 from * maven.org if it doesn't exist, execute the Script tool (using Runtime.exec) * to create a backup.sql script, rename the old database file to *.backup, * created a new database (using the H2 jar file in the class path) using the * Script tool, and then delete the backup.sql file. Most utility methods are * copied from h2/src/tools/org/h2/build/BuildBase.java. */ public class Migrate { public static final String USER = "sa"; public static final String PASSWORD = ""; private static final File OLD_H2_FILE = new File("./historical_jars/h2-1.2.127.jar"); private static final String TEMP_SCRIPT = "backup.sql"; private static final String MAX_MEMORY_FOR_MIGRATION = "256m"; private PrintStream sysOut = System.out; private boolean quiet; private static final Logger LOGGER = Logger.getLogger(Migrate.class); /** * Migrate databases. The user name and password are both "sa". * * @param args the path (default is the current directory) * @throws Exception if conversion fails */ public static void main(String... args) throws Exception { new Migrate().execute(new File(args.length == 1 ? args[0] : "."), true, USER, PASSWORD, false); } /** * Migrate a database. * * @param file the database file (must end with .data.db) or directory * @param recursive if the file parameter is in fact a directory (in which * case the directory is scanned recursively) * @param user the user name of the database * @param password the password * @param runQuiet to run in quiet mode * @throws Exception if conversion fails */ public void execute(File file, boolean recursive, String user, String password, boolean runQuiet) throws Exception { String pathToJavaExe = getJavaExecutablePath(); this.quiet = runQuiet; if (file.isDirectory() && recursive) { for (File f : file.listFiles()) { execute(f, recursive, user, password, runQuiet); } return; } if (!file.getName().endsWith(".data.db")) { return; } LOGGER.info("Migrating the database at " + file.getAbsolutePath() + " to the new format. This might take a while based on the size of your database."); String fileNameWithoutExtension = truncateFileExtension(file.getAbsolutePath()); File newDatabaseFile = new File(fileNameWithoutExtension + ".h2.db"); if(newDatabaseFile.exists()) { LOGGER.info("Removing " + newDatabaseFile.getAbsolutePath() + " [the new database file]"); FileUtils.deleteQuietly(newDatabaseFile); } if (!OLD_H2_FILE.exists()) { throw new IllegalStateException(String.format("h2 file %s not found, migration could not be completed successfully", OLD_H2_FILE.getAbsolutePath())); } String url = "jdbc:h2:" + fileNameWithoutExtension; exec(new String[] { pathToJavaExe, "-Xmx" + MAX_MEMORY_FOR_MIGRATION, "-cp", OLD_H2_FILE.getAbsolutePath(), "org.h2.tools.Script", "-script", TEMP_SCRIPT, "-url", url, "-user", user }); file.renameTo(new File(file.getAbsoluteFile() + ".backup")); RunScript.execute(url, user, password, TEMP_SCRIPT, "UTF-8", true); new File(TEMP_SCRIPT).delete(); LOGGER.info("Migrating the h2db to the new format is complete."); } private String truncateFileExtension(String url) { return url.substring(0, url.length() - ".data.db".length()); } private String getJavaExecutablePath() { String pathToJava; if (File.separator.equals("\\")) { pathToJava = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java.exe"; } else { pathToJava = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; } if (!new File(pathToJava).exists()) { // Fallback to old behaviour pathToJava = "java"; } return pathToJava; } private int exec(String[] command) { try { if (LOGGER.isDebugEnabled()) { LOGGER.debug("About to execute commands:"); for (String c : command) { LOGGER.debug(c); } } Process p = Runtime.getRuntime().exec(command); copyInThread(p.getInputStream(), quiet ? null : sysOut); copyInThread(p.getErrorStream(), quiet ? null : sysOut); p.waitFor(); return p.exitValue(); } catch (Exception e) { throw new RuntimeException(e); } } private void copyInThread(final InputStream in, final OutputStream out) { new Thread() { public void run() { try { while (true) { int x = in.read(); if (x < 0) { return; } if (out != null) { out.write(x); } } } catch (Exception e) { throw new RuntimeException(e); } } } .start(); } }