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ülcü 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 }