EMMA Coverage Report (generated Wed Feb 26 21:48:09 GMT 2014)
[all classes][uk.org.simonsite.log4j.appender.cas]

COVERAGE SUMMARY FOR SOURCE FILE [LoggingEventCASQueue.java]

nameclass, %method, %block, %line, %
LoggingEventCASQueue.java100% (2/2)100% (11/11)97%  (175/181)91%  (41/45)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LoggingEventCASQueue100% (1/1)100% (9/9)97%  (169/175)91%  (40/44)
poll (): LoggingEvent 100% (1/1)64%  (9/14)50%  (3/6)
put (LoggingEvent): void 100% (1/1)98%  (42/43)91%  (10/11)
<static initializer> 100% (1/1)100% (5/5)100% (1/1)
LoggingEventCASQueue (ActiveAsynchronousAppenderProperties): void 100% (1/1)100% (24/24)100% (6/6)
awaitEvent (): LoggingEventCASQueue 100% (1/1)100% (11/11)100% (4/4)
checkInterruptionDuring (String): void 100% (1/1)100% (26/26)100% (3/3)
nextIndex (int, int): int 100% (1/1)100% (11/11)100% (4/4)
take (): LoggingEvent 100% (1/1)100% (4/4)100% (1/1)
takeEvent (): LoggingEvent 100% (1/1)100% (37/37)100% (8/8)
     
class LoggingEventCASQueue$1100% (1/1)100% (2/2)100% (6/6)100% (2/2)
LoggingEventCASQueue$1 (): void 100% (1/1)100% (3/3)100% (1/1)
initialValue (): Integer 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 * 
6 *      http://www.apache.org/licenses/LICENSE-2.0
7 * 
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14package uk.org.simonsite.log4j.appender.cas;
15 
16import java.util.concurrent.atomic.AtomicInteger;
17import java.util.concurrent.atomic.AtomicReferenceArray;
18 
19import org.apache.log4j.spi.LoggingEvent;
20 
21import uk.org.simonsite.log4j.appender.ActiveAsynchronousAppenderProperties;
22import uk.org.simonsite.log4j.appender.LoggingEventQueue;
23 
24/**
25 * Non-blocking queue used to buffer {@link LoggingEvent}s for asynchronous
26 * dispatch. This implementation spins instead of locking. This is thread-safe.
27 * 
28 * @author <a href="mailto:simon_park_mail AT yahoo DOT co DOT uk">Simon
29 *         Park</a>
30 * @version 1.1
31 */
32public final class LoggingEventCASQueue implements LoggingEventQueue {
33 
34  private static final ThreadLocal<Integer> PRODUCER_INDEX = new ThreadLocal<Integer>() {
35 
36    @Override
37    protected final Integer initialValue() {
38      return 0;
39    }
40  };
41 
42  private final AtomicReferenceArray<LoggingEvent> queue;
43 
44  private int consumerIndex;
45 
46  private final AtomicInteger eventsAvailable;
47 
48  public LoggingEventCASQueue(
49      final ActiveAsynchronousAppenderProperties properties) {
50    super();
51    this.eventsAvailable = new AtomicInteger(0);
52    this.queue = new AtomicReferenceArray<LoggingEvent>(
53        new LoggingEvent[properties.getMaxSize()]);
54    this.consumerIndex = 0;
55    PRODUCER_INDEX.set(0);
56  }
57 
58  /**
59   * @see uk.org.simonsite.log4j.appender.LoggingEventQueue#poll()
60   */
61  public final LoggingEvent poll() {
62    if (this.eventsAvailable.get() <= 0) {
63      return null;
64    }
65    try {
66      return this.take();
67    } catch (InterruptedException e) {
68      Thread.currentThread().interrupt();
69      return null;
70    }
71  }
72 
73  /**
74   * @see uk.org.simonsite.log4j.appender.LoggingEventQueue#put(org.apache.log4j.spi.LoggingEvent)
75   */
76  public final void put(final LoggingEvent loggingEvent)
77      throws InterruptedException {
78    if (loggingEvent == null) {
79      return;
80    }
81    final int maxSize = this.queue.length();
82    for (int i = PRODUCER_INDEX.get(); true; i = this.nextIndex(i, maxSize)) {
83      this.checkInterruptionDuring("put onto");
84      if (this.queue.compareAndSet(i, null, loggingEvent)) {
85        i = this.nextIndex(i, maxSize);
86        PRODUCER_INDEX.set(i);
87        this.eventsAvailable.incrementAndGet();
88        break;
89      }
90    }
91  }
92 
93  /**
94   * @see uk.org.simonsite.log4j.appender.LoggingEventQueue#take()
95   */
96  public final LoggingEvent take() throws InterruptedException {
97    return this.awaitEvent().takeEvent();
98  }
99 
100  private LoggingEventCASQueue awaitEvent() throws InterruptedException {
101    // int counter = 100;
102    while (this.eventsAvailable.get() <= 0) {
103      this.checkInterruptionDuring("take from");
104      Thread.yield();
105      // if (counter-- > 0) {
106      // Thread.yield();
107      // } else {
108      // LockSupport.parkNanos(5);
109      // }
110    }
111    return this;
112  }
113 
114  private void checkInterruptionDuring(final String operation)
115      throws InterruptedException {
116    if (Thread.interrupted()) {
117      throw new InterruptedException(this.getClass().getName()
118          + " interrupted during " + operation + " queue of "
119          + LoggingEvent.class.getName() + " objects");
120    }
121  }
122 
123  private int nextIndex(final int currentIndex, final int maxSize) {
124    final int nextIndex = currentIndex + 1;
125    if (nextIndex < maxSize) {
126      return nextIndex;
127    } else {
128      return 0;
129    }
130  }
131 
132  private LoggingEvent takeEvent() throws InterruptedException {
133    LoggingEvent loggingEvent = null;
134    final int maxSize = this.queue.length();
135    for (int i = this.consumerIndex; true; i = this.nextIndex(i, maxSize)) {
136      if ((loggingEvent = this.queue.getAndSet(i, null)) != null) {
137        this.eventsAvailable.decrementAndGet();
138        this.consumerIndex = this.nextIndex(i, maxSize);
139        break;
140      }
141    }
142    return loggingEvent;
143  }
144}

[all classes][uk.org.simonsite.log4j.appender.cas]
EMMA 2.0.5312 (C) Vladimir Roubtsov