A buffer that will block when it is full. You write elements on the buffer
and they can be read using iterator(). This class is safe for
concurrent writes (multiple threads can use add(Object)) but the
iterator() is not thread-safe (it assumes a single reader).

You MUST make sure that the thread that sets up the
BlockingBuffer and which submits a task that writes on the buffer
also sets the Future on the BlockingBuffer so that the
iterator can monitor the Future, detect if it has been canceled, and
throw out the exception from the Future back to the client. Failure
to do this can lead to the iterator not terminating!

This class has internal complexities which arise from the need to
coordinate elements being added to the buffer with elements being
drained by the iterator without access to the internal lock of the
backing queue. If we could use that internal lock then we could get rid
of the spin loops and related cruft.

Field Detail

log

protected static final org.apache.log4j.Logger log

Warning messages are emitted if either the producer or the consumer is
stalled. When Category.isInfoEnabled() is true,
those log messages will be include stack traces which can help to
identify the the consumer or producer.

DEFAULT_PRODUCER_QUEUE_CAPACITY

public static final transient int DEFAULT_PRODUCER_QUEUE_CAPACITY

The default capacity for the internal Queue on which elements (or
chunks of elements) are buffered.

Constructor Detail

BlockingBuffer

BlockingBuffer

capacity - The capacity of the buffer. When the generic type <E>
is an array type, then this is the chunkOfChunksCapacity
and small chunks will be automatically combined based on
availability and latency. When zero (0) a
SynchronousQueue will be used. Otherwise an
ArrayBlockingQueue of the given capacity is used.

BlockingBuffer

capacity - The capacity of the buffer. When the generic type
<E> is an array type, then this is the
chunkOfChunksCapacity and small chunks will be
automatically combined based on availability and latency. When
zero (0) a SynchronousQueue will be used. Otherwise an
LinkedBlockingDeque of the given capacity is used.

minimumChunkSize - The desired minimum chunk size. When the elements stored in
the buffer are chunks (i.e., arrays of some component type),
elements will be combined together to form larger chunks until
this minimumChunkSize is satisfied, the iterator() is
exhausted, or the chunkTimeout is reached.

chunkTimeout - The maximum time to wait in nanoseconds for another chunk to
come along so that we can combine it with the current chunk
for #next(). A value of ZERO(0) disables chunk
combiner.

minimumChunkSize - The desired minimum chunk size. When the elements stored in
the buffer are chunks (i.e., arrays of some component type),
elements will be combined together to form larger chunks until
this chunkSize is satisfied, the iterator() is
exhausted, or the chunkTimeout is reached.

chunkTimeout - The maximum time to wait in nanoseconds for another chunk to
come along so that we can combine it with the current chunk
for #next(). A value of ZERO(0) disables chunk
combiner.

chunkTimeoutUnit - The units in which the chunkTimeout is expressed.

ordered - When true the data are asserted to be ordered and
a merge sort will be applied if chunks are combined such that
the combined chunks will also be ordered (this has no effect
unless the generic type of the buffer is an array type).

isOpen

isOrdered

public boolean isOrdered()

close

public void close()

Closes the BlockingBuffer such that it will not accept new
elements (this is a NOP if unless the buffer is open). Once the buffer is
closed, the BlockingBuffer.BlockingIterator will drain any elements remaining in
the BlockingBuffer and then report false for
BlockingIterator#hasNext()) (this does NOT close the
{@link BlockingIterator}).

abort

Signal abnormal termination of the process writing on the buffer. The
buffer will be closed. The iterator will report the cause via a
wrapped exception the next time any method on its interface is invoked.
The internal queue may be cleared once this method is invoked.

getChunksAddedCount

The #of chunks #add(Object)ed to the buffer. This will be ZERO
unless the generic type of the buffer is an array type.

getElementsAddedCount

public long getElementsAddedCount()

The #of elements #add(Object)ed to the buffer. When the generic
type of the buffer is an array type, this will be the sum of the length
of the arrays #add(Object)ed to the buffer.

getElementsOnQueueCount

public long getElementsOnQueueCount()

The #of elements on the queue. When the queue uses a scalar element
type this will track the size() very closely. However, when
the queue uses an array element type, this will be the sum of the #of
elements across all arrays on the queue.

The most common reason to close an iterator early are that you want to
only visit a limited #of elements. However, if you use either
IAccessPath.iterator(long,long, int) or IRule with an
IQueryOptions to impose that limit, then most processes that
produce IAsynchronousIterators will automatically terminate when
they reach the desired limit, thereby avoiding issuing interrupts. Those
processes include IAccessPath scans where the #of elements to be
visited exceeds the fully materialized chunk threshold and IRule
evaluation.