org.mapdb.Queues Maven / Gradle / Ivy
package org.mapdb;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Various queue algorithms
*/
public final class Queues {
private Queues(){}
public static abstract class SimpleQueue implements BlockingQueue {
protected final boolean useLocks;
protected final ReentrantLock[] locks;
protected static final int TICK = 10*1000;
protected final Engine engine;
protected final Serializer serializer;
protected final Atomic.Long head;
protected static class NodeSerializer implements Serializer> {
private final Serializer serializer;
public NodeSerializer(Serializer serializer) {
this.serializer = serializer;
}
@Override
public void serialize(DataOutput out, Node value) throws IOException {
if(value==Node.EMPTY) return;
DataOutput2.packLong(out,value.next);
serializer.serialize(out, value.value);
}
@Override
public Node deserialize(DataInput in, int available) throws IOException {
if(available==0)return Node.EMPTY;
return new Node(DataInput2.unpackLong(in), serializer.deserialize(in,-1));
}
@Override
public int fixedSize() {
return -1;
}
}
protected final Serializer nodeSerializer;
public SimpleQueue(Engine engine, Serializer serializer, long headRecidRef, boolean useLocks) {
this.engine = engine;
this.serializer = serializer;
head = new Atomic.Long(engine,headRecidRef);
nodeSerializer = new NodeSerializer(serializer);
this.useLocks = useLocks;
if(useLocks){
locks = new ReentrantLock[CC.CONCURRENCY];
for(int i=0;i{
protected static final Node EMPTY = new Node(0L, null);
final protected long next;
final protected E value;
public Node(long next, E value) {
this.next = next;
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
if (next != node.next) return false;
if (value != null ? !value.equals(node.value) : node.value != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (next ^ (next >>> 32));
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
}
@Override
public void clear() {
while(!isEmpty())
poll();
}
@Override
public E remove() {
E ret = poll();
if(ret == null) throw new NoSuchElementException();
return ret;
}
@Override
public E element() {
E ret = peek();
if(ret == null) throw new NoSuchElementException();
return ret;
}
@Override
public boolean offer(E e) {
return add(e);
}
@Override
public void put(E e) throws InterruptedException {
while(!offer(e)){
Thread.sleep(0,TICK);
}
}
@Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
if(offer(e)) return true;
long target = System.currentTimeMillis() + unit.toMillis(timeout);
while(target>=System.currentTimeMillis()){
if(offer(e))
return true;
Thread.sleep(0,TICK);
}
return false;
}
@Override
public E take() throws InterruptedException {
E e = poll();
while(e==null){
Thread.sleep(0,TICK);
e = poll();
}
return e;
}
@Override
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E e = poll();
if(e!=null) return e;
long target = System.currentTimeMillis() + unit.toMillis(timeout);
while(target>=System.currentTimeMillis()){
Thread.sleep(0,TICK);
e = poll();
if(e!=null)
return e;
}
return null;
}
@Override
public int drainTo(Collection super E> c) {
return drainTo(c,Integer.MAX_VALUE);
}
@Override
public int drainTo(Collection super E> c, int maxElements) {
int counter=0;
while(counter iterator() {
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> c) {
throw new UnsupportedOperationException();
}
}
/**
* Last in first out lock-free queue
*
* @param
*/
public static class Stack extends SimpleQueue {
public Stack(Engine engine, Serializer serializer, long headerRecidRef, boolean useLocks) {
super(engine, serializer, headerRecidRef, useLocks);
}
@Override
public boolean add(E e) {
long head2 = head.get();
Node n = new Node(head2, e);
long recid = engine.put(n, nodeSerializer);
while(!head.compareAndSet(head2, recid)){
//failed to update head, so read new value and start over
head2 = head.get();
n = new Node(head2, e);
engine.update(recid, n, nodeSerializer);
}
return true;
}
}
/**
* First in first out lock-free queue
*
* @param
*/
public static class Queue extends SimpleQueue {
protected final Atomic.Long tail;
public Queue(Engine engine, Serializer serializer, long headerRecid,
long nextTailRecid, boolean useLocks) {
super(engine, serializer,headerRecid,useLocks);
tail = new Atomic.Long(engine,nextTailRecid);
}
@Override
public boolean add(E e) {
long nextTail = engine.put(Node.EMPTY,nodeSerializer);
long tail2 = tail.get();
while(!tail.compareAndSet(tail2,nextTail)){
tail2 = tail.get();
}
//now we have tail2 just for us
Node n = new Node(nextTail,e);
engine.update(tail2,n,nodeSerializer);
return true;
}
}
public static class CircularQueue extends SimpleQueue {
protected final Atomic.Long headInsert;
//TODO is there a way to implement this without global locks?
protected final Lock lock = new ReentrantLock(CC.FAIR_LOCKS);
protected final long size;
public CircularQueue(Engine engine, Serializer serializer, long headRecid, long headInsertRecid, long size) {
super(engine, serializer, headRecid,false);
headInsert = new Atomic.Long(engine, headInsertRecid);
this.size = size;
}
@Override
public boolean add(Object o) {
lock.lock();
try{
long nRecid = headInsert.get();
Node n = engine.get(nRecid, nodeSerializer);
n = new Node(n.next, (E) o);
engine.update(nRecid, n, nodeSerializer);
headInsert.set(n.next);
//move 'poll' head if it points to currently replaced item
head.compareAndSet(nRecid, n.next);
return true;
}finally {
lock.unlock();
}
}
@Override
public void clear() {
// praise locking
lock.lock();
try {
for (int i = 0; i < size; i++) {
poll();
}
} finally {
lock.unlock();
}
}
@Override
public E poll() {
lock.lock();
try{
long nRecid = head.get();
Node n = engine.get(nRecid, nodeSerializer);
engine.update(nRecid, new Node(n.next, null), nodeSerializer);
head.set(n.next);
return n.value;
}finally {
lock.unlock();
}
}
@Override
public E peek() {
lock.lock();
try{
long nRecid = head.get();
Node n = engine.get(nRecid, nodeSerializer);
return n.value;
}finally {
lock.unlock();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy