/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.ringbuffer.impl;
import com.hazelcast.ringbuffer.StaleSequenceException;
/**
* The Ringbuffer is responsible for storing the actual content of a ringbuffer.
*
* @param <T> the type of the data stored in the ring buffer
*/
public interface Ringbuffer<T> {
/**
* Returns the capacity of this Ringbuffer.
*
* @return the capacity.
*/
long getCapacity();
/**
* Returns number of items in the ringbuffer (meaning the number of items between the {@link #headSequence()} and
* {@link #tailSequence()}).
*
* @return the size.
*/
long size();
/**
* Returns the sequence of the tail. The tail is the side of the ringbuffer where the items are added to.
* <p>
* The initial value of the tail is -1.
*
* @return the sequence of the tail.
*/
long tailSequence();
/**
* Sets the tail sequence. The tail sequence cannot be less than {@link #headSequence()} - 1.
*
* @param tailSequence the new tail sequence
* @throws IllegalArgumentException if the target sequence is less than {@link #headSequence()} - 1
*/
void setTailSequence(long tailSequence);
/**
* Returns the sequence of the head. The head is the side of the ringbuffer where the oldest items in the
* ringbuffer are found.
* <p>
* If the RingBuffer is empty, the head will be one more than the {@link #tailSequence()}.
* <p>
* The initial value of the head is 0 (1 more than tail).
*
* @return the sequence of the head.
*/
long headSequence();
/**
* Sets the head sequence. The head sequence cannot be larger than {@link #tailSequence()} + 1
*
* @param sequence The new head sequence.
* @throws IllegalArgumentException if the target sequence is greater than {@link #tailSequence()} + 1
*/
void setHeadSequence(long sequence);
/**
* Is the ring buffer empty.
*
* @return is the ring buffer empty
*/
boolean isEmpty();
/**
* Adds an item to the tail of the Ringbuffer. If there is no space in the Ringbuffer, the add will overwrite the oldest
* item in the ringbuffer. The method allows null values.
* <p>
* The returned value is the sequence of the added item. Using this sequence you can read the added item.
* <p>
* <h3>Using the sequence as id</h3>
* This sequence will always be unique for this Ringbuffer instance so it can be used as a unique id generator if you are
* publishing items on this Ringbuffer. However you need to take care of correctly determining an initial id when any node
* uses the ringbuffer for the first time. The most reliable way to do that is to write a dummy item into the ringbuffer and
* use the returned sequence as initial id. On the reading side, this dummy item should be discard. Please keep in mind that
* this id is not the sequence of the item you are about to publish but from a previously published item. So it can't be used
* to find that item.
*
* @param item the item to add.
* @return the sequence of the added item.
*/
long add(T item);
/**
* Reads one item from the Ringbuffer.
* <p>
* This method is not destructive unlike e.g. a queue.take. So the same item can be read by multiple readers or it can be
* read multiple times by the same reader.
*
* @param sequence the sequence of the item to read.
* @return the read item
* @throws StaleSequenceException if the sequence is smaller then {@link #headSequence()}
* or larger than {@link #tailSequence()}. Because a Ringbuffer won't store all event
* indefinitely, it can be that the data for the given sequence doesn't exist anymore
* and the {@link StaleSequenceException} is thrown. It is up to the caller to deal with
* this particular situation, e.g. throw an Exception or restart from the last known head.
* That is why the StaleSequenceException contains the last known head.
*/
T read(long sequence);
/**
* Check if the sequence can be read from the ring buffer or if the sequence is of the next item to be added into the
* ringbuffer. This method also allows the sequence to be one greater than the {@link #tailSequence()}, giving the
* oportunity to block until the item is added into the ring buffer.
*
* @param readSequence the sequence wanting to be read
* @throws StaleSequenceException if the requested sequence is smaller than the {@link #headSequence()}
* @throws IllegalArgumentException if the requested sequence is greater than the {@link #tailSequence()} + 1
*/
void checkBlockableReadSequence(long readSequence);
/**
* Check if the sequence can be read from the ring buffer.
*
* @param sequence the sequence wanting to be read
* @throws StaleSequenceException if the requested sequence is smaller than the {@link #headSequence()}
* @throws IllegalArgumentException if the requested sequence is greater than the {@link #tailSequence()}
*/
void checkReadSequence(long sequence);
/**
* Sets the item at the given sequence. The method allows null data.
*
* @param seq The target sequence.
* @param data The data to be set
*/
void set(long seq, T data);
}