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 }