/* * (C) Copyright IBM Corp. 2009 * * LICENSE: Eclipse Public License v1.0 * http://www.eclipse.org/legal/epl-v10.html */ package com.ibm.gaiandb; import java.util.Collection; import java.util.Iterator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; /** * A concurrent Queue that is optimized for the conditions: * - There can be multiple producers, but only 1 consumer. The consumer only has to wait when there is no data. * - The only methods implemented are: offer(Object), poll(), poll(time, unit), take(), size() (which is expensive) * - For method poll(time, unit), unit is ignored and assumed to be MILLISECONDS * - The producers do not attempt to offer an element to the Queue when it has reached its maximum capacity. * * @author DavidVyvyan */ public class ConcurrentWriteQueue<E> implements BlockingQueue<E> { // Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice. public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2009"; CircularBufferNode in, out; Object consumerLock = new Object(), producerLock = new Object(); private class CircularBufferNode { E elmt; CircularBufferNode tail; } public ConcurrentWriteQueue( int capacity ) { if ( 0 == capacity ) return; CircularBufferNode first = new CircularBufferNode(); CircularBufferNode next = first; for (int i=0; i<capacity-1; i++, next=next.tail) next.tail = new CircularBufferNode(); next.tail = first; in = first; out = in; } public boolean offer(E o) { boolean wasEmpty; synchronized( producerLock ) { wasEmpty = in == out; in.elmt = o; in = in.tail; } if ( wasEmpty ) synchronized( consumerLock ) { consumerLock.notify(); } // notify potentially waiting thread return true; /* boolean wasEmpty = isEmpty(); if ( super.offer(o) ) { if ( wasEmpty ) synchronized(this) { notify(); } return true; } return false; */ } public E poll() { if ( out == in ) return null; E o = out.elmt; out = out.tail; return o; } public E poll(long timeout, TimeUnit unit) throws InterruptedException { if ( out == in ) synchronized( consumerLock ) { consumerLock.wait( timeout ); } E o = out.elmt; out = out.tail; return o; } public E take() throws InterruptedException { return poll(0, TimeUnit.MILLISECONDS); } public int size() { CircularBufferNode snapIn, snapOut; synchronized (this) { snapOut = out; snapIn = in; } int size = 0; for ( CircularBufferNode n = snapOut; n != snapIn ; n = n.tail ) size++; return size; } public int drainTo(Collection<? super E> c) { return 0; } public int drainTo(Collection<? super E> c, int maxElements) { return 0; } public void put(Object o) throws InterruptedException { } public int remainingCapacity() { return 0; } public boolean offer(Object o, long timeout, TimeUnit unit) throws InterruptedException { return false; } public boolean add(Object o) { return false; } public E element() { return null; } public E peek() { return null; } public E remove() { return null; } public boolean addAll(Collection<? extends E> c) { return false; } public void clear() { } public boolean contains(Object o) { return false; } public boolean containsAll(Collection<?> c) { return false; } public boolean isEmpty() { return false; } public Iterator<E> iterator() { return null; } public boolean remove(Object o) { return false; } public boolean removeAll(Collection<?> c) { return false; } public boolean retainAll(Collection<?> c) { return false; } public Object[] toArray() { return null; } public <T> T[] toArray(T[] a) { return null; } }