de.ufinke.cubaja.sort.SortManager.java Source code

Java tutorial

Introduction

Here is the source code for de.ufinke.cubaja.sort.SortManager.java

Source

// Copyright (c) 2009 - 2011, Uwe Finke. All rights reserved.
// Subject to BSD License. See "license.txt" distributed with this package.

package de.ufinke.cubaja.sort;

import java.util.Comparator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.ufinke.cubaja.util.Stopwatch;
import de.ufinke.cubaja.util.Text;

final class SortManager {

    static private final int DEFAULT_RUN_SIZE = 1024 * 128;
    static private final int MINIMUM_RUN_SIZE = 1024;
    static private final int MAX_ARRAY_SIZE = 1024 * 16;
    // ObjectOutputStream drains after buffer of 1K is filled;
    // resulting block to disk is approximately 15K <= block <= 16K
    static private final int DEFAULT_BLOCK_SIZE = 1024 * 15;
    static private final int MINIMUM_BLOCK_SIZE = 1024 * 7;

    static final Text text = Text.getPackageInstance(Sorter.class);

    static private volatile int id = 0;

    static private synchronized int getId() {

        return ++id;
    }

    private final int myId;
    private final String logPrefix;
    private final Log logger;
    private final int logInterval;
    private final Stopwatch stopwatch;

    private final SortConfig config;
    private final Comparator<?> comparator;
    private final SortAlgorithm algorithm;

    private final int runSize;
    private final int arraySize;
    private final int arrayCount;
    private final int blockSize;

    private final ExecutorService executor;
    private final BlockingQueue<Request> sortQueue;
    private final BlockingQueue<Request> fileQueue;
    private final BlockingQueue<Request> mainQueue;

    private AtomicLong putCount;
    private AtomicLong getCount;
    private Timer timer;

    private volatile Throwable error;

    public SortManager(SortConfig config, Comparator<?> comparator) {

        myId = getId();

        this.config = config;
        this.comparator = comparator;

        if (config.isLog()) {
            logger = LogFactory.getLog(Sorter.class);
            logPrefix = "Sort#" + myId + ": ";
            stopwatch = new Stopwatch();
        } else {
            logger = null;
            logPrefix = null;
            stopwatch = null;
        }
        logInterval = config.getLogInterval() * 1000;

        algorithm = config.getAlgorithm();

        int blockSize = config.getBlockSize();
        if (blockSize == 0) {
            blockSize = DEFAULT_BLOCK_SIZE;
        }
        if (blockSize < MINIMUM_BLOCK_SIZE) {
            blockSize = MINIMUM_BLOCK_SIZE;
        }
        this.blockSize = blockSize;

        int runSize = config.getRunSize();
        if (runSize == 0) {
            runSize = DEFAULT_RUN_SIZE;
        }
        if (runSize < MINIMUM_RUN_SIZE) {
            runSize = MINIMUM_RUN_SIZE;
        }
        this.runSize = runSize;

        int arrayCount = 1;
        int arraySize = runSize;
        while (arraySize > MAX_ARRAY_SIZE) {
            arraySize = arraySize >> 1;
            arrayCount = arrayCount << 1;
        }
        this.arrayCount = arrayCount;
        this.arraySize = arraySize;

        int queueCapacity = (arrayCount >> 1) + (arrayCount >> 4) + 1;
        sortQueue = new ArrayBlockingQueue<Request>(queueCapacity);
        fileQueue = new ArrayBlockingQueue<Request>(queueCapacity);
        mainQueue = new ArrayBlockingQueue<Request>(queueCapacity);

        executor = Executors.newCachedThreadPool(createThreadFactory());

        if (isDebug()) {
            putCount = new AtomicLong();
            getCount = new AtomicLong();
            debug("sortOpen", runSize, blockSize, algorithm.getClass().getName());
            if (isTrace()) {
                initTimer(logger, logPrefix, "sortPut", putCount);
            }
        }
    }

    private ThreadFactory createThreadFactory() {

        return new ThreadFactory() {

            public Thread newThread(Runnable r) {

                Thread thread = new Thread(r);
                thread.setDaemon(true);
                return thread;
            }
        };
    }

    public int id() {

        return myId;
    }

    public SortConfig getConfig() {

        return config;
    }

    public Comparator<?> getComparator() {

        return comparator;
    }

    public SortAlgorithm getAlgorithm() {

        return algorithm;
    }

    public boolean isTrace() {

        final Log logger = this.logger;
        return logger != null && logger.isTraceEnabled();
    }

    public boolean isDebug() {

        final Log logger = this.logger;
        return logger != null && logger.isDebugEnabled();
    }

    public void trace(String key, Object... parm) {

        if (isTrace()) {
            logger.trace(logPrefix + text.get(key, parm));
        }
    }

    public void debug(String key, Object... parm) {

        if (isDebug()) {
            logger.debug(logPrefix + text.get(key, parm));
        }
    }

    public void setError(Throwable error) {

        if (this.error != null) {
            return;
        }

        this.error = error;

        if (logger != null) {
            logger.error(logPrefix + text.get("sorterException"), error);
        }

        executor.shutdownNow();
    }

    public boolean hasError() {

        return error != null;
    }

    public void checkError() {

        if (hasError()) {
            throw new SorterException(error);
        }
    }

    public int getRunSize() {

        return runSize;
    }

    public int getArraySize() {

        return arraySize;
    }

    public int getArrayCount() {

        return arrayCount;
    }

    public int getBlockSize() {

        return blockSize;
    }

    public BlockingQueue<Request> getSortQueue() {

        return sortQueue;
    }

    public BlockingQueue<Request> getFileQueue() {

        return fileQueue;
    }

    public BlockingQueue<Request> getMainQueue() {

        return mainQueue;
    }

    public void submit(Runnable task) {

        executor.submit(task);
    }

    public void close() {

        if (isDebug()) {
            if (isTrace()) {
                timer.cancel();
            }
            debug("sortClose", Stopwatch.format(stopwatch.elapsedMillis()));
        }
    }

    public void addPutCount(int count) {

        if (isDebug()) {
            putCount.getAndAdd(count);
        }
    }

    public void addGetCount(int count) {

        if (isDebug()) {
            getCount.getAndAdd(count);
        }
    }

    public void switchState() {

        if (isDebug()) {
            debug("sortSwitch", putCount.get(), Stopwatch.format(stopwatch.elapsedMillis()));
            if (isTrace()) {
                timer.cancel();
                initTimer(logger, logPrefix, "sortGet", getCount);
            }
        }
    }

    private void initTimer(final Log logger, final String prefix, final String key, final AtomicLong counter) {

        TimerTask task = new TimerTask() {

            public void run() {

                logger.trace(prefix + text.get(key, counter.get()));
            }
        };

        timer = new Timer();
        timer.schedule(task, logInterval, logInterval);
    }

}