Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 114   Methods: 14
NCLOC: 73   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
AsynchronousLogSink.java 0% 16.2% 14.3% 13.1%
coverage coverage
 1    package edu.rice.cs.plt.debug;
 2   
 3    import java.io.IOException;
 4    import java.util.Queue;
 5    import java.util.concurrent.ConcurrentLinkedQueue;
 6   
 7    import edu.rice.cs.plt.concurrent.CompletionMonitor;
 8    import edu.rice.cs.plt.lambda.LazyRunnable;
 9    import edu.rice.cs.plt.lambda.WrappedException;
 10   
 11    /**
 12    * <p>A LogSink that processes log messages in a separate thread. This minimizes the impact of logging
 13    * bottlenecks on the performance of the program. When the first log message is sent to this sink,
 14    * a daemon thread is started which records and waits for messages until the program terminates.</p>
 15    *
 16    * <p>The impact of logging on performance cannot be entirely eliminated. In addition to the added
 17    * pressure caused by an additional logging thread, the program thread still must generate a stack
 18    * trace for each logging invocation, and enqueuing each logging message can take both time and space.</p>
 19    *
 20    * <p>An advantage of synchronous logging is that users can infer from the lack of a message in a log that
 21    * a certain invocation never occurred. In contrast, it is possible for asynchronous log messages to be
 22    * created but not recorded before program termination (or any other arbitrary deadline). To avoid this
 23    * problem, users may invoke {@link #flush} at any time, which will block until all messages in a nonempty
 24    * queue have been recorded; additionally, by default a shutdown hook is registered which attempts to flush
 25    * the queue before program shutdown completes.</p>
 26    */
 27    public class AsynchronousLogSink implements LogSink {
 28   
 29    private final LogSink _delegate;
 30    private final Runnable _startThread; // lazily start thread on first invocation
 31    private final Queue<Message> _queue;
 32   
 33    private final CompletionMonitor _emptyNotifier; // signaled -> queue has become empty
 34    private final CompletionMonitor _nonemptyNotifier; // signaled -> queue has become nonempty
 35   
 36    /**
 37    * Create an asynchronous LogSink which passes messages to the given delegate sink. Sets
 38    * {@code flushOnShutdown} to {@code true}.
 39    */
 40  2 public AsynchronousLogSink(LogSink delegate) { this(delegate, true); }
 41   
 42    /**
 43    * Create an asynchronous LogSink which passes messages to the given delegate sink.
 44    * @param flushOnShutdown Whether a shutdown hook invoking {@link #flush} should be registered when
 45    * the logging thread is first started.
 46    */
 47  2 public AsynchronousLogSink(LogSink delegate, final boolean flushOnShutdown) {
 48  2 _delegate = delegate;
 49  2 _startThread = new LazyRunnable(new Runnable() {
 50  0 public void run() {
 51  0 if (flushOnShutdown) {
 52  0 Runtime.getRuntime().addShutdownHook(new Thread() {
 53  0 public void run() {
 54  0 try { flush(); }
 55  0 catch (InterruptedException e) { throw new WrappedException(e); }
 56    }
 57    });
 58    }
 59  0 new DequeueThread().start();
 60    }
 61    });
 62  2 _queue = new ConcurrentLinkedQueue<Message>();
 63  2 _emptyNotifier = new CompletionMonitor(true);
 64  2 _nonemptyNotifier = new CompletionMonitor(false);
 65    }
 66   
 67  0 public void close() throws IOException { _delegate.close(); }
 68   
 69    /** If any log messages have been enqueued but not yet recorded, block until they are recorded. */
 70  0 public void flush() throws InterruptedException {
 71  0 _emptyNotifier.ensureSignaled();
 72    }
 73   
 74  0 public void log(StandardMessage m) { handle(m); }
 75  0 public void logStart(StartMessage m) { handle(m); }
 76  0 public void logEnd(EndMessage m) { handle(m); }
 77  0 public void logError(ErrorMessage m) { handle(m); }
 78  0 public void logStack(StackMessage m) { handle(m); }
 79   
 80  0 private void handle(Message m) {
 81  0 boolean wasEmpty = _queue.isEmpty();
 82  0 _queue.offer(m);
 83  0 if (wasEmpty) {
 84  0 synchronized (this) {
 85  0 if (!_queue.isEmpty()) { // verify state after we have a lock
 86  0 _emptyNotifier.reset();
 87  0 _nonemptyNotifier.signal();
 88    }
 89    }
 90  0 _startThread.run();
 91    }
 92    }
 93   
 94    private class DequeueThread extends Thread {
 95  0 public DequeueThread() { super(AsynchronousLogSink.this.toString()); setDaemon(true); }
 96   
 97  0 public void run() {
 98  0 while (true) {
 99  0 _nonemptyNotifier.attemptEnsureSignaled();
 100  0 while (!_queue.isEmpty()) {
 101  0 _queue.remove().send(_delegate);
 102    }
 103  0 synchronized (AsynchronousLogSink.this) {
 104  0 if (_queue.isEmpty()) { // verify state after we have a lock
 105  0 _nonemptyNotifier.reset();
 106  0 _emptyNotifier.signal();
 107    }
 108    }
 109    }
 110    }
 111   
 112    }
 113   
 114    }