public BlockingCircularBuffer(int bufferSize, int congestionDelay) { events = new OverwritingCircularBuffer<>(bufferSize); lock = new ReentrantLock(true); this.congestionDelay = congestionDelay; }
@Override public void addAll(List<E> elements) { for(E element : elements) { add(element); } }
@Override public E get(long index) { lock.lock(); try { return events.get(index); } finally { lock.unlock(); } }
private void internalAdd(Object element) { if(isFull()) { removeFirst(); overflowCounter++; } size++; array[endIndex] = element; endIndex++; if(endIndex == bufferSize) { endIndex = 0; } if(startIndex == endIndex) { full = true; } }
@Override public List<E> removeAll() { long availableElements = getAvailableElements(); List<E> result = new ArrayList<>((int) availableElements); for(int i = 0; i < availableElements; i++) { result.add(removeFirst()); } return result; }
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out getBufferSize s.defaultWriteObject(); // Write out getAvailableElements long availableElements = getAvailableElements(); s.writeLong(availableElements); // Write out all elements for(int i = 0; i < availableElements; i++) { s.writeObject(getRelative(i)); } }
@Test public void one() { instance.add((long) 1); assertFalse("Instance is empty!", instance.isEmpty()); assertFalse("Instance is full!", instance.isFull()); assertEquals("Size doesn't match!", 1, instance.getAvailableElements()); assertEquals("getBufferSize doesn't match!", TEST_BUFFER_SIZE, instance.getBufferSize()); assertEquals("overflowCounter doesn't match!", 0, instance.getOverflowCounter()); Iterator<Long> iterator = instance.iterator(); assertTrue("iterator doesn't have next!", iterator.hasNext()); Long element = iterator.next(); Long getRelativeValue = instance.getRelative(0); Long getValue = instance.get(0); if(logger.isInfoEnabled()) logger.info("Element #{}: iterValue={}, getRelativeValue={}, getValue={}", 0, element, getRelativeValue, getValue); assertEquals("Unexpected value returned by iterator!", (Long) (long) 1, element); assertEquals("Iterator and getRelative values differ!", element, getRelativeValue); assertEquals("Iterator and get values differ!", element, getValue); }
long bufferSize = impl.getBufferSize(); if(logger.isInfoEnabled()) logger.info("Executing add-remove-reset test with valueCount={} and buffer.getBufferSize={}.", valueCount, bufferSize); impl.addAll(values); if(logger.isInfoEnabled()) logger.info("Buffer after adding: {}", impl); assertTrue("Instance isn't empty!", impl.isEmpty()); assertFalse("Instance is empty!", impl.isEmpty()); assertTrue("Instance isn't full!", impl.isFull()); assertFalse("Instance is full!", impl.isFull()); assertEquals("Size doesn't match!", expectedElementCount, impl.getAvailableElements()); assertEquals("overflowCounter doesn't match!", expectedOverflowCount, impl.getOverflowCounter()); assertEquals("getSize doesn't match!", valueCount, impl.getSize()); List<Long> removedList = impl.removeAll(); assertTrue("Instance isn't empty!", impl.isEmpty()); assertEquals("overflowCounter doesn't match!", expectedOverflowCount, impl.getOverflowCounter()); assertEquals("getSize doesn't match!", valueCount, impl.getSize()); impl.reset(); assertEquals("overflowCounter doesn't match!", 0, impl.getOverflowCounter()); assertEquals("getSize doesn't match!", 0, impl.getSize()); assertTrue("Instance isn't empty!", impl.isEmpty()); assertFalse("Instance is full!", impl.isFull());
@Test public void empty() { assertTrue("Instance is not empty!", instance.isEmpty()); assertFalse("Instance is full!", instance.isFull()); assertEquals("Size doesn't match!", 0, instance.getAvailableElements()); assertEquals("getBufferSize doesn't match!", TEST_BUFFER_SIZE, instance.getBufferSize()); assertEquals("overflowCounter doesn't match!", 0, instance.getOverflowCounter()); Iterator<Long> iterator = instance.iterator(); assertFalse("iterator has next!", iterator.hasNext()); }
try while(events.isFull()) if(logger.isWarnEnabled()) logger.warn("Congestion ({} events) detected, sleeping for {} millis.", events.getAvailableElements(), congestionDelay); events.add(element);
@Override public E getRelative(int index) { long availableElements = getAvailableElements(); if(index < 0 || index >= availableElements) { throw new IndexOutOfBoundsException("Invalid index " + index + "! Must be 0.." + (availableElements - 1) + "."); } int realIndex = (startIndex + index) % bufferSize; @SuppressWarnings({"unchecked"}) E result = (E) array[realIndex]; return result; }
@Override public E removeFirst() { if(isEmpty()) { return null; } @SuppressWarnings({"unchecked"}) E result = (E) array[startIndex]; array[startIndex] = null; int newStart = startIndex + 1; if(newStart == bufferSize) { newStart = 0; } startIndex = newStart; full = false; return result; }
@Override public E get(long index) { if(index < 0 || index >= size) { throw new IndexOutOfBoundsException("Invalid index " + index + "! Must be 0.." + (size - 1) + "."); } int realIndex = (int) (index - overflowCounter); if(realIndex < 0) { return null; } return getRelative(realIndex); }
@Override public int getBufferSize() { return events.getBufferSize(); }
@Override public boolean isFull() { lock.lock(); try { return events.isFull(); } finally { lock.unlock(); } }
@Override public long getSize() { lock.lock(); try { return events.getSize(); } finally { lock.unlock(); } }
@Override public Iterator<E> iterator() { lock.lock(); try { return events.iterator(); } finally { lock.unlock(); } } }
@Test public void overflowOne() { for(int i = 0; i < TEST_BUFFER_SIZE; i++) { instance.add((long) i); } instance.add((long) TEST_BUFFER_SIZE); assertFalse("Instance is empty!", instance.isEmpty()); assertTrue("Instance isn't full!", instance.isFull()); assertEquals("Size doesn't match!", TEST_BUFFER_SIZE, instance.getAvailableElements()); assertEquals("getBufferSize doesn't match!", TEST_BUFFER_SIZE, instance.getBufferSize()); long overflowCounter = instance.getOverflowCounter(); assertEquals("overflowCounter doesn't match!", 1, overflowCounter); Iterator<Long> iterator = instance.iterator(); assertTrue("iterator doesn't have next!", iterator.hasNext()); for(int i = 0; i < TEST_BUFFER_SIZE; i++) { Long element = iterator.next(); Long getRelativeValue = instance.getRelative(i); Long getValue = instance.get(i + overflowCounter); if(logger.isInfoEnabled()) logger.info("Element #{}: iterValue={}, getRelativeValue={}", i, element, getRelativeValue); assertEquals("Unexpected value returned by iterator!", (Long) (long) (i + 1), element); assertEquals("Iterator and getRelative values differ!", element, getRelativeValue); assertEquals("Iterator and get values differ!", element, getValue); } }
long bufferSize = impl.getBufferSize(); if(logger.isInfoEnabled()) logger.info("Executing add-remove-reset test with valueCount={} and buffer.getBufferSize={}.", valueCount, bufferSize); impl.addAll(values); if(logger.isInfoEnabled()) logger.info("Buffer after adding: {}", impl); assertTrue("Instance isn't empty!", impl.isEmpty()); assertFalse("Instance is empty!", impl.isEmpty()); assertTrue("Instance isn't full!", impl.isFull()); assertFalse("Instance is full!", impl.isFull()); assertEquals("Available doesn't match!", expectedElementCount, impl.getAvailableElements()); long overflowCounter = instance.getOverflowCounter(); assertEquals("overflowCounter doesn't match!", expectedOverflowCount, overflowCounter); assertEquals("Size doesn't match!", valueCount, impl.getSize()); for(int i = 0; i < expectedElementCount; i++) assertFalse("Instance is empty!", impl.isEmpty()); assertEquals("Size doesn't match!", expectedElementCount - i, impl.getAvailableElements()); if(logger.isDebugEnabled()) logger.debug("Size before removal of element #{}: {}", i, impl.getAvailableElements()); Long removeValue = impl.removeFirst(); if(logger.isDebugEnabled()) logger.debug("Size after removal of element #{}: {}", i, impl.getAvailableElements()); assertFalse("Instance is full!", impl.isFull()); assertEquals("Size doesn't match!", expectedElementCount - i - 1, impl.getAvailableElements());