/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2009 Sun Microsystems, Inc.
* Portions Copyright 2011 ForgeRock AS
*/
package org.opends.server.replication.common;
import org.opends.server.util.TimeThread;
/**
* This class defines a structure that is used for storing the
* last change numbers generated on this server or received from other servers
* and generating new changenumbers that are guaranteed to be larger than
* all the previously seen or generated change numbers.
*/
public class ChangeNumberGenerator
{
private long lastTime;
private int seqnum;
private int serverId;
/**
* Create a new ChangeNumber Generator.
* @param serverID2 id to use when creating change numbers.
* @param timestamp time to start with.
*/
public ChangeNumberGenerator(int serverID2, long timestamp)
{
this.lastTime = timestamp;
this.serverId = serverID2;
this.seqnum = 0;
}
/**
* Create a new ChangeNumber Generator.
*
* @param id id to use when creating change numbers.
* @param state This generator will be created in a way that makes sure that
* all change numbers generated will be larger than all the
* changenumbers currently in state.
*/
public ChangeNumberGenerator(int id, ServerState state)
{
this.lastTime = TimeThread.getTime();
for (int stateId : state)
{
if (this.lastTime < state.getMaxChangeNumber(stateId).getTime())
this.lastTime = state.getMaxChangeNumber(stateId).getTime();
if (stateId == id)
this.seqnum = state.getMaxChangeNumber(id).getSeqnum();
}
this.serverId = id;
}
/**
* Generate a new ChangeNumber.
*
* @return the generated ChangeNUmber
*/
public ChangeNumber newChangeNumber()
{
long curTime = TimeThread.getTime();
int mySeqnum;
long myTime;
synchronized(this)
{
if (curTime > lastTime)
{
lastTime = curTime;
}
if (++seqnum <= 0)
{
seqnum = 0;
lastTime++;
}
mySeqnum = seqnum;
myTime = lastTime;
}
return new ChangeNumber(myTime, mySeqnum, serverId);
}
/**
* Adjust the lastTime of this Changenumber generator with
* a ChangeNumber that we have received from another server.
* This is necessary because we need that the changenumber generated
* after processing an update received from other hosts to be larger
* than the received changenumber
*
* @param number the ChangeNumber to adjust with
*/
public void adjust(ChangeNumber number)
{
if (number==null)
{
synchronized(this)
{
lastTime = TimeThread.getTime();
seqnum = 0;
}
return;
}
long rcvdTime = number.getTime();
int changeServerId = number.getServerId();
int changeSeqNum = number.getSeqnum();
/* need to synchronize with NewChangeNumber method so that we
* protect writing lastTime fields
*/
synchronized(this)
{
if (lastTime <= rcvdTime)
{
lastTime = ++rcvdTime;
}
if ((serverId == changeServerId) && (seqnum < changeSeqNum))
{
seqnum = changeSeqNum;
}
}
}
/**
* Adjust utility method that takes ServerState as a parameter.
* @param state the ServerState to adjust with
*/
public void adjust(ServerState state)
{
for (int localServerId : state)
{
adjust(state.getMaxChangeNumber(localServerId));
}
}
}