| /* |
| * Copyright 2009 The Apache Software Foundation |
| * |
| * 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.hadoop.hbase.zookeeper; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.Reader; |
| import java.net.BindException; |
| import java.net.InetSocketAddress; |
| import java.net.Socket; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.hadoop.fs.FileUtil; |
| import org.apache.zookeeper.server.NIOServerCnxn; |
| import org.apache.zookeeper.server.ZooKeeperServer; |
| import org.apache.zookeeper.server.persistence.FileTxnLog; |
| |
| /** |
| * TODO: Most of the code in this class is ripped from ZooKeeper tests. Instead |
| * of redoing it, we should contribute updates to their code which let us more |
| * easily access testing helper objects. |
| */ |
| public class MiniZooKeeperCluster { |
| private static final Log LOG = LogFactory.getLog(MiniZooKeeperCluster.class); |
| |
| private static final int TICK_TIME = 2000; |
| private static final int CONNECTION_TIMEOUT = 30000; |
| |
| private boolean started; |
| private int clientPort = 21818; // use non-standard port |
| |
| private NIOServerCnxn.Factory standaloneServerFactory; |
| private int tickTime = 0; |
| |
| /** Create mini ZooKeeper cluster. */ |
| public MiniZooKeeperCluster() { |
| this.started = false; |
| } |
| |
| public void setClientPort(int clientPort) { |
| this.clientPort = clientPort; |
| } |
| |
| public int getClientPort() { |
| return clientPort; |
| } |
| |
| public void setTickTime(int tickTime) { |
| this.tickTime = tickTime; |
| } |
| |
| // / XXX: From o.a.zk.t.ClientBase |
| private static void setupTestEnv() { |
| // during the tests we run with 100K prealloc in the logs. |
| // on windows systems prealloc of 64M was seen to take ~15seconds |
| // resulting in test failure (client timeout on first session). |
| // set env and directly in order to handle static init/gc issues |
| System.setProperty("zookeeper.preAllocSize", "100"); |
| FileTxnLog.setPreallocSize(100); |
| } |
| |
| /** |
| * @param baseDir |
| * @return ClientPort server bound to. |
| * @throws IOException |
| * @throws InterruptedException |
| */ |
| public int startup(File baseDir) throws IOException, |
| InterruptedException { |
| |
| setupTestEnv(); |
| |
| shutdown(); |
| |
| File dir = new File(baseDir, "zookeeper").getAbsoluteFile(); |
| recreateDir(dir); |
| |
| int tickTimeToUse; |
| if (this.tickTime > 0) { |
| tickTimeToUse = this.tickTime; |
| } else { |
| tickTimeToUse = TICK_TIME; |
| } |
| ZooKeeperServer server = new ZooKeeperServer(dir, dir, tickTimeToUse); |
| while (true) { |
| try { |
| standaloneServerFactory = |
| new NIOServerCnxn.Factory(new InetSocketAddress(clientPort)); |
| } catch (BindException e) { |
| LOG.info("Failed binding ZK Server to client port: " + clientPort); |
| //this port is already in use. try to use another |
| clientPort++; |
| continue; |
| } |
| break; |
| } |
| standaloneServerFactory.startup(server); |
| |
| if (!waitForServerUp(clientPort, CONNECTION_TIMEOUT)) { |
| throw new IOException("Waiting for startup of standalone server"); |
| } |
| |
| started = true; |
| LOG.info("Started MiniZK Server on client port: " + clientPort); |
| return clientPort; |
| } |
| |
| private void recreateDir(File dir) throws IOException { |
| if (dir.exists()) { |
| FileUtil.fullyDelete(dir); |
| } |
| try { |
| dir.mkdirs(); |
| } catch (SecurityException e) { |
| throw new IOException("creating dir: " + dir, e); |
| } |
| } |
| |
| /** |
| * @throws IOException |
| */ |
| public void shutdown() throws IOException { |
| if (!started) { |
| return; |
| } |
| |
| standaloneServerFactory.shutdown(); |
| if (!waitForServerDown(clientPort, CONNECTION_TIMEOUT)) { |
| throw new IOException("Waiting for shutdown of standalone server"); |
| } |
| |
| started = false; |
| } |
| |
| // XXX: From o.a.zk.t.ClientBase |
| private static boolean waitForServerDown(int port, long timeout) { |
| long start = System.currentTimeMillis(); |
| while (true) { |
| try { |
| Socket sock = new Socket("localhost", port); |
| try { |
| OutputStream outstream = sock.getOutputStream(); |
| outstream.write("stat".getBytes()); |
| outstream.flush(); |
| } finally { |
| sock.close(); |
| } |
| } catch (IOException e) { |
| return true; |
| } |
| |
| if (System.currentTimeMillis() > start + timeout) { |
| break; |
| } |
| try { |
| Thread.sleep(250); |
| } catch (InterruptedException e) { |
| // ignore |
| } |
| } |
| return false; |
| } |
| |
| // XXX: From o.a.zk.t.ClientBase |
| private static boolean waitForServerUp(int port, long timeout) { |
| long start = System.currentTimeMillis(); |
| while (true) { |
| try { |
| Socket sock = new Socket("localhost", port); |
| BufferedReader reader = null; |
| try { |
| OutputStream outstream = sock.getOutputStream(); |
| outstream.write("stat".getBytes()); |
| outstream.flush(); |
| |
| Reader isr = new InputStreamReader(sock.getInputStream()); |
| reader = new BufferedReader(isr); |
| String line = reader.readLine(); |
| if (line != null && line.startsWith("Zookeeper version:")) { |
| return true; |
| } |
| } finally { |
| sock.close(); |
| if (reader != null) { |
| reader.close(); |
| } |
| } |
| } catch (IOException e) { |
| // ignore as this is expected |
| LOG.info("server localhost:" + port + " not up " + e); |
| } |
| |
| if (System.currentTimeMillis() > start + timeout) { |
| break; |
| } |
| try { |
| Thread.sleep(250); |
| } catch (InterruptedException e) { |
| // ignore |
| } |
| } |
| return false; |
| } |
| } |