001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018// Contributors: Mathias Bogaert 019// joelr@viair.com 020 021package org.apache.log4j.helpers; 022 023import org.apache.log4j.spi.LoggingEvent; 024 025/** 026 <code>BoundedFIFO</code> serves as the bounded first-in-first-out 027 buffer heavily used by the {@link org.apache.log4j.AsyncAppender}. 028 029 @author Ceki Gülcü 030 @since version 0.9.1 */ 031public class BoundedFIFO { 032 033 LoggingEvent[] buf; 034 int numElements = 0; 035 int first = 0; 036 int next = 0; 037 int maxSize; 038 039 /** 040 Instantiate a new BoundedFIFO with a maximum size passed as argument. 041 */ 042 public 043 BoundedFIFO(int maxSize) { 044 if(maxSize < 1) { 045 throw new IllegalArgumentException("The maxSize argument ("+maxSize+ 046 ") is not a positive integer."); 047 } 048 this.maxSize = maxSize; 049 buf = new LoggingEvent[maxSize]; 050 } 051 052 /** 053 Get the first element in the buffer. Returns <code>null</code> if 054 there are no elements in the buffer. */ 055 public 056 LoggingEvent get() { 057 if(numElements == 0) 058 return null; 059 060 LoggingEvent r = buf[first]; 061 buf[first] = null; // help garbage collection 062 063 if(++first == maxSize) { 064 first = 0; 065 } 066 numElements--; 067 return r; 068 } 069 070 /** 071 Place a {@link LoggingEvent} in the buffer. If the buffer is full 072 then the event is <b>silently dropped</b>. It is the caller's 073 responsability to make sure that the buffer has free space. */ 074 public 075 void put(LoggingEvent o) { 076 if(numElements != maxSize) { 077 buf[next] = o; 078 if(++next == maxSize) { 079 next = 0; 080 } 081 numElements++; 082 } 083 } 084 085 /** 086 Get the maximum size of the buffer. 087 */ 088 public 089 int getMaxSize() { 090 return maxSize; 091 } 092 093 /** 094 Return <code>true</code> if the buffer is full, that is, whether 095 the number of elements in the buffer equals the buffer size. */ 096 public 097 boolean isFull() { 098 return numElements == maxSize; 099 } 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}