Author: fpj Date: Fri Feb 24 17:10:20 2012 New Revision: 1293342 URL: http://svn.apache.org/viewvc?rev=1293342&view=rev Log: BOOKKEEPER-172: Upgrade framework for filesystem layouts (ivank via fpj)
Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileSystemUpgrade.java zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java Modified: zookeeper/bookkeeper/trunk/CHANGES.txt zookeeper/bookkeeper/trunk/bookkeeper-server/bin/bookkeeper zookeeper/bookkeeper/trunk/doc/bookkeeperConfig.textile Modified: zookeeper/bookkeeper/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/CHANGES.txt?rev=1293342&r1=1293341&r2=1293342&view=diff ============================================================================== --- zookeeper/bookkeeper/trunk/CHANGES.txt (original) +++ zookeeper/bookkeeper/trunk/CHANGES.txt Fri Feb 24 17:10:20 2012 @@ -63,6 +63,8 @@ Trunk (unreleased changes) BOOKKEEPER-137: Do not create Ledger index files until absolutely necessary. (ivank) + BOOKKEEPER-172: Upgrade framework for filesystem layouts (ivank via fpj) + hedwig-server/ BOOKKEEPER-77: Add a console client for hedwig (Sijie Guo via ivank) Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/bin/bookkeeper URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/bin/bookkeeper?rev=1293342&r1=1293341&r2=1293342&view=diff ============================================================================== --- zookeeper/bookkeeper/trunk/bookkeeper-server/bin/bookkeeper (original) +++ zookeeper/bookkeeper/trunk/bookkeeper-server/bin/bookkeeper Fri Feb 24 17:10:20 2012 @@ -56,6 +56,7 @@ Usage: bookkeeper <command> where command is one of: bookie Run a bookie server localbookie <n> Run a test ensemble of <n> bookies locally + upgrade Upgrade bookie filesystem help This help message or command is the full name of a class with a defined main() method. @@ -126,6 +127,8 @@ elif [ $COMMAND == "localbookie" ]; then NUMBER=$1 shift exec java $OPTS org.apache.bookkeeper.util.LocalBookKeeper $NUMBER $BOOKIE_CONF $@ +elif [ $COMMAND == "upgrade" ]; then + exec java $OPTS org.apache.bookkeeper.bookie.FileSystemUpgrade --conf $BOOKIE_CONF $@ elif [ $COMMAND == "help" ]; then bookkeeper_help; else Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileSystemUpgrade.java URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileSystemUpgrade.java?rev=1293342&view=auto ============================================================================== --- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileSystemUpgrade.java (added) +++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileSystemUpgrade.java Fri Feb 24 17:10:20 2012 @@ -0,0 +1,160 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ + +package org.apache.bookkeeper.bookie; + +import org.apache.commons.cli.BasicParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.ParseException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.Scanner; +import java.util.NoSuchElementException; + +import java.net.MalformedURLException; +import org.apache.bookkeeper.conf.ServerConfiguration; +import org.apache.commons.configuration.ConfigurationException; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Application for upgrading the bookkeeper filesystem + * between versions + */ +public class FileSystemUpgrade { + static Logger LOG = LoggerFactory.getLogger(FileSystemUpgrade.class); + + private int detectPreviousVersion(File directory) throws IOException { + final AtomicBoolean oldDataExists = new AtomicBoolean(false); + directory.list(new FilenameFilter() { + public boolean accept(File dir, String name) { + if (name.endsWith(".txn") || name.endsWith(".idx") || name.endsWith(".log") + || name.equals(Bookie.VERSION_FILENAME)) { + oldDataExists.set(true); + } + return true; + } + }); + if (!oldDataExists.get()) { // no old data, so we're ok + return Bookie.CURRENT_DIRECTORY_LAYOUT_VERSION; + } + File v2versionFile = new File(directory, Bookie.VERSION_FILENAME); + if (!v2versionFile.exists()) { + return 1; + } + Scanner s = new Scanner(v2versionFile); + try { + return s.nextInt(); + } catch (NoSuchElementException nse) { + LOG.error("Couldn't parse version file " + v2versionFile , nse); + throw new IOException("Couldn't parse version file", nse); + } catch (IllegalStateException ise) { + LOG.error("Error reading file " + v2versionFile, ise); + throw new IOException("Error reading version file", ise); + } finally { + s.close(); + } + } + + public static void upgrade(ServerConfiguration conf) { + LOG.info("Upgrading..."); + // noop at the moment + LOG.info("Done"); + } + + public static void finalizeUpgrade(ServerConfiguration conf) { + LOG.info("Finalizing upgrade..."); + // noop at the moment + LOG.info("Done"); + } + + public static void rollback(ServerConfiguration conf) { + LOG.info("Rolling back upgrade..."); + // noop at the moment + LOG.info("Done"); + } + + private static void printHelp(Options opts) { + HelpFormatter hf = new HelpFormatter(); + hf.printHelp("FileSystemUpgrade [options]", opts); + } + + public static void main(String[] args) throws Exception { + org.apache.log4j.Logger root = org.apache.log4j.Logger.getRootLogger(); + root.addAppender(new org.apache.log4j.ConsoleAppender( + new org.apache.log4j.PatternLayout("%-5p [%t]: %m%n"))); + root.setLevel(org.apache.log4j.Level.ERROR); + root.getLogger(FileSystemUpgrade.class).setLevel(org.apache.log4j.Level.INFO); + + final Options opts = new Options(); + opts.addOption("c", "conf", true, "Configuration for Bookie"); + opts.addOption("u", "upgrade", false, "Upgrade bookie directories"); + opts.addOption("f", "finalize", false, "Finalize upgrade"); + opts.addOption("r", "rollback", false, "Rollback upgrade"); + opts.addOption("h", "help", false, "Print help message"); + + BasicParser parser = new BasicParser(); + CommandLine cmdLine = parser.parse(opts, args); + if (cmdLine.hasOption("h")) { + printHelp(opts); + return; + } + + if (!cmdLine.hasOption("c")) { + String err = "Cannot upgrade without configuration"; + LOG.error(err); + printHelp(opts); + throw new IllegalArgumentException(err); + } + + String confFile = cmdLine.getOptionValue("c"); + ServerConfiguration conf = new ServerConfiguration(); + try { + conf.loadConf(new File(confFile).toURI().toURL()); + } catch (MalformedURLException mue) { + LOG.error("Could not open configuration file " + confFile, mue); + throw new IllegalArgumentException(); + } catch (ConfigurationException ce) { + LOG.error("Invalid configuration file " + confFile, ce); + throw new IllegalArgumentException(); + } + + if (cmdLine.hasOption("u")) { + upgrade(conf); + } else if (cmdLine.hasOption("r")) { + rollback(conf); + } else if (cmdLine.hasOption("f")) { + finalizeUpgrade(conf); + } else { + String err = "Must specify -upgrade, -finalize or -rollback"; + LOG.error(err); + printHelp(opts); + throw new IllegalArgumentException(err); + } + } +} \ No newline at end of file Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java?rev=1293342&view=auto ============================================================================== --- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java (added) +++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java Fri Feb 24 17:10:20 2012 @@ -0,0 +1,115 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ + +package org.apache.bookkeeper.bookie; + +import java.io.File; +import java.io.IOException; + +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.BufferedWriter; +import java.io.PrintStream; + + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.apache.bookkeeper.conf.ServerConfiguration; + +public class UpgradeTest { + static String newV1JournalDirectory() throws IOException { + File d = File.createTempFile("bookie", "tmpdir"); + d.delete(); + d.mkdirs(); + new File(d, Long.toHexString(System.currentTimeMillis()) + ".txn").createNewFile(); + return d.getPath(); + } + + static String newV1LedgerDirectory() throws IOException { + File d = File.createTempFile("bookie", "tmpdir"); + d.delete(); + d.mkdirs(); + new File(d, Long.toHexString(System.currentTimeMillis()) + ".log").createNewFile(); + return d.getPath(); + } + + static void createVersion2File(String dir) throws IOException { + File versionFile = new File(dir, "VERSION"); + + FileOutputStream fos = new FileOutputStream(versionFile); + BufferedWriter bw = null; + try { + bw = new BufferedWriter(new OutputStreamWriter(fos)); + bw.write(String.valueOf(2)); + } finally { + if (bw != null) { + bw.close(); + } + fos.close(); + } + } + + static String newV2JournalDirectory() throws IOException { + String d = newV1JournalDirectory(); + createVersion2File(d); + return d; + } + + static String newV2LedgerDirectory() throws IOException { + String d = newV1LedgerDirectory(); + createVersion2File(d); + return d; + } + + @Test + public void testCommandLine() throws Exception { + PrintStream origerr = System.err; + PrintStream origout = System.out; + + File output = File.createTempFile("bookie", "tmpout"); + System.setOut(new PrintStream(output)); + System.setErr(new PrintStream(output)); + try { + FileSystemUpgrade.main(new String[] { "-h" }); + try { + // test without conf + FileSystemUpgrade.main(new String[] { "-u" }); + fail("Should have failed"); + } catch (IllegalArgumentException iae) { + assertTrue("Wrong exception " + iae.getMessage(), + iae.getMessage().contains("without configuration")); + } + File f = File.createTempFile("bookie", "tmpconf"); + try { + // test without upgrade op + FileSystemUpgrade.main(new String[] { "--conf", f.getPath() }); + fail("Should have failed"); + } catch (IllegalArgumentException iae) { + assertTrue("Wrong exception " + iae.getMessage(), + iae.getMessage().contains("Must specify -upgrade")); + } + } finally { + System.setOut(origout); + System.setErr(origerr); + } + } +} \ No newline at end of file Modified: zookeeper/bookkeeper/trunk/doc/bookkeeperConfig.textile URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/doc/bookkeeperConfig.textile?rev=1293342&r1=1293341&r2=1293342&view=diff ============================================================================== --- zookeeper/bookkeeper/trunk/doc/bookkeeperConfig.textile (original) +++ zookeeper/bookkeeper/trunk/doc/bookkeeperConfig.textile Fri Feb 24 17:10:20 2012 @@ -14,7 +14,7 @@ Notice: Licensed under the Apache Licens h1. Abstract -This document contains information about deploying, administering and mantaining BookKeeper. It also discusses best practices and common problems. +This document contains information about deploying, administering and maintaining BookKeeper. It also discusses best practices and common problems. h1. Running a BookKeeper instance @@ -35,13 +35,29 @@ p. To run a bookie, we execute the follo p. The configuration parameters can be set in bookkeeper-server/conf/bk_server.conf. The important parameters are: - * @bookiePort@, Port number that the bookie listens on; - * @zkServers@, Comma separated list of ZooKeeper servers with a hostname:port format; - * @journalDir@, Path for Log Device (stores bookie write-ahead log); - * @ledgerDir@, Path for Ledger Device (stores ledger entries); + +* @bookiePort@, Port number that the bookie listens on; +* @zkServers@, Comma separated list of ZooKeeper servers with a hostname:port format; +* @journalDir@, Path for Log Device (stores bookie write-ahead log); +* @ledgerDir@, Path for Ledger Device (stores ledger entries); p. Ideally, @journalDir@ and @ledgerDir@ are each in a different device. See "BookKeeper Configuration Parameters":./bookkeeperConfigParams.html for a full list of configuration parameters. +h3. Upgrading + +From time to time, we may make changes to the filesystem layout of the bookie, which are incompatible with previous versions of bookkeeper and require that directories used with previous versions are upgraded. If you upgrade your bookkeeper software, and an upgrade is required, then the bookie will fail to start and print an error to the effect that an upgrade is required. + +BookKeeper provides a utility for doing the upgrade. +@bookkeeper-server/bin/bookkeeper upgrade@ + +The upgrade application takes 3 possible switches, @--upgrade@, @--rollback@ or @--finalize@. A normal upgrade process looks like. + +# @bookkeeper-server/bin/bookkeeper upgrade --upgrade@ +# @bookkeeper-server/bin/bookkeeper bookie@ +# Check everything is working. Kill bookie, ^C +# If everything is ok, @bookkeeper-server/bin/bookkeeper upgrade --finalize@ +# Start bookie again @bookkeeper-server/bin/bookkeeper bookie@ +# If something is amiss, you can roll back the upgrade @bookkeeper-server/bin/bookkeeper upgrade --rollback@ h3. Logging