
org.objectweb.dream.queue.buffer.BufferAscendingSequenceNumber Maven / Gradle / Ivy
/**
* Dream
* Copyright (C) 2003-2004 INRIA Rhone-Alpes
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact: [email protected]
*
* Initial developer(s): Vivien Quema
* Contributor(s): Romain Lenglet
*/
package org.objectweb.dream.queue.buffer;
import java.lang.ref.Reference;
import org.objectweb.dream.message.Message;
import org.objectweb.dream.pool.Recyclable;
import org.objectweb.dream.queue.SequenceNumberChunk;
import org.objectweb.dream.util.Error;
import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.fraclet.annotation.annotations.Attribute;
import org.objectweb.fractal.fraclet.annotation.annotations.Service;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.dream.dreamannotation.DreamComponent;
import org.objectweb.dream.dreamannotation.DreamMonolog;
/**
* Implementation of the Buffer
interface using a sorted list. This
* buffer sorts messages according to a sequence number. For that purpose all
* messages must contain a {@link SequenceNumberChunk}chunk. The name under
* which this chunk is registered is specified using the
* sortingChunkName
.
*
* This buffer guarantees that if message m1 (with sequence number sn
* ) is removed from the buffer, then next message to be removed will have
* sequence number sn+1 . As a consequence, the number of available
* message may be different from the number of stored messages.
*
*
* Note: This buffer DOES NOT ALLOW incoming handlers that drop messages.
* Indicators on available space, available messages, and stored
* messages are expressed as number of messages.
*
* @see BufferAdd
* @see BufferRemove
* @see AbstractBuffer
*/
@DreamComponent(controllerDesc = "dreamUnstoppablePrimitive")
public class BufferAscendingSequenceNumber extends AbstractBuffer {
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/**
* The maximal capacity of the buffer. Inherited from {@link AbstractBuffer}
*/
@Attribute(argument = "maxCapacity")
protected int maxCapacity = 0;
/** The last sequence number in sequence. */
@Attribute(argument = "lastInSequence")
protected long lastInSequence = -1;
/**
* The name under which the chunk containing the sequence number is
* registered.
*/
@Attribute(argument = "sortingChunkName")
protected String sortingChunkName;
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
/** The first element stored in this buffer. */
protected Element first = null;
/** The last element stored in this buffer. */
protected Element last = null;
// --------------------------------------------------------------------------
// Services interfaces
// --------------------------------------------------------------------------
/**
* Component reference
*/
@Service
Component weaveableC;
/**
* Logger of the component
*/
@DreamMonolog()
protected Logger logger;
// ---------------------------------------------------------------------------
// Implementation of the AbstractBuffer methods.
// ---------------------------------------------------------------------------
/**
* @see AbstractBuffer#doAdd(Message)
*/
protected void doAdd(Message message) {
SequenceNumberChunk sequenceNumberChunk = messageManagerItf.getChunk(message,
sortingChunkName);
long sequenceNumber = sequenceNumberChunk.getSequenceNumber();
if (sequenceNumber <= lastInSequence) {
// The message has already been stored or delivered.
messageManagerItf.deleteMessage(message);
return;
}
Element current = last;
while (current != null && sequenceNumber < current.sequenceNumber) {
current = current.previous;
}
if (current != null && sequenceNumber == current.sequenceNumber) {
// The message is already stored in the buffer.
messageManagerItf.deleteMessage(message);
return;
}
Element element = new Element();
element.msg = message;
element.sequenceNumber = sequenceNumber;
if (current == null) {
// insert at the beginning
if (first != null) {
// list not empty
element.next = first;
first.previous = element;
} else {
// list is empty, first = last
last = element;
}
first = element;
} else {
// insert after current
element.previous = current;
if (current.next != null) {
// new element is not the new last
element.next = current.next;
element.next.previous = element;
} else {
// insert at the end
last = element;
}
element.previous.next = element;
}
// update last in sequence
// logger.log(BasicLevel.INFO, "inserted element " +
// element.sequenceNumber);
current = element;
int counter = 0;
while (current != null && current.sequenceNumber == lastInSequence + 1) {
counter++;
lastInSequence++;
current = current.next;
}
if (counter > 0) {
incrementAvailableMessagesCount(counter);
}
incrementStoredMessagesCount(1);
}
/**
* @see AbstractBuffer#doRemove()
*/
protected Message doRemove() {
incrementAvailableMessagesCount(-1);
incrementStoredMessagesCount(-1);
Element newFirst = first.next;
if (newFirst != null) {
newFirst.previous = null;
} else {
last = null;
}
Message msg = first.msg;
first = newFirst;
return msg;
}
/**
* @see AbstractBuffer#doGet()
*/
protected Message doGet() {
return first.msg;
}
/**
* @see AbstractBuffer#doRemoveAll()
*/
public Message doRemoveAll() {
Message message = null;
Element current = first;
int i = 0;
while (current != null) {
if (message == null) {
message = messageManagerItf.createMessage();
}
messageManagerItf.addSubMessage(message, current.msg);
first = current.next;
current = first;
i--;
}
incrementAvailableMessagesCount(i);
incrementStoredMessagesCount(i);
return message;
}
// ---------------------------------------------------------------------------
// Overriding of the AttributeController
// interface generated by fraclet
// ---------------------------------------------------------------------------
/**
* Overriding of the AttributeController interface generated by fraclet. It
* manages synchronization and check if the buffer is in an incoherent
* state.
*/
public long getLastInSequence() {
synchronized (lock) {
if (storedMessagesCount > 0) {
// At this time we do not allow this method to be called when
// the buffer
// is not empty. This could be done, but this requires scanning
// the
// buffer in order to remove messages with a sequence number
// below
// lastInSequence and in order to modify the value of
// availableMessageIndicator.
Error.bug(logger);
}
return lastInSequence;
}
}
/**
* Overriding of the AttributeController interface generated by fraclet. It
* manages synchronization.
*/
public void setLastInSequence(long lastInSequence) {
synchronized (lock) {
this.lastInSequence = lastInSequence;
}
}
/**
* @see org.objectweb.dream.queue.buffer.AbstractBuffer#setMaxCapacity(int)
*/
public void setMaxCapacity(int maxCapacity) {
super.setMaxCapacity(maxCapacity);
}
// ---------------------------------------------------------------------------
// Inner class.
// ---------------------------------------------------------------------------
/**
* This class represents elements of a linked list. Each element contains a
* reference to its predecessor (previous
), its successor (
* next
), a message, and a sequence number.
*/
public static class Element implements Recyclable {
Element previous;
Element next;
Message msg;
long sequenceNumber;
Reference extends Recyclable> recyclableReference;
// ---------------------------------------------------------------------------
// Implementation of the Recyclable interface.
// ---------------------------------------------------------------------------
/**
* @see Recyclable#recycle()
*/
public void recycle() {
previous = null;
next = null;
msg = null;
sequenceNumber = -1;
}
/**
* @see Recyclable#setReference(Reference)
*/
public void setReference(Reference extends Recyclable> recyclableReference) {
this.recyclableReference = recyclableReference;
}
/**
* @see Recyclable#getReference()
*/
public Reference extends Recyclable> getReference() {
return recyclableReference;
}
}
}