/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.io; /** * This class provides a buffer with a LRU (<i>least recently used</i>) * displacement strategy. I.e. when searching an object to displace, the object * in the buffer that is the longest time unfixed is chosen. * * <p>This implementation uses a double linked list of the slots in addition to * the array of slots. The first slot in this list is the slot that is unfixed * at last and the last slot in the list is the slot that is unfixed the * longest time. When fixing a slot, it is removed out of the list and it is * appended in front of the list, when it is unfixed. So the last slot in the * list is always the least recently used slot of the buffer. When the list is * empty, all slots of the buffer are fixed.</p> * * <p>Example usage (1). * <pre> * // create a new owner * * String owner = "owner"; * * // create a new LRU buffer with a capacity of 5 objects * * LRUBuffer buffer = new LRUBuffer(5); * * // create a new iterator with 100 integers between 0 and 5 * * Iterator iterator = new DiscreteRandomNumber(new JavaDiscreteRandomWrapper(6), 100); * * // insert all elements of the iterator with a flush function that prints the flushed * // integer into the buffer * * while (iterator.hasNext()) { * Integer i = (Integer)iterator.next(); * System.out.println("insert "+i); * buffer.update(owner, i, i, new AbstractFunction() { * public Object invoke (Object o1, Object o2) { * System.out.println("flush "+o1); * return o1; * } * }, true); * } * </pre> * @param <O> the type of the objects specifing the owner of a buffer's slot. * @param <I> the type of the identifiers used for identifing the buffer's * slots. * @param <E> the type of the elements stored by this buffer. */ public class LRUBuffer<O, I, E> extends Buffer<O, I, E> { /** * The first slot of the double linked list of slots that represents the * duration of being unfixed. The first slot of the list is the slot that * is unfixed at last. */ protected Slot first = null; /** * The last slot of the double linked list of slots that represents the * duration of being unfixed. The last slot of the list is the slot that is * unfixed the longest time. */ protected Slot last = null; /** * This class provides a single slot in a LRU buffer. * * <p>Every slot is linked to its predecessor and successor in the double * linked list representing the duration of being unfixed. When a slot is * fixed, it is not contained in the list and its predecessor and successor * are set to <code>null</code>. In addition to the usual methods of a * slot, slots of LRU buffers support the removal out of the double linked * list by the unlink method. When fixing a slot, it is removed out of the * list and it is appended in front of the list, when it is unfixed. */ protected class Slot extends Buffer.Slot { /** * The predecessor of this slot in the double linked list representing * the duration of being unfixed. When this slot is not contained by * the list or the first element of it, the predecessor is set to * <code>null</code>. */ protected Slot prev = this; /** * The successor of this slot in the double linked list representing * the duration of being unfixed. When this slot is not contained by * the list or the last element of it, the successor is set to * <code>null</code>. */ protected Slot next = this; /** * Constructs a new empty slot with the specified index. The new slot * contains no object, is not fixed and has no predecessor and * successor. * * @param index the index of the new slot. */ public Slot(int index) { super(index); } /** * Removes this slot out of the double linked list representing * duration of being unfixed. */ protected void unlink() { if (prev != null) prev.next = next; else first = next; if (next != null) next.prev = prev; else last = prev; prev = next = this; } /** * Fixes this slot so that the object contained by it cannot be removed * out of the LRU buffer. This implementation also removes the slot out * of the double linked list. */ public void fix() { super.fix(); unlink(); } /** * Unfixes this slot so that the object contained by it can be removed * out of the buffer. This implementation also appends the slot in * front of the double linked list. */ public void unfix() { super.unfix(); unlink(); next = first; first = this; prev = null; if (next != null) next.prev = this; else last = this; } /** * Removes the object and any information belonging to it from this * slot so that it is empty thereafter. This implementation also * removes the slot out of the double linked list. */ public void remove() { super.remove(); unlink(); } } /** * Constructs a new empty LRU buffer with a number of slots specified by * the given capacity and an empty double linked list. * * @param capacity the number of slots in the new LRU buffer. * @param capacityBytes the capacity of the buffer in bytes. If this is * > -1, then the buffered Objects have to efficiently * implement the interface SizeAware, so that the buffer can * determine the correct number of bytes used. */ public LRUBuffer(int capacity, int capacityBytes) { super(capacity, capacityBytes); } /** * Constructs a new empty LRU buffer with a number of slots specified by * the given capacity and an empty double linked list. * * @param capacity the number of slots in the new LRU buffer. */ public LRUBuffer(int capacity) { super(capacity); } /** * Creates a new empty slot with the specified index. The new slot contains * no object, is not fixed and has no predecessor and successor. For * further detail see contract for {@link Buffer#newSlot(int) newSlot} in * Buffer. * * @param index the index of the new slot. * @return a new empty slot with the specified index. */ protected Buffer.Slot newSlot(int index) { return new Slot(index); } /** * Returns the <i>next</i> slot to displace in this LRU buffer. This * implementation returns the last slot in the double linked list * representing the durating of being unfixed. * * @return the least recently used slot in this buffer. */ protected Buffer.Slot victim() { return last; } }