Java tutorial
/** * * 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.net.BindException; import java.net.InetAddress; import org.jboss.netty.channel.ChannelException; import junit.framework.Assert; import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; import org.apache.bookkeeper.conf.ServerConfiguration; import org.apache.bookkeeper.conf.TestBKConfiguration; import org.apache.bookkeeper.proto.BookieServer; import org.apache.bookkeeper.test.BookKeeperClusterTestCase; import org.apache.bookkeeper.util.DiskChecker.DiskErrorException; import org.apache.bookkeeper.zookeeper.ZooKeeperClient; import org.apache.commons.io.FileUtils; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import org.apache.zookeeper.KeeperException; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Testing bookie initialization cases */ public class BookieInitializationTest extends BookKeeperClusterTestCase { private static final Logger LOG = LoggerFactory.getLogger(BookieInitializationTest.class); ZooKeeper newzk = null; public BookieInitializationTest() { super(0); } @Override public void tearDown() throws Exception { if (null != newzk) { newzk.close(); } super.tearDown(); } private static class MockBookie extends Bookie { MockBookie(ServerConfiguration conf) throws IOException, KeeperException, InterruptedException, BookieException { super(conf); } void testRegisterBookie(ServerConfiguration conf) throws IOException { super.doRegisterBookie(); } } /** * Verify the bookie server exit code. On ZooKeeper exception, should return * exit code ZK_REG_FAIL = 4 */ @Test(timeout = 20000) public void testExitCodeZK_REG_FAIL() throws Exception { File tmpDir = createTempDir("bookie", "test"); final ServerConfiguration conf = new ServerConfiguration().setZkServers(null) .setJournalDirName(tmpDir.getPath()).setLedgerDirNames(new String[] { tmpDir.getPath() }); // simulating ZooKeeper exception by assigning a closed zk client to bk BookieServer bkServer = new BookieServer(conf) { protected Bookie newBookie(ServerConfiguration conf) throws IOException, KeeperException, InterruptedException, BookieException { return new MockBookie(conf); } }; bkServer.getBookie().zk = zkc; zkc.close(); bkServer.start(); Assert.assertEquals("Failed to return ExitCode.ZK_REG_FAIL", ExitCode.ZK_REG_FAIL, bkServer.getExitCode()); } @Test(timeout = 20000) public void testBookieRegistrationWithSameZooKeeperClient() throws Exception { File tmpDir = createTempDir("bookie", "test"); final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration().setZkServers(null) .setJournalDirName(tmpDir.getPath()).setLedgerDirNames(new String[] { tmpDir.getPath() }); final String bkRegPath = conf.getZkAvailableBookiesPath() + "/" + InetAddress.getLocalHost().getHostAddress() + ":" + conf.getBookiePort(); MockBookie b = new MockBookie(conf); b.initialize(); b.zk = zkc; b.testRegisterBookie(conf); Assert.assertNotNull("Bookie registration node doesn't exists!", zkc.exists(bkRegPath, false)); // test register bookie again if the registeration node is created by itself. b.testRegisterBookie(conf); Assert.assertNotNull("Bookie registration node doesn't exists!", zkc.exists(bkRegPath, false)); } /** * Verify the bookie reg. Restarting bookie server will wait for the session * timeout when previous reg node exists in zk. On zNode delete event, * should continue startup */ @Test(timeout = 20000) public void testBookieRegistration() throws Exception { File tmpDir = createTempDir("bookie", "test"); final ServerConfiguration conf = new ServerConfiguration().setZkServers(null) .setJournalDirName(tmpDir.getPath()).setLedgerDirNames(new String[] { tmpDir.getPath() }); final String bkRegPath = conf.getZkAvailableBookiesPath() + "/" + InetAddress.getLocalHost().getHostAddress() + ":" + conf.getBookiePort(); MockBookie b = new MockBookie(conf); b.initialize(); b.zk = zkc; b.testRegisterBookie(conf); Stat bkRegNode1 = zkc.exists(bkRegPath, false); Assert.assertNotNull("Bookie registration node doesn't exists!", bkRegNode1); // simulating bookie restart, on restart bookie will create new // zkclient and doing the registration. createNewZKClient(); b.zk = newzk; // deleting the znode, so that the bookie registration should // continue successfully on NodeDeleted event new Thread() { @Override public void run() { try { Thread.sleep(conf.getZkTimeout() / 3); zkc.delete(bkRegPath, -1); } catch (Exception e) { // Not handling, since the testRegisterBookie will fail LOG.error("Failed to delete the znode :" + bkRegPath, e); } } }.start(); try { b.testRegisterBookie(conf); } catch (IOException e) { Throwable t = e.getCause(); if (t instanceof KeeperException) { KeeperException ke = (KeeperException) t; Assert.assertTrue("ErrorCode:" + ke.code() + ", Registration node exists", ke.code() != KeeperException.Code.NODEEXISTS); } throw e; } // verify ephemeral owner of the bkReg znode Stat bkRegNode2 = newzk.exists(bkRegPath, false); Assert.assertNotNull("Bookie registration has been failed", bkRegNode2); Assert.assertTrue( "Bookie is referring to old registration znode:" + bkRegNode1 + ", New ZNode:" + bkRegNode2, bkRegNode1.getEphemeralOwner() != bkRegNode2.getEphemeralOwner()); } /** * Verify the bookie registration, it should throw * KeeperException.NodeExistsException if the znode still exists even after * the zk session timeout. */ @Test(timeout = 30000) public void testRegNodeExistsAfterSessionTimeOut() throws Exception { File tmpDir = createTempDir("bookie", "test"); ServerConfiguration conf = new ServerConfiguration().setZkServers(null).setJournalDirName(tmpDir.getPath()) .setLedgerDirNames(new String[] { tmpDir.getPath() }); String bkRegPath = conf.getZkAvailableBookiesPath() + "/" + InetAddress.getLocalHost().getHostAddress() + ":" + conf.getBookiePort(); MockBookie b = new MockBookie(conf); b.initialize(); b.zk = zkc; b.testRegisterBookie(conf); Stat bkRegNode1 = zkc.exists(bkRegPath, false); Assert.assertNotNull("Bookie registration node doesn't exists!", bkRegNode1); // simulating bookie restart, on restart bookie will create new // zkclient and doing the registration. createNewZKClient(); b.zk = newzk; try { b.testRegisterBookie(conf); fail("Should throw NodeExistsException as the znode is not getting expired"); } catch (IOException e) { Throwable t = e.getCause(); if (t instanceof KeeperException) { KeeperException ke = (KeeperException) t; Assert.assertTrue("ErrorCode:" + ke.code() + ", Registration node doesn't exists", ke.code() == KeeperException.Code.NODEEXISTS); // verify ephemeral owner of the bkReg znode Stat bkRegNode2 = newzk.exists(bkRegPath, false); Assert.assertNotNull("Bookie registration has been failed", bkRegNode2); Assert.assertTrue("Bookie wrongly registered. Old registration znode:" + bkRegNode1 + ", New znode:" + bkRegNode2, bkRegNode1.getEphemeralOwner() == bkRegNode2.getEphemeralOwner()); return; } throw e; } } /** * Verify duplicate bookie server startup. Should throw * java.net.BindException if already BK server is running */ @Test(timeout = 20000) public void testDuplicateBookieServerStartup() throws Exception { File tmpDir = createTempDir("bookie", "test"); ServerConfiguration conf = new ServerConfiguration(); int port = 12555; conf.setZkServers(null).setBookiePort(port).setJournalDirName(tmpDir.getPath()) .setLedgerDirNames(new String[] { tmpDir.getPath() }); BookieServer bs1 = new BookieServer(conf); bs1.start(); // starting bk server with same conf try { BookieServer bs2 = new BookieServer(conf); bs2.start(); fail("Should throw BindException, as the bk server is already running!"); } catch (ChannelException ce) { Assert.assertTrue("Should be caused by a bind exception", ce.getCause() instanceof BindException); Assert.assertTrue("BKServer allowed duplicate startups!", ce.getCause().getMessage().contains("Address already in use")); } } /** * Verify bookie start behaviour when ZK Server is not running. */ @Test(timeout = 20000) public void testStartBookieWithoutZKServer() throws Exception { zkUtil.killServer(); File tmpDir = createTempDir("bookie", "test"); final ServerConfiguration conf = new ServerConfiguration().setZkServers(zkUtil.getZooKeeperConnectString()) .setZkTimeout(5000).setJournalDirName(tmpDir.getPath()) .setLedgerDirNames(new String[] { tmpDir.getPath() }); try { Bookie b = new Bookie(conf); b.initialize(); fail("Should throw ConnectionLossException as ZKServer is not running!"); } catch (KeeperException.ConnectionLossException e) { // expected behaviour } finally { FileUtils.deleteDirectory(tmpDir); } } /** * Check disk full. Expected to throw NoWritableLedgerDirException * during bookie initialisation. */ @Test(timeout = 30000) public void testWithDiskFull() throws Exception { File tempDir = createTempDir("DiskCheck", "test"); long usableSpace = tempDir.getUsableSpace(); long totalSpace = tempDir.getTotalSpace(); final ServerConfiguration conf = new ServerConfiguration().setZkServers(zkUtil.getZooKeeperConnectString()) .setZkTimeout(5000).setJournalDirName(tempDir.getPath()) .setLedgerDirNames(new String[] { tempDir.getPath() }); conf.setDiskUsageThreshold((1f - ((float) usableSpace / (float) totalSpace)) - 0.05f); conf.setDiskUsageWarnThreshold((1f - ((float) usableSpace / (float) totalSpace)) - 0.25f); try { new Bookie(conf).initialize(); fail("Should fail with NoWritableLedgerDirException"); } catch (NoWritableLedgerDirException nlde) { // expected } } /** * Check disk error for file. Expected to throw DiskErrorException. */ @Test(timeout = 30000) public void testWithDiskError() throws Exception { File parent = createTempDir("DiskCheck", "test"); File child = File.createTempFile("DiskCheck", "test", parent); final ServerConfiguration conf = new ServerConfiguration().setZkServers(zkUtil.getZooKeeperConnectString()) .setZkTimeout(5000).setJournalDirName(child.getPath()) .setLedgerDirNames(new String[] { child.getPath() }); // LedgerDirsManager#init() is used in Bookie instantiation. // Simulating disk errors by directly calling #init LedgerDirsManager ldm = new LedgerDirsManager(conf, conf.getLedgerDirs()); try { ldm.checkAllDirs(); fail("Should fail with DiskErrorException"); } catch (DiskErrorException dee) { // expected } } private void createNewZKClient() throws Exception { // create a zookeeper client LOG.debug("Instantiate ZK Client"); newzk = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), 10000); } }