org.hornetq.utils.PriorityLinkedListImpl Maven / Gradle / Ivy
/*
* Copyright 2005-2014 Red Hat, Inc.
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.hornetq.utils;
import java.lang.reflect.Array;
import java.util.NoSuchElementException;
/**
* A priority linked list implementation
*
* It implements this by maintaining an individual LinkedBlockingDeque for each priority level.
*
* @author Tim Fox
* @author Jeff Mesnil
* @version $Revision: 1174 $
*/
public class PriorityLinkedListImpl implements PriorityLinkedList
{
protected LinkedListImpl[] levels;
private int size;
private int lastReset;
private int highestPriority = -1;
private int lastPriority = -1;
public PriorityLinkedListImpl(final int priorities)
{
levels = (LinkedListImpl[]) Array.newInstance(LinkedListImpl.class, priorities);
for (int i = 0; i < priorities; i++)
{
levels[i] = new LinkedListImpl();
}
}
private void checkHighest(final int priority)
{
if (lastPriority != priority || priority > highestPriority)
{
lastPriority = priority;
if (lastReset == Integer.MAX_VALUE)
{
lastReset = 0;
}
else
{
lastReset++;
}
}
if (priority > highestPriority)
{
highestPriority = priority;
}
}
public void addHead(final T t, final int priority)
{
checkHighest(priority);
levels[priority].addHead(t);
size++;
}
public void addTail(final T t, final int priority)
{
checkHighest(priority);
levels[priority].addTail(t);
size++;
}
public T poll()
{
T t = null;
// We are just using a simple prioritization algorithm:
// Highest priority refs always get returned first.
// This could cause starvation of lower priority refs.
// TODO - A better prioritization algorithm
for (int i = highestPriority; i >= 0; i--)
{
LinkedListImpl ll = levels[i];
if (ll.size() != 0)
{
t = ll.poll();
if (t != null)
{
size--;
if (ll.size() == 0)
{
if (highestPriority == i)
{
highestPriority--;
}
}
}
break;
}
}
return t;
}
public void clear()
{
for (LinkedListImpl list : levels)
{
list.clear();
}
size = 0;
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
public LinkedListIterator iterator()
{
return new PriorityLinkedListIterator();
}
private class PriorityLinkedListIterator implements LinkedListIterator
{
private int index;
private final LinkedListIterator[] cachedIters = new LinkedListIterator[levels.length];
private LinkedListIterator lastIter;
private int resetCount = lastReset;
volatile boolean closed = false;
PriorityLinkedListIterator()
{
index = levels.length - 1;
}
@Override
protected void finalize()
{
close();
}
public void repeat()
{
if (lastIter == null)
{
throw new NoSuchElementException();
}
lastIter.repeat();
}
public void close()
{
if (!closed)
{
closed = true;
lastIter = null;
for (LinkedListIterator iter : cachedIters)
{
if (iter != null)
{
iter.close();
}
}
}
}
private void checkReset()
{
if (lastReset != resetCount)
{
index = highestPriority;
resetCount = lastReset;
}
}
public boolean hasNext()
{
checkReset();
while (index >= 0)
{
lastIter = cachedIters[index];
if (lastIter == null)
{
lastIter = cachedIters[index] = levels[index].iterator();
}
boolean b = lastIter.hasNext();
if (b)
{
return true;
}
index--;
if (index < 0)
{
index = levels.length - 1;
break;
}
}
return false;
}
public T next()
{
if (lastIter == null)
{
throw new NoSuchElementException();
}
return lastIter.next();
}
public void remove()
{
if (lastIter == null)
{
throw new NoSuchElementException();
}
lastIter.remove();
// This next statement would be the equivalent of:
// if (index == highestPriority && levels[index].size() == 0)
// However we have to keep checking all the previous levels
// otherwise we would cache a max that will not exist
// what would make us eventually having hasNext() returning false
// as a bug
// Part of the fix for HORNETQ-705
for (int i = index; i >= 0 && levels[index].size() == 0; i--)
{
highestPriority = i;
}
size--;
}
}
}