package se.pp.gustafson.marten.logback.appender;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* A thread safe circular buffer that blocks on {@link SloppyCircularBuffer#dequeue()} if the buffer is empty.
* It's possible that concurrent threads calling {@link SloppyCircularBuffer#enqueue(Object)} may remove more
* objects than strictly necessary. This is deemed as an acceptable behavior of this implementation.
*
* @param <Item>
* The type of items this {@link SloppyCircularBuffer} contains
*/
public final class SloppyCircularBuffer<Item>
{
private final BlockingQueue<Item> queue;
public SloppyCircularBuffer(final int capacity)
{
this.queue = new ArrayBlockingQueue<Item>(capacity);
}
/**
* Add the given Item to this {@link SloppyCircularBuffer} removing older entries if necessary.
*
* @param item
*/
public void enqueue(final Item item)
{
for(; !this.queue.offer(item); this.queue.poll(), Thread.yield())
{}
}
/**
* Remove and return the eldest entry on this {@link SloppyCircularBuffer} blocking indefinitely if no item is available.
*
* @return
* @throws InterruptedException
* if interrupted while waiting for an item to become available.
*/
public Item dequeue() throws InterruptedException
{
return this.queue.take();
}
/**
* Remove and return the eldest entry on this {@link SloppyCircularBuffer} blocking for the given timeout if
* no item is available. Will return <code>null</code> if no item was available and the given timeout
* elapsed.
*
* @param timeout
* @param unit
* @return
* @throws InterruptedException
*/
public Item dequeue(final long timeout, final TimeUnit unit) throws InterruptedException
{
return this.queue.poll(timeout, unit);
}
}