View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  // Contributors:     Mathias Bogaert
    19  //                   joelr@viair.com
    20
    21  package org.apache.log4j.helpers;
    22
    23  import org.apache.log4j.spi.LoggingEvent;
    24
    25  /**
    26     <code>BoundedFIFO</code> serves as the bounded first-in-first-out
    27     buffer heavily used by the {@link org.apache.log4j.AsyncAppender}.
    28
    29     @author Ceki G&uuml;lc&uuml;
    30     @since version 0.9.1 */
    31  public class BoundedFIFO {
    32
    33    LoggingEvent[] buf;
    34    int numElements = 0;
    35    int first = 0;
    36    int next = 0;
    37    int maxSize;
    38
    39    /**
    40       Instantiate a new BoundedFIFO with a maximum size passed as argument.
    41     */
    42    public
    43    BoundedFIFO(int maxSize) {
    44     if(maxSize < 1) {
    45        throw new IllegalArgumentException("The maxSize argument ("+maxSize+
    46  			    ") is not a positive integer.");
    47      }
    48      this.maxSize = maxSize;
    49      buf = new LoggingEvent[maxSize];
    50    }
    51
    52    /**
    53       Get the first element in the buffer. Returns <code>null</code> if
    54       there are no elements in the buffer.  */
    55    public
    56    LoggingEvent get() {
    57      if(numElements == 0)
    58        return null;
    59
    60      LoggingEvent r = buf[first];
    61      buf[first] = null; // help garbage collection
    62
    63      if(++first == maxSize) {
    64  	first = 0;
    65      }
    66      numElements--;
    67      return r;
    68    }
    69
    70    /**
    71       Place a {@link LoggingEvent} in the buffer. If the buffer is full
    72       then the event is <b>silently dropped</b>. It is the caller's
    73       responsability to make sure that the buffer has free space.  */
    74    public
    75    void put(LoggingEvent o) {
    76      if(numElements != maxSize) {
    77        buf[next] = o;
    78        if(++next == maxSize) {
    79  	next = 0;
    80        }
    81        numElements++;
    82      }
    83    }
    84
    85    /**
    86       Get the maximum size of the buffer.
    87     */
    88    public
    89    int getMaxSize() {
    90      return maxSize;
    91    }
    92
    93    /**
    94       Return <code>true</code> if the buffer is full, that is, whether
    95       the number of elements in the buffer equals the buffer size. */
    96    public
    97    boolean isFull() {
    98      return numElements == maxSize;
    99    }
    100
    101   /**
    102      Get the number of elements in the buffer. This number is
    103      guaranteed to be in the range 0 to <code>maxSize</code>
    104      (inclusive).
    105   */
    106   public
    107   int length() {
    108     return numElements;
    109   }
    110
    111
    112   int min(int a, int b) {
    113     return a < b ? a : b;
    114   }
    115
    116
    117   /**
    118      Resize the buffer to a new size. If the new size is smaller than
    119      the old size events might be lost.
    120
    121      @since 1.1
    122    */
    123   synchronized
    124   public
    125   void resize(int newSize) {
    126     if(newSize == maxSize)
    127       return;
    128
    129
    130    LoggingEvent[] tmp = new LoggingEvent[newSize];
    131
    132    // we should not copy beyond the buf array
    133    int len1 = maxSize - first;
    134
    135    // we should not copy beyond the tmp array
    136    len1 = min(len1, newSize);
    137
    138    // er.. how much do we actually need to copy?
    139    // We should not copy more than the actual number of elements.
    140    len1 = min(len1, numElements);
    141
    142    // Copy from buf starting a first, to tmp, starting at position 0, len1 elements.
    143    System.arraycopy(buf, first, tmp, 0, len1);
    144
    145    // Are there any uncopied elements and is there still space in the new array?
    146    int len2 = 0;
    147    if((len1 < numElements) && (len1 < newSize)) {
    148      len2 = numElements - len1;
    149      len2 = min(len2, newSize - len1);
    150      System.arraycopy(buf, 0, tmp, len1, len2);
    151    }
    152
    153    this.buf = tmp;
    154    this.maxSize = newSize;
    155    this.first=0;
    156    this.numElements = len1+len2;
    157    this.next = this.numElements;
    158    if(this.next == this.maxSize) // this should never happen, but again, it just might.
    159      this.next = 0;
    160   }
    161
    162
    163   /**
    164      Returns <code>true</code> if there is just one element in the
    165      buffer. In other words, if there were no elements before the last
    166      {@link #put} operation completed.  */
    167   public
    168   boolean wasEmpty() {
    169     return numElements == 1;
    170   }
    171
    172   /**
    173       Returns <code>true</code> if the number of elements in the
    174       buffer plus 1 equals the maximum buffer size, returns
    175       <code>false</code> otherwise. */
    176   public
    177   boolean wasFull() {
    178     return (numElements+1 == maxSize);
    179   }
    180
    181 }