/**
* VMware Continuent Tungsten Replicator
* Copyright (C) 2015 VMware, 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.
*
* Initial developer(s):
* Contributor(s):
*/
package com.continuent.tungsten.common.patterns.order;
import java.io.Serializable;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
public class Sequence implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private long wrapAround = 0L;
private long generation = 0L;
private boolean isWrapped = false;
private UUID identity = UUID.randomUUID();
private AtomicLong currentValue = new AtomicLong(0);
private AtomicLong lastValue = new AtomicLong(0);
public Sequence(long wrapAround)
{
this.wrapAround = wrapAround;
}
public Sequence()
{
this.wrapAround = Long.MAX_VALUE;
}
public synchronized boolean isBefore(Sequence sequence)
throws SequenceException
{
assertSameParent(sequence);
if (isEqual(sequence))
{
return false;
}
// We can't be before if our generation is later...
if (this.generation > sequence.generation)
{
return false;
}
// If our generation is earlier than the sequence generation
// it means that the sequence generation has wrapped
// beyond the current range and, therefore, we must be
// before that wrapping point.
if (this.generation < sequence.generation)
{
return true;
}
// If both are not wrapped and are of the same generation
if (!this.isWrapped && !sequence.isWrapped
&& (this.generation == sequence.generation))
{
// Just returned whether or not our value is before the sequence
// value
return (currentValue.get() < sequence.currentValue.get());
}
if (this.isWrapped && !sequence.isWrapped
&& this.generation == sequence.generation)
{
return true;
}
return false;
}
public synchronized boolean isBeforeOrEqual(Sequence sequence)
throws SequenceException
{
assertSameParent(sequence);
return (isBefore(sequence) || isEqual(sequence));
}
public synchronized boolean isAfter(Sequence sequence)
throws SequenceException
{
assertSameParent(sequence);
if (isEqual(sequence) || isBefore(sequence))
{
return false;
}
return true;
}
public boolean isEqual(Sequence sequence) throws SequenceException
{
assertSameParent(sequence);
if (currentValue.get() == sequence.currentValue.get()
&& this.generation == sequence.generation)
{
return true;
}
return false;
}
public synchronized void next()
{
lastValue.set(currentValue.get());
if (currentValue.get() == wrapAround)
{
currentValue.set(0);
generation++;
isWrapped = true;
}
else
{
currentValue.incrementAndGet();
isWrapped = false;
}
}
@Override
public synchronized Sequence clone()
{
Sequence clone = new Sequence(wrapAround);
clone.identity = identity;
clone.currentValue.set(currentValue.get());
clone.lastValue.set(lastValue.get());
return clone;
}
public String toString()
{
return "Sequence(" + generation + ":" + currentValue + ")";
}
/**
* Returns the wrapAround value.
*
* @return Returns the wrapAround.
*/
public long getWrapAround()
{
return wrapAround;
}
/**
* Sets the wrapAround value.
*
* @param wrapAround The wrapAround to set.
*/
public void setWrapAround(long wrapAround)
{
this.wrapAround = wrapAround;
}
/**
* Returns the generation value.
*
* @return Returns the generation.
*/
public long getGeneration()
{
return generation;
}
/**
* Sets the generation value.
*
* @param generation The generation to set.
*/
public void setGeneration(long generation)
{
this.generation = generation;
}
/**
* Returns the isWrapped value.
*
* @return Returns the isWrapped.
*/
public boolean isWrapped()
{
return isWrapped;
}
/**
* Sets the isWrapped value.
*
* @param isWrapped The isWrapped to set.
*/
public void setWrapped(boolean isWrapped)
{
this.isWrapped = isWrapped;
}
/**
* Returns the identity value.
*
* @return Returns the identity.
*/
public UUID getIdentity()
{
return identity;
}
/**
* Sets the identity value.
*
* @param identity The identity to set.
*/
public void setIdentity(UUID identity)
{
this.identity = identity;
}
/**
* Returns the currentValue value.
*
* @return Returns the currentValue.
*/
public AtomicLong getCurrentValue()
{
return currentValue;
}
/**
* Sets the currentValue value.
*
* @param currentValue The currentValue to set.
*/
public void setCurrentValue(AtomicLong currentValue)
{
this.currentValue = currentValue;
}
/**
* Returns the lastValue value.
*
* @return Returns the lastValue.
*/
public AtomicLong getLastValue()
{
return lastValue;
}
/**
* Sets the lastValue value.
*
* @param lastValue The lastValue to set.
*/
public void setLastValue(AtomicLong lastValue)
{
this.lastValue = lastValue;
}
public void assertSameParent(Sequence sequence) throws SequenceException
{
if (!identity.toString().equals(sequence.identity.toString()))
{
throw new SequenceException("Parents differ, this=" + identity
+ ", sequence=" + sequence.getIdentity());
}
}
public void reset()
{
currentValue.set(0);
generation = 0;
isWrapped = false;
}
}