org.apache.blur.MiniCluster.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.blur.MiniCluster.java

Source

package org.apache.blur;

/**
 * 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.
 */

import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_BIND_PORT;
import static org.apache.blur.utils.BlurConstants.BLUR_GUI_CONTROLLER_PORT;
import static org.apache.blur.utils.BlurConstants.BLUR_GUI_SHARD_PORT;
import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_BIND_PORT;
import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_BLOCKCACHE_DIRECT_MEMORY_ALLOCATION;
import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_BLOCKCACHE_SLAB_COUNT;
import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_HOSTNAME;
import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_SAFEMODEDELAY;
import static org.apache.blur.utils.BlurConstants.BLUR_ZOOKEEPER_CONNECTION;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.blur.log.Log;
import org.apache.blur.log.LogFactory;
import org.apache.blur.store.buffer.BufferStore;
import org.apache.blur.thirdparty.thrift_0_9_0.TException;
import org.apache.blur.thirdparty.thrift_0_9_0.transport.TTransportException;
import org.apache.blur.thrift.BlurClient;
import org.apache.blur.thrift.ThriftBlurControllerServer;
import org.apache.blur.thrift.ThriftBlurShardServer;
import org.apache.blur.thrift.ThriftServer;
import org.apache.blur.thrift.generated.Blur.Iface;
import org.apache.blur.thrift.generated.BlurException;
import org.apache.blur.thrift.generated.BlurQuery;
import org.apache.blur.thrift.generated.BlurResults;
import org.apache.blur.thrift.generated.Column;
import org.apache.blur.thrift.generated.Record;
import org.apache.blur.thrift.generated.Row;
import org.apache.blur.thrift.generated.RowMutation;
import org.apache.blur.thrift.generated.TableDescriptor;
import org.apache.blur.thrift.util.BlurThriftHelper;
import org.apache.blur.utils.BlurUtil;
import org.apache.blur.utils.MemoryReporter;
import org.apache.blur.zookeeper.ZkMiniCluster;
import org.apache.blur.zookeeper.ZooKeeperClient;
import org.apache.blur.zookeeper.ZookeeperPathConstants;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.VersionInfo;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

public class MiniCluster {

    private static Log LOG = LogFactory.getLog(MiniCluster.class);
    private MiniDFSCluster cluster;
    private final String id = UUID.randomUUID().toString();
    private ZkMiniCluster zkMiniCluster = new ZkMiniCluster();
    private List<MiniClusterServer> controllers = new ArrayList<MiniClusterServer>();
    private List<MiniClusterServer> shards = new ArrayList<MiniClusterServer>();
    private ThreadGroup group = new ThreadGroup(id);
    private Configuration _conf;
    private Object mrMiniCluster;
    private Configuration _mrConf;

    public static void main(String[] args)
            throws IOException, InterruptedException, KeeperException, BlurException, TException {
        MiniCluster miniCluster = new MiniCluster();
        miniCluster.startDfs("./tmp/hdfs");
        miniCluster.startZooKeeper("./tmp/zk");
        miniCluster.startControllers(1, false, false);
        miniCluster.startShards(1, false, false);

        try {
            Iface client = BlurClient.getClient(miniCluster.getControllerConnectionStr());
            miniCluster.createTable("test", client);
            long start = System.nanoTime();
            for (int i = 0; i < 1000; i++) {
                long now = System.nanoTime();
                if (start + 5000000000L < now) {
                    System.out.println("Total [" + i + "]");
                    start = now;
                }
                miniCluster.addRow("test", i, client);
            }

            // This waits for all the data to become visible.
            Thread.sleep(2000);

            for (int i = 0; i < 1000; i++) {
                miniCluster.searchRow("test", i, client);
            }

        } finally {
            miniCluster.stopShards();
            miniCluster.stopControllers();
            miniCluster.shutdownZooKeeper();
            miniCluster.shutdownDfs();
        }
    }

    public void startBlurCluster(String path, int controllerCount, int shardCount) {
        startBlurCluster(path, controllerCount, shardCount, false, false);
    }

    public void startBlurCluster(String path, int controllerCount, int shardCount, boolean randomPort) {
        startBlurCluster(path, controllerCount, shardCount, randomPort, false);
    }

    public void startBlurCluster(final String path, final int controllerCount, final int shardCount,
            final boolean randomPort, final boolean externalProcesses) {
        Thread thread = new Thread(group, new Runnable() {
            @Override
            public void run() {
                MemoryReporter.enable();
                startDfs(path + "/hdfs");
                startZooKeeper(path + "/zk", randomPort);
                setupBuffers();
                startControllers(controllerCount, randomPort, externalProcesses);
                startShards(shardCount, randomPort, externalProcesses);
                try {
                    waitForSafeModeToExit();
                } catch (BlurException e) {
                    throw new RuntimeException(e);
                } catch (TException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void stopMrMiniCluster() throws IOException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        if (useYarn()) {
            engine.put("mrMiniCluster", mrMiniCluster);
            try {
                engine.eval("mrMiniCluster.stop();");
            } catch (ScriptException e) {
                throw new IOException(e);
            }
        } else {
            engine.put("mrMiniCluster", mrMiniCluster);
            try {
                engine.eval("mrMiniCluster.shutdown();");
            } catch (ScriptException e) {
                throw new IOException(e);
            }
        }
    }

    public void startMrMiniCluster() throws IOException {
        _mrConf = startMrMiniClusterInternal(getFileSystemUri().toString());
    }

    public void startMrMiniCluster(String fileSystemUri) throws IOException {
        _mrConf = startMrMiniClusterInternal(fileSystemUri);
    }

    public Configuration getMRConfiguration() {
        return _mrConf;
    }

    private Configuration startMrMiniClusterInternal(String fileSystemUri) throws IOException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");

        if (useYarn()) {
            int nodeManagers = 4;
            Class<?> c = getClass();
            engine.put("c", c);
            engine.put("nodeManagers", nodeManagers);
            engine.put("fileSystemUri", fileSystemUri);
            try {
                engine.eval("conf = new org.apache.hadoop.yarn.conf.YarnConfiguration()");
                engine.eval("org.apache.hadoop.fs.FileSystem.setDefaultUri(conf, fileSystemUri);");
                engine.eval(
                        "mrMiniCluster = org.apache.hadoop.mapred.MiniMRClientClusterFactory.create(c, nodeManagers, conf);");
                engine.eval("mrMiniCluster.start();");
                engine.eval("configuration = mrMiniCluster.getConfig();");
            } catch (ScriptException e) {
                throw new IOException(e);
            }

            Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
            mrMiniCluster = bindings.get("mrMiniCluster");
            return (Configuration) bindings.get("configuration");
        } else {
            int numTaskTrackers = 2;
            int numDir = 1;
            engine.put("fileSystemUri", fileSystemUri);
            engine.put("numTaskTrackers", numTaskTrackers);
            engine.put("numDir", numDir);

            try {
                engine.eval(
                        "mrMiniCluster = new org.apache.hadoop.mapred.MiniMRCluster(numTaskTrackers, fileSystemUri, numDir);");
                engine.eval("configuration = mrMiniCluster.createJobConf();");
            } catch (ScriptException e) {
                throw new IOException(e);
            }
            Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
            mrMiniCluster = bindings.get("mrMiniCluster");
            return (Configuration) bindings.get("configuration");
        }
    }

    public boolean useYarn() {
        String version = VersionInfo.getVersion();
        if (version.startsWith("0.20.") || version.startsWith("1.")) {
            return false;
        }
        // Check for mr1 hadoop2
        if (isMr1Hadoop2()) {
            return false;
        }
        return true;
    }

    public boolean isMr1Hadoop2() {
        try {
            Enumeration<URL> e = ClassLoader.getSystemClassLoader()
                    .getResources("META-INF/maven/org.apache.hadoop/hadoop-client/pom.properties");
            while (e.hasMoreElements()) {
                URL url = e.nextElement();
                InputStream stream = url.openStream();
                Properties properties = new Properties();
                properties.load(stream);
                Object object = properties.get("version");
                if (object.toString().contains("mr1")) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private void waitForSafeModeToExit() throws BlurException, TException, IOException {
        String controllerConnectionStr = getControllerConnectionStr();
        Iface client = BlurClient.getClient(controllerConnectionStr);
        String clusterName = "default";
        boolean inSafeMode;
        boolean isNoLonger = false;
        do {
            inSafeMode = client.isInSafeMode(clusterName);
            if (!inSafeMode) {
                if (isNoLonger) {
                    System.out.println("Cluster " + cluster + " is no longer in safemode.");
                } else {
                    System.out.println("Cluster " + cluster + " is not in safemode.");
                }
                return;
            }
            isNoLonger = true;
            try {
                Thread.sleep(TimeUnit.SECONDS.toMillis(1));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } while (inSafeMode);
    }

    private void setupBuffers() {
        BufferStore.initNewBuffer(128, 128 * 128);
    }

    public void shutdownBlurCluster() {
        stopShards();
        stopControllers();
        shutdownZooKeeper();
        shutdownDfs();
    }

    private void createTable(String test, Iface client) throws BlurException, TException, IOException {
        final TableDescriptor descriptor = new TableDescriptor();
        descriptor.setName(test);
        descriptor.setShardCount(7);
        descriptor.setTableUri(getFileSystemUri() + "/blur/" + test);
        client.createTable(descriptor);
    }

    public String getControllerConnectionStr() {
        String zkConnectionString = zkMiniCluster.getZkConnectionString();
        ZooKeeper zk;
        try {
            zk = new ZooKeeperClient(zkConnectionString, 30000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {

                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String onlineControllersPath = ZookeeperPathConstants.getOnlineControllersPath();
        try {
            List<String> children = zk.getChildren(onlineControllersPath, false);
            StringBuilder builder = new StringBuilder();
            for (String s : children) {
                if (builder.length() != 0) {
                    builder.append(',');
                }
                builder.append(s);
            }
            return builder.toString();
        } catch (KeeperException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                zk.close();
            } catch (InterruptedException e) {
                LOG.error("Unkown error while trying to close ZooKeeper client.", e);
            }
        }
    }

    private void addRow(String table, int i, Iface client) throws BlurException, TException {
        Row row = new Row();
        row.setId(Integer.toString(i));
        Record record = new Record();
        record.setRecordId(Integer.toString(i));
        record.setFamily("test");
        record.addToColumns(new Column("test", Integer.toString(i)));
        row.addToRecords(record);
        RowMutation rowMutation = BlurUtil.toRowMutation(table, row);
        client.mutate(rowMutation);
    }

    private void searchRow(String table, int i, Iface client) throws BlurException, TException {
        BlurQuery blurQuery = BlurThriftHelper.newSimpleQuery("test.test:" + i);
        System.out.println("Running [" + blurQuery + "]");
        BlurResults results = client.query(table, blurQuery);
        if (results.getTotalResults() != 1L) {
            throw new RuntimeException("we got a problem here.");
        }
    }

    public void stopControllers() {
        IOUtils.cleanup(LOG, controllers.toArray(new Closeable[] {}));
    }

    public void stopShards() {
        IOUtils.cleanup(LOG, shards.toArray(new Closeable[] {}));
    }

    public void startControllers(int num, boolean randomPort, boolean externalProcesses) {
        BlurConfiguration configuration = getBlurConfiguration();
        startControllers(configuration, num, randomPort, externalProcesses);
    }

    private BlurConfiguration getBlurConfiguration(BlurConfiguration overrides) {
        BlurConfiguration conf = getBlurConfiguration();

        for (Map.Entry<String, String> over : overrides.getProperties().entrySet()) {
            conf.set(over.getKey().toString(), over.getValue().toString());
        }
        return conf;
    }

    private BlurConfiguration getBlurConfiguration() {
        BlurConfiguration configuration;
        try {
            configuration = new BlurConfiguration();
        } catch (IOException e) {
            LOG.error(e);
            throw new RuntimeException(e);
        }
        configuration.set(BLUR_ZOOKEEPER_CONNECTION, getZkConnectionString());
        configuration.set(BLUR_SHARD_BLOCKCACHE_DIRECT_MEMORY_ALLOCATION, "false");
        configuration.set(BLUR_SHARD_BLOCKCACHE_SLAB_COUNT, "0");
        configuration.setLong(BLUR_SHARD_SAFEMODEDELAY, 5000);
        configuration.setInt(BLUR_GUI_CONTROLLER_PORT, -1);
        configuration.setInt(BLUR_GUI_SHARD_PORT, -1);

        return configuration;
    }

    public void startControllers(BlurConfiguration configuration, int num, boolean randomPort,
            boolean externalProcesses) {
        BlurConfiguration localConf = getBlurConfiguration(configuration);
        if (randomPort) {
            localConf.setInt(BLUR_CONTROLLER_BIND_PORT, 0);
        }
        for (int i = 0; i < num; i++) {
            try {
                MiniClusterServer miniClusterServer = toMiniClusterServer(i, TYPE.controller, localConf,
                        externalProcesses);
                controllers.add(miniClusterServer);
                startServer(miniClusterServer);
            } catch (Exception e) {
                LOG.error(e);
                throw new RuntimeException(e);
            }
        }
    }

    enum TYPE {
        shard, controller
    }

    private MiniClusterServer toMiniClusterServer(int serverIndex, TYPE type, final BlurConfiguration configuration,
            boolean externalProcesses) {
        if (externalProcesses) {
            return toMiniClusterServerExternal(serverIndex, type, configuration);
        } else {
            return toMiniClusterServerInternal(serverIndex, type, configuration);
        }
    }

    private MiniClusterServer toMiniClusterServerExternal(final int serverIndex, final TYPE type,
            BlurConfiguration configuration) {
        // write out configuration to tmp file.
        // build args
        // build class path
        try {
            File dir = new File("./target/blurtesttemp");
            dir.mkdirs();
            final File file = new File(dir, "blurtestconf." + UUID.randomUUID().toString() + ".properties")
                    .getAbsoluteFile();
            OutputStream outputStream = new FileOutputStream(file);
            configuration.write(outputStream);
            outputStream.close();

            System.out.println("File [" + file.getAbsolutePath() + "] exists [" + file.exists() + "]");

            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    file.delete();
                }
            }));

            String javaHome = System.getProperty("java.home");
            String classPath = System.getProperty("java.class.path");

            List<String> command = new ArrayList<String>();
            command.add(javaHome + "/bin/java");
            command.add("-Xmx512m");
            command.add("-Xms512m");
            command.add("-cp");
            command.add(classPath);
            command.add(ExternalThriftServer.class.getName());
            command.add(type.name());
            command.add(Integer.toString(serverIndex));
            command.add(file.getAbsolutePath());
            final ProcessBuilder builder = new ProcessBuilder(command);

            final MiniClusterServer miniClusterServer = new MiniClusterServer() {

                private Process _process;
                private AtomicBoolean _online = new AtomicBoolean();

                @Override
                public void close() throws IOException {
                    kill();
                }

                @Override
                public void waitUntilOnline() {
                    while (!_online.get()) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            LOG.error("Unknown error while trying to wait for process to come online.", e);
                        }
                    }
                }

                @Override
                public void start() {
                    try {
                        _process = builder.start();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    pipeOutputToStdOut(_process.getInputStream());
                    pipeOutputToStdOut(_process.getErrorStream());
                }

                private void pipeOutputToStdOut(final InputStream inputStream) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                            String line;
                            try {
                                while ((line = reader.readLine()) != null) {
                                    LOG.info("Process Output Type [" + type + "] Index [" + serverIndex + "] Line ["
                                            + line + "]");
                                    if (line.trim().equals("ONLINE")) {
                                        _online.set(true);
                                    }
                                }
                            } catch (IOException e) {
                                LOG.error("Unknown error while trying to follow input stream.", e);
                            }
                        }
                    }).start();
                }

                @Override
                public void kill() {
                    if (_process != null) {
                        _process.destroy();
                    }
                }
            };
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    miniClusterServer.kill();
                }
            }));
            return miniClusterServer;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    private MiniClusterServer toMiniClusterServerInternal(int serverIndex, TYPE type,
            final BlurConfiguration configuration) {
        final ThriftServer thriftServer;
        try {
            thriftServer = getThriftServer(serverIndex, type, configuration);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return new MiniClusterServer() {

            @Override
            public void close() throws IOException {
                thriftServer.close();
            }

            @Override
            public void kill() {
                ZooKeeper zk = null;
                try {
                    int shardPort = ThriftServer.getBindingPort(thriftServer.getServerTransport());
                    String nodeNameHostname = ThriftServer.getNodeName(configuration, BLUR_SHARD_HOSTNAME);
                    String nodeName = nodeNameHostname + ":" + shardPort;
                    zk = new ZooKeeperClient(getZkConnectionString(), 30000, new Watcher() {
                        @Override
                        public void process(WatchedEvent event) {

                        }
                    });
                    String onlineShardsPath = ZookeeperPathConstants
                            .getOnlineShardsPath(org.apache.blur.utils.BlurConstants.BLUR_CLUSTER);
                    String path = onlineShardsPath + "/" + nodeName;
                    zk.delete(path, -1);
                    zk.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    if (zk != null) {
                        try {
                            zk.close();
                        } catch (InterruptedException e) {
                            LOG.error("Unknown error while trying to close ZooKeeper client.", e);
                        }
                    }
                }
            }

            @Override
            public void start() {
                try {
                    thriftServer.start();
                } catch (TTransportException e) {
                    LOG.error(e);
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void waitUntilOnline() {
                while (true) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        return;
                    }
                    int localPort = ThriftServer.getBindingPort(thriftServer.getServerTransport());
                    if (localPort == 0) {
                        continue;
                    } else {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            LOG.error("Unknown error", e);
                        }
                        return;
                    }
                }
            }

        };
    }

    private ThriftServer getThriftServer(int serverIndex, TYPE type, BlurConfiguration configuration)
            throws Exception {
        switch (type) {
        case controller:
            return ThriftBlurControllerServer.createServer(serverIndex, configuration);
        case shard:
            return ThriftBlurShardServer.createServer(serverIndex, configuration);
        default:
            throw new RuntimeException("Type not supported [" + type + "]");
        }
    }

    public void startShards(int num, boolean randomPort, boolean externalProcesses) {
        BlurConfiguration configuration = getBlurConfiguration();
        startShards(configuration, num, randomPort, externalProcesses);
    }

    public void startShards(final BlurConfiguration configuration, int num, final boolean randomPort,
            final boolean externalProcesses) {
        final BlurConfiguration localConf = getBlurConfiguration(configuration);
        if (randomPort) {
            localConf.setInt(BLUR_SHARD_BIND_PORT, 0);
        }
        ExecutorService executorService = Executors.newFixedThreadPool(num);
        List<Future<MiniClusterServer>> futures = new ArrayList<Future<MiniClusterServer>>();
        for (int i = 0; i < num; i++) {
            final int index = i;
            futures.add(executorService.submit(new Callable<MiniClusterServer>() {
                @Override
                public MiniClusterServer call() throws Exception {
                    return toMiniClusterServer(index, TYPE.shard, localConf, externalProcesses);
                }
            }));
        }
        for (int i = 0; i < num; i++) {
            try {
                MiniClusterServer server = futures.get(i).get();
                shards.add(server);
                startServer(server);
            } catch (Exception e) {
                LOG.error(e);
                throw new RuntimeException(e);
            }
        }
    }

    public void killShardServer(int shardServer) throws IOException, InterruptedException, KeeperException {
        killShardServer(getBlurConfiguration(), shardServer);
    }

    public void killShardServer(final BlurConfiguration configuration, int shardServer)
            throws IOException, InterruptedException, KeeperException {
        MiniClusterServer miniClusterServer = shards.get(shardServer);
        miniClusterServer.kill();
    }

    private static void startServer(final MiniClusterServer server) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                server.start();
            }
        }).start();
        server.waitUntilOnline();
    }

    public Configuration getConfiguration() {
        return _conf;
    }

    public String getZkConnectionString() {
        return zkMiniCluster.getZkConnectionString();
    }

    public void startZooKeeper(String path) {
        zkMiniCluster.startZooKeeper(path);
    }

    public void startZooKeeper(String path, boolean randomPort) {
        zkMiniCluster.startZooKeeper(path, randomPort);
    }

    public void startZooKeeper(boolean format, String path) {
        zkMiniCluster.startZooKeeper(format, path);
    }

    public void startZooKeeper(boolean format, String path, boolean randomPort) {
        zkMiniCluster.startZooKeeper(format, path, randomPort);
    }

    public void startZooKeeper(Properties properties, String path) {
        zkMiniCluster.startZooKeeper(properties, path);
    }

    public void startZooKeeper(Properties properties, String path, boolean randomPort) {
        zkMiniCluster.startZooKeeper(properties, path, randomPort);
    }

    public void startZooKeeper(final Properties properties, boolean format, String path, final boolean randomPort) {
        zkMiniCluster.startZooKeeper(properties, format, path, randomPort);
    }

    public FileSystem getFileSystem() throws IOException {
        return cluster.getFileSystem();
    }

    public URI getFileSystemUri() throws IOException {
        return getFileSystem().getUri();
    }

    public void startDfs(String path) {
        startDfs(true, path);
    }

    public void startDfs(boolean format, String path) {
        startDfs(new Configuration(), format, path);
    }

    public void startDfs(Configuration conf, String path) {
        startDfs(conf, true, path);
    }

    public void startDfs(final Configuration conf, final boolean format, final String path) {
        startDfs(conf, format, path, null);
    }

    public void startDfs(final Configuration conf, final boolean format, final String path, final String[] racks) {
        Thread thread = new Thread(group, new Runnable() {
            @SuppressWarnings("deprecation")
            @Override
            public void run() {
                _conf = conf;
                String perm;
                Path p = new Path(new File(path).getAbsolutePath());
                try {
                    FileSystem fileSystem = p.getFileSystem(conf);
                    if (!fileSystem.exists(p)) {
                        if (!fileSystem.mkdirs(p)) {
                            throw new RuntimeException("Could not create path [" + path + "]");
                        }
                    }
                    FileStatus fileStatus = fileSystem.getFileStatus(p);
                    FsPermission permission = fileStatus.getPermission();
                    perm = permission.getUserAction().ordinal() + "" + permission.getGroupAction().ordinal() + ""
                            + permission.getOtherAction().ordinal();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                LOG.info("dfs.datanode.data.dir.perm=" + perm);
                conf.set("dfs.datanode.data.dir.perm", perm);
                System.setProperty("test.build.data", path);
                try {
                    if (racks == null) {
                        cluster = new MiniDFSCluster(conf, 1, format, racks);
                    } else {
                        cluster = new MiniDFSCluster(conf, racks.length, format, racks);
                    }
                } catch (Exception e) {
                    LOG.error("error opening file system", e);
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        try {
            thread.join();
            cluster.waitActive();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void shutdownZooKeeper() {
        zkMiniCluster.shutdownZooKeeper();
    }

    public void shutdownDfs() {
        if (cluster != null) {
            LOG.info("Shutting down Mini DFS ");
            try {
                cluster.shutdown();
            } catch (Exception e) {
                // / Can get a java.lang.reflect.UndeclaredThrowableException thrown
                // here because of an InterruptedException. Don't let exceptions in
                // here be cause of test failure.
            }
            try {
                FileSystem fs = cluster.getFileSystem();
                if (fs != null) {
                    LOG.info("Shutting down FileSystem");
                    fs.close();
                }
                FileSystem.closeAll();
            } catch (IOException e) {
                LOG.error("error closing file system", e);
            }

            // This has got to be one of the worst hacks I have ever had to do.
            // This is needed to shutdown 2 thread pools that are not shutdown by
            // themselves.
            ThreadGroup threadGroup = group;
            Thread[] threads = new Thread[100];
            int enumerate = threadGroup.enumerate(threads);
            for (int i = 0; i < enumerate; i++) {
                Thread thread = threads[i];
                if (thread.getName().startsWith("pool")) {
                    if (thread.isAlive()) {
                        thread.interrupt();
                        LOG.info("Stopping ThreadPoolExecutor [" + thread.getName() + "]");
                        Object target = getField(Thread.class, thread, "target");
                        if (target != null) {
                            ThreadPoolExecutor e = (ThreadPoolExecutor) getField(ThreadPoolExecutor.class, target,
                                    "this$0");
                            if (e != null) {
                                e.shutdownNow();
                            }
                        }
                        try {
                            LOG.info("Waiting for thread pool to exit [" + thread.getName() + "]");
                            thread.join();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
    }

    private static Object getField(Class<?> c, Object o, String fieldName) {
        try {
            Field field = c.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(o);
        } catch (NoSuchFieldException e) {
            try {
                Field field = o.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(o);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}