org.apache.hadoop.hdfs.notifier.benchmark.TxnConsumer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.notifier.benchmark.TxnConsumer.java

Source

/**
 * 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.hdfs.notifier.benchmark;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.notifier.EventType;
import org.apache.hadoop.hdfs.notifier.NamespaceNotification;
import org.apache.hadoop.hdfs.notifier.NamespaceNotifierClient;
import org.apache.hadoop.hdfs.notifier.NamespaceNotifierClient.NotConnectedToServerException;
import org.apache.hadoop.hdfs.notifier.NamespaceNotifierClient.WatchAlreadyPlacedException;
import org.apache.hadoop.hdfs.notifier.NotifierUtils;
import org.apache.hadoop.hdfs.notifier.TransactionIdTooOldException;
import org.apache.hadoop.hdfs.notifier.Watcher;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.RunningJob;
import org.apache.hadoop.mapred.TextInputFormat;
import org.apache.hadoop.mapred.TextOutputFormat;

public class TxnConsumer {

    final static Log LOG = LogFactory.getLog(TxnConsumer.class);

    public static String TEST_FILE_LABEL = "test.file.label";
    public static String TEST_DIR_LABEL = "test.dir.label";
    public static String SERVER_ADDR_STR_LABEL = "server.addr.str.label";
    public static String SERVER_PORT_STR_LABEL = "server.port.str.label";

    private static final String NUM_MAPPERS_KEY = "-numtasks";
    private static final String NUM_SUBDIRS_KEY = "-numsubdirs";
    private static final String NUM_FILES_SUB_DIR_KEY = "-numfiles";
    private static final String NUM_ROUND_KEY = "-round";
    private static final String WORKPLACE_KEY = "-workplace";
    private static final String NOTIFIER_SERVER_ADDR_KEY = "-notifieraddr";
    private static final String NOTIFIER_SERVER_PORT_KEY = "-notifierport";

    private static final int SERVER_DEFAULT_PORT = 31000;
    private static final int CLIENT_PROT = 32000;

    private static int numMappers = 10;
    private static int numSubDirs = 100;
    private static int numFilesEachSubDirs = 100;
    private static int round = 100;
    private static String workplace = "";

    // the namespace notifier server address string
    // sample: address1,address2
    private static String notifierServerAddrStr = "";
    // the namespace notifier server port string
    // sample: port1, port2
    private static String notifierServerPortStr = "";

    private Configuration conf;

    public TxnConsumer(Configuration conf) {
        this.conf = conf;
    }

    static class ConsumerMapper implements Mapper<LongWritable, Text, Text, Text> {

        private JobConf jobConf;
        private String workplace;
        private NamespaceNotifierClient myClient;

        private long expectedTotal;
        private long expectedFileAdd;
        private long expectedFileClose;
        private long expectedDirAdd;
        private long expectedNodeDelete;

        private static List<String> notifierServerAddrList;
        private static List<Integer> notifierServerPortList;

        @Override
        public void configure(JobConf job) {
            this.jobConf = job;
            this.workplace = jobConf.get(TEST_DIR_LABEL);

            expectedFileAdd = round * numSubDirs * numFilesEachSubDirs;
            expectedFileClose = expectedFileAdd;
            expectedDirAdd = round * numSubDirs;
            expectedNodeDelete = expectedFileAdd + expectedDirAdd;
            expectedTotal = expectedFileAdd + expectedFileClose + expectedDirAdd + expectedNodeDelete;

            String serverAddrStr = jobConf.get(NOTIFIER_SERVER_ADDR_KEY);
            String serverPortStr = jobConf.get(NOTIFIER_SERVER_PORT_KEY);

            LOG.info("serverAddr: " + serverAddrStr + ", serverPort: " + serverPortStr);

            notifierServerAddrList = Arrays.asList(serverAddrStr.split(","));
            int index = 0;
            notifierServerPortList = new ArrayList<Integer>(notifierServerAddrList.size());
            if (!notifierServerPortStr.trim().isEmpty()) {
                List tmpList = Arrays.asList(serverPortStr.split(","));
                while (index < notifierServerAddrList.size() && index < tmpList.size()) {
                    notifierServerPortList.add(Integer.valueOf((String) tmpList.get(index++)));
                }
            }

            while (index++ < notifierServerAddrList.size()) {
                notifierServerPortList.add(SERVER_DEFAULT_PORT);
            }
        }

        @Override
        public void close() throws IOException {

        }

        @Override
        public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter)
                throws IOException {
            workplace += value.toString();

            SimpleWatcher myWatcher = new SimpleWatcher();

            try {
                myClient = new NamespaceNotifierClient(myWatcher, notifierServerAddrList, notifierServerPortList,
                        CLIENT_PROT);

                Thread clientThread = new Thread(myClient);
                clientThread.start();

                LOG.info("Expected number of notifications:\nTotal Notifications: " + expectedTotal
                        + "\nAdd_file Notifications: " + expectedFileAdd + "\nClose_file Notifications: "
                        + expectedFileClose + "\nAdd_dir Notifications: " + expectedDirAdd
                        + "\nNode_delete Notifications: " + expectedNodeDelete);

                while (!getAllExpectedNotis(myWatcher)) {
                    countReceivedNotis(myWatcher);
                    Thread.sleep(10000);
                    reporter.progress();
                }

                output.collect(value, new Text(myWatcher.toString()));

            } catch (Exception e) {
                LOG.error("Got error: " + e.getMessage(), e);
                throw new IOException(e);
            }
        }

        private boolean getAllExpectedNotis(SimpleWatcher watcher) {

            return (watcher.totalNoti.get() == expectedTotal) && (watcher.totalAddFile.get() == expectedFileAdd)
                    && (watcher.totalCloseFile.get() == expectedFileClose)
                    && (watcher.totalAddDir.get() == expectedDirAdd)
                    && (watcher.totalDeleteNode.get() == expectedNodeDelete);
        }

        private void countReceivedNotis(SimpleWatcher watcher) {
            LOG.info("Received: \nTotal Notifications: " + watcher.totalNoti.get() + "\nAdd_file Notifications: "
                    + watcher.totalAddFile.get() + "\nClose_file Notifications: " + watcher.totalCloseFile.get()
                    + "\nAdd_dir Notifications: " + watcher.totalAddDir.get() + "\nNode_delete Notifications: "
                    + watcher.totalDeleteNode.get());
        }

        private void placeWatch() throws TransactionIdTooOldException, NotConnectedToServerException,
                InterruptedException, WatchAlreadyPlacedException {
            String path = new Path(workplace).toUri().getPath();
            myClient.placeWatch(path, EventType.FILE_ADDED, -1);
            myClient.placeWatch(path, EventType.FILE_CLOSED, -1);
            myClient.placeWatch(path, EventType.DIR_ADDED, -1);
            myClient.placeWatch(path, EventType.NODE_DELETED, -1);
        }

        public class SimpleWatcher implements Watcher {
            public volatile boolean connected = false;
            public AtomicLong totalNoti = new AtomicLong();
            public AtomicLong totalAddFile = new AtomicLong();
            public AtomicLong totalCloseFile = new AtomicLong();
            public AtomicLong totalAddDir = new AtomicLong();
            public AtomicLong totalDeleteNode = new AtomicLong();

            @Override
            public void handleNamespaceNotification(NamespaceNotification notification) {
                LOG.info("Received notification: " + NotifierUtils.asString(notification));
                totalNoti.incrementAndGet();

                if (notification.type == EventType.FILE_ADDED.getByteValue()) {
                    totalAddFile.incrementAndGet();
                } else if (notification.type == EventType.FILE_CLOSED.getByteValue()) {
                    totalCloseFile.incrementAndGet();
                } else if (notification.type == EventType.NODE_DELETED.getByteValue()) {
                    totalDeleteNode.incrementAndGet();
                } else if (notification.type == EventType.DIR_ADDED.getByteValue()) {
                    totalAddDir.incrementAndGet();
                }
            }

            @Override
            public void connectionFailed() {
                LOG.warn("Connection failed.");
                connected = false;
            }

            @Override
            public void connectionSuccesful() {
                LOG.info("Connection successful.");
                connected = true;

                try {
                    placeWatch();
                    LOG.info("Watch placed.");
                } catch (TransactionIdTooOldException e) {
                    LOG.warn(e.getMessage(), e);
                } catch (NotConnectedToServerException e) {
                    LOG.warn(e.getMessage(), e);
                } catch (InterruptedException e) {
                    LOG.warn(e.getMessage(), e);
                } catch (WatchAlreadyPlacedException e) {
                    LOG.warn(e.getMessage(), e);
                }
            }

            public String toString() {
                StringBuilder sb = new StringBuilder();
                sb.append("total Notification: ").append(totalNoti.get());
                sb.append("total File Add: ").append(totalAddFile.get());
                sb.append("total File Close: ").append(totalCloseFile.get());
                sb.append("total Add Dir: ").append(totalAddDir.get());
                sb.append("total Delete Node: ").append(totalDeleteNode.get());

                return sb.toString();
            }
        }
    }

    static class ConsumerReducer implements Reducer<Text, Text, Text, Text> {
        @Override
        public void configure(JobConf job) {
        }

        @Override
        public void close() throws IOException {
        }

        @Override
        public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter)
                throws IOException {
            while (values.hasNext()) {
                output.collect(key, values.next());
            }
        }
    }

    private static void createSplitFiles(Configuration conf, Path splitDir) throws IOException {
        FileSystem fs = splitDir.getFileSystem(conf);
        for (int i = 0; i < numMappers; i++) {
            String mapperDir = "mapper" + i;
            Path path = new Path(splitDir, mapperDir);
            OutputStream os = fs.create(path, true);
            os.write(mapperDir.getBytes());
            os.close();
        }
    }

    private JobConf createJobConf(Configuration conf2) throws IOException {
        JobConf jobConf = new JobConf(conf);
        String jobName = "transaction_consumer";
        jobConf.setJobName(jobName);

        String splitDir = workplace + "split/";

        jobConf.set(TEST_DIR_LABEL, workplace);
        jobConf.set(NOTIFIER_SERVER_ADDR_KEY, notifierServerAddrStr);
        jobConf.set(NOTIFIER_SERVER_PORT_KEY, notifierServerPortStr);

        jobConf.setMapSpeculativeExecution(false);
        jobConf.setReduceSpeculativeExecution(false);

        jobConf.setJarByClass(TxnConsumer.class);
        jobConf.setMapperClass(ConsumerMapper.class);
        jobConf.setReducerClass(ConsumerReducer.class);

        jobConf.setMapOutputKeyClass(Text.class);
        jobConf.setMapOutputValueClass(Text.class);
        jobConf.setOutputKeyClass(Text.class);
        jobConf.setOutputValueClass(Text.class);
        jobConf.setInputFormat(TextInputFormat.class);
        jobConf.setOutputFormat(TextOutputFormat.class);

        FileInputFormat.addInputPath(jobConf, new Path(splitDir));
        Random random = new Random();
        FileOutputFormat.setOutputPath(jobConf, new Path(workplace, "output" + random.nextLong()));

        jobConf.setNumMapTasks(numMappers);

        createSplitFiles(conf, new Path(splitDir));

        return jobConf;
    }

    private void printUsage() {
        System.out.println("NotifierShell -consumetxn -workplace workplace " + NOTIFIER_SERVER_ADDR_KEY
                + " notifierAddrList " + "[" + NOTIFIER_SERVER_PORT_KEY + " notifierPortList] " + "["
                + NUM_MAPPERS_KEY + " numMappers] " + "[" + NUM_SUBDIRS_KEY + " numSubDirs] " + "["
                + NUM_FILES_SUB_DIR_KEY + " numFiles] " + "[" + NUM_ROUND_KEY + " numRound]");
    }

    public void start(String[] args, int startIndex) throws IOException {
        try {
            while (startIndex < args.length) {
                String cmd = args[startIndex++];
                if (cmd.equals(NUM_MAPPERS_KEY)) {
                    numMappers = Integer.valueOf(args[startIndex++]);
                } else if (cmd.equals(NUM_SUBDIRS_KEY)) {
                    numSubDirs = Integer.valueOf(args[startIndex++]);
                } else if (cmd.equals(NUM_FILES_SUB_DIR_KEY)) {
                    numFilesEachSubDirs = Integer.valueOf(args[startIndex++]);
                } else if (cmd.equals(NUM_ROUND_KEY)) {
                    round = Integer.valueOf(args[startIndex++]);
                } else if (cmd.equals(WORKPLACE_KEY)) {
                    workplace = args[startIndex++];
                } else if (cmd.equals(NOTIFIER_SERVER_ADDR_KEY)) {
                    notifierServerAddrStr = args[startIndex++];
                } else if (cmd.equals(NOTIFIER_SERVER_PORT_KEY)) {
                    notifierServerPortStr = args[startIndex++];
                } else {
                    printUsage();
                    System.exit(-1);
                }
            }
        } catch (Exception e) {
            printUsage();
            System.exit(-1);
        }

        if (workplace.trim().isEmpty() || notifierServerAddrStr.trim().isEmpty()) {
            printUsage();
            System.exit(-1);
        }

        if (!workplace.endsWith(Path.SEPARATOR)) {
            workplace += Path.SEPARATOR;
        }

        JobConf jobConf = createJobConf(conf);

        JobClient client = new JobClient(jobConf);
        RunningJob runningJob = client.submitJob(jobConf);
        runningJob.waitForCompletion();
    }
}