mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
02.57.2013 157717b205d4c1f957cf810e04e06f11530c619c
opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -4404,14 +4404,14 @@
   * The name of the attribute in a purge conflicts historical task definition
   * that specifies the maximum duration of the task.
   */
  public static final String ATTR_TASK_CONFLICTS_HIST_PURGE_FIRST_CN =
  public static final String ATTR_TASK_CONFLICTS_HIST_PURGE_FIRST_CSN =
     NAME_PREFIX_TASK + "purge-conflicts-historical-first-purged-changenumber";
  /**
   * The name of the attribute in a purge conflicts historical task definition
   * that specifies the maximum duration of the task.
   */
  public static final String ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CN =
  public static final String ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CSN =
       NAME_PREFIX_TASK + "purge-conflicts-historical-last-purged-changenumber";
  /**
opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java
@@ -24,6 +24,7 @@
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions Copyright 2011-2012 ForgeRock AS
 *      Portions Copyright 2013 ForgeRock AS
 */
package org.opends.server.plugins;
@@ -43,7 +44,7 @@
import org.opends.server.api.plugin.PluginResult;
import org.opends.server.config.ConfigException;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.OperationContext;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.Control;
@@ -53,8 +54,10 @@
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostOperationOperation;
import static org.opends.messages.PluginMessages.*;
import static org.opends.server.util.ServerConstants.*;
/**
 * This class implements a Directory Server plugin that will add the
 * replication CSN to a response whenever the CSN control is received.
@@ -64,27 +67,25 @@
       implements ConfigurationChangeListener<ChangeNumberControlPluginCfg>
{
  // The current configuration for this plugin.
  /** The current configuration for this plugin. */
  private ChangeNumberControlPluginCfg currentConfig;
  /**
   * The control used by this plugin.
   */
  /** The control used by this plugin. */
  public static class ChangeNumberControl extends Control
  {
    private ChangeNumber cn;
    private CSN csn;
    /**
     * Constructs a new change number control.
     *
     * @param  isCritical Indicates whether support for this control should be
     *                    considered a critical part of the server processing.
     * @param cn          The change number.
     * @param isCritical Indicates whether support for this control should be
     *                   considered a critical part of the server processing.
     * @param csn        The CSN.
     */
    public ChangeNumberControl(boolean isCritical, ChangeNumber cn)
    public ChangeNumberControl(boolean isCritical, CSN csn)
    {
      super(OID_CSN_CONTROL, isCritical);
      this.cn = cn;
      this.csn = csn;
    }
    /**
@@ -95,17 +96,17 @@
     * @throws IOException If a problem occurs while writing to the stream.
     */
    protected void writeValue(ASN1Writer writer) throws IOException {
      writer.writeOctetString(cn.toString());
      writer.writeOctetString(csn.toString());
    }
    /**
     * Retrieves the change number.
     * Retrieves the CSN.
     *
     * @return The change number.
     * @return The CSN.
     */
    public ChangeNumber getChangeNumber()
    public CSN getCSN()
    {
      return cn;
      return csn;
    }
  }
@@ -303,8 +304,8 @@
  }
  /**
   * Retrieves the Change number from the synchronization context
   * and sets the control response in the operation.
   * Retrieves the CSN from the synchronization context and sets the control
   * response in the operation.
   *
   * @param operation the operation
   */
@@ -316,7 +317,7 @@
          OperationContext ctx = (OperationContext)
            operation.getAttachment(OperationContext.SYNCHROCONTEXT);
          if (ctx != null) {
            ChangeNumber cn = ctx.getChangeNumber();
            CSN cn = ctx.getCSN();
            if (cn != null) {
              Control responseControl =
                  new ChangeNumberControl(c.isCritical(), cn);
opends/src/server/org/opends/server/replication/common/CSN.java
File was renamed from opends/src/server/org/opends/server/replication/common/ChangeNumber.java
@@ -27,6 +27,7 @@
 */
package org.opends.server.replication.common;
import java.io.Serializable;
import java.util.Date;
import org.opends.server.types.ByteSequence;
@@ -35,10 +36,9 @@
import org.opends.server.types.ByteStringBuilder;
/**
 * Class used to represent Change Numbers.
 * Class used to represent Change Sequence Numbers.
 */
public class ChangeNumber implements java.io.Serializable,
                                     java.lang.Comparable<ChangeNumber>
public class CSN implements Serializable, Comparable<CSN>
{
  /**
   * The number of bytes used by the byte string representation of a change
@@ -65,16 +65,16 @@
  private final int serverId;
  /**
   * Parses the provided {@link #toString()} representation of a change number.
   * Parses the provided {@link #toString()} representation of a CSN.
   *
   * @param s
   *          The string to be parsed.
   * @return The parsed change number.
   * @return The parsed CSN.
   * @see #toString()
   */
  public static ChangeNumber valueOf(String s)
  public static CSN valueOf(String s)
  {
    return new ChangeNumber(s);
    return new CSN(s);
  }
  /**
@@ -83,24 +83,24 @@
   *
   * @param bs
   *          The byte sequence to be parsed.
   * @return The decoded change number.
   * @return The decoded CSN.
   * @see #toByteString()
   */
  public static ChangeNumber valueOf(ByteSequence bs)
  public static CSN valueOf(ByteSequence bs)
  {
    ByteSequenceReader reader = bs.asReader();
    long timeStamp = reader.getLong();
    int serverId = reader.getShort() & 0xffff;
    int seqnum = reader.getInt();
    return new ChangeNumber(timeStamp, seqnum, serverId);
    return new CSN(timeStamp, seqnum, serverId);
  }
  /**
   * Create a new ChangeNumber from a String.
   * Create a new {@link CSN} from a String.
   *
   * @param str the string from which to create a ChangeNumber
   * @param str the string from which to create a {@link CSN}
   */
  public ChangeNumber(String str)
  public CSN(String str)
  {
    String temp = str.substring(0, 16);
    timeStamp = Long.parseLong(temp, 16);
@@ -113,13 +113,13 @@
  }
  /**
   * Create a new ChangeNumber.
   * Create a new {@link CSN}.
   *
   * @param timeStamp timeStamp for the ChangeNumber
   * @param timeStamp timeStamp for the {@link CSN}
   * @param seqNum sequence number
   * @param serverId identity of server
   */
  public ChangeNumber(long timeStamp, int seqNum, int serverId)
  public CSN(long timeStamp, int seqNum, int serverId)
  {
    this.serverId = serverId;
    this.timeStamp = timeStamp;
@@ -136,8 +136,8 @@
  }
  /**
   * Get the timestamp associated to this ChangeNumber in seconds.
   * @return timestamp associated to this ChangeNumber in seconds
   * Get the timestamp associated to this {@link CSN} in seconds.
   * @return timestamp associated to this {@link CSN} in seconds
   */
  public long getTimeSec()
  {
@@ -169,12 +169,12 @@
  @Override
  public boolean equals(Object obj)
  {
    if (obj instanceof ChangeNumber)
    if (obj instanceof CSN)
    {
      ChangeNumber cn = (ChangeNumber) obj;
      return this.seqnum == cn.seqnum &&
          this.serverId == cn.serverId &&
          this.timeStamp == cn.timeStamp;
      CSN csn = (CSN) obj;
      return this.seqnum == csn.seqnum &&
          this.serverId == csn.serverId &&
          this.timeStamp == csn.timeStamp;
    }
    return false;
  }
@@ -189,12 +189,12 @@
  }
  /**
   * Encodes this change number as a byte string.
   * Encodes this CSN as a byte string.
   * <p>
   * NOTE: this representation must not be modified otherwise interop with
   * earlier protocol versions will be broken.
   *
   * @return The encoded representation of this change number.
   * @return The encoded representation of this CSN.
   * @see #valueOf(ByteSequence)
   */
  public ByteString toByteString()
@@ -204,14 +204,14 @@
  }
  /**
   * Encodes this change number into the provided byte string builder.
   * Encodes this CSN into the provided byte string builder.
   * <p>
   * NOTE: this representation must not be modified otherwise interop with
   * earlier protocol versions will be broken.
   *
   * @param builder
   *          The byte string builder.
   * @return The byte string builder containing the encoded change number.
   * @return The byte string builder containing the encoded CSN.
   * @see #valueOf(ByteSequence)
   */
  public ByteStringBuilder toByteString(ByteStringBuilder builder)
@@ -221,7 +221,7 @@
  }
  /**
   * Convert the ChangeNumber to a printable String.
   * Convert the {@link CSN} to a printable String.
   * <p>
   * NOTE: this representation must not be modified otherwise interop with
   * earlier protocol versions will be broken.
@@ -235,7 +235,7 @@
  }
  /**
   * Convert the ChangeNumber to a printable String with a user friendly
   * Convert the {@link CSN} to a printable String with a user friendly
   * format.
   *
   * @return the string
@@ -250,75 +250,78 @@
  }
  /**
   * Compares 2 ChangeNumber.
   * @param CN1 the first ChangeNumber to compare
   * @param CN2 the second ChangeNumber to compare
   * @return value 0 if changeNumber matches, negative if first
   * changeNumber is smaller, positive otherwise
   * Compares 2 {@link CSN}.
   * @param csn1 the first {@link CSN} to compare
   * @param csn2 the second {@link CSN} to compare
   * @return value 0 if CSN matches, negative if first
   * CSN is smaller, positive otherwise
   */
  public static int compare(ChangeNumber CN1, ChangeNumber CN2)
  public static int compare(CSN csn1, CSN csn2)
  {
    if (CN1 == null)
    if (csn1 == null)
    {
      if (CN2 == null)
      if (csn2 == null)
        return 0;
      return -1;
    }
    else if (CN2 == null)
    else if (csn2 == null)
      return 1;
    else if (CN1.timeStamp < CN2.timeStamp)
    else if (csn1.timeStamp < csn2.timeStamp)
      return -1;
    else if (CN2.timeStamp < CN1.timeStamp)
    else if (csn2.timeStamp < csn1.timeStamp)
      return 1;
    else
    {
      // timestamps are equals compare seqnums
      if (CN1.seqnum < CN2.seqnum)
      if (csn1.seqnum < csn2.seqnum)
        return -1;
      else if (CN2.seqnum < CN1.seqnum)
      else if (csn2.seqnum < csn1.seqnum)
        return 1;
      else
      {
        // timestamp and seqnum are equals compare serverIds
        if (CN1.serverId < CN2.serverId)
        if (csn1.serverId < csn2.serverId)
          return -1;
        else if (CN2.serverId < CN1.serverId)
        else if (csn2.serverId < csn1.serverId)
          return 1;
        // if we get here ChangeNumber are equals
        // if we get here {@link CSN} are equals
        return 0;
      }
    }
  }
 /**
  * Computes the difference in number of changes between 2
  * change numbers. First one is expected to be newer than second one. If this
  * is not the case, 0 will be returned.
  * @param op1 the first ChangeNumber
  * @param op2 the second ChangeNumber
  * @return the difference
  */
  public static int diffSeqNum(ChangeNumber op1, ChangeNumber op2)
  /**
   * Computes the difference in number of changes between 2 CSNs. First one is
   * expected to be newer than second one. If this is not the case, 0 will be
   * returned.
   *
   * @param csn1
   *          the first {@link CSN}
   * @param csn2
   *          the second {@link CSN}
   * @return the difference
   */
  public static int diffSeqNum(CSN csn1, CSN csn2)
  {
    if (op1 == null)
    if (csn1 == null)
    {
      return 0;
    }
    if (op2 == null)
    if (csn2 == null)
    {
      return op1.getSeqnum();
      return csn1.getSeqnum();
    }
    if (op2.newerOrEquals(op1))
    if (csn2.newerOrEquals(csn1))
    {
      return 0;
    }
    int seqnum1 = op1.getSeqnum();
    long time1 = op1.getTime();
    int seqnum2 = op2.getSeqnum();
    long time2 = op2.getTime();
    int seqnum1 = csn1.getSeqnum();
    long time1 = csn1.getTime();
    int seqnum2 = csn2.getSeqnum();
    long time2 = csn2.getTime();
    if (time2 <= time1)
    {
@@ -332,56 +335,56 @@
  }
  /**
   * check if the current Object is strictly older than ChangeNumber
   * check if the current Object is strictly older than {@link CSN}
   * given in parameter.
   * @param CN the ChangeNumber to compare with
   * @param csn the {@link CSN} to compare with
   * @return true if strictly older, false if younger or same
   */
  public boolean older(ChangeNumber CN)
  public boolean older(CSN csn)
  {
    return compare(this, CN) < 0;
    return compare(this, csn) < 0;
  }
  /**
   * check if the current Object is older than ChangeNumber
   * check if the current Object is older than {@link CSN}
   * given in parameter.
   * @param CN the ChangeNumber to compare with
   * @param csn the {@link CSN} to compare with
   * @return true if older or equal, false if younger
   */
  public boolean olderOrEqual(ChangeNumber CN)
  public boolean olderOrEqual(CSN csn)
  {
    return compare(this, CN) <= 0;
    return compare(this, csn) <= 0;
  }
  /**
   * Check if the current Object is newer than ChangeNumber.
   * @param CN the ChangeNumber to compare with
   * Check if the current Object is newer than {@link CSN}.
   * @param csn the {@link CSN} to compare with
   * @return true if newer
   */
  public boolean newerOrEquals(ChangeNumber CN)
  public boolean newerOrEquals(CSN csn)
  {
    return compare(this, CN) >= 0;
    return compare(this, csn) >= 0;
  }
  /**
   * Check if the current Object is strictly newer than ChangeNumber.
   * @param CN the ChangeNumber to compare with
   * Check if the current Object is strictly newer than {@link CSN}.
   * @param csn the {@link CSN} to compare with
   * @return true if strictly newer
   */
  public boolean newer(ChangeNumber CN)
  public boolean newer(CSN csn)
  {
    return compare(this, CN) > 0;
    return compare(this, csn) > 0;
  }
  /**
   * Compares this object with the specified object for order.
   * @param cn the ChangeNumber to compare with.
   * @param csn the {@link CSN} to compare with.
   * @return a negative integer, zero, or a positive integer as this object
   *         is less than, equal to, or greater than the specified object.
   */
  @Override
  public int compareTo(ChangeNumber cn)
  public int compareTo(CSN csn)
  {
    return compare(this, cn);
    return compare(this, csn);
  }
}
opends/src/server/org/opends/server/replication/common/CSNGenerator.java
File was renamed from opends/src/server/org/opends/server/replication/common/ChangeNumberGenerator.java
@@ -23,30 +23,30 @@
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2011 ForgeRock AS
 *      Portions Copyright 2011-2013 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.
 * This class defines a structure that is used for storing the last {@link CSN}s
 * generated on this server or received from other servers and generating new
 * {@link CSN}s that are guaranteed to be larger than all the previously seen or
 * generated CSNs.
 */
public class ChangeNumberGenerator
public class CSNGenerator
{
  private long lastTime;
  private int seqnum;
  private int serverId;
  /**
   * Create a new ChangeNumber Generator.
   * @param serverID2 id to use when creating change numbers.
   * Create a new {@link CSNGenerator}.
   * @param serverID2 id to use when creating {@link CSN}s.
   * @param timestamp time to start with.
   */
  public ChangeNumberGenerator(int serverID2, long timestamp)
  public CSNGenerator(int serverID2, long timestamp)
  {
    this.lastTime = timestamp;
    this.serverId = serverID2;
@@ -54,33 +54,33 @@
  }
  /**
  * Create a new ChangeNumber Generator.
  * Create a new {@link CSNGenerator}.
  *
  * @param id id to use when creating change numbers.
  * @param id id to use when creating {@link CSN}s.
  * @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.
  *              all {@link CSN}s generated will be larger than all the
  *              {@link CSN}s currently in state.
  */
 public ChangeNumberGenerator(int id, ServerState state)
 public CSNGenerator(int id, ServerState state)
 {
   this.lastTime = TimeThread.getTime();
   for (int stateId : state)
   {
     if (this.lastTime < state.getChangeNumber(stateId).getTime())
       this.lastTime = state.getChangeNumber(stateId).getTime();
     if (this.lastTime < state.getCSN(stateId).getTime())
       this.lastTime = state.getCSN(stateId).getTime();
     if (stateId == id)
       this.seqnum = state.getChangeNumber(id).getSeqnum();
       this.seqnum = state.getCSN(id).getSeqnum();
   }
   this.serverId = id;
 }
  /**
   * Generate a new ChangeNumber.
   * Generate a new {@link CSN}.
   *
   * @return the generated ChangeNUmber
   * @return the generated {@link CSN}
   */
  public ChangeNumber newChangeNumber()
  public CSN newCSN()
  {
    long curTime = TimeThread.getTime();
    int mySeqnum;
@@ -102,20 +102,22 @@
      myTime = lastTime;
    }
    return new ChangeNumber(myTime, mySeqnum, serverId);
    return new CSN(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
   * Adjust the lastTime of this {@link CSNGenerator} with a {@link CSN} that we
   * have received from another server.
   * <p>
   * This is necessary because we need that the {@link CSN} generated after
   * processing an update received from other hosts to be larger than the
   * received {@link CSN}
   *
   * @param number the ChangeNumber to adjust with
   * @param number
   *          the {@link CSN} to adjust with
   */
  public void adjust(ChangeNumber number)
  public void adjust(CSN number)
  {
    if (number==null)
    {
@@ -132,8 +134,9 @@
    int changeServerId = number.getServerId();
    int changeSeqNum = number.getSeqnum();
    /* need to synchronize with NewChangeNumber method so that we
     * protect writing lastTime fields
    /*
     * need to synchronize with newCSN method so that we protect writing
     * lastTime fields
     */
    synchronized(this)
    {
@@ -157,7 +160,7 @@
  {
    for (int localServerId : state)
    {
      adjust(state.getChangeNumber(localServerId));
      adjust(state.getCSN(localServerId));
     }
  }
}
opends/src/server/org/opends/server/replication/common/FirstChangeNumberVirtualAttributeProvider.java
@@ -143,7 +143,7 @@
        ReplicationServer rs = eclwe.getReplicationServer();
        rs.disableEligibility(excludedDomains);
        int[] limits = rs.getECLDraftCNLimits(
            rs.getEligibleCN(), excludedDomains);
            rs.getEligibleCSN(), excludedDomains);
        first = String.valueOf(limits[0]);
      }
opends/src/server/org/opends/server/replication/common/LastChangeNumberVirtualAttributeProvider.java
@@ -143,7 +143,7 @@
        ReplicationServer rs = eclwe.getReplicationServer();
        rs.disableEligibility(excludedDomains);
        int[] limits = rs.getECLDraftCNLimits(
            rs.getEligibleCN(), excludedDomains);
            rs.getEligibleCSN(), excludedDomains);
        last = String.valueOf(limits[1]);
      }
opends/src/server/org/opends/server/replication/common/MultiDomainServerState.java
@@ -88,29 +88,29 @@
  }
  /**
   * Update the ServerState of the provided baseDN with the
   * replication change number provided.
   * Update the ServerState of the provided baseDN with the replication
   * {@link CSN} provided.
   *
   * @param baseDN       The provided baseDN.
   * @param changeNumber The provided ChangeNumber.
   * @param csn          The provided CSN.
   *
   * @return a boolean indicating if the update was meaningful.
   */
  public boolean update(String baseDN, ChangeNumber changeNumber)
  public boolean update(String baseDN, CSN csn)
  {
    if (changeNumber == null)
    if (csn == null)
      return false;
    synchronized(this)
    {
      int serverId =  changeNumber.getServerId();
      int serverId =  csn.getServerId();
      ServerState oldServerState = list.get(baseDN);
      if (oldServerState == null)
        oldServerState = new ServerState();
      if (changeNumber.newer(oldServerState.getChangeNumber(serverId)))
      if (csn.newer(oldServerState.getCSN(serverId)))
      {
        oldServerState.update(changeNumber);
        oldServerState.update(csn);
        list.put(baseDN, oldServerState);
        return true;
      }
@@ -229,7 +229,7 @@
        String[] domains = multidomainserverstate.split(";");
        for (String domain : domains)
        {
          // For each domain, split the changenumbers by server
          // For each domain, split the CSNs by server
          // and build a server state (SHOULD BE OPTIMIZED)
          ServerState serverStateByDomain = new ServerState();
@@ -243,11 +243,11 @@
          if (fields.length > 1)
          {
            String strState = fields[1];
            String[] strCN = strState.split(" ");
            for (String sr : strCN)
            String[] strCSN = strState.split(" ");
            for (String sr : strCSN)
            {
              ChangeNumber fromChangeNumber = new ChangeNumber(sr);
              serverStateByDomain.update(fromChangeNumber);
              CSN fromCSN = new CSN(sr);
              serverStateByDomain.update(fromCSN);
            }
          }
          startStates.put(domainBaseDN, serverStateByDomain);
opends/src/server/org/opends/server/replication/common/ServerState.java
@@ -38,18 +38,16 @@
import org.opends.server.types.ByteString;
/**
 * This class is used to associate serverIds with ChangeNumbers.
 * This class is used to associate serverIds with {@link CSN}s.
 * <p>
 * For example, it is exchanged with the replication servers at connection
 * establishment time to communicate
 * "which ChangeNumbers last seen by a serverId"
 * establishment time to communicate "which CSNs was last seen by a serverId".
 */
public class ServerState implements Iterable<Integer>
{
  /** Associates a serverId with a ChangeNumber. */
  private final Map<Integer, ChangeNumber> serverIdToChangeNumber =
      new HashMap<Integer, ChangeNumber>();
  /** Associates a serverId with a CSN. */
  private final Map<Integer, CSN> serverIdToCSN = new HashMap<Integer, CSN>();
  /**
   * Whether the state has been saved to persistent storage. It starts at true,
   * and moves to false when an update is made to the current object.
@@ -71,9 +69,9 @@
   */
  public void clear()
  {
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      serverIdToChangeNumber.clear();
      serverIdToCSN.clear();
    }
  }
@@ -95,8 +93,8 @@
    {
      while (endpos > pos)
      {
        // FIXME JNR: why store the serverId separately from the changeNumber
        // since the changeNumber already contains the serverId?
        // FIXME JNR: why store the serverId separately from the CSN since the
        // CSN already contains the serverId?
        // read the ServerId
        int length = getNextLength(in, pos);
@@ -104,14 +102,14 @@
        int serverId = Integer.valueOf(serverIdString);
        pos += length +1;
        // read the ChangeNumber
        // read the CSN
        length = getNextLength(in, pos);
        String cnString = new String(in, pos, length, "UTF-8");
        ChangeNumber cn = new ChangeNumber(cnString);
        String csnString = new String(in, pos, length, "UTF-8");
        CSN csn = new CSN(csnString);
        pos += length +1;
        // Add the serverId
        serverIdToChangeNumber.put(serverId, cn);
        serverIdToCSN.put(serverId, csn);
      }
    } catch (UnsupportedEncodingException e)
    {
@@ -121,7 +119,7 @@
  /**
   * Get the length of the next String encoded in the in byte array.
   * This method is used to cut the different parts (server ids, change number)
   * This method is used to cut the different parts (serverIds, CSN)
   * of a server state.
   *
   * @param in the byte array where to calculate the string.
@@ -143,26 +141,25 @@
  }
  /**
   * Update the Server State with a ChangeNumber.
   * Update the Server State with a CSN.
   *
   * @param changeNumber    The committed ChangeNumber.
   *
   * @param csn The committed CSN.
   * @return a boolean indicating if the update was meaningful.
   */
  public boolean update(ChangeNumber changeNumber)
  public boolean update(CSN csn)
  {
    if (changeNumber == null)
    if (csn == null)
      return false;
    saved = false;
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      int serverId = changeNumber.getServerId();
      ChangeNumber oldCN = serverIdToChangeNumber.get(serverId);
      if (oldCN == null || changeNumber.newer(oldCN))
      int serverId = csn.getServerId();
      CSN oldCSN = serverIdToCSN.get(serverId);
      if (oldCSN == null || csn.newer(oldCSN))
      {
        serverIdToChangeNumber.put(serverId, changeNumber);
        serverIdToCSN.put(serverId, csn);
        return true;
      }
      return false;
@@ -170,12 +167,10 @@
  }
  /**
   * Update the Server State with a Server State. Every change number of this
   * object is updated with the change number of the passed server state if
   * it is newer.
   * Update the Server State with a Server State. Every CSN of this object is
   * updated with the CSN of the passed server state if it is newer.
   *
   * @param serverState the server state to use for the update.
   *
   * @return a boolean indicating if the update was meaningful.
   */
  public boolean update(ServerState serverState)
@@ -184,9 +179,9 @@
      return false;
    boolean updated = false;
    for (ChangeNumber cn : serverState.serverIdToChangeNumber.values())
    for (CSN csn : serverState.serverIdToCSN.values())
    {
      if (update(cn))
      if (update(csn))
      {
        updated = true;
      }
@@ -206,7 +201,7 @@
      return false;
    }
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      clear();
      return update(serverState);
@@ -228,9 +223,9 @@
  {
    Set<String> set = new HashSet<String>();
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      for (ChangeNumber change : serverIdToChangeNumber.values())
      for (CSN change : serverIdToCSN.values())
      {
        Date date = new Date(change.getTime());
        set.add(change + " " + date + " " + change.getTime());
@@ -241,20 +236,20 @@
  }
  /**
   * Return an ArrayList of ANS1OctetString encoding the ChangeNumbers
   * Return an ArrayList of ANS1OctetString encoding the CSNs
   * contained in the ServerState.
   * @return an ArrayList of ANS1OctetString encoding the ChangeNumbers
   * @return an ArrayList of ANS1OctetString encoding the CSNs
   * contained in the ServerState.
   */
  public ArrayList<ByteString> toASN1ArrayList()
  {
    ArrayList<ByteString> values = new ArrayList<ByteString>(0);
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      for (ChangeNumber changeNumber : serverIdToChangeNumber.values())
      for (CSN csn : serverIdToCSN.values())
      {
        values.add(ByteString.valueOf(changeNumber.toString()));
        values.add(ByteString.valueOf(csn.toString()));
      }
    }
    return values;
@@ -275,20 +270,20 @@
  public void writeTo(ASN1Writer writer, short protocolVersion)
      throws IOException
  {
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      if (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V7)
      {
        for (ChangeNumber cn : serverIdToChangeNumber.values())
        for (CSN csn : serverIdToCSN.values())
        {
          writer.writeOctetString(cn.toByteString());
          writer.writeOctetString(csn.toByteString());
        }
      }
      else
      {
        for (ChangeNumber cn : serverIdToChangeNumber.values())
        for (CSN csn : serverIdToCSN.values())
        {
          writer.writeOctetString(cn.toString());
          writer.writeOctetString(csn.toString());
        }
      }
    }
@@ -303,13 +298,13 @@
  {
    StringBuilder buffer = new StringBuilder();
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      for (ChangeNumber change : serverIdToChangeNumber.values())
      for (CSN change : serverIdToCSN.values())
      {
        buffer.append(change).append(" ");
      }
      if (!serverIdToChangeNumber.isEmpty())
      if (!serverIdToCSN.isEmpty())
        buffer.deleteCharAt(buffer.length() - 1);
    }
@@ -317,39 +312,37 @@
  }
  /**
   * Returns the {@code ChangeNumber} contained in this server state which
   * corresponds to the provided server ID.
   * Returns the {@code CSN} contained in this server state which corresponds to
   * the provided server ID.
   *
   * @param serverId
   *          The server ID.
   * @return The {@code ChangeNumber} contained in this server state which
   * @return The {@code CSN} contained in this server state which
   *         corresponds to the provided server ID.
   */
  public ChangeNumber getChangeNumber(int serverId)
  public CSN getCSN(int serverId)
  {
    return serverIdToChangeNumber.get(serverId);
    return serverIdToCSN.get(serverId);
  }
  /**
   * Returns the largest (most recent) {@code ChangeNumber} in this server
   * state.
   * Returns the largest (most recent) {@code CSN} in this server state.
   *
   * @return The largest (most recent) {@code ChangeNumber} in this server
   *         state.
   * @return The largest (most recent) {@code CSN} in this server state.
   */
  public ChangeNumber getMaxChangeNumber()
  public CSN getMaxCSN()
  {
    ChangeNumber maxCN = null;
    CSN maxCSN = null;
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      for (ChangeNumber tmpMax : serverIdToChangeNumber.values())
      for (CSN csn : serverIdToCSN.values())
      {
        if (maxCN == null || tmpMax.newer(maxCN))
          maxCN = tmpMax;
        if (maxCSN == null || csn.newer(maxCSN))
          maxCSN = csn;
      }
    }
    return maxCN;
    return maxCSN;
  }
  /**
@@ -373,14 +366,14 @@
   */
  public byte[] getBytes() throws UnsupportedEncodingException
  {
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      final int size = serverIdToChangeNumber.size();
      final int size = serverIdToCSN.size();
      List<String> idList = new ArrayList<String>(size);
      List<String> cnList = new ArrayList<String>(size);
      List<String> csnList = new ArrayList<String>(size);
      // calculate the total length needed to allocate byte array
      int length = 0;
      for (Entry<Integer, ChangeNumber> entry : serverIdToChangeNumber
      for (Entry<Integer, CSN> entry : serverIdToCSN
          .entrySet())
      {
        // serverId is useless, see comment in ServerState ctor
@@ -388,9 +381,9 @@
        idList.add(serverIdStr);
        length += serverIdStr.length() + 1;
        String changeNumberStr = entry.getValue().toString();
        cnList.add(changeNumberStr);
        length += changeNumberStr.length() + 1;
        String csnStr = entry.getValue().toString();
        csnList.add(csnStr);
        length += csnStr.length() + 1;
      }
      byte[] result = new byte[length];
@@ -400,7 +393,7 @@
      {
        String str = idList.get(i);
        pos = addByteArray(str.getBytes("UTF-8"), result, pos);
        str = cnList.get(i);
        str = csnList.get(i);
        pos = addByteArray(str.getBytes("UTF-8"), result, pos);
      }
      return result;
@@ -413,12 +406,12 @@
  @Override
  public Iterator<Integer> iterator()
  {
    return serverIdToChangeNumber.keySet().iterator();
    return serverIdToCSN.keySet().iterator();
  }
  /**
   * Check that all the ChangeNumbers in the covered serverState are also in
   * this serverState.
   * Check that all the CSNs in the covered serverState are also in this
   * serverState.
   *
   * @param covered The ServerState that needs to be checked.
   * @return A boolean indicating if this ServerState covers the ServerState
@@ -426,7 +419,7 @@
   */
  public boolean cover(ServerState covered)
  {
    for (ChangeNumber coveredChange : covered.serverIdToChangeNumber.values())
    for (CSN coveredChange : covered.serverIdToCSN.values())
    {
      if (!cover(coveredChange))
      {
@@ -437,16 +430,16 @@
  }
  /**
   * Checks that the ChangeNumber given as a parameter is in this ServerState.
   * Checks that the CSN given as a parameter is in this ServerState.
   *
   * @param   covered The ChangeNumber that should be checked.
   * @return  A boolean indicating if this ServerState contains the ChangeNumber
   *          given in parameter.
   * @param   covered The CSN that should be checked.
   * @return  A boolean indicating if this ServerState contains the CSN given in
   *          parameter.
   */
  public boolean cover(ChangeNumber covered)
  public boolean cover(CSN covered)
  {
    ChangeNumber change =
        this.serverIdToChangeNumber.get(covered.getServerId());
    CSN change =
        this.serverIdToCSN.get(covered.getServerId());
    return change != null && !change.older(covered);
  }
@@ -457,7 +450,7 @@
   */
  public boolean isEmpty()
  {
    return serverIdToChangeNumber.isEmpty();
    return serverIdToCSN.isEmpty();
  }
  /**
@@ -467,9 +460,9 @@
  public ServerState duplicate()
  {
    ServerState newState = new ServerState();
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      newState.serverIdToChangeNumber.putAll(serverIdToChangeNumber);
      newState.serverIdToCSN.putAll(serverIdToCSN);
    }
    return newState;
  }
@@ -492,21 +485,23 @@
    }
    int diff = 0;
    for (Integer serverId : ss1.serverIdToChangeNumber.keySet())
    for (Integer serverId : ss1.serverIdToCSN.keySet())
    {
      ChangeNumber cn1 = ss1.serverIdToChangeNumber.get(serverId);
      if (cn1 != null)
      CSN csn1 = ss1.serverIdToCSN.get(serverId);
      if (csn1 != null)
      {
        ChangeNumber cn2 = ss2.serverIdToChangeNumber.get(serverId);
         if (cn2 != null)
         {
           diff += ChangeNumber.diffSeqNum(cn1, cn2);
         } else {
           // ss2 does not have a change for this server id but ss1, so the
           // server holding ss1 has every changes represented in cn1 in advance
           // compared to server holding ss2, add this amount
           diff += cn1.getSeqnum();
         }
        CSN csn2 = ss2.serverIdToCSN.get(serverId);
        if (csn2 != null)
        {
          diff += CSN.diffSeqNum(csn1, csn2);
        }
        else
        {
          // ss2 does not have a change for this server id but ss1, so the
          // server holding ss1 has every changes represented in csn1 in advance
          // compared to server holding ss2, add this amount
          diff += csn1.getSeqnum();
        }
      }
    }
@@ -534,23 +529,23 @@
  }
  /**
   * Build a copy of the ServerState with only ChangeNumbers older than
   * a specific ChangeNumber. This is used when building the initial
   * Build a copy of the ServerState with only CSNs older than
   * a specific CSN. This is used when building the initial
   * Cookie in the External Changelog, to cope with purged changes.
   * @param cn The ChangeNumber to compare the ServerState with
   * @return a copy of the ServerState which only contains the ChangeNumbers
   *         older than cn.
   * @param csn The CSN to compare the ServerState with
   * @return a copy of the ServerState which only contains the CSNs older than
   *         csn.
   */
  public ServerState duplicateOnlyOlderThan(ChangeNumber cn)
  public ServerState duplicateOnlyOlderThan(CSN csn)
  {
    ServerState newState = new ServerState();
    synchronized (serverIdToChangeNumber)
    synchronized (serverIdToCSN)
    {
      for (ChangeNumber change : serverIdToChangeNumber.values())
      for (CSN change : serverIdToCSN.values())
      {
        if (change.older(cn))
        if (change.older(csn))
        {
          newState.serverIdToChangeNumber.put(change.getServerId(), change);
          newState.serverIdToCSN.put(change.getServerId(), change);
        }
      }
    }
opends/src/server/org/opends/server/replication/plugin/AttrHistorical.java
@@ -30,13 +30,12 @@
import java.util.Iterator;
import java.util.Map;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
/**
 * This class store historical information for a provided attribute.
 */
@@ -49,14 +48,14 @@
   *
   * @param modsIterator  The iterator on the mods from which the mod is
   *                      extracted.
   * @param changeNumber  The changeNumber associated to the operation.
   * @param csn  The CSN associated to the operation.
   * @param modifiedEntry The entry modified by this operation.
   * @param mod           The modification.
   *
   * @return a boolean indicating if a conflict was detected.
   */
  public abstract boolean replayOperation(
      Iterator<Modification> modsIterator, ChangeNumber changeNumber,
      Iterator<Modification> modsIterator, CSN csn,
      Entry modifiedEntry, Modification mod);
  /**
@@ -68,11 +67,11 @@
   * It does not check if the operation to process is conflicting or not with
   * previous operations. The caller is responsible for this.
   *
   * @param changeNumber The changeNumber of the operation to process
   * @param csn The CSN of the operation to process
   * @param mod The modify operation to process.
   */
  public abstract void processLocalOrNonConflictModification(
      ChangeNumber changeNumber, Modification mod);
      CSN csn, Modification mod);
  /**
   * Create a new object from a provided attribute type. Historical is empty.
@@ -103,17 +102,17 @@
   *
   * @return the last time when this attribute was deleted
   */
  public abstract ChangeNumber getDeleteTime();
  public abstract CSN getDeleteTime();
  /**
   * Assign the provided information to this object.
   *
   * @param histKey the key to assign.
   * @param value   the associated value or null if there is no value;
   * @param cn      the associated ChangeNumber.
   * @param csn     the associated CSN.
   */
  public abstract void assign(
      HistAttrModificationKey histKey, AttributeValue value, ChangeNumber cn);
      HistAttrModificationKey histKey, AttributeValue value, CSN csn);
}
opends/src/server/org/opends/server/replication/plugin/AttrHistoricalMultiple.java
@@ -31,14 +31,8 @@
import java.util.LinkedHashMap;
import java.util.Map;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
/**
 * This class is used to store historical information for multiple valued
@@ -52,16 +46,16 @@
public class AttrHistoricalMultiple extends AttrHistorical
{
  /** Last time when the attribute was deleted. */
  private ChangeNumber deleteTime;
  private CSN deleteTime;
  /** Last time the attribute was modified. */
  private ChangeNumber lastUpdateTime;
  private CSN lastUpdateTime;
  /**
   * Change history for the values of this attribute. We are using a
   * LinkedHashMap here because we want:
   * <ol>
   * <li>Fast access for removing/adding a AttrValueHistorical keyed by the
   * AttributeValue => Use a Map</li>
   * <li>Ordering changes according to the changeNumber of each changes => Use a
   * <li>Ordering changes according to the CSN of each changes => Use a
   * LinkedHashMap</li>
   * </ol>
   */
@@ -74,8 +68,8 @@
    * @param updateTime the last time this attribute was updated
    * @param valuesHist the new attribute values when updated.
    */
   public AttrHistoricalMultiple(ChangeNumber deleteTime,
       ChangeNumber updateTime,
   public AttrHistoricalMultiple(CSN deleteTime,
       CSN updateTime,
       Map<AttrValueHistorical,AttrValueHistorical> valuesHist)
   {
     this.deleteTime = deleteTime;
@@ -99,7 +93,7 @@
    * Returns the last time when the attribute was updated.
    * @return the last time when the attribute was updated
    */
   private ChangeNumber getLastUpdateTime()
   private CSN getLastUpdateTime()
   {
     return lastUpdateTime;
   }
@@ -109,17 +103,17 @@
    * @return the last time when the attribute was deleted
    */
   @Override
   public ChangeNumber getDeleteTime()
   public CSN getDeleteTime()
   {
     return deleteTime;
   }
   /**
    * Duplicate an object.
    * ChangeNumber are duplicated by references
    * @return the duplicated object.
    *
    * Duplicate an object. CSNs are duplicated by references.
    * <p>
    * Method only called in tests
    *
    * @return the duplicated object.
    */
   AttrHistoricalMultiple duplicate()
   {
@@ -128,33 +122,32 @@
   }
   /**
    * Delete all historical information that is older than
    * the provided ChangeNumber for this attribute type.
    * Delete all historical information that is older than the provided CSN for
    * this attribute type.
    * Add the delete attribute state information
    * @param CN time when the delete was done
    * @param csn time when the delete was done
    */
   protected void delete(ChangeNumber CN)
   protected void delete(CSN csn)
   {
     // iterate through the values in the valuesInfo
     // and suppress all the values that have not been added
     // after the date of this delete.
     // iterate through the values in the valuesInfo and suppress all the values
     // that have not been added after the date of this delete.
     Iterator<AttrValueHistorical> it = valuesHist.keySet().iterator();
     while (it.hasNext())
     {
       AttrValueHistorical info = it.next();
       if (CN.newerOrEquals(info.getValueUpdateTime()) &&
           CN.newerOrEquals(info.getValueDeleteTime()))
       if (csn.newerOrEquals(info.getValueUpdateTime()) &&
           csn.newerOrEquals(info.getValueDeleteTime()))
         it.remove();
     }
     if (CN.newer(deleteTime))
     if (csn.newer(deleteTime))
     {
       deleteTime = CN;
       deleteTime = csn;
     }
     if (CN.newer(lastUpdateTime))
     if (csn.newer(lastUpdateTime))
     {
       lastUpdateTime = CN;
       lastUpdateTime = csn;
     }
   }
@@ -162,16 +155,16 @@
    * Update the historical of this attribute after a delete value.
    *
    * @param val value that was deleted
    * @param CN time when the delete was done
    * @param csn time when the delete was done
    */
   protected void delete(AttributeValue val, ChangeNumber CN)
   protected void delete(AttributeValue val, CSN csn)
   {
     AttrValueHistorical info = new AttrValueHistorical(val, null, CN);
     AttrValueHistorical info = new AttrValueHistorical(val, null, csn);
     valuesHist.remove(info);
     valuesHist.put(info, info);
     if (CN.newer(lastUpdateTime))
     if (csn.newer(lastUpdateTime))
     {
       lastUpdateTime = CN;
       lastUpdateTime = csn;
     }
   }
@@ -181,19 +174,19 @@
     * @param attr
     *          the attribute containing the set of values that were
     *          deleted
     * @param CN
     * @param csn
     *          time when the delete was done
     */
  protected void delete(Attribute attr, ChangeNumber CN)
  protected void delete(Attribute attr, CSN csn)
  {
    for (AttributeValue val : attr)
    {
      AttrValueHistorical info = new AttrValueHistorical(val, null, CN);
      AttrValueHistorical info = new AttrValueHistorical(val, null, csn);
      valuesHist.remove(info);
      valuesHist.put(info, info);
      if (CN.newer(lastUpdateTime))
      if (csn.newer(lastUpdateTime))
      {
        lastUpdateTime = CN;
        lastUpdateTime = csn;
      }
    }
  }
@@ -203,17 +196,17 @@
     *
     * @param addedValue
     *          values that was added
     * @param CN
     * @param csn
     *          time when the value was added
     */
   protected void add(AttributeValue addedValue, ChangeNumber CN)
   protected void add(AttributeValue addedValue, CSN csn)
   {
     AttrValueHistorical info = new AttrValueHistorical(addedValue, CN, null);
     AttrValueHistorical info = new AttrValueHistorical(addedValue, csn, null);
     valuesHist.remove(info);
     valuesHist.put(info, info);
     if (CN.newer(lastUpdateTime))
     if (csn.newer(lastUpdateTime))
     {
       lastUpdateTime = CN;
       lastUpdateTime = csn;
     }
   }
@@ -222,19 +215,19 @@
     *
     * @param attr
     *          the attribute containing the set of added values
     * @param CN
     * @param csn
     *          time when the add is done
     */
  private void add(Attribute attr, ChangeNumber CN)
  private void add(Attribute attr, CSN csn)
  {
    for (AttributeValue val : attr)
    {
      AttrValueHistorical info = new AttrValueHistorical(val, CN, null);
      AttrValueHistorical info = new AttrValueHistorical(val, csn, null);
      valuesHist.remove(info);
      valuesHist.put(info, info);
      if (CN.newer(lastUpdateTime))
      if (csn.newer(lastUpdateTime))
      {
        lastUpdateTime = CN;
        lastUpdateTime = csn;
      }
    }
  }
@@ -254,15 +247,14 @@
   * {@inheritDoc}
   */
  @Override
  public boolean replayOperation(
      Iterator<Modification> modsIterator, ChangeNumber changeNumber,
  public boolean replayOperation(Iterator<Modification> modsIterator, CSN csn,
      Entry modifiedEntry, Modification m)
  {
    // We are replaying an operation that was already done
    // on another master server and this operation has a potential
    // conflict with some more recent operations on this same entry
    // we need to take the more complex path to solve them
    if ((ChangeNumber.compare(changeNumber, getLastUpdateTime()) < 0) ||
    if ((CSN.compare(csn, getLastUpdateTime()) < 0) ||
        (m.getModificationType() != ModificationType.REPLACE))
    {
      // the attribute was modified after this change -> conflict
@@ -270,7 +262,7 @@
      switch (m.getModificationType())
      {
      case DELETE:
        if (changeNumber.older(getDeleteTime()))
        if (csn.older(getDeleteTime()))
        {
          /* this delete is already obsoleted by a more recent delete
           * skip this mod
@@ -279,18 +271,18 @@
          break;
        }
        if (!conflictDelete(changeNumber, m, modifiedEntry))
        if (!conflictDelete(csn, m, modifiedEntry))
        {
          modsIterator.remove();
        }
        break;
      case ADD:
        conflictAdd(changeNumber, m, modsIterator);
        conflictAdd(csn, m, modsIterator);
        break;
      case REPLACE:
        if (changeNumber.older(getDeleteTime()))
        if (csn.older(getDeleteTime()))
        {
          /* this replace is already obsoleted by a more recent delete
           * skip this mod
@@ -310,11 +302,11 @@
        Attribute addedValues = m.getAttribute();
        m.setAttribute(new AttributeBuilder(addedValues, true).toAttribute());
        conflictDelete(changeNumber, m, modifiedEntry);
        conflictDelete(csn, m, modifiedEntry);
        Attribute keptValues = m.getAttribute();
        m.setAttribute(addedValues);
        conflictAdd(changeNumber, m, modsIterator);
        conflictAdd(csn, m, modsIterator);
        AttributeBuilder builder = new AttributeBuilder(keptValues);
        builder.addAll(m.getAttribute());
@@ -329,7 +321,7 @@
    }
    else
    {
      processLocalOrNonConflictModification(changeNumber, m);
      processLocalOrNonConflictModification(csn, m);
      return false;// the attribute was not modified more recently
    }
  }
@@ -343,12 +335,11 @@
   * It does not check if the operation to process is conflicting or not with
   * previous operations. The caller is responsible for this.
   *
   * @param changeNumber The changeNumber of the operation to process
   * @param csn The CSN of the operation to process
   * @param mod The modify operation to process.
   */
  @Override
  public void processLocalOrNonConflictModification(ChangeNumber changeNumber,
      Modification mod)
  public void processLocalOrNonConflictModification(CSN csn, Modification mod)
  {
    /*
     * The operation is either a non-conflicting operation or a local
@@ -368,30 +359,30 @@
    case DELETE:
      if (modAttr.isEmpty())
      {
        delete(changeNumber);
        delete(csn);
      }
      else
      {
        delete(modAttr, changeNumber);
        delete(modAttr, csn);
      }
      break;
    case ADD:
      if (type.isSingleValue())
      {
        delete(changeNumber);
        delete(csn);
      }
      add(modAttr, changeNumber);
      add(modAttr, csn);
      break;
    case REPLACE:
      /* TODO : can we replace specific attribute values ????? */
      delete(changeNumber);
      add(modAttr, changeNumber);
      delete(csn);
      add(modAttr, csn);
      break;
    case INCREMENT:
      /* FIXME : we should update ChangeNumber */
      /* FIXME : we should update CSN */
      break;
    }
  }
@@ -400,13 +391,12 @@
   * Process a delete attribute values that is conflicting with a previous
   * modification.
   *
   * @param changeNumber The changeNumber of the currently processed change
   * @param csn The CSN of the currently processed change
   * @param m the modification that is being processed
   * @param modifiedEntry the entry that is modified (before current mod)
   * @return false if there is nothing to do
   */
  private boolean conflictDelete(ChangeNumber changeNumber, Modification m,
      Entry modifiedEntry)
  private boolean conflictDelete(CSN csn, Modification m, Entry modifiedEntry)
  {
    /*
     * We are processing a conflicting DELETE modification
@@ -438,7 +428,7 @@
      {
        AttrValueHistorical valInfo = it.next();
        if (changeNumber.older(valInfo.getValueUpdateTime()))
        if (csn.older(valInfo.getValueUpdateTime()))
        {
          /*
           * this value has been updated after this delete, therefore
@@ -453,7 +443,7 @@
           * information unless it is a Deleted attribute value that is
           * more recent than this DELETE
           */
          if (changeNumber.newerOrEquals(valInfo.getValueDeleteTime()))
          if (csn.newerOrEquals(valInfo.getValueDeleteTime()))
          {
            it.remove();
          }
@@ -462,13 +452,13 @@
      m.setAttribute(builder.toAttribute());
      if (changeNumber.newer(getDeleteTime()))
      if (csn.newer(getDeleteTime()))
      {
        deleteTime = changeNumber;
        deleteTime = csn;
      }
      if (changeNumber.newer(getLastUpdateTime()))
      if (csn.newer(getLastUpdateTime()))
      {
        lastUpdateTime = changeNumber;
        lastUpdateTime = csn;
      }
    }
    else
@@ -483,19 +473,19 @@
        /* update historical information */
        AttrValueHistorical valInfo =
          new AttrValueHistorical(val, null, changeNumber);
          new AttrValueHistorical(val, null, csn);
        AttrValueHistorical oldValInfo = valuesHist.get(valInfo);
        if (oldValInfo != null)
        {
          /* this value already exist in the historical information */
          if (changeNumber.equals(oldValInfo.getValueUpdateTime()))
          if (csn.equals(oldValInfo.getValueUpdateTime()))
          {
            // This value was added earlier in the same operation
            // we need to keep the delete.
            addedInCurrentOp = true;
          }
          if (changeNumber.newerOrEquals(oldValInfo.getValueDeleteTime()) &&
              changeNumber.newerOrEquals(oldValInfo.getValueUpdateTime()))
          if (csn.newerOrEquals(oldValInfo.getValueDeleteTime()) &&
              csn.newerOrEquals(oldValInfo.getValueUpdateTime()))
          {
            valuesHist.remove(oldValInfo);
            valuesHist.put(valInfo, valInfo);
@@ -533,9 +523,9 @@
      m.setAttribute(builder.toAttribute());
      if (changeNumber.newer(getLastUpdateTime()))
      if (csn.newer(getLastUpdateTime()))
      {
        lastUpdateTime = changeNumber;
        lastUpdateTime = csn;
      }
    }
@@ -546,12 +536,12 @@
   * Process a add attribute values that is conflicting with a previous
   * modification.
   *
   * @param changeNumber  the historical info associated to the entry
   * @param csn  the historical info associated to the entry
   * @param m the modification that is being processed
   * @param modsIterator iterator on the list of modification
   * @return false if operation becomes empty and must not be processed
   */
  private boolean conflictAdd(ChangeNumber changeNumber, Modification m,
  private boolean conflictAdd(CSN csn, Modification m,
      Iterator<Modification> modsIterator)
  {
    /*
@@ -564,7 +554,7 @@
     * real entry
     */
    if (changeNumber.older(getDeleteTime()))
    if (csn.older(getDeleteTime()))
    {
      /* A delete has been done more recently than this add
       * forget this MOD ADD
@@ -577,7 +567,7 @@
    for (AttributeValue addVal : m.getAttribute())
    {
      AttrValueHistorical valInfo =
        new AttrValueHistorical(addVal, changeNumber, null);
        new AttrValueHistorical(addVal, csn, null);
      AttrValueHistorical oldValInfo = valuesHist.get(valInfo);
      if (oldValInfo == null)
      {
@@ -596,7 +586,7 @@
           * in all cases suppress this value from the value list
           * as it is already present in the entry
           */
          if (changeNumber.newer(oldValInfo.getValueUpdateTime()))
          if (csn.newer(oldValInfo.getValueUpdateTime()))
          {
            valuesHist.remove(oldValInfo);
            valuesHist.put(valInfo, valInfo);
@@ -608,7 +598,7 @@
          /* this value is marked as a deleted value
           * check if this mod is more recent the this delete
           */
          if (changeNumber.newerOrEquals(oldValInfo.getValueDeleteTime()))
          if (csn.newerOrEquals(oldValInfo.getValueDeleteTime()))
          {
            /* this add is more recent,
             * remove the old delete historical information
@@ -639,9 +629,9 @@
      modsIterator.remove();
    }
    if (changeNumber.newer(getLastUpdateTime()))
    if (csn.newer(getLastUpdateTime()))
    {
      lastUpdateTime = changeNumber;
      lastUpdateTime = csn;
    }
    return true;
@@ -652,34 +642,34 @@
   */
  @Override
  public void assign(HistAttrModificationKey histKey, AttributeValue value,
      ChangeNumber cn)
      CSN csn)
  {
    switch (histKey)
    {
    case ADD:
      if (value != null)
      {
        add(value, cn);
        add(value, csn);
      }
      break;
    case DEL:
      if (value != null)
      {
        delete(value, cn);
        delete(value, csn);
      }
      break;
    case REPL:
      delete(cn);
      delete(csn);
      if (value != null)
      {
        add(value, cn);
        add(value, csn);
      }
      break;
    case DELATTR:
        delete(cn);
      delete(csn);
      break;
    }
  }
opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java
@@ -31,13 +31,8 @@
import java.util.Iterator;
import java.util.Map;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
/**
 * This class is used to store historical information for single valued
@@ -50,9 +45,9 @@
public class AttrHistoricalSingle extends AttrHistorical
{
  /** Last time when the attribute was deleted. */
  private ChangeNumber deleteTime = null;
  private CSN deleteTime = null;
  /** Last time when a value was added. */
  private ChangeNumber addTime = null;
  private CSN addTime = null;
  /** Last added value. */
  private AttributeValue value = null;
@@ -66,7 +61,7 @@
   * {@inheritDoc}
   */
  @Override
  public ChangeNumber getDeleteTime()
  public CSN getDeleteTime()
  {
    return this.deleteTime;
  }
@@ -92,8 +87,7 @@
   * {@inheritDoc}
   */
  @Override
  public void processLocalOrNonConflictModification(ChangeNumber changeNumber,
      Modification mod)
  public void processLocalOrNonConflictModification(CSN csn, Modification mod)
  {
    AttributeValue newValue = null;
    Attribute modAttr = mod.getAttribute();
@@ -106,13 +100,13 @@
    {
    case DELETE:
      this.addTime = null;
      this.deleteTime = changeNumber;
      this.deleteTime = csn;
      this.value = newValue;
      lastMod = HistAttrModificationKey.DEL;
      break;
    case ADD:
      this.addTime = changeNumber;
      this.addTime = csn;
      this.value = newValue;
      lastMod = HistAttrModificationKey.ADD;
      break;
@@ -122,20 +116,20 @@
      {
        // REPLACE with null value is actually a DELETE
        this.addTime = null;
        this.deleteTime = changeNumber;
        this.deleteTime = csn;
        this.value = null;
        lastMod = HistAttrModificationKey.DEL;
      }
      else
      {
        this.deleteTime = addTime = changeNumber;
        this.deleteTime = addTime = csn;
        lastMod = HistAttrModificationKey.REPL;
      }
      this.value = newValue;
      break;
    case INCREMENT:
      /* FIXME : we should update ChangeNumber */
      /* FIXME : we should update CSN */
      break;
    }
  }
@@ -144,8 +138,8 @@
   * {@inheritDoc}
   */
  @Override
  public boolean replayOperation(Iterator<Modification> modsIterator,
      ChangeNumber changeNumber, Entry modifiedEntry, Modification mod)
  public boolean replayOperation(Iterator<Modification> modsIterator, CSN csn,
      Entry modifiedEntry, Modification mod)
  {
    boolean conflict = false;
@@ -159,13 +153,13 @@
    switch (mod.getModificationType())
    {
    case DELETE:
      if (changeNumber.newer(addTime))
      if (csn.newer(addTime))
      {
        if (newValue == null || newValue.equals(value) || value == null)
        {
          if (changeNumber.newer(deleteTime))
          if (csn.newer(deleteTime))
          {
            deleteTime = changeNumber;
            deleteTime = csn;
          }
          AttributeType type = modAttr.getAttributeType();
          if (!modifiedEntry.hasAttribute(type))
@@ -192,14 +186,14 @@
          modsIterator.remove();
        }
      }
      else if (changeNumber.equals(addTime))
      else if (csn.equals(addTime))
      {
        if ((lastMod == HistAttrModificationKey.ADD)
            || (lastMod == HistAttrModificationKey.REPL))
        {
          if (changeNumber.newer(deleteTime))
          if (csn.newer(deleteTime))
          {
            deleteTime = changeNumber;
            deleteTime = csn;
          }
          addTime = null;
          lastMod = HistAttrModificationKey.DEL;
@@ -219,29 +213,28 @@
      break;
    case ADD:
      if (changeNumber.newerOrEquals(deleteTime) && changeNumber.older(addTime))
      if (csn.newerOrEquals(deleteTime) && csn.older(addTime))
      {
        conflict = true;
        mod.setModificationType(ModificationType.REPLACE);
        addTime = changeNumber;
        addTime = csn;
        value = newValue;
        lastMod = HistAttrModificationKey.REPL;
      }
      else
      {
        if (changeNumber.newerOrEquals(deleteTime)
        if (csn.newerOrEquals(deleteTime)
            && ((addTime == null ) || addTime.older(deleteTime)))
        {
          // no conflict : don't do anything beside setting the addTime
          addTime = changeNumber;
          addTime = csn;
          value = newValue;
          lastMod = HistAttrModificationKey.ADD;
        }
        else
        {
          // Case where changeNumber = addTime = deleteTime
          if (changeNumber.equals(deleteTime)
              && changeNumber.equals(addTime)
          // Case where CSN = addTime = deleteTime
          if (csn.equals(deleteTime) && csn.equals(addTime)
              && (lastMod == HistAttrModificationKey.DEL))
          {
            // No conflict, record the new value.
@@ -259,7 +252,7 @@
      break;
    case REPLACE:
      if (changeNumber.older(deleteTime))
      if (csn.older(deleteTime))
      {
        conflict = true;
        modsIterator.remove();
@@ -270,21 +263,21 @@
        {
          addTime = null;
          value = newValue;
          deleteTime = changeNumber;
          deleteTime = csn;
          lastMod = HistAttrModificationKey.DEL;
        }
        else
        {
          addTime = changeNumber;
          addTime = csn;
          value = newValue;
          deleteTime = changeNumber;
          deleteTime = csn;
          lastMod = HistAttrModificationKey.REPL;
        }
      }
      break;
    case INCREMENT:
      /* FIXME : we should update ChangeNumber */
      /* FIXME : we should update CSN */
      break;
    }
    return conflict;
@@ -295,29 +288,29 @@
   */
  @Override
  public void assign(HistAttrModificationKey histKey,
      AttributeValue value, ChangeNumber cn)
      AttributeValue value, CSN csn)
  {
    switch (histKey)
    {
    case ADD:
      this.addTime = cn;
      this.addTime = csn;
      this.value = value;
      break;
    case DEL:
      this.deleteTime = cn;
      this.deleteTime = csn;
      if (value != null)
        this.value = value;
      break;
    case REPL:
      this.addTime = this.deleteTime = cn;
      this.addTime = this.deleteTime = csn;
      if (value != null)
        this.value = value;
      break;
    case DELATTR:
      this.deleteTime = cn;
      this.deleteTime = csn;
      break;
    }
  }
opends/src/server/org/opends/server/replication/plugin/AttrValueHistorical.java
@@ -27,7 +27,7 @@
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.AttributeValue;
/**
@@ -36,23 +36,23 @@
public class AttrValueHistorical
{
  private AttributeValue value;
  private ChangeNumber valueDeleteTime;
  private ChangeNumber valueUpdateTime;
  private CSN valueDeleteTime;
  private CSN valueUpdateTime;
  /**
   * Build an AttrValueHistorical for a provided AttributeValue, providing
   * the last time the provided value is either updated or deleted.
   * @param value    the provided attributeValue
   * @param CNupdate last time when this value was updated
   * @param CNdelete last time when this value for deleted
   * @param csnUpdate last time when this value was updated
   * @param csnDelete last time when this value for deleted
   */
  public AttrValueHistorical(AttributeValue value,
                   ChangeNumber CNupdate,
                   ChangeNumber CNdelete)
                   CSN csnUpdate,
                   CSN csnDelete)
  {
    this.value = value;
    this.valueUpdateTime = CNupdate;
    this.valueDeleteTime = CNdelete;
    this.valueUpdateTime = csnUpdate;
    this.valueDeleteTime = csnDelete;
  }
  /**
@@ -69,10 +69,7 @@
      AttrValueHistorical objVal = (AttrValueHistorical) obj;
      return (value.equals(objVal.getAttributeValue()));
    }
    else
    {
      return false;
    }
    return false;
  }
  /**
@@ -90,7 +87,7 @@
   * Get the last time when the value was deleted.
   * @return the last time when the value was deleted
   */
  public ChangeNumber getValueDeleteTime()
  public CSN getValueDeleteTime()
  {
    return valueDeleteTime;
  }
@@ -99,7 +96,7 @@
   * Get the last time when the value was updated.
   * @return the last time when the value was updated
   */
  public ChangeNumber getValueUpdateTime()
  public CSN getValueUpdateTime()
  {
    return valueUpdateTime;
  }
opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java
@@ -27,17 +27,12 @@
 */
package org.opends.server.replication.plugin;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.*;
import org.opends.messages.Message;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.OperationContext;
import org.opends.server.types.*;
import org.opends.server.types.operation.PreOperationAddOperation;
@@ -45,6 +40,11 @@
import org.opends.server.types.operation.PreOperationModifyOperation;
import org.opends.server.util.TimeThread;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class is used to store historical information that is
 * used to resolve modify conflicts
@@ -87,24 +87,23 @@
  /**
   * The delay to purge the historical information.
   * This delay indicates the time the domain keeps the historical
   * information necessary to solve conflicts.When a change stored in the
   * historical part of the user entry has a date (from its replication
   * ChangeNumber) older than this delay, it is candidate to be purged.
   * The purge is triggered on 2 events: modify of the entry, dedicated purge
   * task.
   *
   * The purge is done when the historical is encoded.
   * <p>
   * This delay indicates the time the domain keeps the historical information
   * necessary to solve conflicts. When a change stored in the historical part
   * of the user entry has a date (from its replication CSN) older than this
   * delay, it is candidate to be purged. The purge is triggered on 2 events:
   * modify of the entry, dedicated purge task. The purge is done when the
   * historical is encoded.
   */
  private long purgeDelayInMillisec = -1;
  /**
   * The oldest ChangeNumber stored in this entry historical attribute.
   * The oldest CSN stored in this entry historical attribute.
   * null when this historical object has been created from
   * an entry that has no historical attribute and after the last
   * historical has been purged.
   */
  private ChangeNumber oldestChangeNumber = null;
  private CSN oldestCSN = null;
  /**
   * For stats/monitoring purpose, the number of historical values
@@ -117,8 +116,8 @@
   * The in-memory historical information is made of.
   *
   * EntryHistorical ::= ADDDate MODDNDate attributesInfo
   * ADDDate       ::= ChangeNumber  // the date the entry was added
   * MODDNDate     ::= ChangeNumber  // the date the entry was last renamed
   * ADDDate       ::= CSN  // the date the entry was added
   * MODDNDate     ::= CSN  // the date the entry was last renamed
   *
   * attributesInfo      ::= (AttrInfoWithOptions)*
   *                         one AttrInfoWithOptions by attributeType
@@ -136,14 +135,14 @@
   *                         AttrValueHistorical is the historical of the
   *                         the modification of one value
   *
   * AddTime             ::= ChangeNumber // last time the attribute was added
   * AddTime             ::= CSN // last time the attribute was added
   *                                      // to the entry
   * DeleteTime          ::= ChangeNumber // last time the attribute was deleted
   * DeleteTime          ::= CSN // last time the attribute was deleted
   *                                      // from the entry
   *
   * AttrValueHistorical ::= AttributeValue valueDeleteTime valueUpdateTime
   * valueDeleteTime     ::= ChangeNumber
   * valueUpdateTime     ::= ChangeNumber
   * valueDeleteTime     ::= CSN
   * valueUpdateTime     ::= CSN
   *
   * - a list indexed on AttributeType of AttrInfoWithOptions :
   *     each value is the historical for this attribute
@@ -153,10 +152,10 @@
   */
  /** The date when the entry was added. */
  private ChangeNumber entryADDDate = null;
  private CSN entryADDDate = null;
  /** The date when the entry was last renamed. */
  private ChangeNumber entryMODDNDate = null;
  private CSN entryMODDNDate = null;
  /**
   * Contains Historical information for each attribute sorted by attribute
@@ -190,8 +189,7 @@
  {
    boolean bConflict = false;
    List<Modification> mods = modifyOperation.getModifications();
    ChangeNumber modOpChangeNumber =
      OperationContext.getChangeNumber(modifyOperation);
    CSN modOpCSN = OperationContext.getCSN(modifyOperation);
    for (Iterator<Modification> modsIterator = mods.iterator();
         modsIterator.hasNext(); )
@@ -203,8 +201,7 @@
      // contained in the mod
      AttrHistorical attrHist = getOrCreateAttrHistorical(m);
      if (attrHist.replayOperation(modsIterator, modOpChangeNumber,
                                   modifiedEntry, m))
      if (attrHist.replayOperation(modsIterator, modOpCSN, modifiedEntry, m))
      {
        bConflict = true;
      }
@@ -235,8 +232,7 @@
  {
    List<Modification> mods = modifyOperation.getModifications();
    Entry modifiedEntry = modifyOperation.getModifiedEntry();
    ChangeNumber changeNumber =
      OperationContext.getChangeNumber(modifyOperation);
    CSN csn = OperationContext.getCSN(modifyOperation);
    /*
     * If this is a local operation we need :
@@ -254,7 +250,7 @@
        // (eventually read from the provided modification)
        AttrHistorical attrHist = getOrCreateAttrHistorical(mod);
        if (attrHist != null)
          attrHist.processLocalOrNonConflictModification(changeNumber, mod);
          attrHist.processLocalOrNonConflictModification(csn, mod);
      }
    }
@@ -280,8 +276,8 @@
  public void setHistoricalAttrToOperation(
      PreOperationModifyDNOperation modifyDNOperation)
  {
    // Update this historical information with the operation ChangeNumber.
    this.entryMODDNDate = OperationContext.getChangeNumber(modifyDNOperation);
    // Update this historical information with the operation CSN.
    this.entryMODDNDate = OperationContext.getCSN(modifyDNOperation);
    // Update the operations mods and the modified entry so that the
    // historical information gets stored in the DB and indexed accordingly.
@@ -305,7 +301,7 @@
   * from the replication context attached to the provided operation
   * and set this attribute in the operation.
   *
   *   For ADD, the historical is made of the changeNumber read from the
   *   For ADD, the historical is made of the CSN read from the
   *   synchronization context attached to the operation.
   *
   *   Called for both local and synchronization ADD preOperation.
@@ -328,10 +324,10 @@
    AttributeType historicalAttrType =
      DirectoryServer.getSchema().getAttributeType(HISTORICAL_ATTRIBUTE_NAME);
    // Get the changeNumber from the attached synchronization context
    // Get the CSN from the attached synchronization context
    // Create the attribute (encoded)
    ChangeNumber addCn = OperationContext.getChangeNumber(addOperation);
    AttributeValue attrValue = encodeHistorical(addCn, "add");
    CSN addCSN = OperationContext.getCSN(addOperation);
    AttributeValue attrValue = encodeHistorical(addCSN, "add");
    Attribute attr = Attributes.create(historicalAttrType, attrValue);
    // Set the created attribute to the operation
@@ -345,20 +341,19 @@
   * operation type . For ADD Operation : "dn:changeNumber:add", for MODDN
   * Operation : "dn:changeNumber:moddn", etc.
   *
   * @param cn
   * @param csn
   *          The date when the ADD Operation happened.
   * @param operationType
   *          the operation type to encode
   * @return The attribute value containing the historical information for the
   *         Operation type.
   */
  private static AttributeValue encodeHistorical(ChangeNumber cn,
      String operationType)
  private static AttributeValue encodeHistorical(CSN csn, String operationType)
  {
    AttributeType historicalAttrType =
      DirectoryServer.getSchema().getAttributeType(HISTORICAL_ATTRIBUTE_NAME);
    String strValue = "dn:" + cn + ":" + operationType;
    String strValue = "dn:" + csn + ":" + operationType;
    return AttributeValues.create(historicalAttrType, strValue);
  }
@@ -470,7 +465,7 @@
          optionsString = optionsBuilder.toString();
        }
        ChangeNumber deleteTime = attrHist.getDeleteTime();
        CSN deleteTime = attrHist.getDeleteTime();
        /* generate the historical information for deleted attributes */
        boolean delAttr = deleteTime != null;
@@ -500,7 +495,7 @@
              continue;
            }
            final ChangeNumber updateTime = attrValHist.getValueUpdateTime();
            final CSN updateTime = attrValHist.getValueUpdateTime();
            // FIXME very suspicious use of == in the next if statement,
            // unit tests do not like changing it
            if (delAttr && updateTime == deleteTime && value != null)
@@ -553,9 +548,9 @@
    return builder.toAttribute();
  }
  private boolean needsPurge(ChangeNumber cn, long purgeDate)
  private boolean needsPurge(CSN csn, long purgeDate)
  {
    boolean needsPurge = purgeDelayInMillisec > 0 && cn.getTime() <= purgeDate;
    boolean needsPurge = purgeDelayInMillisec > 0 && csn.getTime() <= purgeDate;
    if (needsPurge)
    {
      // this hist must be purged now, because older than the purge delay
@@ -565,14 +560,14 @@
  }
  private String encode(String operation, AttributeType type,
      String optionsString, ChangeNumber changeTime)
      String optionsString, CSN changeTime)
  {
    return type.getNormalizedPrimaryName() + optionsString + ":" + changeTime
        + ":" + operation;
  }
  private String encode(String operation, AttributeType type,
      String optionsString, ChangeNumber changeTime, AttributeValue value)
      String optionsString, CSN changeTime, AttributeValue value)
  {
    return type.getNormalizedPrimaryName() + optionsString + ":" + changeTime
        + ":" + operation + ":" + value;
@@ -590,27 +585,26 @@
  }
  /**
   * Indicates if the Entry was renamed or added after the ChangeNumber
   * that is given as a parameter.
   * Indicates if the Entry was renamed or added after the CSN that is given as
   * a parameter.
   *
   * @param cn The ChangeNumber with which the ADD or Rename date must be
   *           compared.
   *
   * @return A boolean indicating if the Entry was renamed or added after
   *                   the ChangeNumber that is given as a parameter.
   * @param csn
   *          The CSN with which the ADD or Rename date must be compared.
   * @return A boolean indicating if the Entry was renamed or added after the
   *         CSN that is given as a parameter.
   */
  public boolean addedOrRenamedAfter(ChangeNumber cn)
  public boolean addedOrRenamedAfter(CSN csn)
  {
    return cn.older(entryADDDate) || cn.older(entryMODDNDate);
    return csn.older(entryADDDate) || csn.older(entryMODDNDate);
  }
  /**
   * Returns the lastChangeNumber when the entry DN was modified.
   * Returns the lastCSN when the entry DN was modified.
   *
   * @return The lastChangeNumber when the entry DN was modified.
   * @return The lastCSN when the entry DN was modified.
   */
  public ChangeNumber getDNDate()
  public CSN getDNDate()
  {
    if (entryADDDate == null)
      return entryMODDNDate;
@@ -671,20 +665,20 @@
          AttributeType attrType = histVal.getAttrType();
          Set<String> options = histVal.getOptions();
          ChangeNumber cn = histVal.getCn();
          CSN csn = histVal.getCSN();
          AttributeValue value = histVal.getAttributeValue();
          HistAttrModificationKey histKey = histVal.getHistKey();
          // update the oldest ChangeNumber stored in the new entry historical
          newHistorical.updateOldestCN(cn);
          // update the oldest CSN stored in the new entry historical
          newHistorical.updateOldestCSN(csn);
          if (histVal.isADDOperation())
          {
            newHistorical.entryADDDate = cn;
            newHistorical.entryADDDate = csn;
          }
          else if (histVal.isMODDNOperation())
          {
            newHistorical.entryMODDNDate = cn;
            newHistorical.entryMODDNDate = csn;
          }
          else
          {
@@ -731,7 +725,7 @@
              lastOptions = options;
            }
            attrInfo.assign(histKey, value, cn);
            attrInfo.assign(histKey, value, csn);
          }
        }
      }
@@ -761,8 +755,8 @@
   */
  public static Iterable<FakeOperation> generateFakeOperations(Entry entry)
  {
    TreeMap<ChangeNumber, FakeOperation> operations =
            new TreeMap<ChangeNumber, FakeOperation>();
    TreeMap<CSN, FakeOperation> operations =
            new TreeMap<CSN, FakeOperation>();
    List<Attribute> attrs = getHistoricalAttr(entry);
    if (attrs != null)
    {
@@ -777,25 +771,25 @@
            // Found some historical information indicating that this
            // entry was just added.
            // Create the corresponding ADD operation.
            operations.put(histVal.getCn(),
                new FakeAddOperation(histVal.getCn(), entry));
            operations.put(histVal.getCSN(),
                new FakeAddOperation(histVal.getCSN(), entry));
          }
          else if (histVal.isMODDNOperation())
          {
            // Found some historical information indicating that this
            // entry was just renamed.
            // Create the corresponding ADD operation.
            operations.put(histVal.getCn(),
                new FakeModdnOperation(histVal.getCn(), entry));
            operations.put(histVal.getCSN(),
                new FakeModdnOperation(histVal.getCSN(), entry));
          }
          else
          {
            // Found some historical information for modify operation.
            // Generate the corresponding ModifyOperation or update
            // the already generated Operation if it can be found.
            ChangeNumber cn = histVal.getCn();
            CSN csn = histVal.getCSN();
            Modification mod = histVal.generateMod();
            FakeOperation fakeOperation = operations.get(cn);
            FakeOperation fakeOperation = operations.get(csn);
            if (fakeOperation instanceof FakeModifyOperation)
            {
@@ -807,9 +801,9 @@
            {
              String uuidString = getEntryUUID(entry);
              FakeModifyOperation modifyFakeOperation =
                  new FakeModifyOperation(entry.getDN(), cn, uuidString);
                  new FakeModifyOperation(entry.getDN(), csn, uuidString);
              modifyFakeOperation.addModification(mod);
              operations.put(histVal.getCn(), modifyFakeOperation);
              operations.put(histVal.getCSN(), modifyFakeOperation);
            }
          }
        }
@@ -883,30 +877,29 @@
  }
  /**
   * Potentially update the oldest ChangeNumber stored in this entry historical
   * with the provided ChangeNumber when its older than the current oldest.
   * Potentially update the oldest CSN stored in this entry historical
   * with the provided CSN when its older than the current oldest.
   *
   * @param cn the provided ChangeNumber.
   * @param csn the provided CSN.
   */
  private void updateOldestCN(ChangeNumber cn)
  private void updateOldestCSN(CSN csn)
  {
    if (cn != null
        && (this.oldestChangeNumber == null
            || cn.older(this.oldestChangeNumber)))
      this.oldestChangeNumber = cn;
    if (csn != null
        && (this.oldestCSN == null || csn.older(this.oldestCSN)))
      this.oldestCSN = csn;
  }
  /**
   * Returns the oldest ChangeNumber stored in this entry historical attribute.
   * Returns the oldest CSN stored in this entry historical attribute.
   *
   * @return the oldest ChangeNumber stored in this entry historical attribute.
   * @return the oldest CSN stored in this entry historical attribute.
   *         Returns null when this historical object has been created from
   *         an entry that has no historical attribute and after the last
   *         historical has been purged.
   */
  public ChangeNumber getOldestCN()
  public CSN getOldestCSN()
  {
    return this.oldestChangeNumber;
    return this.oldestCSN;
  }
  /**
opends/src/server/org/opends/server/replication/plugin/FakeAddOperation.java
@@ -23,11 +23,11 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.types.Entry;
@@ -46,12 +46,12 @@
  /**
   * Creates a new AddFakeOperations.
   *
   * @param cn     The ChangeNumber when the entry was created.
   * @param csn     The CSN when the entry was created.
   * @param entry  The entry that the ADD operation will create.
   */
  public FakeAddOperation(ChangeNumber cn, Entry entry)
  public FakeAddOperation(CSN csn, Entry entry)
  {
    super(cn);
    super(csn);
    this.entry = entry;
  }
@@ -61,7 +61,7 @@
  @Override
  public AddMsg generateMessage()
  {
    return new AddMsg(getChangeNumber(), entry.getDN().toString(),
    return new AddMsg(getCSN(), entry.getDN().toString(),
               EntryHistorical.getEntryUUID(entry),
               LDAPReplicationDomain.findEntryUUID(
                   entry.getDN().getParentDNInSuffix()),
opends/src/server/org/opends/server/replication/plugin/FakeDelOperation.java
@@ -23,39 +23,36 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
/**
 *
 * This class if used to build pseudo DEL Operation from the historical
 * information that stay in the entry in the database.
 *
 * This is useful when a LDAP server can't find a LDAP server that
 * has already seen all its changes and therefore need to retransmit them.
 *
 */
public class FakeDelOperation extends FakeOperation
{
  final private String dn;
  private final String dn;
  private final String entryUUID;
  /**
   * Creates a new FakeDelOperation from the provided information.
   *
   * @param dn             The dn of the entry that was deleted.
   * @param changeNumber   The ChangeNumber of the operation.
   * @param csn   The CSN of the operation.
   * @param entryUUID      The Unique ID of the deleted entry.
   */
  public FakeDelOperation(String dn, ChangeNumber changeNumber,
      String entryUUID)
  public FakeDelOperation(String dn, CSN csn, String entryUUID)
  {
    super(changeNumber);
    super(csn);
    this.dn = dn;
    this.entryUUID = entryUUID;
  }
@@ -67,7 +64,7 @@
  @Override
  public ReplicationMsg generateMessage()
  {
    return new DeleteMsg(dn, this.getChangeNumber(), entryUUID);
    return new DeleteMsg(dn, getCSN(), entryUUID);
  }
  /**
opends/src/server/org/opends/server/replication/plugin/FakeModdnOperation.java
@@ -23,24 +23,22 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.ModifyDNMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
/**
 * This class if used to build fake MODDN Operation from the historical
 * information that stay in the entry in the database.
 *
 * This is useful when a LDAP server can't find a LDAP server that
 * has already seen all its changes and therefore need to retransmit them.
 *
 */
public class FakeModdnOperation extends FakeOperation
{
@@ -49,12 +47,12 @@
  /**
   * Creates a new FakeModdnOperation.
   *
   * @param cn     The ChangeNumber when the entry was last renamed.
   * @param csn     The CSN when the entry was last renamed.
   * @param entry   The entry that the MODDN operation will rename.
   */
  public FakeModdnOperation(ChangeNumber cn, Entry entry)
  public FakeModdnOperation(CSN csn, Entry entry)
  {
    super(cn);
    super(csn);
    this.entry = entry;
  }
@@ -65,7 +63,7 @@
  public ReplicationMsg generateMessage()
  {
    DN dn = entry.getDN();
    return new ModifyDNMsg(dn.toString(), this.getChangeNumber(),
    return new ModifyDNMsg(dn.toString(), getCSN(),
        EntryHistorical.getEntryUUID(entry),
        LDAPReplicationDomain.findEntryUUID(dn.getParent()),
        false, dn.getParent().toString(), dn.getRDN().toString());
opends/src/server/org/opends/server/replication/plugin/FakeModifyOperation.java
@@ -23,13 +23,14 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import java.util.ArrayList;
import java.util.List;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.ModifyMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
import org.opends.server.types.DN;
@@ -40,12 +41,11 @@
 * information that stay in the entry in the database.
 *
 * This is useful when a LDAP server can't find a LDAP server that
 * has already seen all its changes and therefore need to retransmit them
 *
 * has already seen all its changes and therefore need to retransmit them.
 */
public class FakeModifyOperation extends FakeOperation
{
  private ArrayList<Modification> mods = new ArrayList<Modification>();
  private List<Modification> mods = new ArrayList<Modification>();
  private DN dn;
  private String entryuuid;
@@ -53,12 +53,12 @@
   * Creates a new ModifyFakeOperation with the provided information.
   *
   * @param dn The DN on which the Operation was applied.
   * @param changenumber The ChangeNumber of the operation.
   * @param csn The CSN of the operation.
   * @param entryuuid The unique ID of the entry on which the Operation applies.
   */
  public FakeModifyOperation(DN dn, ChangeNumber changenumber, String entryuuid)
  public FakeModifyOperation(DN dn, CSN csn, String entryuuid)
  {
    super(changenumber);
    super(csn);
    this.dn = dn;
    this.entryuuid = entryuuid;
  }
@@ -81,6 +81,6 @@
  @Override
  public ReplicationMsg generateMessage()
  {
    return new ModifyMsg(super.getChangeNumber(), dn, mods, entryuuid);
    return new ModifyMsg(getCSN(), dn, mods, entryuuid);
  }
}
opends/src/server/org/opends/server/replication/plugin/FakeOperation.java
@@ -23,43 +23,42 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.ReplicationMsg;
/**
 * This class if used to build fake Operation from the historical
 * information that stay in the entry in the database.
 *
 * This is useful when a LDAP server can't find a LDAP server that
 * has already seen all its changes and therefore need to retransmit them
 *
 * has already seen all its changes and therefore need to retransmit them.
 */
public abstract class FakeOperation
{
  private ChangeNumber changeNumber;
  private CSN csn;
  /**
   * Creates a new FakeOperation using the provided ChangeNumber.
   * Creates a new FakeOperation using the provided CSN.
   *
   * @param changeNumber The ChangeNumber to use to build the FakeOperation.
   * @param csn The CSN to use to build the FakeOperation.
   */
  public FakeOperation(ChangeNumber changeNumber)
  public FakeOperation(CSN csn)
  {
    this.changeNumber = changeNumber;
    this.csn = csn;
  }
  /**
   * Get the ChangeNumber.
   * Get the CSN.
   *
   * @return Returns the changeNumber.
   * @return Returns the CSN.
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
  /**
opends/src/server/org/opends/server/replication/plugin/FakeOperationComparator.java
@@ -23,12 +23,12 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import java.util.Comparator;
/**
 * This Class implements a Comparator that can be used to build TreeSet
 * containing FakeOperations sorted by the ChangeNumber order.
@@ -38,10 +38,11 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(FakeOperation op1, FakeOperation op2)
  {
    if (op1 == null)
      return -1;
    return op1.getChangeNumber().compareTo(op2.getChangeNumber());
    return op1.getCSN().compareTo(op2.getCSN());
  }
}
opends/src/server/org/opends/server/replication/plugin/HistoricalAttributeValue.java
@@ -31,10 +31,9 @@
import java.util.Set;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
/**
 * This class stores an internal usable representation of the value of
 * the historical related to an entry.
@@ -59,7 +58,7 @@
 *
 *  so after split
 *  token[0] will contain the attribute name
 *  token[1] will contain the change number
 *  token[1] will contain the CSN
 *  token[2] will contain the type of historical information
 *  token[3] will contain the attribute value
 *
@@ -72,8 +71,8 @@
  private AttributeType attrType;
  private String attrString;
  private AttributeValue attributeValue;
  private ChangeNumber cn;
  private LinkedHashSet<String> options;
  private CSN csn;
  private Set<String> options;
  private HistAttrModificationKey histKey;
  private String stringValue;
@@ -129,7 +128,7 @@
      }
    }
    cn = new ChangeNumber(token[1]);
    csn = new CSN(token[1]);
    histKey = HistAttrModificationKey.decodeKey(token[2]);
    stringValue = null;
    if (histKey != HistAttrModificationKey.DELATTR)
@@ -171,12 +170,12 @@
  }
  /**
   * Get the ChangeNUmber of this HistVal.
   * @return Returns the ChangeNumber of this HistVal.
   * Get the CSN of this HistVal.
   * @return Returns the CSN of this HistVal.
   */
  public ChangeNumber getCn()
  public CSN getCSN()
  {
    return cn;
    return csn;
  }
  /**
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -107,15 +107,13 @@
   */
  private class ScanSearchListener implements InternalSearchListener
  {
    private final ChangeNumber startingChangeNumber;
    private final ChangeNumber endChangeNumber;
    private final CSN startCSN;
    private final CSN endCSN;
    public ScanSearchListener(
        ChangeNumber startingChangeNumber,
        ChangeNumber endChangeNumber)
    public ScanSearchListener(CSN startCSN, CSN endCSN)
    {
      this.startingChangeNumber = startingChangeNumber;
      this.endChangeNumber = endChangeNumber;
      this.startCSN = startCSN;
      this.endCSN = endCSN;
    }
    @Override
@@ -123,20 +121,19 @@
        InternalSearchOperation searchOperation, SearchResultEntry searchEntry)
        throws DirectoryException
    {
      // Build the list of Operations that happened on this entry
      // after startingChangeNumber and before endChangeNumber and
      // add them to the replayOperations list
      // Build the list of Operations that happened on this entry after startCSN
      // and before endCSN and add them to the replayOperations list
      Iterable<FakeOperation> updates =
        EntryHistorical.generateFakeOperations(searchEntry);
      for (FakeOperation op : updates)
      {
        ChangeNumber cn = op.getChangeNumber();
        if ((cn.newer(startingChangeNumber)) && (cn.older(endChangeNumber)))
        CSN csn = op.getCSN();
        if (csn.newer(startCSN) && csn.older(endCSN))
        {
          synchronized (replayOperations)
          {
            replayOperations.put(cn, op);
            replayOperations.put(csn, op);
          }
        }
      }
@@ -184,7 +181,7 @@
  private volatile long generationId = -1;
  private volatile boolean generationIdSavedStatus = false;
  private final ChangeNumberGenerator generator;
  private final CSNGenerator generator;
  /**
   * This object is used to store the list of update currently being
@@ -222,8 +219,8 @@
   * This list is used to temporary store operations that needs to be replayed
   * at session establishment time.
   */
  private final SortedMap<ChangeNumber, FakeOperation> replayOperations =
    new TreeMap<ChangeNumber, FakeOperation>();
  private final SortedMap<CSN, FakeOperation> replayOperations =
    new TreeMap<CSN, FakeOperation>();
  /**
   * The isolation policy that this domain is going to use.
@@ -338,25 +335,25 @@
  /**
   * This configuration boolean indicates if this ReplicationDomain should log
   * ChangeNumbers.
   * CSNs.
   */
  private boolean logChangeNumber = false;
  private boolean logCSN = false;
  /**
   * This configuration integer indicates the time the domain keeps the
   * historical information necessary to solve conflicts.<br>
   * When a change stored in the historical part of the user entry has a date
   * (from its replication ChangeNumber) older than this delay, it is candidate
   * to be purged.
   * (from its replication CSN) older than this delay, it is candidate to be
   * purged.
   */
  private long histPurgeDelayInMilliSec = 0;
  /**
   * The last change number purged in this domain. Allows to have a continuous
   * purging process from one purge processing (task run) to the next one.
   * Values 0 when the server starts.
   * The last CSN purged in this domain. Allows to have a continuous purging
   * process from one purge processing (task run) to the next one. Values 0 when
   * the server starts.
   */
  private ChangeNumber lastChangeNumberPurgedFromHist = new ChangeNumber(0,0,0);
  private CSN lastCSNPurgedFromHist = new CSN(0,0,0);
  /**
   * The thread that periodically saves the ServerState of this
@@ -410,16 +407,14 @@
   */
  private class RSUpdater extends DirectoryThread
  {
    private final ChangeNumber startChangeNumber;
    private final CSN startCSN;
    protected RSUpdater(ChangeNumber replServerMaxChangeNumber)
    protected RSUpdater(CSN replServerMaxCSN)
    {
      super("Replica DS(" + serverId
          + ") missing change publisher for domain \""
          + baseDn.toString() + "\"");
      this.startChangeNumber = replServerMaxChangeNumber;
      this.startCSN = replServerMaxCSN;
    }
    /**
@@ -439,7 +434,7 @@
       */
      try
      {
        if (buildAndPublishMissingChanges(startChangeNumber, broker))
        if (buildAndPublishMissingChanges(startCSN, broker))
        {
          message = DEBUG_CHANGES_SENT.get();
          logError(message);
@@ -511,7 +506,7 @@
    this.isolationPolicy = configuration.getIsolationPolicy();
    this.configDn = configuration.dn();
    this.logChangeNumber = configuration.isLogChangenumber();
    this.logCSN = configuration.isLogChangenumber();
    this.updateToReplayQueue = updateToReplayQueue;
    this.histPurgeDelayInMilliSec =
      configuration.getConflictsHistoricalPurgeDelay()*60*1000;
@@ -549,17 +544,17 @@
    /*
     * Create a new Persistent Server State that will be used to store
     * the last ChangeNumber seen from all LDAP servers in the topology.
     * the last CSN seen from all LDAP servers in the topology.
     */
    state = new PersistentServerState(baseDn, serverId, getServerState());
    flushThread = new ServerStateFlush();
    /*
     * ChangeNumberGenerator is used to create new unique ChangeNumbers
     * for each operation done on this replication domain.
     * CSNGenerator is used to create new unique CSNs for each operation done on
     * this replication domain.
     *
     * The generator time is adjusted to the time of the last CN received from
     * The generator time is adjusted to the time of the last CSN received from
     * remote other servers.
     */
    generator = getGenerator();
@@ -1766,9 +1761,9 @@
    {
      // There is no replication context attached to the operation
      // so this is not a replication operation.
      ChangeNumber changeNumber = generateChangeNumber(deleteOperation);
      CSN csn = generateCSN(deleteOperation);
      String modifiedEntryUUID = EntryHistorical.getEntryUUID(deletedEntry);
      ctx = new DeleteContext(changeNumber, modifiedEntryUUID);
      ctx = new DeleteContext(csn, modifiedEntryUUID);
      deleteOperation.setAttachment(SYNCHROCONTEXT, ctx);
      synchronized (replayOperations)
@@ -1779,10 +1774,10 @@
          replayOperations.remove(replayOperations.firstKey());
        }
        replayOperations.put(
            changeNumber,
            csn,
            new FakeDelOperation(
                deleteOperation.getEntryDN().toString(),
                changeNumber,modifiedEntryUUID ));
                csn, modifiedEntryUUID));
      }
    }
@@ -2017,7 +2012,7 @@
       */
      EntryHistorical hist = EntryHistorical.newInstanceFromEntry(
          modifyDNOperation.getOriginalEntry());
      if (hist.addedOrRenamedAfter(ctx.getChangeNumber()))
      if (hist.addedOrRenamedAfter(ctx.getCSN()))
      {
        return new SynchronizationProviderResult.StopProcessing(
            ResultCode.NO_OPERATION, null);
@@ -2027,7 +2022,7 @@
    {
      // There is no replication context attached to the operation
      // so this is not a replication operation.
      ChangeNumber changeNumber = generateChangeNumber(modifyDNOperation);
      CSN csn = generateCSN(modifyDNOperation);
      String newParentId = null;
      if (modifyDNOperation.getNewSuperior() != null)
      {
@@ -2036,7 +2031,7 @@
      Entry modifiedEntry = modifyDNOperation.getOriginalEntry();
      String modifiedEntryUUID = EntryHistorical.getEntryUUID(modifiedEntry);
      ctx = new ModifyDnContext(changeNumber, modifiedEntryUUID, newParentId);
      ctx = new ModifyDnContext(csn, modifiedEntryUUID, newParentId);
      modifyDNOperation.setAttachment(SYNCHROCONTEXT, ctx);
    }
    return new SynchronizationProviderResult.ContinueProcessing();
@@ -2052,8 +2047,7 @@
  public SynchronizationProviderResult handleConflictResolution(
         PreOperationModifyOperation modifyOperation)
  {
    if ((!modifyOperation.isSynchronizationOperation())
        && (!brokerIsConnected()))
    if (!modifyOperation.isSynchronizationOperation() && !brokerIsConnected())
    {
      Message msg = ERR_REPLICATION_COULD_NOT_CONNECT.get(baseDn.toString());
      return new SynchronizationProviderResult.StopProcessing(
@@ -2112,12 +2106,12 @@
    if (ctx == null)
    {
      // No replication ctx attached => not a replicated operation
      // - create a ctx with : changeNumber, entryUUID
      // - create a ctx with : CSN, entryUUID
      // - attach the context to the op
      ChangeNumber changeNumber = generateChangeNumber(modifyOperation);
      CSN csn = generateCSN(modifyOperation);
      String modifiedEntryUUID = EntryHistorical.getEntryUUID(modifiedEntry);
      ctx = new ModifyContext(changeNumber, modifiedEntryUUID);
      ctx = new ModifyContext(csn, modifiedEntryUUID);
      modifyOperation.setAttachment(SYNCHROCONTEXT, ctx);
    }
@@ -2172,7 +2166,7 @@
   */
  public void doPreOperation(PreOperationAddOperation addOperation)
  {
    AddContext ctx = new AddContext(generateChangeNumber(addOperation),
    AddContext ctx = new AddContext(generateCSN(addOperation),
        EntryHistorical.getEntryUUID(addOperation),
        findEntryUUID(addOperation.getEntryDN().getParentDNInSuffix()));
@@ -2189,11 +2183,11 @@
    ResultCode result = op.getResultCode();
    // Note that a failed non-replication operation might not have a change
    // number.
    ChangeNumber curChangeNumber = OperationContext.getChangeNumber(op);
    if ((curChangeNumber != null) && (logChangeNumber))
    CSN curCSN = OperationContext.getCSN(op);
    if (curCSN != null && logCSN)
    {
      op.addAdditionalLogItem(AdditionalLogItem.unquotedKeyValue(getClass(),
          "replicationCN", curChangeNumber));
          "replicationCSN", curCSN));
    }
    if (result == ResultCode.SUCCESS)
@@ -2203,12 +2197,12 @@
        numReplayedPostOpCalled++;
        try
        {
          remotePendingChanges.commit(curChangeNumber);
          remotePendingChanges.commit(curCSN);
        }
        catch  (NoSuchElementException e)
        {
          Message message = ERR_OPERATION_NOT_FOUND_IN_PENDING.get(
              op.toString(), curChangeNumber.toString());
              op.toString(), curCSN.toString());
          logError(message);
          return;
        }
@@ -2225,7 +2219,7 @@
          * This is an operation type that we do not know about
          * It should never happen.
          */
          pendingChanges.remove(curChangeNumber);
          pendingChanges.remove(curCSN);
          Message message =
              ERR_UNKNOWN_TYPE.get(op.getOperationType().toString());
          logError(message);
@@ -2247,7 +2241,7 @@
        try
        {
          msg.encode();
          pendingChanges.commitAndPushCommittedChanges(curChangeNumber, msg);
          pendingChanges.commitAndPushCommittedChanges(curCSN, msg);
        } catch (UnsupportedEncodingException e)
        {
          // will be caught at publish time.
@@ -2255,7 +2249,7 @@
        catch  (NoSuchElementException e)
        {
          Message message = ERR_OPERATION_NOT_FOUND_IN_PENDING.get(
              op.toString(), curChangeNumber.toString());
              op.toString(), curCSN.toString());
          logError(message);
          return;
        }
@@ -2293,9 +2287,9 @@
    {
      // Remove an unsuccessful non-replication operation from the pending
      // changes list.
      if (curChangeNumber != null)
      if (curCSN != null)
      {
        pendingChanges.remove(curChangeNumber);
        pendingChanges.remove(curCSN);
        pendingChanges.pushCommittedChanges();
      }
    }
@@ -2352,20 +2346,20 @@
       attrs, null);
     Entry entryToRename = null;
     ChangeNumber entryToRenameCN = null;
     CSN entryToRenameCSN = null;
     for (SearchResultEntry entry : searchOp.getSearchEntries())
     {
       EntryHistorical history = EntryHistorical.newInstanceFromEntry(entry);
       if (entryToRename == null)
       {
         entryToRename = entry;
         entryToRenameCN = history.getDNDate();
         entryToRenameCSN = history.getDNDate();
       }
       else if (!history.addedOrRenamedAfter(entryToRenameCN))
       else if (!history.addedOrRenamedAfter(entryToRenameCSN))
       {
         // this conflict is older than the previous, keep it.
         entryToRename = entry;
         entryToRenameCN = history.getDNDate();
         entryToRenameCSN = history.getDNDate();
       }
     }
@@ -2519,7 +2513,7 @@
    Operation op = null;
    boolean replayDone = false;
    boolean dependency = false;
    ChangeNumber changeNumber = null;
    CSN csn = null;
    int retryCount = 10;
    // Try replay the operation, then flush (replaying) any pending operation
@@ -2547,7 +2541,7 @@
          // are processed locally.
          op.addRequestControl(new LDAPControl(OID_MANAGE_DSAIT_CONTROL));
          changeNumber = OperationContext.getChangeNumber(op);
          csn = OperationContext.getCSN(op);
          op.run();
          ResultCode result = op.getResultCode();
@@ -2616,7 +2610,7 @@
              // the update became a dummy update and the result
              // of the conflict resolution phase is to do nothing.
              // however we still need to push this change to the serverState
              updateError(changeNumber);
              updateError(csn);
            }
            else
            {
@@ -2645,7 +2639,7 @@
          logError(message);
          numUnresolvedNamingConflicts.incrementAndGet();
          replayErrorMsg = message.toString();
          updateError(changeNumber);
          updateError(csn);
        }
      } catch (ASN1Exception e)
      {
@@ -2658,7 +2652,7 @@
        replayErrorMsg = logDecodingOperationError(msg, e);
      } catch (Exception e)
      {
        if (changeNumber != null)
        if (csn != null)
        {
          /*
           * An Exception happened during the replay process.
@@ -2670,7 +2664,7 @@
            stackTraceToSingleLineString(e), op.toString());
          logError(message);
          replayErrorMsg = message.toString();
          updateError(changeNumber);
          updateError(csn);
        } else
        {
          replayErrorMsg = logDecodingOperationError(msg, e);
@@ -2691,7 +2685,7 @@
      // Prepare restart of loop
      replayDone = false;
      dependency = false;
      changeNumber = null;
      csn = null;
      retryCount = 10;
    } while (msg != null);
@@ -2711,13 +2705,13 @@
   * It is necessary because the postOperation does not always get
   * called when error or Exceptions happen during the operation replay.
   *
   * @param changeNumber the ChangeNumber of the operation with error.
   * @param csn the CSN of the operation with error.
   */
  public void updateError(ChangeNumber changeNumber)
  public void updateError(CSN csn)
  {
    try
    {
      remotePendingChanges.commit(changeNumber);
      remotePendingChanges.commit(csn);
    }
    catch (NoSuchElementException e)
    {
@@ -2726,21 +2720,20 @@
      if (debugEnabled())
      {
        TRACER.debugInfo(
                "LDAPReplicationDomain.updateError: Unable to find remote "
                    + "pending change for change number %s",
                changeNumber);
            "LDAPReplicationDomain.updateError: Unable to find remote "
                + "pending change for CSN %s", csn);
      }
    }
  }
  /**
   * Generate a new change number and insert it in the pending list.
   * Generate a new CSN and insert it in the pending list.
   *
   * @param operation The operation for which the change number must be
   *                  generated.
   * @return The new change number.
   * @param operation
   *          The operation for which the CSN must be generated.
   * @return The new CSN.
   */
  private ChangeNumber generateChangeNumber(PluginOperation operation)
  private CSN generateCSN(PluginOperation operation)
  {
    return pendingChanges.putLocalOperation(operation);
  }
@@ -2909,7 +2902,7 @@
      // The other type of errors can not be caused by naming conflicts.
      // Log a message for the repair tool.
      Message message = ERR_ERROR_REPLAYING_OPERATION.get(
          op.toString(), ctx.getChangeNumber().toString(),
          op.toString(), ctx.getCSN().toString(),
          result.toString(), op.getErrorMessage().toString());
      logError(message);
      return true;
@@ -2982,7 +2975,7 @@
     // The other type of errors can not be caused by naming conflicts.
     // Log a message for the repair tool.
     Message message = ERR_ERROR_REPLAYING_OPERATION.get(
         op.toString(), ctx.getChangeNumber().toString(),
         op.toString(), ctx.getCSN().toString(),
         result.toString(), op.getErrorMessage().toString());
     logError(message);
     return true;
@@ -3103,7 +3096,7 @@
    // The other type of errors can not be caused by naming conflicts.
    // Log a message for the repair tool.
    Message message = ERR_ERROR_REPLAYING_OPERATION.get(
        op.toString(), ctx.getChangeNumber().toString(),
        op.toString(), ctx.getCSN().toString(),
        result.toString(), op.getErrorMessage().toString());
    logError(message);
    return true;
@@ -3202,7 +3195,7 @@
      // The other type of errors can not be caused by naming conflicts.
      // log a message for the repair tool.
      Message message = ERR_ERROR_REPLAYING_OPERATION.get(
          op.toString(), ctx.getChangeNumber().toString(),
          op.toString(), ctx.getCSN().toString(),
          result.toString(), op.getErrorMessage().toString());
      logError(message);
      return true;
@@ -3493,7 +3486,7 @@
    state.clearInMemory();
    state.loadState();
    generator.adjust(state.getMaxChangeNumber(serverId));
    generator.adjust(state.getMaxCSN(serverId));
    // Retrieves the generation ID associated with the data imported
    generationId = loadGenerationId();
@@ -3909,8 +3902,7 @@
    {
      String includeAttributeStrings[] =
        {"objectclass", "sn", "cn", "entryuuid"};
      HashSet<AttributeType> includeAttributes;
      includeAttributes = new HashSet<AttributeType>();
      Set<AttributeType> includeAttributes = new HashSet<AttributeType>();
      for (String attrName : includeAttributeStrings)
      {
        AttributeType attrType  = DirectoryServer.getAttributeType(attrName);
@@ -4213,13 +4205,13 @@
  /**
   * Push the modifications contained in the given parameter as
   * a modification that would happen on a local server.
   * The modifications are not applied to the local database,
   * historical information is not updated but a ChangeNumber
   * is generated and the ServerState associated to this domain is
   * updated.
   * @param modifications The modification to push
   * Push the modifications contained in the given parameter as a modification
   * that would happen on a local server. The modifications are not applied to
   * the local database, historical information is not updated but a CSN is
   * generated and the ServerState associated to this domain is updated.
   *
   * @param modifications
   *          The modification to push
   */
  public void synchronizeModifications(List<Modification> modifications)
  {
@@ -4231,8 +4223,8 @@
                          modifications);
    LocalBackendModifyOperation localOp = new LocalBackendModifyOperation(op);
    ChangeNumber cn = generateChangeNumber(localOp);
    OperationContext ctx = new ModifyContext(cn, "schema");
    CSN csn = generateCSN(localOp);
    OperationContext ctx = new ModifyContext(csn, "schema");
    localOp.setAttachment(SYNCHROCONTEXT, ctx);
    localOp.setResultCode(ResultCode.SUCCESS);
    synchronize(localOp);
@@ -4290,7 +4282,7 @@
         ReplicationDomainCfg configuration)
  {
    isolationPolicy = configuration.getIsolationPolicy();
    logChangeNumber = configuration.isLogChangenumber();
    logCSN = configuration.isLogChangenumber();
    histPurgeDelayInMilliSec =
      configuration.getConflictsHistoricalPurgeDelay()*60*1000;
@@ -4400,9 +4392,7 @@
  {
    try
    {
      DN eclConfigEntryDN = DN.decode(
          "cn=external changeLog," + configDn);
      DN eclConfigEntryDN = DN.decode("cn=external changeLog," + configDn);
      if (DirectoryServer.getConfigHandler().entryExists(eclConfigEntryDN))
      {
        DirectoryServer.getConfigHandler().deleteEntry(eclConfigEntryDN, null);
@@ -4558,8 +4548,7 @@
       * Check that the ReplicationServer has seen all our previous
       * changes.
       */
      ChangeNumber replServerMaxChangeNumber =
        replicationServerState.getChangeNumber(serverId);
      CSN replServerMaxCSN = replicationServerState.getCSN(serverId);
      // we don't want to update from here (a DS) an empty RS because
      // normally the RS should have been updated by other RSes except for
@@ -4567,17 +4556,14 @@
      // ... hence the RS we are connected to should not be empty
      // ... or if it is empty, it is due to a voluntary reset
      // and we don't want to update it with our changes that could be huge.
      if ((replServerMaxChangeNumber != null) &&
          (replServerMaxChangeNumber.getSeqnum()!=0))
      if (replServerMaxCSN != null && replServerMaxCSN.getSeqnum() != 0)
      {
        ChangeNumber ourMaxChangeNumber = state.getMaxChangeNumber(serverId);
        if ((ourMaxChangeNumber != null) &&
            (!ourMaxChangeNumber.olderOrEqual(replServerMaxChangeNumber)))
        CSN ourMaxCSN = state.getMaxCSN(serverId);
        if (ourMaxCSN != null && !ourMaxCSN.olderOrEqual(replServerMaxCSN))
        {
          pendingChanges.setRecovering(true);
          broker.setRecoveryRequired(true);
          new RSUpdater(replServerMaxChangeNumber).start();
          new RSUpdater(replServerMaxCSN).start();
        }
      }
    } catch (Exception e)
@@ -4590,31 +4576,27 @@
  }
  /**
   * Build the list of changes that have been processed by this server
   * after the ChangeNumber given as a parameter and publish them
   * using the given session.
   * Build the list of changes that have been processed by this server after the
   * CSN given as a parameter and publish them using the given session.
   *
   * @param startingChangeNumber  The ChangeNumber where we need to start the
   *                              search
   * @param session               The session to use to publish the changes
   *
   * @return                      A boolean indicating he success of the
   *                              operation.
   * @throws Exception            if an Exception happens during the search.
   * @param startCSN
   *          The CSN where we need to start the search
   * @param session
   *          The session to use to publish the changes
   * @return A boolean indicating he success of the operation.
   * @throws Exception
   *           if an Exception happens during the search.
   */
  public boolean buildAndPublishMissingChanges(
      ChangeNumber startingChangeNumber,
      ReplicationBroker session)
      throws Exception
  public boolean buildAndPublishMissingChanges(CSN startCSN,
      ReplicationBroker session) throws Exception
  {
    // Trim the changes in replayOperations that are older than
    // the startingChangeNumber.
    // Trim the changes in replayOperations that are older than the startCSN.
    synchronized (replayOperations)
    {
      Iterator<ChangeNumber> it = replayOperations.keySet().iterator();
      Iterator<CSN> it = replayOperations.keySet().iterator();
      while (it.hasNext())
      {
        if (it.next().olderOrEqual(startingChangeNumber))
        if (it.next().olderOrEqual(startCSN))
        {
          it.remove();
        }
@@ -4625,9 +4607,9 @@
      }
    }
    ChangeNumber lastRetrievedChange;
    CSN lastRetrievedChange;
    InternalSearchOperation op;
    ChangeNumber currentStartChangeNumber = startingChangeNumber;
    CSN currentStartCSN = startCSN;
    do
    {
      lastRetrievedChange = null;
@@ -4637,18 +4619,15 @@
      // So we search by interval of 10 seconds
      // and store the results in the replayOperations list
      // so that they are sorted before sending them.
      long missingChangesDelta = currentStartChangeNumber.getTime() + 10000;
      ChangeNumber endChangeNumber =
        new ChangeNumber(
            missingChangesDelta, 0xffffffff, serverId);
      long missingChangesDelta = currentStartCSN.getTime() + 10000;
      CSN endCSN = new CSN(missingChangesDelta, 0xffffffff, serverId);
      ScanSearchListener listener =
        new ScanSearchListener(currentStartChangeNumber, endChangeNumber);
      op = searchForChangedEntries(
          baseDn, currentStartChangeNumber, endChangeNumber, listener);
        new ScanSearchListener(currentStartCSN, endCSN);
      op = searchForChangedEntries(baseDn, currentStartCSN, endCSN, listener);
      // Publish and remove all the changes from the replayOperations list
      // that are older than the endChangeNumber.
      // that are older than the endCSN.
      List<FakeOperation> opsToSend = new LinkedList<FakeOperation>();
      synchronized (replayOperations)
      {
@@ -4656,10 +4635,10 @@
        while (itOp.hasNext())
        {
          FakeOperation fakeOp = itOp.next();
          if ((fakeOp.getChangeNumber().olderOrEqual(endChangeNumber))
              && state.cover(fakeOp.getChangeNumber()))
          if ((fakeOp.getCSN().olderOrEqual(endCSN))
              && state.cover(fakeOp.getCSN()))
          {
            lastRetrievedChange = fakeOp.getChangeNumber();
            lastRetrievedChange = fakeOp.getCSN();
            opsToSend.add(fakeOp);
            itOp.remove();
          }
@@ -4677,11 +4656,11 @@
      opsToSend.clear();
      if (lastRetrievedChange != null)
      {
        currentStartChangeNumber = lastRetrievedChange;
        currentStartCSN = lastRetrievedChange;
      }
      else
      {
        currentStartChangeNumber = endChangeNumber;
        currentStartCSN = endCSN;
      }
    } while (pendingChanges.recoveryUntil(lastRetrievedChange) &&
@@ -4692,47 +4671,48 @@
  /**
   * Search for the changes that happened since fromChangeNumber
   * based on the historical attribute. The only changes that will
   * be send will be the one generated on the serverId provided in
   * fromChangeNumber.
   * @param baseDn the base DN
   * @param fromChangeNumber The ChangeNumber from which we want the changes
   * @param lastChangeNumber The max ChangeNumber that the search should return
   * @param resultListener   The listener that will process the entries returned
   * Search for the changes that happened since fromCSN based on the historical
   * attribute. The only changes that will be send will be the one generated on
   * the serverId provided in fromCSN.
   *
   * @param baseDn
   *          the base DN
   * @param fromCSN
   *          The CSN from which we want the changes
   * @param lastCSN
   *          The max CSN that the search should return
   * @param resultListener
   *          The listener that will process the entries returned
   * @return the internal search operation
   * @throws Exception when raised.
   * @throws Exception
   *           when raised.
   */
  public static InternalSearchOperation searchForChangedEntries(
    DN baseDn,
    ChangeNumber fromChangeNumber,
    ChangeNumber lastChangeNumber,
    InternalSearchListener resultListener)
    throws Exception
  public static InternalSearchOperation searchForChangedEntries(DN baseDn,
      CSN fromCSN, CSN lastCSN, InternalSearchListener resultListener)
      throws Exception
  {
    InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
    Integer serverId = fromChangeNumber.getServerId();
    Integer serverId = fromCSN.getServerId();
    String maxValueForId;
    if (lastChangeNumber == null)
    if (lastCSN == null)
    {
      maxValueForId = "ffffffffffffffff" + String.format("%04x", serverId)
                      + "ffffffff";
    }
    else
    {
      maxValueForId = lastChangeNumber.toString();
      maxValueForId = lastCSN.toString();
    }
    LDAPFilter filter = LDAPFilter.decode(
       "(&(" + EntryHistorical.HISTORICAL_ATTRIBUTE_NAME + ">=dummy:"
       + fromChangeNumber + ")(" + EntryHistorical.HISTORICAL_ATTRIBUTE_NAME +
       "<=dummy:" + maxValueForId + "))");
        "(&(" + HISTORICAL_ATTRIBUTE_NAME + ">=dummy:" + fromCSN + ")" +
          "(" + HISTORICAL_ATTRIBUTE_NAME + "<=dummy:" + maxValueForId + "))");
    Set<String> attrs = new LinkedHashSet<String>(1);
    attrs.add(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME);
    attrs.add(EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME);
    Set<String> attrs = new LinkedHashSet<String>(3);
    attrs.add(HISTORICAL_ATTRIBUTE_NAME);
    attrs.add(ENTRYUUID_ATTRIBUTE_NAME);
    attrs.add("*");
    return conn.processSearch(
      ByteString.valueOf(baseDn.toString()),
@@ -4744,24 +4724,24 @@
  }
  /**
   * Search for the changes that happened since fromChangeNumber
   * based on the historical attribute. The only changes that will
   * be send will be the one generated on the serverId provided in
   * fromChangeNumber.
   * @param baseDn the base DN
   * @param fromChangeNumber The change number from which we want the changes
   * @param resultListener that will process the entries returned.
   * Search for the changes that happened since fromCSN based on the historical
   * attribute. The only changes that will be send will be the one generated on
   * the serverId provided in fromCSN.
   *
   * @param baseDn
   *          the base DN
   * @param fromCSN
   *          The CSN from which we want the changes
   * @param resultListener
   *          that will process the entries returned.
   * @return the internal search operation
   * @throws Exception when raised.
   * @throws Exception
   *           when raised.
   */
  public static InternalSearchOperation searchForChangedEntries(
    DN baseDn,
    ChangeNumber fromChangeNumber,
    InternalSearchListener resultListener)
    throws Exception
  public static InternalSearchOperation searchForChangedEntries(DN baseDn,
      CSN fromCSN, InternalSearchListener resultListener) throws Exception
  {
    return searchForChangedEntries(
        baseDn, fromChangeNumber, null, resultListener);
    return searchForChangedEntries(baseDn, fromCSN, null, resultListener);
  }
@@ -4778,7 +4758,6 @@
  public long countEntries() throws DirectoryException
  {
    Backend backend = retrievesBackend(baseDn);
    if (!backend.supportsLDIFExport())
    {
      Message message = ERR_INIT_EXPORT_NOT_SUPPORTED.get(
@@ -5515,24 +5494,24 @@
     TRACER.debugInfo("[PURGE] purgeConflictsHistorical "
         + "on domain: " + baseDn
         + "endDate:" + new Date(endDate)
         + "lastChangeNumberPurgedFromHist: "
         + lastChangeNumberPurgedFromHist.toStringUI());
         + "lastCSNPurgedFromHist: "
         + lastCSNPurgedFromHist.toStringUI());
     LDAPFilter filter = null;
     try
     {
       filter = LDAPFilter.decode(
         "(" + EntryHistorical.HISTORICAL_ATTRIBUTE_NAME + ">=dummy:"
         + lastChangeNumberPurgedFromHist + ")");
         + lastCSNPurgedFromHist + ")");
     } catch (LDAPException e)
     {
       // Not possible. We know the filter just above is correct.
     }
     Set<String> attrs = new LinkedHashSet<String>(1);
     attrs.add(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME);
     attrs.add(EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME);
     Set<String> attrs = new LinkedHashSet<String>(3);
     attrs.add(HISTORICAL_ATTRIBUTE_NAME);
     attrs.add(ENTRYUUID_ATTRIBUTE_NAME);
     attrs.add("*");
     InternalSearchOperation searchOp =  conn.processSearch(
         ByteString.valueOf(baseDn.toString()),
@@ -5544,7 +5523,7 @@
     int count = 0;
     if (task != null)
       task.setProgressStats(lastChangeNumberPurgedFromHist, count);
       task.setProgressStats(lastCSNPurgedFromHist, count);
     for (SearchResultEntry entry : searchOp.getSearchEntries())
     {
@@ -5556,7 +5535,7 @@
       }
       EntryHistorical entryHist = EntryHistorical.newInstanceFromEntry(entry);
       lastChangeNumberPurgedFromHist = entryHist.getOldestCN();
       lastCSNPurgedFromHist = entryHist.getOldestCSN();
       entryHist.setPurgeDelay(this.histPurgeDelayInMilliSec);
       Attribute attr = entryHist.encodeAndPurge();
       count += entryHist.getLastPurgedValuesCount();
@@ -5583,7 +5562,7 @@
       }
       else if (task != null)
       {
         task.setProgressStats(lastChangeNumberPurgedFromHist, count);
         task.setProgressStats(lastCSNPurgedFromHist, count);
       }
     }
  }
opends/src/server/org/opends/server/replication/plugin/PendingChange.java
@@ -23,10 +23,11 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.types.DN;
@@ -39,12 +40,12 @@
 */
public class PendingChange implements Comparable<PendingChange>
{
  private ChangeNumber changeNumber;
  private CSN changeNumber;
  private boolean committed;
  private LDAPUpdateMsg msg;
  private PluginOperation op;
  private ServerState dependencyState = null;
  private DN targetDN = null;
  private ServerState dependencyState;
  private DN targetDN;
  /**
   * Construct a new PendingChange.
@@ -52,7 +53,7 @@
   * @param op the operation to use
   * @param msg the message to use (can be null for local operations)
   */
  public PendingChange(ChangeNumber changeNumber,
  public PendingChange(CSN changeNumber,
                       PluginOperation op,
                       LDAPUpdateMsg msg)
  {
@@ -84,7 +85,7 @@
   * Get the ChangeNumber associated to this PendingChange.
   * @return the ChangeNumber
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
  }
@@ -133,7 +134,7 @@
   * @param changeNumber The ChangeNumber to add in the list of dependencies
   *                     of this PendingChange.
   */
  public void addDependency(ChangeNumber changeNumber)
  public void addDependency(CSN changeNumber)
  {
    if (dependencyState == null)
    {
@@ -184,8 +185,9 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public int compareTo(PendingChange o)
  {
    return this.getChangeNumber().compareTo(o.getChangeNumber());
    return this.getCSN().compareTo(o.getCSN());
  }
}
opends/src/server/org/opends/server/replication/plugin/PendingChanges.java
@@ -31,8 +31,8 @@
import java.util.SortedMap;
import java.util.TreeMap;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.replication.service.ReplicationDomain;
import org.opends.server.types.operation.PluginOperation;
@@ -42,7 +42,7 @@
 * in progress and not yet committed in the database.
 *
 * It is used to make sure that operations are sent to the Replication
 * Server in the order defined by their ChangeNumber.
 * Server in the order defined by their CSN.
 * It is also used to update the ServerState at the appropriate time.
 *
 * On object of this class is instantiated for each ReplicationDomain.
@@ -52,14 +52,14 @@
  /**
   * A map used to store the pending changes.
   */
  private SortedMap<ChangeNumber, PendingChange> pendingChanges =
    new TreeMap<ChangeNumber, PendingChange>();
  private SortedMap<CSN, PendingChange> pendingChanges =
    new TreeMap<CSN, PendingChange>();
  /**
   * The ChangeNumberGenerator to use to create new unique ChangeNumbers
   * The {@link CSNGenerator} to use to create new unique CSNs
   * for each operation done on the replication domain.
   */
  private ChangeNumberGenerator changeNumberGenerator;
  private CSNGenerator csnGenerator;
  /**
   * The ReplicationDomain that will be used to send UpdateMsg.
@@ -69,30 +69,28 @@
  private boolean recoveringOldChanges = false;
  /**
   * Creates a new PendingChanges using the provided ChangeNumberGenerator.
   * Creates a new PendingChanges using the provided CSNGenerator.
   *
   * @param changeNumberGenerator The ChangeNumberGenerator to use to create
   *                               new unique ChangeNumbers.
   * @param domain  The ReplicationDomain that will be used to send
   *                UpdateMsg.
   * @param csnGenerator The CSNGenerator to use to create new unique CSNs.
   * @param domain  The ReplicationDomain that will be used to send UpdateMsg.
   */
  public PendingChanges(
      ChangeNumberGenerator changeNumberGenerator, ReplicationDomain domain)
      CSNGenerator csnGenerator, ReplicationDomain domain)
  {
    this.changeNumberGenerator = changeNumberGenerator;
    this.csnGenerator = csnGenerator;
    this.domain = domain;
  }
  /**
   * Remove and return an update form the pending changes list.
   *
   * @param changeNumber The ChangeNumber of the update to remove.
   *
   * @param csn
   *          The CSN of the update to remove.
   * @return The UpdateMsg that was just removed.
   */
  public synchronized LDAPUpdateMsg remove(ChangeNumber changeNumber)
  public synchronized LDAPUpdateMsg remove(CSN csn)
  {
    return pendingChanges.remove(changeNumber).getMsg();
    return pendingChanges.remove(csn).getMsg();
  }
  /**
@@ -108,14 +106,12 @@
  /**
   * Mark an update message as committed.
   *
   * @param changeNumber The ChangeNumber of the update message that must be
   *                     set as committed.
   * @param csn The CSN of the update message that must be set as committed.
   * @param msg          The message associated to the update.
   */
  public synchronized void commit(ChangeNumber changeNumber,
      LDAPUpdateMsg msg)
  public synchronized void commit(CSN csn,      LDAPUpdateMsg msg)
  {
    PendingChange curChange = pendingChanges.get(changeNumber);
    PendingChange curChange = pendingChanges.get(csn);
    if (curChange == null)
    {
      throw new NoSuchElementException();
@@ -127,12 +123,11 @@
  /**
   * Mark an update message as committed.
   *
   * @param changeNumber The ChangeNumber of the update message that must be
   *                     set as committed.
   * @param csn The CSN of the update message that must be set as committed.
   */
  public synchronized void commit(ChangeNumber changeNumber)
  public synchronized void commit(CSN csn)
  {
    PendingChange curChange = pendingChanges.get(changeNumber);
    PendingChange curChange = pendingChanges.get(csn);
    if (curChange == null)
    {
      throw new NoSuchElementException();
@@ -146,14 +141,14 @@
   *
   * @param operation The local operation for which an UpdateMsg must
   *                  be added in the pending list.
   * @return The ChangeNumber now associated to the operation.
   * @return The CSN now associated to the operation.
   */
  public synchronized ChangeNumber putLocalOperation(PluginOperation operation)
  public synchronized CSN putLocalOperation(PluginOperation operation)
  {
    ChangeNumber changeNumber = changeNumberGenerator.newChangeNumber();
    PendingChange change = new PendingChange(changeNumber, operation, null);
    pendingChanges.put(changeNumber, change);
    return changeNumber;
    CSN csn = csnGenerator.newCSN();
    PendingChange change = new PendingChange(csn, operation, null);
    pendingChanges.put(csn, change);
    return csn;
  }
  /**
@@ -169,9 +164,9 @@
      return numSentUpdates;
    }
    // peek the oldest changeNumber
    ChangeNumber firstChangeNumber = pendingChanges.firstKey();
    PendingChange firstChange = pendingChanges.get(firstChangeNumber);
    // peek the oldest CSN
    CSN firstCSN = pendingChanges.firstKey();
    PendingChange firstChange = pendingChanges.get(firstCSN);
    while (firstChange != null && firstChange.isCommitted())
    {
@@ -188,10 +183,10 @@
        {
          // do not push updates until the RS catches up.
          // @see #setRecovering(boolean)
          domain.getServerState().update(updateMsg.getChangeNumber());
          domain.getServerState().update(updateMsg.getCSN());
        }
      }
      pendingChanges.remove(firstChangeNumber);
      pendingChanges.remove(firstCSN);
      if (pendingChanges.isEmpty())
      {
@@ -199,9 +194,9 @@
      }
      else
      {
        // peek the oldest changeNumber
        firstChangeNumber = pendingChanges.firstKey();
        firstChange = pendingChanges.get(firstChangeNumber);
        // peek the oldest CSN
        firstCSN = pendingChanges.firstKey();
        firstChange = pendingChanges.get(firstCSN);
      }
    }
    return numSentUpdates;
@@ -213,52 +208,50 @@
   * in a single atomic operation.
   *
   *
   * @param changeNumber The ChangeNumber of the update message that must be
   *                     set as committed.
   * @param csn The CSN of the update message that must be set as committed.
   * @param msg          The message associated to the update.
   *
   * @return The number of pushed updates.
   */
  public synchronized int commitAndPushCommittedChanges(
      ChangeNumber changeNumber, LDAPUpdateMsg msg)
  public synchronized int commitAndPushCommittedChanges(CSN csn,
      LDAPUpdateMsg msg)
  {
    commit(changeNumber, msg);
    commit(csn, msg);
    return pushCommittedChanges();
  }
  /**
   * Set the PendingChangesList structure in a mode where it is
   * waiting for the RS to receive all the previous changes to
   * be sent before starting to process the changes normally.
   * In this mode, The Domain does not publish the changes from
   * the pendingChanges because there are older changes that
   * need to be published before.
   * Set the PendingChangesList structure in a mode where it is waiting for the
   * RS to receive all the previous changes to be sent before starting to
   * process the changes normally. In this mode, The Domain does not publish the
   * changes from the pendingChanges because there are older changes that need
   * to be published before.
   *
   * @param b The recovering status that must be set.
   * @param recovering
   *          The recovering status that must be set.
   */
  public void setRecovering(boolean b)
  public void setRecovering(boolean recovering)
  {
    recoveringOldChanges = b;
    recoveringOldChanges = recovering;
  }
  /**
   * Allows to update the recovery situation by comparing the ChangeNumber of
   * the last change that was sent to the ReplicationServer with the
   * ChangeNumber of the last operation that was taken out of the
   * PendingChanges list.
   * If he two match then the recovery is completed and normal procedure can
   * restart. Otherwise the RSUpdate thread must continue to look for
   * older changes and no changes can be committed from the pendingChanges list.
   * Allows to update the recovery situation by comparing the CSN of the last
   * change that was sent to the ReplicationServer with the CSN of the last
   * operation that was taken out of the PendingChanges list. If the two match
   * then the recovery is completed and normal procedure can restart. Otherwise
   * the RSUpdate thread must continue to look for older changes and no changes
   * can be committed from the pendingChanges list.
   *
   * @param recovered  The ChangeNumber of the last change that was published
   *                   to the ReplicationServer.
   *
   * @return           A boolean indicating if the recovery is completed (false)
   *                   or must continue (true).
   * @param recovered
   *          The CSN of the last change that was published to the
   *          ReplicationServer.
   * @return A boolean indicating if the recovery is completed (false) or must
   *         continue (true).
   */
  public synchronized boolean recoveryUntil(ChangeNumber recovered)
  public synchronized boolean recoveryUntil(CSN recovered)
  {
    ChangeNumber lastLocalChange = domain.getLastLocalChange();
    CSN lastLocalChange = domain.getLastLocalChange();
    if (recovered != null && recovered.newerOrEquals(lastLocalChange))
    {
      recoveringOldChanges = false;
opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -26,38 +26,25 @@
 *      Portions copyright 2012-2013 ForgeRock AS.
 */
package org.opends.server.replication.plugin;
import org.opends.messages.Message;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.messages.ReplicationMessages.*;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.opends.messages.Message;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ModificationType;
import org.opends.server.types.RawModification;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
import org.opends.server.types.*;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
/**
 * This class implements a ServerState that is stored in the backend
@@ -108,29 +95,28 @@
  }
  /**
   * Checks that the ChangeNumber given as a parameter is in this ServerState.
   * Checks that the CSN given as a parameter is in this ServerState.
   *
   * @param   covered The ChangeNumber that should be checked.
   * @return  A boolean indicating if this ServerState contains the ChangeNumber
   * @param   covered The CSN that should be checked.
   * @return  A boolean indicating if this ServerState contains the CSN
   *          given in parameter.
   */
  public boolean cover(ChangeNumber covered)
  public boolean cover(CSN covered)
  {
    return state.cover(covered);
  }
  /**
   * Update the Server State with a ChangeNumber.
   * All operations with smaller CSN and the same serverID must be committed
   * before calling this method.
   * Update the Server State with a CSN. All operations with smaller CSN and the
   * same serverID must be committed before calling this method.
   *
   * @param changeNumber    The committed ChangeNumber.
   *
   * @param csn
   *          The committed CSN.
   * @return a boolean indicating if the update was meaningful.
   */
  public boolean update(ChangeNumber changeNumber)
  public boolean update(CSN csn)
  {
    return state.update(changeNumber);
    return state.update(csn);
  }
  /**
@@ -288,8 +274,7 @@
      Attribute attr = attrs.get(0);
      for (AttributeValue value : attr)
      {
        ChangeNumber changeNumber = new ChangeNumber(value.toString());
        update(changeNumber);
        update(new CSN(value.toString()));
      }
    }
  }
@@ -396,23 +381,23 @@
  public final void checkAndUpdateServerState() {
    Message message;
    InternalSearchOperation op;
    ChangeNumber serverStateMaxCn;
    ChangeNumber dbMaxCn;
    CSN serverStateMaxCsn;
    CSN dbMaxCsn;
    final AttributeType histType = DirectoryServer.getAttributeType(
          EntryHistorical.HISTORICAL_ATTRIBUTE_NAME);
    // Retrieves the entries that have changed since the
    // maxCn stored in the serverState
    // maxCsn stored in the serverState
    synchronized (this)
    {
      serverStateMaxCn = state.getChangeNumber(serverId);
      serverStateMaxCsn = state.getCSN(serverId);
      if (serverStateMaxCn == null)
      if (serverStateMaxCsn == null)
        return;
      try {
        op = LDAPReplicationDomain.searchForChangedEntries(baseDn,
            serverStateMaxCn, null);
            serverStateMaxCsn, null);
      }
      catch (Exception  e)
      {
@@ -428,7 +413,7 @@
      }
      else
      {
        dbMaxCn = serverStateMaxCn;
        dbMaxCsn = serverStateMaxCsn;
        for (SearchResultEntry resEntry : op.getSearchEntries())
        {
          for (AttributeValue attrValue :
@@ -436,27 +421,26 @@
          {
            HistoricalAttributeValue histVal =
                new HistoricalAttributeValue(attrValue.toString());
            ChangeNumber cn = histVal.getCn();
            if ((cn != null) && (cn.getServerId() == serverId))
            CSN csn = histVal.getCSN();
            if (csn != null && csn.getServerId() == serverId)
            {
              // compare the csn regarding the maxCn we know and
              // compare the csn regarding the maxCsn we know and
              // store the biggest
              if (ChangeNumber.compare(dbMaxCn, cn) < 0)
              if (CSN.compare(dbMaxCsn, csn) < 0)
              {
                dbMaxCn = cn;
                dbMaxCsn = csn;
              }
            }
          }
        }
        if (ChangeNumber.compare(dbMaxCn, serverStateMaxCn) > 0)
        if (CSN.compare(dbMaxCsn, serverStateMaxCsn) > 0)
        {
          // Update the serverState with the new maxCn
          // Update the serverState with the new maxCsn
          // present in the database
          this.update(dbMaxCn);
          this.update(dbMaxCsn);
          message = NOTE_SERVER_STATE_RECOVERY.get(
              baseDn.toNormalizedString(), dbMaxCn.toString());
              baseDn.toNormalizedString(), dbMaxCsn.toString());
          logError(message);
        }
      }
@@ -464,14 +448,14 @@
  }
  /**
   * Get the largest ChangeNumber seen for a given LDAP server ID.
   * Get the largest CSN seen for a given LDAP server ID.
   *
   * @param serverID    The server ID.
   *
   * @return            The largest ChangeNumber seen.
   * @param serverId
   *          The serverId
   * @return The largest CSN seen
   */
  public ChangeNumber getMaxChangeNumber(int serverID)
  public CSN getMaxCSN(int serverId)
  {
    return state.getChangeNumber(serverID);
    return state.getCSN(serverId);
  }
}
opends/src/server/org/opends/server/replication/plugin/RemotePendingChanges.java
@@ -27,28 +27,19 @@
 */
package org.opends.server.replication.plugin;
import java.util.NoSuchElementException;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.*;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
import org.opends.server.replication.protocol.OperationContext;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.replication.protocol.*;
import org.opends.server.types.DN;
import org.opends.server.types.Operation;
/**
 *
 * This class is used to store the list of remote changes received
 * from a replication server and that are either currently being replayed
 * or that are waiting for being replayed.
@@ -57,15 +48,14 @@
 * the dependencies between operations.
 *
 * One of this object is instantiated for each ReplicationDomain.
 *
 */
public final class RemotePendingChanges
{
  /**
   * A map used to store the pending changes.
   */
  private SortedMap<ChangeNumber, PendingChange> pendingChanges =
    new TreeMap<ChangeNumber, PendingChange>();
  private SortedMap<CSN, PendingChange> pendingChanges =
    new TreeMap<CSN, PendingChange>();
  /**
   * A sorted set containing the list of PendingChanges that have
@@ -110,33 +100,32 @@
   */
  public synchronized void putRemoteUpdate(LDAPUpdateMsg update)
  {
    ChangeNumber changeNumber = update.getChangeNumber();
    pendingChanges.put(changeNumber, new PendingChange(changeNumber, null,
                                                        update));
    CSN csn = update.getCSN();
    pendingChanges.put(csn, new PendingChange(csn, null, update));
  }
  /**
   * Mark an update message as committed.
   *
   * @param changeNumber The ChangeNumber of the update message that must be
   *                     set as committed.
   * @param csn
   *          The CSN of the update message that must be set as committed.
   */
  public synchronized void commit(ChangeNumber changeNumber)
  public synchronized void commit(CSN csn)
  {
    PendingChange curChange = pendingChanges.get(changeNumber);
    PendingChange curChange = pendingChanges.get(csn);
    if (curChange == null)
    {
      throw new NoSuchElementException();
    }
    curChange.setCommitted(true);
    ChangeNumber firstChangeNumber = pendingChanges.firstKey();
    PendingChange firstChange = pendingChanges.get(firstChangeNumber);
    CSN firstCSN = pendingChanges.firstKey();
    PendingChange firstChange = pendingChanges.get(firstCSN);
    while ((firstChange != null) && firstChange.isCommitted())
    {
      state.update(firstChangeNumber);
      pendingChanges.remove(firstChangeNumber);
      state.update(firstCSN);
      pendingChanges.remove(firstCSN);
      if (pendingChanges.isEmpty())
      {
@@ -144,8 +133,8 @@
      }
      else
      {
        firstChangeNumber = pendingChanges.firstKey();
        firstChange = pendingChanges.get(firstChangeNumber);
        firstCSN = pendingChanges.firstKey();
        firstChange = pendingChanges.get(firstCSN);
      }
    }
  }
@@ -182,7 +171,7 @@
  private void addDependency(
      PendingChange dependentChange, PendingChange pendingChange)
  {
    dependentChange.addDependency(pendingChange.getChangeNumber());
    dependentChange.addDependency(pendingChange.getCSN());
    dependentChanges.add(dependentChange);
  }
@@ -206,14 +195,14 @@
  {
    boolean hasDependencies = false;
    DN targetDn = op.getEntryDN();
    ChangeNumber changeNumber = OperationContext.getChangeNumber(op);
    PendingChange change = pendingChanges.get(changeNumber);
    CSN csn = OperationContext.getCSN(op);
    PendingChange change = pendingChanges.get(csn);
    if (change == null)
      return false;
    for (PendingChange pendingChange : pendingChanges.values())
    {
      if (pendingChange.getChangeNumber().older(changeNumber))
      if (pendingChange.getCSN().older(csn))
      {
        LDAPUpdateMsg pendingMsg = pendingChange.getMsg();
        if (pendingMsg != null)
@@ -296,14 +285,14 @@
  {
    boolean hasDependencies = false;
    DN targetDn = op.getEntryDN();
    ChangeNumber changeNumber = OperationContext.getChangeNumber(op);
    PendingChange change = pendingChanges.get(changeNumber);
    CSN csn = OperationContext.getCSN(op);
    PendingChange change = pendingChanges.get(csn);
    if (change == null)
      return false;
    for (PendingChange pendingChange : pendingChanges.values())
    {
      if (pendingChange.getChangeNumber().older(changeNumber))
      if (pendingChange.getCSN().older(csn))
      {
        LDAPUpdateMsg pendingMsg = pendingChange.getMsg();
        if (pendingMsg != null)
@@ -354,8 +343,8 @@
  public synchronized boolean checkDependencies(ModifyDNMsg msg)
  {
    boolean hasDependencies = false;
    ChangeNumber changeNumber = msg.getChangeNumber();
    PendingChange change = pendingChanges.get(changeNumber);
    CSN csn = msg.getCSN();
    PendingChange change = pendingChanges.get(csn);
    if (change == null)
      return false;
@@ -364,7 +353,7 @@
    for (PendingChange pendingChange : pendingChanges.values())
    {
      if (pendingChange.getChangeNumber().older(changeNumber))
      if (pendingChange.getCSN().older(csn))
      {
        LDAPUpdateMsg pendingMsg = pendingChange.getMsg();
        if (pendingMsg != null)
@@ -441,14 +430,14 @@
  {
    boolean hasDependencies = false;
    DN targetDn = op.getEntryDN();
    ChangeNumber changeNumber = OperationContext.getChangeNumber(op);
    PendingChange change = pendingChanges.get(changeNumber);
    CSN csn = OperationContext.getCSN(op);
    PendingChange change = pendingChanges.get(csn);
    if (change == null)
      return false;
    for (PendingChange pendingChange : pendingChanges.values())
    {
      if (pendingChange.getChangeNumber().older(changeNumber))
      if (pendingChange.getCSN().older(csn))
      {
        LDAPUpdateMsg pendingMsg = pendingChange.getMsg();
        if (pendingMsg != null)
opends/src/server/org/opends/server/replication/protocol/AckMsg.java
@@ -34,14 +34,13 @@
import java.util.List;
import java.util.zip.DataFormatException;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * AckMsg messages are used for acknowledging an update that has been sent
 * requesting an ack: update sent in Assured Mode, either safe data or safe
 * read sub mode.
 * The change number refers to the update change number that was requested to be
 * acknowledged.
 * The CSN refers to the update CSN that was requested to be acknowledged.
 * If some errors occurred during attempt to acknowledge the update in the path
 * to final servers, errors are marked with the following fields:
 * - hasTimeout:
@@ -61,49 +60,57 @@
 */
public class AckMsg extends ReplicationMsg
{
  // ChangeNumber of the update that was acked.
  private ChangeNumber changeNumber;
  /** CSN of the update that was acked. */
  private CSN csn;
  // Did some servers go in timeout when the matching update (corresponding to
  // change number) was sent ?
  /**
   * Did some servers go in timeout when the matching update (corresponding to
   * CSN) was sent?.
   */
  private boolean hasTimeout = false;
  // Were some servers in wrong status when the matching
  // update (correspondig to change number) was sent ?
  /**
   * Were some servers in wrong status when the matching update (corresponding
   * to CSN) was sent?.
   */
  private boolean hasWrongStatus = false;
  // Did some servers make an error replaying the sent matching update
  // (corresponding to change number) ?
  /**
   * Did some servers make an error replaying the sent matching update
   * (corresponding to CSN)?.
   */
  private boolean hasReplayError = false;
  // The list of server ids that had errors for the sent matching update
  // (corresponding to change number). Each server id of the list had one of the
  // 3 possible errors (timeout/degraded or admin/replay error)
  /**
   * The list of server ids that had errors for the sent matching update
   * (corresponding to CSN). Each server id of the list had one of the 3
   * possible errors (timeout/degraded or admin/replay error).
   */
  private List<Integer> failedServers = new ArrayList<Integer>();
  /**
   * Creates a new AckMsg from a ChangeNumber (no errors).
   * Creates a new AckMsg from a CSN (no errors).
   *
   * @param changeNumber The ChangeNumber used to build the AckMsg.
   * @param csn The CSN used to build the AckMsg.
   */
  public AckMsg(ChangeNumber changeNumber)
  public AckMsg(CSN csn)
  {
    this.changeNumber = changeNumber;
    this.csn = csn;
  }
  /**
   * Creates a new AckMsg from a ChangeNumber (with specified error info).
   * Creates a new AckMsg from a CSN (with specified error info).
   *
   * @param changeNumber The ChangeNumber used to build the AckMsg.
   * @param csn The CSN used to build the AckMsg.
   * @param hasTimeout The hasTimeout info
   * @param hasWrongStatus The hasWrongStatus info
   * @param hasReplayError The hasReplayError info
   * @param failedServers The list of failed servers
   */
  public AckMsg(ChangeNumber changeNumber, boolean hasTimeout,
    boolean hasWrongStatus, boolean hasReplayError, List<Integer> failedServers)
  public AckMsg(CSN csn, boolean hasTimeout, boolean hasWrongStatus,
      boolean hasReplayError, List<Integer> failedServers)
  {
    this.changeNumber = changeNumber;
    this.csn = csn;
    this.hasTimeout = hasTimeout;
    this.hasWrongStatus = hasWrongStatus;
    this.hasReplayError = hasReplayError;
@@ -159,33 +166,33 @@
    {
      /*
       * The message is stored in the form:
       * <operation type><change number><has timeout><has degraded><has replay
       * <operation type><CSN><has timeout><has degraded><has replay
       * error><failed server ids>
       */
      /* First byte is the type */
      // First byte is the type
      if (in[0] != MSG_TYPE_ACK)
      {
        throw new DataFormatException("byte[] is not a valid modify msg");
      }
      int pos = 1;
      /* Read the changeNumber */
      // Read the CSN
      int length = getNextLength(in, pos);
      String changenumberStr = new String(in, pos, length, "UTF-8");
      changeNumber = new ChangeNumber(changenumberStr);
      String csnStr = new String(in, pos, length, "UTF-8");
      csn = new CSN(csnStr);
      pos += length + 1;
      /* Read the hasTimeout flag */
      // Read the hasTimeout flag
      hasTimeout = in[pos++] == 1;
      /* Read the hasWrongStatus flag */
      // Read the hasWrongStatus flag
      hasWrongStatus = in[pos++] == 1;
      /* Read the hasReplayError flag */
      // Read the hasReplayError flag
      hasReplayError = in[pos++] == 1;
      /* Read the list of failed server ids */
      // Read the list of failed server ids
      while (pos < in.length)
      {
        length = getNextLength(in, pos);
@@ -201,13 +208,13 @@
  }
  /**
   * Get the ChangeNumber from the message.
   * Get the CSN from the message.
   *
   * @return the ChangeNumber
   * @return the CSN
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
  /**
@@ -220,30 +227,30 @@
    {
      /*
       * The message is stored in the form:
       * <operation type><change number><has timeout><has degraded><has replay
       * <operation type><CSN><has timeout><has degraded><has replay
       * error><failed server ids>
       */
      ByteArrayOutputStream oStream = new ByteArrayOutputStream(200);
      /* Put the type of the operation */
      // Put the type of the operation
      oStream.write(MSG_TYPE_ACK);
      /* Put the ChangeNumber */
      byte[] changeNumberByte = changeNumber.toString().getBytes("UTF-8");
      oStream.write(changeNumberByte);
      // Put the CSN
      byte[] csnByte = csn.toString().getBytes("UTF-8");
      oStream.write(csnByte);
      oStream.write(0);
      /* Put the hasTimeout flag */
      oStream.write((hasTimeout ? (byte) 1 : (byte) 0));
      // Put the hasTimeout flag
      oStream.write(hasTimeout ? 1 : 0);
      /* Put the hasWrongStatus flag */
      oStream.write((hasWrongStatus ? (byte) 1 : (byte) 0));
      // Put the hasWrongStatus flag
      oStream.write(hasWrongStatus ? 1 : 0);
      /* Put the hasReplayError flag */
      oStream.write((hasReplayError ? (byte) 1 : (byte) 0));
      // Put the hasReplayError flag
      oStream.write(hasReplayError ? 1 : 0);
      /* Put the list of server ids */
      // Put the list of server ids
      for (Integer sid : failedServers)
      {
        byte[] byteServerId = String.valueOf(sid).getBytes("UTF-8");
opends/src/server/org/opends/server/replication/protocol/AddContext.java
@@ -23,15 +23,14 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class describes the context that is attached to
 * Add Operation.
 * This class describes the context that is attached to Add Operation.
 */
public class AddContext extends OperationContext
{
@@ -43,14 +42,13 @@
  /**
   * Creates a new AddContext with the provided information.
   *
   * @param changeNumber The change number of the add operation.
   * @param csn The CSN of the add operation.
   * @param entryUUID the Unique Id of the added entry.
   * @param parentEntryUUID The unique Id of the parent of the added entry.
   */
  public AddContext(ChangeNumber changeNumber, String entryUUID,
      String parentEntryUUID)
  public AddContext(CSN csn, String entryUUID, String parentEntryUUID)
  {
    super(changeNumber, entryUUID);
    super(csn, entryUUID);
    this.parentEntryUUID = parentEntryUUID;
  }
opends/src/server/org/opends/server/replication/protocol/AddMsg.java
@@ -27,9 +27,6 @@
 */
package org.opends.server.replication.protocol;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DirectoryServer;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
@@ -37,18 +34,20 @@
import java.util.Map;
import java.util.zip.DataFormatException;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.plugin.EntryHistorical;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationAddOperation;
import static org.opends.server.replication.protocol.OperationContext.*;
import static org.opends.server.util.StaticUtils.toLowerCase;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class is used to exchange Add operation between LDAP servers
@@ -56,10 +55,10 @@
 */
public class AddMsg extends LDAPUpdateMsg
{
  // Attributes are managed encoded
  /** Attributes are managed encoded. */
  private byte[] encodedAttributes;
  // Parent is managed decoded
  /** Parent is managed decoded. */
  private String parentEntryUUID;
  /**
@@ -84,7 +83,7 @@
  /**
   * Creates a new AddMessage.
   *
   * @param cn                    ChangeNumber of the add.
   * @param csn                   CSN of the add.
   * @param dn                    DN of the added entry.
   * @param entryUUID             The Unique identifier of the added entry.
   * @param parentEntryUUID       The unique Id of the parent of the added
@@ -93,7 +92,7 @@
   * @param userAttributes        user attributes of the added entry.
   * @param operationalAttributes operational attributes of the added entry.
   */
  public AddMsg(ChangeNumber cn,
  public AddMsg(CSN csn,
                String dn,
                String entryUUID,
                String parentEntryUUID,
@@ -101,7 +100,7 @@
                Map<AttributeType,List<Attribute>> userAttributes,
                Map<AttributeType,List<Attribute>> operationalAttributes)
  {
    super (cn, entryUUID, dn);
    super (csn, entryUUID, dn);
    // Stores parentUniqueID not encoded
    this.parentEntryUUID = parentEntryUUID;
@@ -115,7 +114,7 @@
  /**
   * Creates a new AddMessage.
   *
   * @param cn ChangeNumber of the add.
   * @param csn CSN of the add.
   * @param dn DN of the added entry.
   * @param uniqueId The Unique identifier of the added entry.
   * @param parentId The unique Id of the parent of the added entry.
@@ -123,7 +122,7 @@
   * @param userAttributes user attributes of the added entry.
   * @param operationalAttributes operational attributes of the added entry.
   */
  public AddMsg(ChangeNumber cn,
  public AddMsg(CSN csn,
                String dn,
                String uniqueId,
                String parentId,
@@ -131,7 +130,7 @@
                Collection<Attribute> userAttributes,
                Collection<Attribute> operationalAttributes)
  {
    super (cn, uniqueId, dn);
    super (csn, uniqueId, dn);
    // Stores parentUniqueID not encoded
    this.parentEntryUUID = parentId;
@@ -183,7 +182,7 @@
        InternalClientConnection.nextOperationID(),
        InternalClientConnection.nextMessageID(), null,
        ByteString.valueOf(newDn), attr);
    AddContext ctx = new AddContext(getChangeNumber(), getEntryUUID(),
    AddContext ctx = new AddContext(getCSN(), getEntryUUID(),
        parentEntryUUID);
    add.setAttachment(SYNCHROCONTEXT, ctx);
    return add;
@@ -498,7 +497,7 @@
      return "AddMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag;
    }
@@ -507,7 +506,7 @@
      return "AddMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag +
        " assuredMode: " + assuredMode +
opends/src/server/org/opends/server/replication/protocol/ChangeTimeHeartbeatMsg.java
@@ -27,17 +27,13 @@
 */
package org.opends.server.replication.protocol;
import java.util.zip.DataFormatException;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.ByteSequenceReader;
import org.opends.server.types.ByteString;
import org.opends.server.types.ByteStringBuilder;
/**
 * Class that define messages sent by a replication domain (DS) to the
 * replication server to let the RS know the DS current change time.
@@ -45,34 +41,30 @@
public class ChangeTimeHeartbeatMsg extends ReplicationMsg
{
  /**
   * The ChangeNumber containing the change time.
   * The CSN containing the change time.
   */
  private final ChangeNumber changeNumber;
  private final CSN csn;
  /**
   * Constructor of a Change Time Heartbeat message providing the change time
   * value in a change number.
   * value in a CSN.
   *
   * @param cn
   *          The provided change number.
   * @param csn
   *          The provided CSN.
   */
  public ChangeTimeHeartbeatMsg(ChangeNumber cn)
  public ChangeTimeHeartbeatMsg(CSN csn)
  {
    this.changeNumber = cn;
    this.csn = csn;
  }
  /**
   * Get a change number with the transmitted change time.
   * Get a CSN with the transmitted change time.
   *
   * @return the ChangeNumber
   * @return the CSN
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
@@ -101,13 +93,11 @@
      if (version >= ProtocolVersion.REPLICATION_PROTOCOL_V7)
      {
        changeNumber = ChangeNumber.valueOf(reader
            .getByteSequence(ChangeNumber.BYTE_ENCODING_LENGTH));
        csn = CSN.valueOf(reader.getByteSequence(CSN.BYTE_ENCODING_LENGTH));
      }
      else
      {
        changeNumber = ChangeNumber.valueOf(reader
            .getString(ChangeNumber.STRING_ENCODING_LENGTH));
        csn = CSN.valueOf(reader.getString(CSN.STRING_ENCODING_LENGTH));
        reader.get(); // Read trailing 0 byte.
      }
@@ -135,17 +125,17 @@
    if (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V7)
    {
      final ByteStringBuilder builder = new ByteStringBuilder(
          ChangeNumber.BYTE_ENCODING_LENGTH + 1 /* type + csn */);
          CSN.BYTE_ENCODING_LENGTH + 1 /* type + csn */);
      builder.append(MSG_TYPE_CT_HEARTBEAT);
      changeNumber.toByteString(builder);
      csn.toByteString(builder);
      return builder.toByteArray();
    }
    else
    {
      final ByteStringBuilder builder = new ByteStringBuilder(
          ChangeNumber.STRING_ENCODING_LENGTH + 2 /* type + csn str + nul */);
          CSN.STRING_ENCODING_LENGTH + 2 /* type + csn str + nul */);
      builder.append(MSG_TYPE_CT_HEARTBEAT);
      builder.append(changeNumber.toString());
      builder.append(csn.toString());
      builder.append((byte) 0); // For compatibility with earlier protocol
                                // versions.
      return builder.toByteArray();
opends/src/server/org/opends/server/replication/protocol/DeleteContext.java
@@ -23,11 +23,11 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class is used to describe the context attached to a Delete Operation.
@@ -37,11 +37,11 @@
  /**
   * Creates a new DeleteContext with the provided information.
   *
   * @param changeNumber The change number of the Delete Operation.
   * @param csn The CSN of the Delete Operation.
   * @param entryUUID The unique Id of the deleted entry.
   */
  public DeleteContext(ChangeNumber changeNumber, String entryUUID)
  public DeleteContext(CSN csn, String entryUUID)
  {
    super(changeNumber, entryUUID);
    super(csn, entryUUID);
  }
}
opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
@@ -35,7 +35,7 @@
import org.opends.server.controls.SubtreeDeleteControl;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.ByteString;
import org.opends.server.types.Operation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
@@ -72,13 +72,12 @@
   * Creates a new delete message.
   *
   * @param dn           The dn with which the message must be created.
   * @param changeNumber The change number with which the message must be
   *                     created.
   * @param csn          The CSN with which the message must be created.
   * @param entryUUID    The unique id with which the message must be created.
   */
  public DeleteMsg(String dn, ChangeNumber changeNumber, String entryUUID)
  public DeleteMsg(String dn, CSN csn, String entryUUID)
  {
    super(new DeleteContext(changeNumber, entryUUID), dn);
    super(new DeleteContext(csn, entryUUID), dn);
  }
  /**
@@ -123,7 +122,7 @@
    if (isSubtreeDelete)
      del.addRequestControl(new SubtreeDeleteControl(false));
    DeleteContext ctx = new DeleteContext(getChangeNumber(), getEntryUUID());
    DeleteContext ctx = new DeleteContext(getCSN(), getEntryUUID());
    del.setAttachment(SYNCHROCONTEXT, ctx);
    return del;
  }
@@ -255,7 +254,7 @@
      return "DeleteMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag;
    }
@@ -264,7 +263,7 @@
      return "DeleteMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag +
        " assuredMode: " + assuredMode +
opends/src/server/org/opends/server/replication/protocol/LDAPUpdateMsg.java
@@ -39,19 +39,9 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.Attribute;
import org.opends.server.types.ByteSequenceReader;
import org.opends.server.types.ByteString;
import org.opends.server.types.ByteStringBuilder;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Operation;
import org.opends.server.types.RawAttribute;
import org.opends.server.types.operation.PostOperationAddOperation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostOperationOperation;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
import org.opends.server.types.operation.*;
/**
 * Abstract class that must be extended to define a message
@@ -62,7 +52,7 @@
  /**
   * The DN on which the update was originally done.
   */
  protected String dn = null;
  protected String dn;
  /**
   * The entryUUID of the entry that was updated.
@@ -72,7 +62,7 @@
  /**
   * Encoded form of the LDAPUpdateMsg.
   */
  protected byte[] bytes = null;
  protected byte[] bytes;
  /**
   * Encoded form of entry attributes.
@@ -97,7 +87,7 @@
  public LDAPUpdateMsg(OperationContext ctx, String dn)
  {
    this.protocolVersion = ProtocolVersion.getCurrentVersion();
    this.changeNumber = ctx.getChangeNumber();
    this.csn = ctx.getCSN();
    this.entryUUID = ctx.getEntryUUID();
    this.dn = dn;
  }
@@ -105,17 +95,17 @@
  /**
   * Creates a new UpdateMessage with the given information.
   *
   * @param cn        The ChangeNumber of the operation for which the
   * @param csn       The CSN of the operation for which the
   *                  UpdateMessage is created.
   * @param entryUUID The Unique identifier of the entry that is updated
   *                  by the operation for which the UpdateMessage is created.
   * @param dn        The DN of the entry on which the change
   *                  that caused the creation of this object happened
   */
  public LDAPUpdateMsg(ChangeNumber cn, String entryUUID, String dn)
  public LDAPUpdateMsg(CSN csn, String entryUUID, String dn)
  {
    this.protocolVersion = ProtocolVersion.getCurrentVersion();
    this.changeNumber = cn;
    this.csn = csn;
    this.entryUUID = entryUUID;
    this.dn = dn;
  }
@@ -248,45 +238,44 @@
    throws UnsupportedEncodingException
  {
    byte[] byteDn = dn.getBytes("UTF-8");
    byte[] changeNumberByte =
      this.getChangeNumber().toString().getBytes("UTF-8");
    byte[] csnByte = getCSN().toString().getBytes("UTF-8");
    byte[] byteEntryuuid = getEntryUUID().getBytes("UTF-8");
    /* The message header is stored in the form :
     * <operation type><protocol version><changenumber><dn><entryuuid><assured>
     * <operation type><protocol version><CSN><dn><entryuuid><assured>
     * <assured mode> <safe data level>
     * the length of result byte array is therefore :
     *   1 + 1 + change number length + 1 + dn length + 1 + uuid length + 1 + 1
     *   1 + 1 + CSN length + 1 + dn length + 1 + uuid length + 1 + 1
     *   + 1 + 1 + additional_length
     */
    int length = 8 + changeNumberByte.length + byteDn.length
    int length = 8 + csnByte.length + byteDn.length
                 + byteEntryuuid.length + additionalLength;
    byte[] encodedMsg = new byte[length];
    /* put the type of the operation */
    // put the type of the operation
    encodedMsg[0] = type;
    /* put the protocol version */
    // put the protocol version
    encodedMsg[1] = (byte) version;
    int pos = 2;
    /* Put the ChangeNumber */
    pos = addByteArray(changeNumberByte, encodedMsg, pos);
    // Put the CSN
    pos = addByteArray(csnByte, encodedMsg, pos);
    /* Put the DN and a terminating 0 */
    // Put the DN and a terminating 0
    pos = addByteArray(byteDn, encodedMsg, pos);
    /* Put the entry uuid and a terminating 0 */
    // Put the entry uuid and a terminating 0
    pos = addByteArray(byteEntryuuid, encodedMsg, pos);
    /* Put the assured flag */
    // Put the assured flag
    encodedMsg[pos++] = (assuredFlag ? (byte) 1 : 0);
    /* Put the assured mode */
    // Put the assured mode
    encodedMsg[pos++] = assuredMode.getValue();
    /* Put the safe data level */
    // Put the safe data level
    encodedMsg[pos++] = safeDataLevel;
    return encodedMsg;
@@ -309,35 +298,34 @@
    throws UnsupportedEncodingException
  {
    byte[] byteDn = dn.getBytes("UTF-8");
    byte[] changeNumberByte =
      this.getChangeNumber().toString().getBytes("UTF-8");
    byte[] csnByte = getCSN().toString().getBytes("UTF-8");
    byte[] byteEntryuuid = getEntryUUID().getBytes("UTF-8");
    /* The message header is stored in the form :
     * <operation type><changenumber><dn><assured><entryuuid><change>
     * <operation type><CSN><dn><assured><entryuuid><change>
     * the length of result byte array is therefore :
     *   1 + change number length + 1 + dn length + 1  + 1 +
     *   1 + CSN length + 1 + dn length + 1  + 1 +
     *   uuid length + 1 + additional_length
     */
    int length = 5 + changeNumberByte.length + byteDn.length
    int length = 5 + csnByte.length + byteDn.length
                 + byteEntryuuid.length + additionalLength;
    byte[] encodedMsg = new byte[length];
    /* put the type of the operation */
    // put the type of the operation
    encodedMsg[0] = type;
    int pos = 1;
    /* put the ChangeNumber */
    pos = addByteArray(changeNumberByte, encodedMsg, pos);
    // put the CSN
    pos = addByteArray(csnByte, encodedMsg, pos);
    /* put the assured information */
    // put the assured information
    encodedMsg[pos++] = (assuredFlag ? (byte) 1 : 0);
    /* put the DN and a terminating 0 */
    // put the DN and a terminating 0
    pos = addByteArray(byteDn, encodedMsg, pos);
    /* put the entry uuid and a terminating 0 */
    // put the entry uuid and a terminating 0
    pos = addByteArray(byteEntryuuid, encodedMsg, pos);
    return encodedMsg;
@@ -446,7 +434,7 @@
   public int decodeHeader(byte[] types, byte[] encodedMsg)
                          throws DataFormatException
   {
     /* first byte is the type */
     // first byte is the type
     boolean foundMatchingType = false;
     for (byte type : types)
     {
@@ -472,35 +460,35 @@
       return decodeHeader_V1(encodedMsg);
     }
     /* read the protocol version */
     // read the protocol version
     protocolVersion = encodedMsg[1];
     try
     {
       /* Read the changeNumber */
       // Read the CSN
       int pos = 2;
       int length = getNextLength(encodedMsg, pos);
       String changeNumberStr = new String(encodedMsg, pos, length, "UTF-8");
       String csnStr = new String(encodedMsg, pos, length, "UTF-8");
       pos += length + 1;
       changeNumber = new ChangeNumber(changeNumberStr);
       csn = new CSN(csnStr);
       /* Read the dn */
       // Read the dn
       length = getNextLength(encodedMsg, pos);
       dn = new String(encodedMsg, pos, length, "UTF-8");
       pos += length + 1;
       /* Read the entryuuid */
       // Read the entryuuid
       length = getNextLength(encodedMsg, pos);
       entryUUID = new String(encodedMsg, pos, length, "UTF-8");
       pos += length + 1;
       /* Read the assured information */
       // Read the assured information
       assuredFlag = encodedMsg[pos++] == 1;
       /* Read the assured mode */
       // Read the assured mode
       assuredMode = AssuredMode.valueOf(encodedMsg[pos++]);
       /* Read the safe data level */
       // Read the safe data level
       safeDataLevel = encodedMsg[pos++];
       return pos;
@@ -539,22 +527,22 @@
    try
    {
      /* read the changeNumber */
      // read the CSN
      int pos = 1;
      int length = getNextLength(encodedMsg, pos);
      String changeNumberStr = new String(encodedMsg, pos, length, "UTF-8");
      String csnStr = new String(encodedMsg, pos, length, "UTF-8");
      pos += length + 1;
      changeNumber = new ChangeNumber(changeNumberStr);
      csn = new CSN(csnStr);
      /* read the assured information */
      // read the assured information
      assuredFlag = encodedMsg[pos++] == 1;
      /* read the dn */
      // read the dn
      length = getNextLength(encodedMsg, pos);
      dn = new String(encodedMsg, pos, length, "UTF-8");
      pos += length + 1;
      /* read the entryuuid */
      // read the entryuuid
      length = getNextLength(encodedMsg, pos);
      entryUUID = new String(encodedMsg, pos, length, "UTF-8");
      pos += length + 1;
opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java
@@ -23,8 +23,8 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import java.util.ArrayList;
@@ -36,15 +36,9 @@
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.plugin.EntryHistorical;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeUsage;
import org.opends.server.types.ByteStringBuilder;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Modification;
import org.opends.server.types.RawModification;
import org.opends.server.types.*;
/**
 * This class holds every common code for the modify messages (mod, moddn).
@@ -80,16 +74,16 @@
  /**
   * Creates a new ModifyCommonMsg with the given informations.
   *
   * @param cn        The ChangeNumber of the operation for which the
   * @param csn       The CSN of the operation for which the
   *                  UpdateMessage is created.
   * @param entryUUID The Unique identifier of the entry that is updated
   *                  by the operation for which the UpdateMessage is created.
   * @param dn        The DN of the entry on which the change
   *                  that caused the creation of this object happened
   */
  public ModifyCommonMsg(ChangeNumber cn, String entryUUID, String dn)
  public ModifyCommonMsg(CSN csn, String entryUUID, String dn)
  {
    super(cn, entryUUID, dn);
    super(csn, entryUUID, dn);
  }
  /**
opends/src/server/org/opends/server/replication/protocol/ModifyContext.java
@@ -23,11 +23,11 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class describe the replication context that is attached to
@@ -39,11 +39,11 @@
  /**
   * Creates a new Modify Context with the provided parameters.
   *
   * @param changeNumber The change number of the operation.
   * @param csn The CSN of the operation.
   * @param entryUUID the unique Id of the modified entry.
   */
  public ModifyContext(ChangeNumber changeNumber, String entryUUID)
  public ModifyContext(CSN csn, String entryUUID)
  {
    super(changeNumber, entryUUID);
    super(csn, entryUUID);
  }
}
opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
@@ -27,8 +27,6 @@
 */
package org.opends.server.replication.protocol;
import static org.opends.server.replication.protocol.OperationContext.*;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.zip.DataFormatException;
@@ -36,16 +34,12 @@
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Modification;
import org.opends.server.types.Operation;
import org.opends.server.types.RDN;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import static org.opends.server.replication.protocol.OperationContext.*;
/**
 * Message used to send Modify DN information.
 */
@@ -86,7 +80,7 @@
   * using mods.
   *
   * @param dn The dn to use for building the message.
   * @param changeNumber The changeNumberto use for building the message.
   * @param csn The CSN to use for building the message.
   * @param entryUUID          The unique id to use for building the message.
   * @param newSuperiorEntryUUID The new parent unique id to use for building
   *                     the message.
@@ -95,12 +89,11 @@
   * @param newSuperior  The new Superior entry to use for building the message.
   * @param newRDN       The new Rdn to use for building the message.
   */
  public ModifyDNMsg(String dn, ChangeNumber changeNumber, String entryUUID,
  public ModifyDNMsg(String dn, CSN csn, String entryUUID,
                     String newSuperiorEntryUUID, boolean deleteOldRdn,
                     String newSuperior, String newRDN)
  {
    super(new ModifyDnContext(changeNumber, entryUUID, newSuperiorEntryUUID),
        dn);
    super(new ModifyDnContext(csn, entryUUID, newSuperiorEntryUUID), dn);
    this.newSuperiorEntryUUID = newSuperiorEntryUUID;
    this.deleteOldRdn = deleteOldRdn;
@@ -112,7 +105,7 @@
   * Construct a new Modify DN message (with mods).
   *
   * @param dn The dn to use for building the message.
   * @param changeNumber The changeNumberto use for building the message.
   * @param csn The CSNto use for building the message.
   * @param entryUUID The unique id to use for building the message.
   * @param newSuperiorEntryUUID The new parent unique id to use for building
   *                     the message.
@@ -122,11 +115,11 @@
   * @param newRDN       The new Rdn to use for building the message.
   * @param mods         The mod of the operation.
   */
  public ModifyDNMsg(String dn, ChangeNumber changeNumber, String entryUUID,
  public ModifyDNMsg(String dn, CSN csn, String entryUUID,
      String newSuperiorEntryUUID, boolean deleteOldRdn, String newSuperior,
      String newRDN, List<Modification> mods)
  {
    this(dn, changeNumber, entryUUID, newSuperiorEntryUUID, deleteOldRdn,
    this(dn, csn, entryUUID, newSuperiorEntryUUID, deleteOldRdn,
        newSuperior, newRDN);
    this.encodedMods = encodeMods(mods);
  }
@@ -180,7 +173,7 @@
      moddn.addModification(mod);
    }
    ModifyDnContext ctx = new ModifyDnContext(getChangeNumber(), getEntryUUID(),
    ModifyDnContext ctx = new ModifyDnContext(getCSN(), getEntryUUID(),
        newSuperiorEntryUUID);
    moddn.setAttachment(SYNCHROCONTEXT, ctx);
    return moddn;
@@ -555,7 +548,7 @@
      return "ModifyDNMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag +
        " newRDN: " + newRDN +
@@ -567,7 +560,7 @@
      return "ModifyDNMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " newRDN: " + newRDN +
        " newSuperior: " + newSuperior +
opends/src/server/org/opends/server/replication/protocol/ModifyDnContext.java
@@ -23,11 +23,11 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class describe the replication context that is attached to
@@ -40,16 +40,15 @@
  /**
   * Creates a new ModifyDN Context with the provided parameters.
   *
   * @param changeNumber The change number of the operation.
   * @param csn The CSN of the operation.
   * @param entryUUID the unique Id of the modified entry.
   * @param newSuperiorEntryUUID The unique Identifier of the new parent,
   *                    can be null if the entry is to stay below the same
   *                    parent.
   */
  public ModifyDnContext(ChangeNumber changeNumber, String entryUUID,
                         String newSuperiorEntryUUID)
  public ModifyDnContext(CSN csn, String entryUUID, String newSuperiorEntryUUID)
  {
    super(changeNumber, entryUUID);
    super(csn, entryUUID);
    this.newSuperiorEntryUUID = newSuperiorEntryUUID;
  }
opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java
@@ -27,8 +27,6 @@
 */
package org.opends.server.replication.protocol;
import static org.opends.server.replication.protocol.OperationContext.*;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
@@ -37,15 +35,12 @@
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Modification;
import org.opends.server.types.Operation;
import org.opends.server.types.RawModification;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationModifyOperation;
import static org.opends.server.replication.protocol.OperationContext.*;
/**
 * Message used to send Modify information.
 */
@@ -66,16 +61,15 @@
  /**
   * Creates a new Modify message using the provided information.
   *
   * @param changeNumber The ChangeNumber for the operation.
   * @param csn The CSN for the operation.
   * @param dn           The baseDN of the operation.
   * @param mods         The mod of the operation.
   * @param entryUUID    The unique id of the entry on which the modification
   *                     needs to apply.
   */
  public ModifyMsg(ChangeNumber changeNumber, DN dn, List<Modification> mods,
                   String entryUUID)
  public ModifyMsg(CSN csn, DN dn, List<Modification> mods, String entryUUID)
  {
    super(new ModifyContext(changeNumber, entryUUID),
    super(new ModifyContext(csn, entryUUID),
          dn.toNormalizedString());
    this.encodedMods = encodeMods(mods);
  }
@@ -145,7 +139,7 @@
        InternalClientConnection.nextOperationID(),
        InternalClientConnection.nextMessageID(), null,
        ByteString.valueOf(newDn), ldapmods);
    ModifyContext ctx = new ModifyContext(getChangeNumber(), getEntryUUID());
    ModifyContext ctx = new ModifyContext(getCSN(), getEntryUUID());
    mod.setAttachment(SYNCHROCONTEXT, ctx);
    return mod;
  }
@@ -162,7 +156,7 @@
      return "ModifyMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag;
    }
@@ -171,7 +165,7 @@
      return "ModifyMsg content: " +
        " protocolVersion: " + protocolVersion +
        " dn: " + dn +
        " changeNumber: " + changeNumber +
        " changeNumber: " + csn +
        " uniqueId: " + entryUUID +
        " assuredFlag: " + assuredFlag +
        " assuredMode: " + assuredMode +
opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
@@ -38,7 +38,7 @@
import org.opends.server.protocols.asn1.ASN1;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.types.ByteSequenceReader;
import org.opends.server.types.ByteString;
@@ -266,31 +266,31 @@
        boolean isLDAPServer = false;
        asn1Reader.readStartSequence();
        // loop on the list of CN of the state
        // loop on the list of CSN of the state
        while(asn1Reader.hasNextElement())
        {
          ChangeNumber cn;
          CSN csn;
          if (version >= ProtocolVersion.REPLICATION_PROTOCOL_V7)
          {
            cn = ChangeNumber.valueOf(asn1Reader.readOctetString());
            csn = CSN.valueOf(asn1Reader.readOctetString());
          }
          else
          {
            cn = ChangeNumber.valueOf(asn1Reader.readOctetStringAsString());
            csn = CSN.valueOf(asn1Reader.readOctetStringAsString());
          }
          if ((data.replServerDbState != null) && (serverId == 0))
          if (data.replServerDbState != null && serverId == 0)
          {
            // we are on the first CN that is a fake CN to store the serverId
            // we are on the first CSN that is a fake CSN to store the serverId
            // and the older update time
            serverId = cn.getServerId();
            outime = cn.getTime();
            isLDAPServer = (cn.getSeqnum()>0);
            serverId = csn.getServerId();
            outime = csn.getTime();
            isLDAPServer = csn.getSeqnum() > 0;
          }
          else
          {
            // we are on a normal CN
            newState.update(cn);
            // we are on a normal CSN
            newState.update(csn);
          }
        }
        asn1Reader.readEndSequence();
@@ -411,23 +411,22 @@
      writer.writeStartSequence();
      {
        /*
         * A fake change number helps storing the LDAP server ID. The sequence
         * number will be used to differentiate between an LDAP server (1) or an
         * RS (0).
         * A fake CSN helps storing the LDAP server ID. The sequence number will
         * be used to differentiate between an LDAP server (1) or an RS (0).
         */
        ChangeNumber cn = new ChangeNumber(
        CSN csn = new CSN(
            server.getValue().approxFirstMissingDate, seqNum,
            server.getKey());
        if (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V7)
        {
          writer.writeOctetString(cn.toByteString());
          writer.writeOctetString(csn.toByteString());
        }
        else
        {
          writer.writeOctetString(cn.toString());
          writer.writeOctetString(csn.toString());
        }
        // the changenumbers that make the state
        // the CSNs that make the state
        server.getValue().state.writeTo(writer, protocolVersion);
      }
      writer.writeEndSequence();
opends/src/server/org/opends/server/replication/protocol/OperationContext.java
@@ -23,11 +23,11 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 *      Portions copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.Operation;
import org.opends.server.types.operation.PluginOperation;
@@ -43,9 +43,9 @@
  public static final String SYNCHROCONTEXT = "replicationContext";
  /**
   * The change Number of the Operation.
   * The CSN of the Operation.
   */
  private ChangeNumber changeNumber;
  private CSN csn;
  /**
   * The unique Id of the entry that was modified in the original operation.
@@ -54,23 +54,23 @@
  /**
   * Create a new OperationContext.
   * @param changeNumber The change number of the operation.
   * @param csn The CSN of the operation.
   * @param entryUUID The unique Identifier of the modified entry.
   */
  protected OperationContext(ChangeNumber changeNumber, String entryUUID)
  protected OperationContext(CSN csn, String entryUUID)
  {
    this.changeNumber = changeNumber;
    this.csn = csn;
    this.entryUUID = entryUUID;
  }
  /**
   * Gets The change number of the Operation.
   * Gets the CSN of the Operation.
   *
   * @return The change number of the Operation.
   * @return The CSN of the Operation.
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
  /**
@@ -84,40 +84,40 @@
  }
  /**
   * Get the change number of an operation.
   * Get the CSN of an operation.
   *
   * @param  op The operation.
   *
   * @return The change number of the provided operation, or null if there is
   *         no change number associated with the operation.
   * @return The CSN of the provided operation, or null if there is
   *         no CSN associated with the operation.
   */
  public static ChangeNumber getChangeNumber(Operation op)
  public static CSN getCSN(Operation op)
  {
    OperationContext ctx = (OperationContext)op.getAttachment(SYNCHROCONTEXT);
    if (ctx == null)
    {
      return null;
    }
    return ctx.changeNumber;
    return ctx.csn;
  }
  /**
   * Get the change number of an operation from the synchronization context
   * Get the CSN of an operation from the synchronization context
   * attached to the provided operation.
   *
   * @param  op The operation.
   *
   * @return The change number of the provided operation, or null if there is
   *         no change number associated with the operation.
   * @return The CSN of the provided operation, or null if there is
   *         no CSN associated with the operation.
   */
  public static ChangeNumber getChangeNumber(PluginOperation op)
  public static CSN getCSN(PluginOperation op)
  {
    OperationContext ctx = (OperationContext)op.getAttachment(SYNCHROCONTEXT);
    if (ctx == null)
    {
      return null;
    }
    return ctx.changeNumber;
    return ctx.csn;
  }
  /**
@@ -129,11 +129,10 @@
    if (obj instanceof OperationContext)
    {
      OperationContext ctx = (OperationContext) obj;
      return ((this.changeNumber.equals(ctx.getChangeNumber()) &&
          (this.entryUUID.equals(ctx.getEntryUUID()))));
      return this.csn.equals(ctx.getCSN())
          && this.entryUUID.equals(ctx.getEntryUUID());
    }
    else
      return false;
    return false;
  }
  /**
@@ -142,7 +141,7 @@
  @Override
  public int hashCode()
  {
    return changeNumber.hashCode() + entryUUID.hashCode();
    return csn.hashCode() + entryUUID.hashCode();
  }
opends/src/server/org/opends/server/replication/protocol/StartECLSessionMsg.java
@@ -34,13 +34,12 @@
import java.util.Set;
import java.util.zip.DataFormatException;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.util.StaticUtils;
/**
 * This class specifies the parameters of a search request on the ECL.
 * It is used as an interface between the requestor (plugin part)
 * - either as an han
 */
public class StartECLSessionMsg extends ReplicationMsg
{
@@ -54,14 +53,14 @@
  /**
   * This specifies that the ECL is requested from a provided interval
   * of change numbers (as defined by draft-good-ldap-changelog [CHANGELOG]
   * and NOT replication change numbers).
   * and NOT replication CSNs).
   * TODO: not yet implemented
   */
  public final static short REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER = 1;
  /**
   * This specifies that the ECL is requested only for the entry that have
   * a repl change number matching the provided one.
   * a CSN matching the provided one.
   * TODO: not yet implemented
   */
  public final static short REQUEST_TYPE_EQUALS_REPL_CHANGE_NUMBER = 2;
@@ -100,9 +99,9 @@
  /**
   * When eclRequestType = EQUALS_REPL_CHANGE_NUMBER, specifies the provided
   * replication change number.
   * replication CSN.
   */
  private ChangeNumber changeNumber;
  private CSN csn;
  /** Specifies whether the search is persistent and changesOnly. */
  private short  isPersistent = NON_PERSISTENT;
@@ -161,11 +160,11 @@
        Integer.valueOf(new String(in, pos, length, "UTF-8"));
      pos += length +1;
      // replication changeNumber
      // replication CSN
      length = getNextLength(in, pos);
      String changenumberStr = new String(in, pos, length, "UTF-8");
      String csnStr = new String(in, pos, length, "UTF-8");
      pos += length + 1;
      changeNumber = new ChangeNumber(changenumberStr);
      csn = new CSN(csnStr);
      // persistentSearch mode
      length = getNextLength(in, pos);
@@ -210,7 +209,7 @@
    crossDomainServerState = "";
    firstDraftChangeNumber = -1;
    lastDraftChangeNumber = -1;
    changeNumber = new ChangeNumber(0,0,0);
    csn = new CSN(0, 0, 0);
    isPersistent = NON_PERSISTENT;
    operationId = "-1";
    excludedBaseDNs = new HashSet<String>();
@@ -227,28 +226,20 @@
    try
    {
      byte[] byteMode =
        Short.toString(eclRequestType).getBytes("UTF-8");
      byte[] byteSequenceNumber =
        String.valueOf(firstDraftChangeNumber).getBytes("UTF-8");
      byte[] byteStopSequenceNumber =
        String.valueOf(lastDraftChangeNumber).getBytes("UTF-8");
      byte[] byteChangeNumber =
        changeNumber.toString().getBytes("UTF-8");
      byte[] bytePsearch =
        Short.toString(isPersistent).getBytes();
      byte[] byteGeneralizedState =
        String.valueOf(crossDomainServerState).getBytes("UTF-8");
      byte[] byteOperationId =
        String.valueOf(operationId).getBytes("UTF-8");
      byte[] byteExcludedDNs =
        String.valueOf(excludedBaseDNsString).getBytes("UTF-8");
      byte[] byteMode = toBytes(eclRequestType);
      byte[] byteSequenceNumber = toBytes(firstDraftChangeNumber);
      byte[] byteStopSequenceNumber = toBytes(lastDraftChangeNumber);
      byte[] byteCSN = csn.toString().getBytes("UTF-8");
      byte[] bytePsearch = toBytes(isPersistent);
      byte[] byteGeneralizedState = toBytes(crossDomainServerState);
      byte[] byteOperationId = toBytes(operationId);
      byte[] byteExcludedDNs = toBytes(excludedBaseDNsString);
      int length =
        byteMode.length + 1 +
        byteSequenceNumber.length + 1 +
        byteStopSequenceNumber.length + 1 +
        byteChangeNumber.length + 1 +
        byteCSN.length + 1 +
        bytePsearch.length + 1 +
        byteGeneralizedState.length + 1 +
        byteOperationId.length + 1 +
@@ -261,13 +252,12 @@
      pos = addByteArray(byteMode, resultByteArray, pos);
      pos = addByteArray(byteSequenceNumber, resultByteArray, pos);
      pos = addByteArray(byteStopSequenceNumber, resultByteArray, pos);
      pos = addByteArray(byteChangeNumber, resultByteArray, pos);
      pos = addByteArray(byteCSN, resultByteArray, pos);
      pos = addByteArray(bytePsearch, resultByteArray, pos);
      pos = addByteArray(byteGeneralizedState, resultByteArray, pos);
      pos = addByteArray(byteOperationId, resultByteArray, pos);
      pos = addByteArray(byteExcludedDNs, resultByteArray, pos);
      return resultByteArray;
    } catch (IOException e)
    {
      // never happens
@@ -275,6 +265,15 @@
    }
  }
  private byte[] toBytes(int i) throws UnsupportedEncodingException
  {
    return toBytes(String.valueOf(i));
  }
  private byte[] toBytes(String s) throws UnsupportedEncodingException
  {
    return String.valueOf(s).getBytes("UTF-8");
  }
  /**
   * {@inheritDoc}
@@ -285,7 +284,7 @@
    return getClass().getCanonicalName() + " [" +
            " requestType="+ eclRequestType +
            " persistentSearch="       + isPersistent +
            " changeNumber="           + changeNumber +
            " csn=" + csn +
            " firstDraftChangeNumber=" + firstDraftChangeNumber +
            " lastDraftChangeNumber="  + lastDraftChangeNumber +
            " generalizedState="       + crossDomainServerState +
@@ -330,21 +329,21 @@
  }
  /**
   * Getter on the replication change number.
   * @return the replication change number.
   * Getter on the replication CSN.
   * @return the replication CSN.
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
  /**
   * Setter on the replication change number.
   * @param changeNumber the provided replication change number.
   * Setter on the replication CSN.
   * @param csn the provided replication CSN.
   */
  public void setChangeNumber(ChangeNumber changeNumber)
  public void setCSN(CSN csn)
  {
    this.changeNumber = changeNumber;
    this.csn = csn;
  }
  /**
   * Getter on the type of request.
opends/src/server/org/opends/server/replication/protocol/UpdateMsg.java
@@ -27,11 +27,11 @@
 */
package org.opends.server.replication.protocol;
import java.io.UnsupportedEncodingException;
import java.util.zip.DataFormatException;
import java.io.UnsupportedEncodingException;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * Abstract class that must be extended to define a message
@@ -46,9 +46,9 @@
  protected short protocolVersion;
  /**
   * The ChangeNumber of this update.
   * The CSN of this update.
   */
  protected ChangeNumber changeNumber;
  protected CSN csn;
  /**
   * True when the update must use assured replication.
@@ -89,7 +89,7 @@
    // Decode header
    int pos = decodeHeader(MSG_TYPE_GENERIC_UPDATE, bytes);
    /* Read the payload : all the remaining bytes but the terminating 0 */
    // Read the payload : all the remaining bytes but the terminating 0
    int length = bytes.length - pos;
    payload = new byte[length];
    try
@@ -112,24 +112,23 @@
   * <p>
   * This constructor is only used for testing.
   *
   * @param changeNumber  The ChangeNumber associated with the change
   *                      encoded in this message.
   * @param csn  The CSN associated with the change encoded in this message.
   * @param payload       The payload that must be encoded in this message.
   */
  public UpdateMsg(ChangeNumber changeNumber, byte[] payload)
  public UpdateMsg(CSN csn, byte[] payload)
  {
    this.payload = payload;
    this.protocolVersion = ProtocolVersion.getCurrentVersion();
    this.changeNumber = changeNumber;
    this.csn = csn;
  }
  /**
   * Get the ChangeNumber from the message.
   * @return the ChangeNumber
   * Get the CSN from the message.
   * @return the CSN
   */
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return changeNumber;
    return csn;
  }
  /**
@@ -161,7 +160,7 @@
  public boolean equals(Object obj)
  {
    return obj != null && obj.getClass() == this.getClass() &&
        changeNumber.equals(((UpdateMsg) obj).changeNumber);
        csn.equals(((UpdateMsg) obj).csn);
  }
  /**
@@ -170,15 +169,16 @@
  @Override
  public int hashCode()
  {
    return changeNumber.hashCode();
    return csn.hashCode();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compareTo(UpdateMsg msg)
  {
    return changeNumber.compareTo(msg.getChangeNumber());
    return csn.compareTo(msg.getCSN());
  }
  /**
@@ -257,37 +257,36 @@
  protected byte[] encodeHeader(byte type, int additionalLength, short version)
    throws UnsupportedEncodingException
  {
    byte[] changeNumberByte =
      this.getChangeNumber().toString().getBytes("UTF-8");
    byte[] csnByte = getCSN().toString().getBytes("UTF-8");
    /* The message header is stored in the form :
     * <operation type><protocol version><changenumber><assured>
     * <operation type><protocol version><CSN><assured>
     * <assured mode> <safe data level>
     * the length of result byte array is therefore :
     *   1 + 1 + change number length + 1 + 1
     *   1 + 1 + CSN length + 1 + 1
     *   + 1 + 1 + additional_length
     */
    int length = 6 + changeNumberByte.length + additionalLength;
    int length = 6 + csnByte.length + additionalLength;
    byte[] encodedMsg = new byte[length];
    /* put the type of the operation */
    // put the type of the operation
    encodedMsg[0] = type;
    /* put the protocol version */
    // put the protocol version
    encodedMsg[1] = (byte)ProtocolVersion.getCurrentVersion();
    int pos = 2;
    /* Put the ChangeNumber */
    pos = addByteArray(changeNumberByte, encodedMsg, pos);
    // Put the CSN
    pos = addByteArray(csnByte, encodedMsg, pos);
    /* Put the assured flag */
    // Put the assured flag
    encodedMsg[pos++] = (assuredFlag ? (byte) 1 : 0);
    /* Put the assured mode */
    // Put the assured mode
    encodedMsg[pos++] = assuredMode.getValue();
    /* Put the safe data level */
    // Put the safe data level
    encodedMsg[pos++] = safeDataLevel;
    return encodedMsg;
@@ -306,32 +305,32 @@
                          throws DataFormatException
  {
    /* The message header is stored in the form :
     * <operation type><protocol version><changenumber><assured>
     * <operation type><protocol version><CSN><assured>
     * <assured mode> <safe data level>
     */
    if (!(type == encodedMsg[0]))
      throw new DataFormatException("byte[] is not a valid update msg: "
        + encodedMsg[0]);
    /* read the protocol version */
    protocolVersion = (short)encodedMsg[1];
    // read the protocol version
    protocolVersion = encodedMsg[1];
    try
    {
      /* Read the changeNumber */
      // Read the CSN
      int pos = 2;
      int length = getNextLength(encodedMsg, pos);
      String changenumberStr = new String(encodedMsg, pos, length, "UTF-8");
      String csnStr = new String(encodedMsg, pos, length, "UTF-8");
      pos += length + 1;
      changeNumber = new ChangeNumber(changenumberStr);
      csn = new CSN(csnStr);
      /* Read the assured information */
      // Read the assured information
      assuredFlag = encodedMsg[pos++] == 1;
      /* Read the assured mode */
      // Read the assured mode
      assuredMode = AssuredMode.valueOf(encodedMsg[pos++]);
      /* Read the safe data level */
      // Read the safe data level
      safeDataLevel = encodedMsg[pos++];
      return pos;
@@ -368,13 +367,13 @@
  public byte[] getBytes(short protocolVersion)
      throws UnsupportedEncodingException
  {
    /* Encode the header in a byte[] large enough to also contain the payload */
    // Encode the header in a byte[] large enough to also contain the payload
    byte[] resultByteArray = encodeHeader(MSG_TYPE_GENERIC_UPDATE,
        payload.length, ProtocolVersion.getCurrentVersion());
    int pos = resultByteArray.length - payload.length;
    /* Add the payload */
    // Add the payload
    for (int i = 0; i < payload.length; i++, pos++)
    {
      resultByteArray[pos] = payload[i];
opends/src/server/org/opends/server/replication/server/ECLServerHandler.java
@@ -36,7 +36,7 @@
import org.opends.messages.Category;
import org.opends.messages.Message;
import org.opends.messages.Severity;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.common.ServerStatus;
@@ -94,10 +94,9 @@
   */
  private String startCookie;
  /**
   * Specifies the value of the cookie before the change currently processed
   * is returned. It is updated with the change number of the change
   * currently processed (thus becoming the "current" cookie just
   * before the change is returned.
   * Specifies the value of the cookie before the change currently processed is
   * returned. It is updated with the CSN of the change currently processed
   * (thus becoming the "current" cookie just before the change is returned.
   */
  private MultiDomainServerState previousCookie = new MultiDomainServerState();
  /**
@@ -106,10 +105,10 @@
  private Set<String> excludedBaseDNs = new HashSet<String>();
  /**
   * Eligible changeNumber - only changes older or equal to eligibleCN
   * are published in the ECL.
   * Eligible CSN - only changes older or equal to eligibleCSN * are published
   * in the ECL.
   */
  private ChangeNumber eligibleCN = null;
  private CSN eligibleCSN;
  /**
   * Provides a string representation of this object.
@@ -177,7 +176,7 @@
          .append("] [rsd=").append(rsd)
          .append("] [nextMsg=").append(nextMsg).append("(")
          .append(nextMsg != null ?
          new Date(nextMsg.getChangeNumber().getTime()).toString():"")
          new Date(nextMsg.getCSN().getTime()).toString():"")
          .append(")")
          .append("] [nextNonEligibleMsg=").append(nextNonEligibleMsg)
          .append("] [startState=").append(startState)
@@ -188,7 +187,7 @@
    /**
     * Get the next message eligible regarding
     * the crossDomain eligible CN. Put it in the context table.
     * the crossDomain eligible CSN. Put it in the context table.
     * @param opid The operation id.
     */
    private void getNextEligibleMessageForDomain(String opid)
@@ -207,15 +206,15 @@
        if (nextNonEligibleMsg != null)
        {
          boolean hasBecomeEligible =
            (nextNonEligibleMsg.getChangeNumber().getTime()
                <= eligibleCN.getTime());
            (nextNonEligibleMsg.getCSN().getTime()
                <= eligibleCSN.getTime());
          if (debugEnabled())
            TRACER.debugInfo(" In ECLServerHandler, for " + mh.getBaseDN() +
                " getNextEligibleMessageForDomain(" + opid+ ") "
              + " stored nonEligibleMsg " + nextNonEligibleMsg
              + " has now become eligible regarding "
              + " the eligibleCN ("+ eligibleCN
              + " the eligibleCSN ("+ eligibleCSN
              + " ):" + hasBecomeEligible);
          if (hasBecomeEligible)
@@ -238,7 +237,7 @@
            // to be returned in the external changelog.
            // So let's check if the chg time is older than the trim date
          } while ((newMsg!=null) &&
              (newMsg.getChangeNumber().getTime() < domainLatestTrimDate));
              (newMsg.getCSN().getTime() < domainLatestTrimDate));
          if (debugEnabled())
            TRACER.debugInfo(" In ECLServerHandler, for " + mh.getBaseDN() +
@@ -250,17 +249,17 @@
          // in non blocking mode, return null when no more msg
          if (newMsg != null)
          {
            boolean isEligible = (newMsg.getChangeNumber().getTime()
                <= eligibleCN.getTime());
            boolean isEligible = (newMsg.getCSN().getTime()
                <= eligibleCSN.getTime());
          if (debugEnabled())
              TRACER.debugInfo(" In ECLServerHandler, for " + mh.getBaseDN()
                + " getNextEligibleMessageForDomain(" + opid+ ") "
                + "newMsg isEligible=" + isEligible + " since "
                + "newMsg=[" + newMsg.getChangeNumber()
                + " " + new Date(newMsg.getChangeNumber().getTime())
                + "] eligibleCN=[" + eligibleCN
                + " " + new Date(eligibleCN.getTime())+"]"
                + "newMsg=[" + newMsg.getCSN()
                + " " + new Date(newMsg.getCSN().getTime())
                + "] eligibleCSN=[" + eligibleCSN
                + " " + new Date(eligibleCSN.getTime())+"]"
                + dumpState());
            if (isEligible)
@@ -601,11 +600,11 @@
    // startDraftCN provided in the request IS NOT in the DraftCNDb
    /*
     * Get the draftLimits (from the eligibleCN got at the beginning of the
     * Get the draftLimits (from the eligibleCSN got at the beginning of the
     * operation) in order to have the first and possible last DraftCN.
     */
    final int[] limits =
        replicationServer.getECLDraftCNLimits(eligibleCN, excludedBaseDNs);
        replicationServer.getECLDraftCNLimits(eligibleCSN, excludedBaseDNs);
    final int firstDraftCN = limits[0];
    final int lastDraftCN = limits[1];
@@ -712,7 +711,7 @@
        // Assign the start state for the domain
        if (isPersistent == PERSISTENT_CHANGES_ONLY)
        {
          newDomainCtxt.startState = rsd.getEligibleState(eligibleCN);
          newDomainCtxt.startState = rsd.getEligibleState(eligibleCSN);
          startStatesFromProvidedCookie.remove(rsd.getBaseDn());
        }
        else
@@ -731,10 +730,10 @@
            // what we have in the replication changelog
            if (newDomainCtxt.startState == null)
            {
              ChangeNumber latestTrimCN =
                  new ChangeNumber(newDomainCtxt.domainLatestTrimDate, 0, 0);
              CSN latestTrimCSN =
                  new CSN(newDomainCtxt.domainLatestTrimDate, 0, 0);
              newDomainCtxt.startState =
                  rsd.getStartState().duplicateOnlyOlderThan(latestTrimCN);
                  rsd.getStartState().duplicateOnlyOlderThan(latestTrimCSN);
            }
          }
          else
@@ -756,8 +755,8 @@
            }
          }
          // Set the stop state for the domain from the eligibleCN
          newDomainCtxt.stopState = rsd.getEligibleState(eligibleCN);
          // Set the stop state for the domain from the eligibleCSN
          newDomainCtxt.stopState = rsd.getEligibleState(eligibleCSN);
        }
        newDomainCtxt.currentState = new ServerState();
@@ -866,9 +865,9 @@
    */
    for (int serverId : rsDomain.getStartState())
    {
      ChangeNumber dbOldestChange =
          rsDomain.getStartState().getChangeNumber(serverId);
      ChangeNumber providedChange = cookie.getChangeNumber(serverId);
      CSN dbOldestChange =
          rsDomain.getStartState().getCSN(serverId);
      CSN providedChange = cookie.getCSN(serverId);
      if (providedChange != null
          && providedChange.older(dbOldestChange))
      {
@@ -1018,7 +1017,7 @@
    excludedBaseDNs = startECLSessionMsg.getExcludedBaseDNs();
    replicationServer.disableEligibility(excludedBaseDNs);
    eligibleCN = replicationServer.getEligibleCN();
    eligibleCSN = replicationServer.getEligibleCSN();
    initializeChangelogSearch(startECLSessionMsg);
@@ -1056,11 +1055,11 @@
      closeInitPhase();
    }
    /* TODO: From replication changenumber
    /* TODO: From replication CSN
    //--
    if (startCLMsg.getStartMode()==2)
    {
      if (CLSearchFromProvidedExactCN(startCLMsg.getChangeNumber()))
      if (CLSearchFromProvidedExactCSN(startCLMsg.getCSN()))
        return;
    }
@@ -1069,14 +1068,14 @@
    {
      // to get the CL first and last
      initializeCLDomCtxts(null); // from start
      ChangeNumber crossDomainEligibleCN = computeCrossDomainEligibleCN();
      CSN crossDomainEligibleCSN = computeCrossDomainEligibleCSN();
      try
      {
        // to get the CL first and last
        // last rely on the crossDomainEligibleCN thus must have been
        // last rely on the crossDomainEligibleCSN thus must have been
        // computed before
        int[] limits = computeCLLimits(crossDomainEligibleCN);
        int[] limits = computeCLLimits(crossDomainEligibleCSN);
        // Send the response
        CLLimitsMsg msg = new CLLimitsMsg(limits[0], limits[1]);
        session.publish(msg);
@@ -1253,7 +1252,7 @@
        // Set and test the domain of the oldestChange see if we reached
        // the end of the phase for this domain
        oldestContext.currentState.update(
            change.getUpdateMsg().getChangeNumber());
            change.getUpdateMsg().getCSN());
        if (oldestContext.currentState.cover(oldestContext.stopState))
        {
@@ -1294,7 +1293,7 @@
          oldestContext.nextMsg = null; // clean
          oldestContext.currentState.update(
              change.getUpdateMsg().getChangeNumber());
              change.getUpdateMsg().getCSN());
          if (draftCompat)
          {
@@ -1317,12 +1316,12 @@
    {
      if (debugEnabled())
        TRACER.debugInfo("getNextECLUpdate updates previousCookie:"
          + oldestChange.getUpdateMsg().getChangeNumber());
          + oldestChange.getUpdateMsg().getCSN());
      // Update the current state
      previousCookie.update(
          oldestChange.getBaseDN(),
          oldestChange.getUpdateMsg().getChangeNumber());
          oldestChange.getUpdateMsg().getCSN());
      // Set the current value of global state in the returned message
      oldestChange.setCookie(previousCookie);
@@ -1357,9 +1356,8 @@
    // The following loop allows to loop until being on the same cn
    // in the 2 dbs
    // replogcn : the oldest change from the changelog db
    ChangeNumber cnFromChangelogDb =
        oldestChange.getUpdateMsg().getChangeNumber();
    // replogCSN : the oldest change from the changelog db
    CSN csnFromChangelogDb = oldestChange.getUpdateMsg().getCSN();
    String dnFromChangelogDb = oldestChange.getBaseDN();
    while (true)
@@ -1373,19 +1371,19 @@
      // the next change from the DraftCN db
      ChangeNumber cnFromDraftCNDb = changelogDBIter.getChangeNumber();
      CSN csnFromDraftCNDb = changelogDBIter.getCSN();
      String dnFromDraftCNDb = changelogDBIter.getBaseDN();
      if (debugEnabled())
        TRACER.debugInfo("getNextECLUpdate generating draftCN "
            + " comparing the 2 db DNs :" + dnFromChangelogDb + "?="
            + cnFromChangelogDb + " timestamps:"
            + new Date(cnFromChangelogDb.getTime()) + " ?older"
            + new Date(cnFromDraftCNDb.getTime()));
            + csnFromChangelogDb + " timestamps:"
            + new Date(csnFromChangelogDb.getTime()) + " ?older"
            + new Date(csnFromDraftCNDb.getTime()));
      if (areSameChange(cnFromChangelogDb, dnFromChangelogDb,
          cnFromDraftCNDb, dnFromDraftCNDb))
      if (areSameChange(csnFromChangelogDb, dnFromChangelogDb,
          csnFromDraftCNDb, dnFromDraftCNDb))
      {
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
@@ -1397,13 +1395,13 @@
      }
      if (!cnFromDraftCNDb.older(cnFromChangelogDb))
      if (!csnFromDraftCNDb.older(csnFromChangelogDb))
      {
        // the change from the changelogDb is older
        // it should have been stored lately
        // let's continue to traverse the changelogdb
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate: will skip " + cnFromChangelogDb
          TRACER.debugInfo("getNextECLUpdate: will skip " + csnFromChangelogDb
              + " and read next from the regular changelog.");
        return false; // TO BE CHECKED
      }
@@ -1418,7 +1416,7 @@
        // found in the changelogDb.
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
              + " will skip " + cnFromDraftCNDb
              + " will skip " + csnFromDraftCNDb
              + " and read next change from the DraftCNDb.");
        isEndOfDraftCNReached = !changelogDBIter.next();
@@ -1426,7 +1424,7 @@
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
              + " has skipped to " + " sn=" + changelogDBIter.getDraftCN()
              + " cn=" + changelogDBIter.getChangeNumber()
              + " csn=" + changelogDBIter.getCSN()
              + " End of draftCNDb ?" + isEndOfDraftCNReached);
      }
      catch (ChangelogException e)
@@ -1441,12 +1439,11 @@
    }
  }
  private boolean areSameChange(ChangeNumber cn1, String dn1, ChangeNumber cn2,
      String dn2)
  private boolean areSameChange(CSN csn1, String dn1, CSN csn2, String dn2)
  {
    boolean sameDN = dn1.compareTo(dn2) == 0;
    boolean sameCN = cn1.compareTo(cn2) == 0;
    return sameDN && sameCN;
    boolean sameCSN = csn1.compareTo(csn2) == 0;
    return sameDN && sameCSN;
  }
  private void assignNewDraftCNAndStore(ECLUpdateMsg change)
@@ -1462,7 +1459,7 @@
        change.getDraftChangeNumber(),
        previousCookie.toString(),
        change.getBaseDN(),
        change.getUpdateMsg().getChangeNumber());
        change.getUpdateMsg().getCSN());
  }
  /**
@@ -1556,11 +1553,11 @@
  }
  /**
   * Refresh the eligibleCN by requesting the replication server.
   * Refresh the eligibleCSN by requesting the replication server.
   */
  public void refreshEligibleCN()
  public void refreshEligibleCSN()
  {
    eligibleCN = replicationServer.getEligibleCN();
    eligibleCSN = replicationServer.getEligibleCSN();
  }
}
opends/src/server/org/opends/server/replication/server/ECLServerWriter.java
@@ -227,7 +227,7 @@
      try
      {
        handler.refreshEligibleCN();
        handler.refreshEligibleCSN();
        update = handler.takeECLUpdate();
      }
      catch(DirectoryException de)
opends/src/server/org/opends/server/replication/server/ExpectedAcksInfo.java
@@ -31,8 +31,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.AckMsg;
/**
@@ -47,17 +48,17 @@
 */
public abstract class ExpectedAcksInfo
{
  // The server handler of the server that sent the assured update message and
  // to who we want to return the final ack
  /**
   * The server handler of the server that sent the assured update message and
   * to who we want to return the final ack.
   */
  private ServerHandler requesterServerHandler = null;
  // The requested assured mode of matching update message
  /** The requested assured mode of matching update message. */
  private AssuredMode assuredMode = null;
  /**
   * The change number of the assured update message we want acks for.
   */
  protected ChangeNumber changeNumber = null;
  /** The CSN of the assured update message we want acks for. */
  protected CSN csn = null;
  /**
   * Is the treatment of the acks for the update message completed or not ?
@@ -92,19 +93,18 @@
  /**
   * Creates a new ExpectedAcksInfo.
   * @param changeNumber The change number of the assured update message
   * @param csn The CSN of the assured update message
   * @param requesterServerHandler The server handler of the server that sent
   * the assured update message
   * @param assuredMode The assured mode requested by the assured update message
   * @param expectedServers The list of servers we want an ack from
   */
  protected ExpectedAcksInfo(ChangeNumber changeNumber,
    ServerHandler requesterServerHandler, AssuredMode assuredMode,
    List<Integer> expectedServers)
  protected ExpectedAcksInfo(CSN csn, ServerHandler requesterServerHandler,
      AssuredMode assuredMode, List<Integer> expectedServers)
  {
    this.requesterServerHandler = requesterServerHandler;
    this.assuredMode = assuredMode;
    this.changeNumber = changeNumber;
    this.csn = csn;
    // Initialize list of servers we expect acks from
    for (Integer serverId : expectedServers)
opends/src/server/org/opends/server/replication/server/MessageHandler.java
@@ -36,7 +36,7 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.changelog.api.*;
@@ -334,7 +334,7 @@
                do
                {
                  msg1 = msgQueue.removeFirst();
                } while (!msg.getChangeNumber().equals(msg1.getChangeNumber()));
                } while (!msg.getCSN().equals(msg1.getCSN()));
                updateServerState(msg);
                return msg1;
              }
@@ -432,9 +432,9 @@
   * Returns null when the queue is empty.
   * @return The older change number.
   */
  public ChangeNumber getOlderUpdateCN()
  public CSN getOlderUpdateCSN()
  {
    ChangeNumber result = null;
    CSN result = null;
    synchronized (msgQueue)
    {
      if (following)
@@ -442,7 +442,7 @@
        if (!msgQueue.isEmpty())
        {
          UpdateMsg msg = msgQueue.first();
          result = msg.getChangeNumber();
          result = msg.getCSN();
        }
      }
      else
@@ -450,7 +450,7 @@
        if (!lateQueue.isEmpty())
        {
          UpdateMsg msg = lateQueue.first();
          result = msg.getChangeNumber();
          result = msg.getCSN();
        }
        else
        {
@@ -468,14 +468,14 @@
    return result;
  }
  private ChangeNumber findOldestChangeNumberFromReplicaDBs()
  private CSN findOldestChangeNumberFromReplicaDBs()
  {
    SortedSet<ReplicaDBCursor> sortedCursors = null;
    try
    {
      sortedCursors = collectAllCursorsWithChanges();
      UpdateMsg msg = sortedCursors.first().getChange();
      return msg.getChangeNumber();
      return msg.getCSN();
    }
    catch (Exception e)
    {
@@ -489,9 +489,9 @@
  /**
   * Collects all the {@link ReplicaDBCursor}s that have changes and sort them
   * with the oldest {@link ChangeNumber} first.
   * with the oldest {@link CSN} first.
   *
   * @return a List of cursors with changes sorted by their {@link ChangeNumber}
   * @return a List of cursors with changes sorted by their {@link CSN}
   *         (oldest first)
   */
  private NavigableSet<ReplicaDBCursor> collectAllCursorsWithChanges()
@@ -501,7 +501,7 @@
    for (int serverId : replicationServerDomain.getServerIds())
    {
      // get the last already sent CN from that server to get a cursor
      final ChangeNumber lastCsn = serverState.getChangeNumber(serverId);
      final CSN lastCsn = serverState.getCSN(serverId);
      addCursorIfNotEmpty(results,
          replicationServerDomain.getCursorFrom(serverId, lastCsn));
    }
@@ -670,7 +670,7 @@
   */
  public boolean updateServerState(UpdateMsg msg)
  {
    return serverState.update(msg.getChangeNumber());
    return serverState.update(msg.getCSN());
  }
  /**
opends/src/server/org/opends/server/replication/server/MsgQueue.java
@@ -27,28 +27,26 @@
 */
package org.opends.server.replication.server;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import java.util.SortedMap;
import java.util.TreeMap;
import org.opends.messages.Message;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
/**
 * This class is used to build ordered lists of UpdateMsg.
 * The order is defined by the order of the ChangeNumber of the UpdateMsg.
 * The order is defined by the order of the CSN of the UpdateMsg.
 */
public class MsgQueue
{
  private SortedMap<ChangeNumber, UpdateMsg>  map =
    new TreeMap<ChangeNumber, UpdateMsg>();
  private SortedMap<CSN, UpdateMsg> map = new TreeMap<CSN, UpdateMsg>();
  private final Object lock = new Object();
  // The total number of bytes for all the message in the queue.
  /** The total number of bytes for all the message in the queue. */
  private int bytesCount = 0;
  /**
@@ -113,21 +111,21 @@
  {
    synchronized (lock)
    {
      UpdateMsg msgSameChangeNumber = map.put(update.getChangeNumber(), update);
      if (msgSameChangeNumber != null)
      UpdateMsg msgSameCSN = map.put(update.getCSN(), update);
      if (msgSameCSN != null)
      {
        try
        {
          if (msgSameChangeNumber.getBytes().length != update.getBytes().length
              || msgSameChangeNumber.isAssured() != update.isAssured()
              || msgSameChangeNumber.getVersion() != update.getVersion())
          if (msgSameCSN.getBytes().length != update.getBytes().length
              || msgSameCSN.isAssured() != update.isAssured()
              || msgSameCSN.getVersion() != update.getVersion())
          {
            // Adding 2 msgs with the same ChangeNumber is ok only when
            // Adding 2 msgs with the same CSN is ok only when
            // the 2 msgs are the same
            bytesCount += (update.size() - msgSameChangeNumber.size());
            bytesCount += (update.size() - msgSameCSN.size());
            Message errMsg = ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN.get(
                msgSameChangeNumber.getChangeNumber().toString(),
                msgSameChangeNumber.toString(), update.toString());
                msgSameCSN.getCSN().toString(),
                msgSameCSN.toString(), update.toString());
            logError(errMsg);
          }
        }
@@ -152,7 +150,7 @@
    synchronized (lock)
    {
      UpdateMsg update = map.get(map.firstKey());
      map.remove(update.getChangeNumber());
      map.remove(update.getCSN());
      bytesCount -= update.size();
      if ((map.size() == 0) && (bytesCount != 0))
      {
@@ -167,19 +165,19 @@
  /**
   * Returns <tt>true</tt> if this map contains an UpdateMsg
   * with the same ChangeNumber as the given UpdateMsg.
   * with the same CSN as the given UpdateMsg.
   *
   * @param msg UpdateMsg whose presence in this queue is to be tested.
   *
   * @return <tt>true</tt> if this map contains an UpdateMsg
   *         with the same ChangeNumber as the given UpdateMsg.
   *         with the same CSN as the given UpdateMsg.
   *
   */
  public boolean contains(UpdateMsg msg)
  {
    synchronized (lock)
    {
      return map.containsKey(msg.getChangeNumber());
      return map.containsKey(msg.getCSN());
    }
  }
opends/src/server/org/opends/server/replication/server/NotAssuredUpdateMsg.java
@@ -29,11 +29,12 @@
import java.io.UnsupportedEncodingException;
import java.util.zip.DataFormatException;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.replication.protocol.ProtocolVersion;
import org.opends.server.replication.protocol.UpdateMsg;
/**
 * This is a facility class that is in fact an hack to optimize replication
@@ -100,13 +101,13 @@
      /* Look for assured flag position:
       * The message header is stored in the form :
       * <operation type><changenumber><dn><assured><entryuuid><change>
       * <operation type><CSN><dn><assured><entryuuid><change>
       * the length of result byte array is therefore :
       *   1 + change number length + 1 + dn length + 1  + 1 +
       *   1 + CSN length + 1 + dn length + 1  + 1 +
       *   uuid length + 1 + additional_length
       * See LDAPUpdateMsg.encodeHeader_V1() for more information
       */
      // Find end of change number then end of dn
      // Find end of CSN then end of dn
      for (pos = 1; pos < maxLen; pos++)
      {
        if (bytes[pos] == (byte) 0)
@@ -120,13 +121,12 @@
        }
      }
      if (!found)
        throw new UnsupportedEncodingException("Could not find end of " +
          "change number.");
        throw new UnsupportedEncodingException("Could not find end of CSN.");
      pos++;
      if (pos >= maxLen)
        throw new UnsupportedEncodingException("Reached end of packet.");
      // Force assured flag to false
      bytes[pos] = (byte) 0;
      bytes[pos] = 0;
      // Store computed V1 serialized form
      realUpdateMsgNotAssuredBytesV1 = bytes;
@@ -149,14 +149,14 @@
      /* Look for assured flag position:
       * The message header is stored in the form :
       * <operation type><protocol version><changenumber><dn><entryuuid>
       * <operation type><protocol version><CSN><dn><entryuuid>
       * <assured> <assured mode> <safe data level>
       * the length of result byte array is therefore :
       *   1 + 1 + change number length + 1 + dn length + 1 + uuid length +
       *   1 + 1 + CSN length + 1 + dn length + 1 + uuid length +
       *   1 + 1 + 1 + 1 + additional_length
       * See LDAPUpdateMsg.encodeHeader() for more information
       */
      // Find end of change number then end of dn then end of uuid
      // Find end of CSN then end of dn then end of uuid
      for (pos = 2; pos < maxLen; pos++)
      {
        if (bytes[pos] == (byte) 0)
@@ -170,13 +170,12 @@
        }
      }
      if (!found)
        throw new UnsupportedEncodingException("Could not find end of " +
          "change number.");
        throw new UnsupportedEncodingException("Could not find end of CSN.");
      pos++;
      if (pos >= maxLen)
        throw new UnsupportedEncodingException("Reached end of packet.");
      // Force assured flag to false
      bytes[pos] = (byte) 0;
      bytes[pos] = 0;
      // Store computed VLATEST serialized form
      realUpdateMsgNotAssuredBytesVLatest = bytes;
@@ -204,14 +203,14 @@
      // This is a generic update message
      /* Look for assured flag position:
       * The message header is stored in the form :
       * <operation type><protocol version><changenumber><assured>
       * <operation type><protocol version><CSN><assured>
       * <assured mode> <safe data level>
       * the length of result byte array is therefore :
       *   1 + 1 + change number length + 1 + 1
       *   1 + 1 + CSN length + 1 + 1
       *   + 1 + 1 + additional_length
       * See UpdateMsg.encodeHeader() for more  information
       */
      // Find end of change number
      // Find end of CSN
      for (pos = 2; pos < maxLen; pos++)
      {
        if (bytes[pos] == (byte) 0)
@@ -225,13 +224,12 @@
        }
      }
      if (!found)
        throw new UnsupportedEncodingException("Could not find end of " +
          "change number.");
        throw new UnsupportedEncodingException("Could not find end of CSN.");
      pos++;
      if (pos >= maxLen)
        throw new UnsupportedEncodingException("Reached end of packet.");
      // Force assured flag to false
      bytes[pos] = (byte) 0;
      bytes[pos] = 0;
      // Store computed VLatest serialized form
      realUpdateMsgNotAssuredBytesVLatest = bytes;
@@ -242,9 +240,9 @@
   * {@inheritDoc}
   */
  @Override
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    return realUpdateMsg.getChangeNumber();
    return realUpdateMsg.getCSN();
  }
  /**
@@ -278,8 +276,8 @@
    {
      if (obj.getClass() != realUpdateMsg.getClass())
        return false;
      return realUpdateMsg.getChangeNumber().
        equals(((UpdateMsg)obj).getChangeNumber());
      return realUpdateMsg.getCSN().
        equals(((UpdateMsg)obj).getCSN());
    }
    else
    {
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -45,7 +45,7 @@
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.plugin.MultimasterReplication;
import org.opends.server.replication.plugin.ReplicationServerListener;
@@ -494,8 +494,8 @@
        {
          break;
        }
        writeChangesAfterChangeNumber(exportContainer, exportConfig,
            ldifWriter, null, null);
        writeChangesAfterCSN(exportContainer, exportConfig, ldifWriter, null,
            null);
      }
    }
    finally
@@ -618,11 +618,11 @@
  /**
   * Exports or returns all the changes from a ReplicationServerDomain coming
   * after the changeNumber specified in the searchOperation.
   * after the CSN specified in the searchOperation.
   */
  private void writeChangesAfterChangeNumber(ReplicationServerDomain rsd,
  private void writeChangesAfterCSN(ReplicationServerDomain rsd,
      final LDIFExportConfig exportConfig, LDIFWriter ldifWriter,
      SearchOperation searchOperation, final ChangeNumber previousCN)
      SearchOperation searchOperation, final CSN previousCSN)
  {
    for (int serverId : rsd.getServerIds())
    {
@@ -631,7 +631,7 @@
        return;
      }
      ReplicaDBCursor cursor = rsd.getCursorFrom(serverId, previousCN);
      ReplicaDBCursor cursor = rsd.getCursorFrom(serverId, previousCSN);
      if (cursor != null)
      {
        try
@@ -693,25 +693,24 @@
    }
  }
  private ChangeNumber extractChangeNumber(SearchOperation searchOperation)
  private CSN extractCSN(SearchOperation searchOperation)
  {
    if (searchOperation != null)
    {
      return extractChangeNumber(searchOperation.getFilter());
      return extractCSN(searchOperation.getFilter());
    }
    return null;
  }
  /**
   * Attempt to extract a ChangeNumber from searchFilter like
   * Attempt to extract a CSN from searchFilter like
   * ReplicationChangeNumber=xxxx or ReplicationChangeNumber>=xxxx.
   *
   * @param filter The filter to evaluate.
   *
   * @return       The extracted ChangeNumber or null if no ChangeNumber
   *               was found.
   * @param filter
   *          The filter to evaluate.
   * @return The extracted CSN or null if no CSN was found.
   */
  private ChangeNumber extractChangeNumber(SearchFilter filter)
  private CSN extractCSN(SearchFilter filter)
  {
    // Try to optimize for filters like replicationChangeNumber>=xxxxx
    // or replicationChangeNumber=xxxxx :
@@ -726,15 +725,15 @@
      {
        try
        {
          ChangeNumber startingCN =
             new ChangeNumber(filter.getAssertionValue().getValue().toString());
          return new ChangeNumber(startingCN.getTime(),
              startingCN.getSeqnum() - 1, startingCN.getServerId());
          CSN startingCSN =
             new CSN(filter.getAssertionValue().getValue().toString());
          return new CSN(startingCSN.getTime(),
              startingCSN.getSeqnum() - 1, startingCSN.getServerId());
        }
        catch (Exception e)
        {
          // don't try to optimize the search if the ChangeNumber is
          // not a valid replication ChangeNumber.
          // not a valid replication CSN.
        }
      }
    }
@@ -742,12 +741,12 @@
    {
      for (SearchFilter filterComponent : filter.getFilterComponents())
      {
        // This code does not expect more than one CN in the search filter.
        // This code does not expect more than one CSN in the search filter.
        // It is ok, since it is only used by developers/testers for debugging.
        final ChangeNumber previousCN = extractChangeNumber(filterComponent);
        if (previousCN != null)
        final CSN previousCSN = extractCSN(filterComponent);
        if (previousCSN != null)
        {
          return previousCN;
          return previousCSN;
        }
      }
    }
@@ -781,7 +780,7 @@
          AddOperation addOperation = (AddOperation)msg.createOperation(conn);
          dn = DN.decode("puid=" + addMsg.getParentEntryUUID() + "+" +
              CHANGE_NUMBER + "=" + msg.getChangeNumber() + "+" +
              CHANGE_NUMBER + "=" + msg.getCSN() + "+" +
              msg.getDn() + "," + BASE_DN);
          Map<AttributeType,List<Attribute>> attrs =
@@ -862,7 +861,7 @@
            entry.addObjectClass(extensibleObjectOC);
          addAttribute(entry.getUserAttributes(), CHANGE_NUMBER,
              msg.getChangeNumber().toString());
              msg.getCSN().toString());
          addAttribute(entry.getUserAttributes(), "replicationDomain", baseDN);
          // Get the base DN, scope, and filter for the search.
@@ -904,7 +903,7 @@
  private DN computeDN(LDAPUpdateMsg msg) throws DirectoryException
  {
    return DN.decode("uuid=" + msg.getEntryUUID() + "," + CHANGE_NUMBER + "="
        + msg.getChangeNumber() + "," + msg.getDn() + "," + BASE_DN);
        + msg.getCSN() + "," + msg.getDn() + "," + BASE_DN);
  }
  private Entry writeChangeRecord(LDIFWriter ldifWriter,
@@ -1206,9 +1205,9 @@
        findSearchContainers(searchBaseDN);
    for (ReplicationServerDomain exportContainer : searchContainers)
    {
      final ChangeNumber previousCN = extractChangeNumber(searchOperation);
      writeChangesAfterChangeNumber(exportContainer, null, null,
          searchOperation, previousCN);
      final CSN previousCSN = extractCSN(searchOperation);
      writeChangesAfterCSN(exportContainer, null, null, searchOperation,
          previousCSN);
    }
  }
opends/src/server/org/opends/server/replication/server/ReplicationDomainMonitor.java
@@ -34,7 +34,7 @@
import java.util.concurrent.TimeUnit;
import org.opends.messages.Message;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.MonitorMsg;
import org.opends.server.replication.protocol.MonitorRequestMsg;
@@ -260,10 +260,10 @@
  {
    // Let's process our directly connected DS
    // - in the ServerHandler for a given DS1, the stored state contains :
    // -- the max CN produced by DS1
    // -- the last CN consumed by DS1 from DS2..n
    // -- the max CSN produced by DS1
    // -- the last CSN consumed by DS1 from DS2..n
    // - in the RSdomain/dbHandler, the built-in state contains :
    // -- the max CN produced by each server
    // -- the max CSN produced by each server
    // So for a given DS connected we can take the state and the max from
    // the DS/state.
@@ -272,27 +272,27 @@
      final int serverId = ds.getServerId();
      final ServerState dsState = ds.getServerState().duplicate();
      ChangeNumber maxcn = dsState.getChangeNumber(serverId);
      if (maxcn == null)
      CSN maxCSN = dsState.getCSN(serverId);
      if (maxCSN == null)
      {
        // This directly connected LS has never produced any change
        maxcn = new ChangeNumber(0, 0, serverId);
        maxCSN = new CSN(0, 0, serverId);
      }
      pendingMonitorData.setMaxCN(serverId, maxcn);
      pendingMonitorData.setMaxCSN(serverId, maxCSN);
      pendingMonitorData.setLDAPServerState(serverId, dsState);
      pendingMonitorData.setFirstMissingDate(serverId,
          ds.getApproxFirstMissingDate());
    }
    // Then initialize the max CN for the LS that produced something
    // Then initialize the max CSN for the LS that produced something
    // - from our own local db state
    // - whatever they are directly or indirectly connected
    final ServerState dbServerState = domain.getDbServerState();
    pendingMonitorData.setRSState(domain.getLocalRSServerId(), dbServerState);
    for (int serverId : dbServerState)
    {
      ChangeNumber storedCN = dbServerState.getChangeNumber(serverId);
      pendingMonitorData.setMaxCN(serverId, storedCN);
      CSN storedCSN = dbServerState.getCSN(serverId);
      pendingMonitorData.setMaxCSN(serverId, storedCSN);
    }
  }
@@ -320,10 +320,10 @@
      try
      {
        // Here is the RS state : list <serverID, lastChangeNumber>
        // For each LDAP Server, we keep the max CN across the RSes
        // Here is the RS state : list <serverID, lastCSN>
        // For each LDAP Server, we keep the max CSN across the RSes
        ServerState replServerState = msg.getReplServerDbState();
        pendingMonitorData.setMaxCNs(replServerState);
        pendingMonitorData.setMaxCSNs(replServerState);
        // store the remote RS states.
        pendingMonitorData.setRSState(msg.getSenderID(), replServerState);
@@ -332,7 +332,7 @@
        for (int dsServerId : toIterable(msg.ldapIterator()))
        {
          ServerState dsServerState = msg.getLDAPServerState(dsServerId);
          pendingMonitorData.setMaxCNs(dsServerState);
          pendingMonitorData.setMaxCSNs(dsServerState);
          pendingMonitorData.setLDAPServerState(dsServerId, dsServerState);
          pendingMonitorData.setFirstMissingDate(dsServerId,
              msg.getLDAPApproxFirstMissingDate(dsServerId));
opends/src/server/org/opends/server/replication/server/ReplicationDomainMonitorData.java
@@ -33,7 +33,7 @@
import java.util.concurrent.ConcurrentMap;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.util.TimeThread;
@@ -52,7 +52,7 @@
  /**
   *
   * - For each server, the max (most recent) CN produced
   * - For each server, the max (most recent) CSN produced
   *
   * - For each server, its state i.e. the last processed from of each
   *   other LDAP server.
@@ -73,9 +73,9 @@
  private ConcurrentMap<Integer, ServerState> rsStates =
    new ConcurrentHashMap<Integer, ServerState>();
  /** For each LDAP server, the last(max) CN it published. */
  private ConcurrentMap<Integer, ChangeNumber> maxCNs =
    new ConcurrentHashMap<Integer, ChangeNumber>();
  /** For each LDAP server, the last(max) CSN it published. */
  private ConcurrentMap<Integer, CSN> maxCSNs =
    new ConcurrentHashMap<Integer, CSN>();
  /**
   * For each LDAP server, an approximation of the date of the first missing
@@ -164,24 +164,23 @@
      long lsiMissingChanges = 0;
      if (lsiState != null) {
        for (Entry<Integer, ChangeNumber> entry2 : maxCNs.entrySet())
        for (Entry<Integer, CSN> entry2 : maxCSNs.entrySet())
        {
          final Integer lsjServerId = entry2.getKey();
          final ChangeNumber lsjMaxCN = entry2.getValue();
          ChangeNumber lsiLastCN = lsiState.getChangeNumber(lsjServerId);
          final CSN lsjMaxCSN = entry2.getValue();
          CSN lsiLastCSN = lsiState.getCSN(lsjServerId);
          int missingChangesLsiLsj =
              ChangeNumber.diffSeqNum(lsjMaxCN, lsiLastCN);
          int missingChangesLsiLsj = CSN.diffSeqNum(lsjMaxCSN, lsiLastCSN);
          if (debugEnabled()) {
            mds += "+ diff(" + lsjMaxCN + "-"
                + lsiLastCN + ")=" + missingChangesLsiLsj;
            mds += "+ diff(" + lsjMaxCSN + "-"
                + lsiLastCSN + ")=" + missingChangesLsiLsj;
          }
          /*
          Regarding a DS that is generating changes. If it is a local DS1,
          we get its server state, store it, then retrieve server states of
          remote DSs. When a remote server state is coming, it may contain
          a change number for DS1 which is newer than the one we locally
          a CSN for DS1 which is newer than the one we locally
          stored in the server state of DS1. To prevent seeing DS1 has
          missing changes whereas it is wrong, we replace the value with 0
          if it is a low value. We cannot overwrite big values as they may be
@@ -218,18 +217,17 @@
      long lsiMissingChanges = 0;
      if (lsiState != null)
      {
        for (Entry<Integer, ChangeNumber> entry2 : maxCNs.entrySet())
        for (Entry<Integer, CSN> entry2 : maxCSNs.entrySet())
        {
          final Integer lsjServerId = entry2.getKey();
          final ChangeNumber lsjMaxCN = entry2.getValue();
          ChangeNumber lsiLastCN = lsiState.getChangeNumber(lsjServerId);
          final CSN lsjMaxCSN = entry2.getValue();
          CSN lsiLastCSN = lsiState.getCSN(lsjServerId);
          int missingChangesLsiLsj =
              ChangeNumber.diffSeqNum(lsjMaxCN, lsiLastCN);
          int missingChangesLsiLsj = CSN.diffSeqNum(lsjMaxCSN, lsiLastCSN);
          if (debugEnabled()) {
            mds += "+ diff(" + lsjMaxCN + "-"
                + lsiLastCN + ")=" + missingChangesLsiLsj;
            mds += "+ diff(" + lsjMaxCSN + "-"
                + lsiLastCSN + ")=" + missingChangesLsiLsj;
          }
          lsiMissingChanges += missingChangesLsiLsj;
        }
@@ -238,7 +236,7 @@
      {
        mds += "=" + lsiMissingChanges;
      }
      this.missingChangesRS.put(lsiServerId,lsiMissingChanges);
      this.missingChangesRS.put(lsiServerId, lsiMissingChanges);
      if (debugEnabled())
      {
@@ -258,12 +256,12 @@
  {
    String mds = "Monitor data=\n";
    // maxCNs
    for (Entry<Integer, ChangeNumber> entry : maxCNs.entrySet())
    // maxCSNs
    for (Entry<Integer, CSN> entry : maxCSNs.entrySet())
    {
      final Integer serverId = entry.getKey();
      final ChangeNumber cn = entry.getValue();
      mds += "\nmaxCNs(" + serverId + ")= " + cn.toStringUI();
      final CSN csn = entry.getValue();
      mds += "\nmaxCSNs(" + serverId + ")= " + csn.toStringUI();
    }
    // LDAP data
@@ -291,35 +289,35 @@
  }
  /**
   * From a provided state, sets the max CN of the monitor data.
   * From a provided state, sets the max CSN of the monitor data.
   * @param state the provided state.
   */
  public void setMaxCNs(ServerState state)
  public void setMaxCSNs(ServerState state)
  {
    for (Integer serverId : state) {
      ChangeNumber newCN = state.getChangeNumber(serverId);
      setMaxCN(serverId, newCN);
      CSN newCSN = state.getCSN(serverId);
      setMaxCSN(serverId, newCSN);
    }
  }
  /**
   * For the provided serverId, sets the provided CN as the max if
   * For the provided serverId, sets the provided CSN as the max if
   * it is newer than the current max.
   * @param serverId the provided serverId
   * @param newCN the provided new CN
   * @param newCSN the provided new CSN
   */
  public void setMaxCN(int serverId, ChangeNumber newCN)
  public void setMaxCSN(int serverId, CSN newCSN)
  {
    if (newCN==null) return;
    if (newCSN==null) return;
    ChangeNumber currentMaxCN = maxCNs.get(serverId);
    if (currentMaxCN == null)
    CSN currentMaxCSN = maxCSNs.get(serverId);
    if (currentMaxCSN == null)
    {
      maxCNs.put(serverId, newCN);
      maxCSNs.put(serverId, newCSN);
    }
    else if (newCN.newer(currentMaxCN))
    else if (newCSN.newer(currentMaxCSN))
    {
      maxCNs.replace(serverId, newCN);
      maxCSNs.replace(serverId, newCSN);
    }
  }
opends/src/server/org/opends/server/replication/server/ReplicationServer.java
@@ -1563,7 +1563,7 @@
  /**
   * Excluded a list of domain from eligibility computation.
   * @param excludedBaseDNs the provided list of baseDNs excluded from
   *                          the computation of eligibleCN.
   *                          the computation of eligibleCSN.
   */
  public void disableEligibility(Set<String> excludedBaseDNs)
  {
@@ -1571,50 +1571,50 @@
  }
  /**
   * Returns the eligible CN cross domains - relies on the eligible CN from
   * Returns the eligible CSN cross domains - relies on the eligible CSN from
   * each domain.
   * @return the cross domain eligible CN.
   * @return the cross domain eligible CSN.
   */
  public ChangeNumber getEligibleCN()
  public CSN getEligibleCSN()
  {
    String debugLog = "";
    // traverse the domains and get the eligible CN from each domain
    // store the oldest one as the cross domain eligible CN
    ChangeNumber eligibleCN = null;
    // traverse the domains and get the eligible CSN from each domain
    // store the oldest one as the cross domain eligible CSN
    CSN eligibleCSN = null;
    for (ReplicationServerDomain domain : getReplicationServerDomains())
    {
      if (contains(excludedBaseDNs, domain.getBaseDn()))
        continue;
      final ChangeNumber domainEligibleCN = domain.getEligibleCN();
      if (eligibleCN == null
          || (domainEligibleCN != null && domainEligibleCN.older(eligibleCN)))
      final CSN domainEligibleCSN = domain.getEligibleCSN();
      if (eligibleCSN == null
          ||(domainEligibleCSN != null && domainEligibleCSN.older(eligibleCSN)))
      {
        eligibleCN = domainEligibleCN;
        eligibleCSN = domainEligibleCSN;
      }
      if (debugEnabled())
      {
        final String dates = domainEligibleCN == null ?
            "" : new Date(domainEligibleCN.getTime()).toString();
        final String dates = domainEligibleCSN == null ?
            "" : new Date(domainEligibleCSN.getTime()).toString();
        debugLog += "[baseDN=" + domain.getBaseDn()
            + "] [eligibleCN=" + domainEligibleCN + ", " + dates + "]";
            + "] [eligibleCSN=" + domainEligibleCSN + ", " + dates + "]";
      }
    }
    if (eligibleCN==null )
    if (eligibleCSN==null )
    {
      eligibleCN = new ChangeNumber(TimeThread.getTime(), 0, 0);
      eligibleCSN = new CSN(TimeThread.getTime(), 0, 0);
    }
    if (debugEnabled()) {
      TRACER.debugInfo("In " + this + " getEligibleCN() ends with " +
        " the following domainEligibleCN for each domain :" + debugLog +
        " thus CrossDomainEligibleCN=" + eligibleCN +
        "  ts=" + new Date(eligibleCN.getTime()).toString());
      TRACER.debugInfo("In " + this + " getEligibleCSN() ends with " +
        " the following domainEligibleCSN for each domain :" + debugLog +
        " thus CrossDomainEligibleCSN=" + eligibleCSN +
        "  ts=" + new Date(eligibleCSN.getTime()).toString());
    }
    return eligibleCN;
    return eligibleCSN;
  }
  private boolean contains(Set<String> col, String elem)
@@ -1699,13 +1699,13 @@
  /**
   * Get first and last DraftCN.
   *
   * @param  crossDomainEligibleCN The provided crossDomainEligibleCN used as
   * @param  crossDomainEligibleCSN The provided crossDomainEligibleCSN used as
   *                               the upper limit for the lastDraftCN
   * @param  excludedBaseDNs       The baseDNs that are excluded from the ECL.
   * @return                       The first and last draftCN.
   * @throws DirectoryException    When it happens.
   */
  public int[] getECLDraftCNLimits(ChangeNumber crossDomainEligibleCN,
  public int[] getECLDraftCNLimits(CSN crossDomainEligibleCSN,
      Set<String> excludedBaseDNs) throws DirectoryException
  {
    /* The content of the DraftCNdb depends on the SEARCH operations done before
@@ -1724,7 +1724,7 @@
     *  - initialized with the last record from the DraftCNdb (0 if none)
     *    and consider the genState associated
     *  - to the last DraftCN, we add the count of updates in the replchangelog
     *     FROM that genState TO the crossDomainEligibleCN
     *     FROM that genState TO the crossDomainEligibleCSN
     *     (this diff is done domain by domain)
     */
@@ -1735,7 +1735,7 @@
    int firstDraftCN = changelogDB.getFirstDraftCN();
    Map<String,ServerState> domainsServerStateForLastSeqnum = null;
    ChangeNumber changeNumberForLastSeqnum = null;
    CSN csnForLastSeqnum = null;
    String domainForLastSeqnum = null;
    if (firstDraftCN < 1)
    {
@@ -1756,8 +1756,8 @@
          splitGenStateToServerStates(lastSeqnumGenState);
      }
      // Get the changeNumber associated with the current last DraftCN
      changeNumberForLastSeqnum = changelogDB.getChangeNumber(lastDraftCN);
      // Get the CSN associated with the current last DraftCN
      csnForLastSeqnum = changelogDB.getCSN(lastDraftCN);
      // Get the domain associated with the current last DraftCN
      domainForLastSeqnum = changelogDB.getBaseDN(lastDraftCN);
@@ -1775,11 +1775,10 @@
      if (domainsServerStateForLastSeqnum == null)
      {
        // Count changes of this domain from the beginning of the changelog
        ChangeNumber trimCN =
            new ChangeNumber(rsd.getLatestDomainTrimDate(), 0,0);
        CSN trimCSN = new CSN(rsd.getLatestDomainTrimDate(), 0, 0);
        ec = rsd.getEligibleCount(
                  rsd.getStartState().duplicateOnlyOlderThan(trimCN),
                  crossDomainEligibleCN);
                  rsd.getStartState().duplicateOnlyOlderThan(trimCSN),
                  crossDomainEligibleCSN);
      }
      else
      {
@@ -1791,14 +1790,13 @@
        //  the date of the most recent change from this last draft record
        if (newestDate == 0)
        {
          newestDate = changeNumberForLastSeqnum.getTime();
          newestDate = csnForLastSeqnum.getTime();
        }
        // And count changes of this domain from the date of the
        // lastseqnum record (that does not refer to this domain)
        ChangeNumber cnx = new ChangeNumber(newestDate,
            changeNumberForLastSeqnum.getSeqnum(), 0);
        ec = rsd.getEligibleCount(cnx, crossDomainEligibleCN);
        CSN csnx = new CSN(newestDate, csnForLastSeqnum.getSeqnum(), 0);
        ec = rsd.getEligibleCount(csnx, crossDomainEligibleCSN);
        if (domainForLastSeqnum.equalsIgnoreCase(rsd.getBaseDn()))
          ec--;
@@ -1839,7 +1837,7 @@
          || rsd.getDbServerState().isEmpty())
        continue;
      result.update(rsd.getBaseDn(), rsd.getEligibleState(getEligibleCN()));
      result.update(rsd.getBaseDn(), rsd.getEligibleState(getEligibleCSN()));
    }
    return result;
  }
opends/src/server/org/opends/server/replication/server/ReplicationServerDomain.java
@@ -136,7 +136,7 @@
   * The needed info for each received assured update message we are waiting
   * acks for.
   * <p>
   * Key: a change number matching a received update message which requested
   * Key: a CSN matching a received update message which requested
   * assured mode usage (either safe read or safe data mode)
   * <p>
   * Value: The object holding every info needed about the already received acks
@@ -145,8 +145,8 @@
   * @see ExpectedAcksInfo For more details, see ExpectedAcksInfo and its sub
   *      classes javadoc.
   */
  private final ConcurrentHashMap<ChangeNumber, ExpectedAcksInfo> waitingAcks =
    new ConcurrentHashMap<ChangeNumber, ExpectedAcksInfo>();
  private final Map<CSN, ExpectedAcksInfo> waitingAcks =
    new ConcurrentHashMap<CSN, ExpectedAcksInfo>();
  /**
   * The timer used to run the timeout code (timer tasks) for the assured update
@@ -193,8 +193,8 @@
  public void put(UpdateMsg update, ServerHandler sourceHandler)
    throws IOException
  {
    ChangeNumber cn = update.getChangeNumber();
    int serverId = cn.getServerId();
    CSN csn = update.getCSN();
    int serverId = csn.getServerId();
    sourceHandler.updateServerState(update);
    sourceHandler.incrementInCount();
@@ -271,11 +271,11 @@
        // The following timer will time out and send an timeout ack to the
        // requester if the acks are not received in time. The timer will also
        // remove the object from this map.
        waitingAcks.put(cn, preparedAssuredInfo.expectedAcksInfo);
        waitingAcks.put(csn, preparedAssuredInfo.expectedAcksInfo);
        // Arm timer for this assured update message (wait for acks until it
        // times out)
        AssuredTimeoutTask assuredTimeoutTask = new AssuredTimeoutTask(cn);
        AssuredTimeoutTask assuredTimeoutTask = new AssuredTimeoutTask(csn);
        assuredTimeoutTimer.schedule(assuredTimeoutTask,
            localReplicationServer.getAssuredTimeout());
        // Purge timer every 100 treated messages
@@ -319,7 +319,7 @@
        {
          if (debugEnabled())
          {
            debug("update " + update.getChangeNumber()
            debug("update " + update.getCSN()
                + " will not be sent to replication server "
                + rsHandler.getServerId() + " with generation id "
                + rsHandler.getGenerationId() + " different from local "
@@ -362,7 +362,7 @@
        {
          if (dsStatus == ServerStatus.BAD_GEN_ID_STATUS)
          {
            debug("update " + update.getChangeNumber()
            debug("update " + update.getCSN()
                + " will not be sent to directory server "
                + dsHandler.getServerId() + " with generation id "
                + dsHandler.getGenerationId() + " different from local "
@@ -370,7 +370,7 @@
          }
          if (dsStatus == ServerStatus.FULL_UPDATE_STATUS)
          {
            debug("update " + update.getChangeNumber()
            debug("update " + update.getCSN()
                + " will not be sent to directory server "
                + dsHandler.getServerId() + " as it is in full update");
          }
@@ -499,7 +499,7 @@
  private PreparedAssuredInfo processSafeReadUpdateMsg(
    UpdateMsg update, ServerHandler sourceHandler) throws IOException
  {
    ChangeNumber cn = update.getChangeNumber();
    CSN csn = update.getCSN();
    byte groupId = localReplicationServer.getGroupId();
    byte sourceGroupId = sourceHandler.getGroupId();
    List<Integer> expectedServers = new ArrayList<Integer>();
@@ -550,7 +550,7 @@
    if (expectedServers.size() > 0)
    {
      // Some other acks to wait for
      preparedAssuredInfo.expectedAcksInfo = new SafeReadExpectedAcksInfo(cn,
      preparedAssuredInfo.expectedAcksInfo = new SafeReadExpectedAcksInfo(csn,
        sourceHandler, expectedServers, wrongStatusServers);
      preparedAssuredInfo.expectedServers = expectedServers;
    }
@@ -558,7 +558,7 @@
    if (preparedAssuredInfo.expectedServers == null)
    {
      // No eligible servers found, send the ack immediately
      sourceHandler.send(new AckMsg(cn));
      sourceHandler.send(new AckMsg(csn));
    }
    return preparedAssuredInfo;
@@ -582,7 +582,7 @@
  private PreparedAssuredInfo processSafeDataUpdateMsg(
    UpdateMsg update, ServerHandler sourceHandler) throws IOException
  {
    ChangeNumber cn = update.getChangeNumber();
    CSN csn = update.getCSN();
    boolean interestedInAcks = false;
    byte safeDataLevel = update.getSafeDataLevel();
    byte groupId = localReplicationServer.getGroupId();
@@ -608,7 +608,7 @@
             * mode with safe data level 1, coming from a DS. No need to wait
             * for more acks
             */
            sourceHandler.send(new AckMsg(cn));
            sourceHandler.send(new AckMsg(csn));
          } else
          {
            /**
@@ -628,7 +628,7 @@
           */
          if (safeDataLevel > (byte) 1)
          {
            sourceHandler.send(new AckMsg(cn));
            sourceHandler.send(new AckMsg(csn));
          }
        }
    }
@@ -656,14 +656,14 @@
        byte finalSdl = (nExpectedServers >= neededAdditionalServers) ?
          (byte)sdl : // Keep level as it was
          (byte)(nExpectedServers+1); // Change level to match what's available
        preparedAssuredInfo.expectedAcksInfo = new SafeDataExpectedAcksInfo(cn,
        preparedAssuredInfo.expectedAcksInfo = new SafeDataExpectedAcksInfo(csn,
          sourceHandler, finalSdl, expectedServers);
        preparedAssuredInfo.expectedServers = expectedServers;
      } else
      {
        // level > 1 and source is a DS but no eligible servers found, send the
        // ack immediately
        sourceHandler.send(new AckMsg(cn));
        sourceHandler.send(new AckMsg(csn));
      }
    }
@@ -706,8 +706,8 @@
  {
    // Retrieve the expected acks info for the update matching the original
    // sent update.
    ChangeNumber cn = ack.getChangeNumber();
    ExpectedAcksInfo expectedAcksInfo = waitingAcks.get(cn);
    CSN csn = ack.getCSN();
    ExpectedAcksInfo expectedAcksInfo = waitingAcks.get(csn);
    if (expectedAcksInfo != null)
    {
@@ -728,7 +728,7 @@
        if (expectedAcksInfo.processReceivedAck(ackingServer, ack))
        {
          // Remove the object from the map as no more needed
          waitingAcks.remove(cn);
          waitingAcks.remove(csn);
          AckMsg finalAck = expectedAcksInfo.createAck(false);
          ServerHandler origServer = expectedAcksInfo.getRequesterServer();
          try
@@ -744,7 +744,7 @@
            mb.append(ERR_RS_ERROR_SENDING_ACK.get(
              Integer.toString(localReplicationServer.getServerId()),
              Integer.toString(origServer.getServerId()),
              cn.toString(), baseDn));
              csn.toString(), baseDn));
            mb.append(stackTraceToSingleLineString(e));
            logError(mb.toMessage());
            stopServer(origServer, false);
@@ -755,7 +755,7 @@
        }
      }
    }
    /* Else the timeout occurred for the update matching this change number
    /* Else the timeout occurred for the update matching this CSN
     * and the ack with timeout error has probably already been sent.
     */
  }
@@ -767,15 +767,15 @@
   */
  private class AssuredTimeoutTask extends TimerTask
  {
    private ChangeNumber cn = null;
    private CSN csn = null;
    /**
     * Constructor for the timer task.
     * @param cn The changeNumber of the assured update we are waiting acks for
     * @param csn The CSN of the assured update we are waiting acks for
     */
    public AssuredTimeoutTask(ChangeNumber cn)
    public AssuredTimeoutTask(CSN csn)
    {
      this.cn = cn;
      this.csn = csn;
    }
    /**
@@ -785,7 +785,7 @@
    @Override
    public void run()
    {
      ExpectedAcksInfo expectedAcksInfo = waitingAcks.get(cn);
      ExpectedAcksInfo expectedAcksInfo = waitingAcks.get(csn);
      if (expectedAcksInfo != null)
      {
@@ -798,14 +798,14 @@
            return;
          }
          // Remove the object from the map as no more needed
          waitingAcks.remove(cn);
          waitingAcks.remove(csn);
          // Create the timeout ack and send him to the server the assured
          // update message came from
          AckMsg finalAck = expectedAcksInfo.createAck(true);
          ServerHandler origServer = expectedAcksInfo.getRequesterServer();
          if (debugEnabled())
          {
            debug("sending timeout for assured update with change number " + cn
            debug("sending timeout for assured update with CSN " + csn
                + " to serverId=" + origServer.getServerId());
          }
          try
@@ -821,7 +821,7 @@
            mb.append(ERR_RS_ERROR_SENDING_ACK.get(
                Integer.toString(localReplicationServer.getServerId()),
                Integer.toString(origServer.getServerId()),
                cn.toString(), baseDn));
                csn.toString(), baseDn));
            mb.append(stackTraceToSingleLineString(e));
            logError(mb.toMessage());
            stopServer(origServer, false);
@@ -1268,13 +1268,12 @@
   *
   * @param serverId
   *          Identifier of the server for which the cursor is created.
   * @param startAfterCN
   * @param startAfterCSN
   *          Starting point for the cursor.
   * @return the created {@link ReplicaDBCursor}. Null when no DB is
   *         available or the DB is empty for the provided serverId .
   * @return the created {@link ReplicaDBCursor}. Null when no DB is available
   *         or the DB is empty for the provided serverId .
   */
  public ReplicaDBCursor getCursorFrom(int serverId,
      ChangeNumber startAfterCN)
  public ReplicaDBCursor getCursorFrom(int serverId, CSN startAfterCSN)
  {
    DbHandler dbHandler = sourceDbHandlers.get(serverId);
    if (dbHandler == null)
@@ -1285,7 +1284,7 @@
    ReplicaDBCursor cursor;
    try
    {
      cursor = dbHandler.generateCursorFrom(startAfterCN);
      cursor = dbHandler.generateCursorFrom(startAfterCSN);
    }
    catch (Exception e)
    {
@@ -1303,13 +1302,13 @@
 /**
  * Count the number of changes in the replication changelog for the provided
  * serverID, between 2 provided changenumbers.
  * serverID, between 2 provided CSNs.
  * @param serverId Identifier of the server for which to compute the count.
  * @param from lower limit changenumber.
  * @param to   upper limit changenumber.
  * @param from lower limit CSN.
  * @param to   upper limit CSN.
  * @return the number of changes.
  */
  public long getCount(int serverId, ChangeNumber from, ChangeNumber to)
  public long getCount(int serverId, CSN from, CSN to)
  {
    DbHandler dbHandler = sourceDbHandlers.get(serverId);
    if (dbHandler != null)
@@ -2646,57 +2645,59 @@
   * <pre>
   *     s1               s2          s3
   *     --               --          --
   *                                 cn31
   *     cn15
   *                                 csn31
   *     csn15
   *
   *  ----------------------------------------- eligibleCN
   *     cn14
   *                     cn26
   *     cn13
   *  ----------------------------------------- eligibleCSN
   *     csn14
   *                     csn26
   *     csn13
   * </pre>
   *
   * The eligibleState is : s1;cn14 / s2;cn26 / s3;cn31
   * The eligibleState is : s1;csn14 / s2;csn26 / s3;csn31
   *
   * @param eligibleCN              The provided eligibleCN.
   * @param eligibleCSN
   *          The provided eligible CSN.
   * @return The computed eligible server state.
   */
  public ServerState getEligibleState(ChangeNumber eligibleCN)
  public ServerState getEligibleState(CSN eligibleCSN)
  {
    ServerState dbState = getDbServerState();
    // The result is initialized from the dbState.
    // From it, we don't want to keep the changes newer than eligibleCN.
    // From it, we don't want to keep the changes newer than eligibleCSN.
    ServerState result = dbState.duplicate();
    if (eligibleCN != null)
    if (eligibleCSN != null)
    {
      for (int serverId : dbState)
      {
        DbHandler h = sourceDbHandlers.get(serverId);
        ChangeNumber mostRecentDbCN = dbState.getChangeNumber(serverId);
        CSN mostRecentDbCSN = dbState.getCSN(serverId);
        try {
          // Is the most recent change in the Db newer than eligible CN ?
          // if yes (like cn15 in the example above, then we have to go back
          // to the Db and look for the change older than  eligible CN (cn14)
          if (eligibleCN.olderOrEqual(mostRecentDbCN)) {
            // let's try to seek the first change <= eligibleCN
          // Is the most recent change in the Db newer than eligible CSN ?
          // if yes (like csn15 in the example above, then we have to go back
          // to the Db and look for the change older than eligible CSN (csn14)
          if (eligibleCSN.olderOrEqual(mostRecentDbCSN))
          {
            // let's try to seek the first change <= eligibleCSN
            ReplicaDBCursor cursor = null;
            try {
              cursor = h.generateCursorFrom(eligibleCN);
              cursor = h.generateCursorFrom(eligibleCSN);
              if (cursor != null && cursor.getChange() != null) {
                ChangeNumber newCN = cursor.getChange().getChangeNumber();
                result.update(newCN);
                CSN newCSN = cursor.getChange().getCSN();
                result.update(newCSN);
              }
            } catch (ChangelogException e) {
              // there's no change older than eligibleCN (case of s3/cn31)
              result.update(new ChangeNumber(0, 0, serverId));
              // there's no change older than eligibleCSN (case of s3/csn31)
              result.update(new CSN(0, 0, serverId));
            } finally {
              close(cursor);
            }
          } else {
            // for this serverId, all changes in the ChangelogDb are holder
            // than eligibleCN , the most recent in the db is our guy.
            result.update(mostRecentDbCN);
            // than eligibleCSN, the most recent in the db is our guy.
            result.update(mostRecentDbCSN);
          }
        } catch (Exception e) {
          logError(ERR_WRITER_UNEXPECTED_EXCEPTION
@@ -2733,15 +2734,17 @@
  }
  /**
   * Returns the eligibleCN for that domain - relies on the ChangeTimeHeartbeat
   * state.
   * For each DS, take the oldest CN from the changetime heartbeat state
   * and from the changelog db last CN. Can be null.
   * @return the eligible CN.
   * Returns the eligible CSN for that domain - relies on the
   * ChangeTimeHeartbeat state.
   * <p>
   * For each DS, take the oldest CSN from the changetime heartbeat state and
   * from the changelog db last CSN. Can be null.
   *
   * @return the eligible CSN.
   */
  public ChangeNumber getEligibleCN()
  public CSN getEligibleCSN()
  {
    ChangeNumber eligibleCN = null;
    CSN eligibleCSN = null;
    for (DbHandler db : sourceDbHandlers.values())
    {
@@ -2749,8 +2752,8 @@
      int serverId = db.getServerId();
      // Should it be considered for eligibility ?
      ChangeNumber heartbeatLastCN =
        getChangeTimeHeartbeatState().getChangeNumber(serverId);
      CSN heartbeatLastCSN =
        getChangeTimeHeartbeatState().getCSN(serverId);
      // If the most recent UpdateMsg or CLHeartbeatMsg received is very old
      // then the domain is considered down and not considered for eligibility
@@ -2776,24 +2779,24 @@
        continue;
      }
      ChangeNumber changelogLastCN = db.getLastChange();
      if (changelogLastCN != null
          && (eligibleCN == null || changelogLastCN.newer(eligibleCN)))
      CSN changelogLastCSN = db.getLastChange();
      if (changelogLastCSN != null
          && (eligibleCSN == null || changelogLastCSN.newer(eligibleCSN)))
      {
        eligibleCN = changelogLastCN;
        eligibleCSN = changelogLastCSN;
      }
      if (heartbeatLastCN != null
          && (eligibleCN == null || heartbeatLastCN.newer(eligibleCN)))
      if (heartbeatLastCSN != null
          && (eligibleCSN == null || heartbeatLastCSN.newer(eligibleCSN)))
      {
        eligibleCN = heartbeatLastCN;
        eligibleCSN = heartbeatLastCSN;
      }
    }
    if (debugEnabled())
    {
      debug("getEligibleCN() returns result =" + eligibleCN);
      debug("getEligibleCSN() returns result =" + eligibleCSN);
    }
    return eligibleCN;
    return eligibleCSN;
  }
  private boolean isServerConnected(int serverId)
@@ -2816,7 +2819,7 @@
  /**
   * Processes a ChangeTimeHeartbeatMsg received, by storing the CN (timestamp)
   * Processes a ChangeTimeHeartbeatMsg received, by storing the CSN (timestamp)
   * value received, and forwarding the message to the other RSes.
   * @param senderHandler The handler for the server that sent the heartbeat.
   * @param msg The message to process.
@@ -2840,7 +2843,7 @@
    try
    {
      storeReceivedCTHeartbeat(msg.getChangeNumber());
      storeReceivedCTHeartbeat(msg.getCSN());
      if (senderHandler.isDataServer())
      {
        // If we are the first replication server warned,
@@ -2874,34 +2877,34 @@
  /**
   * Store a change time value received from a data server.
   * @param cn The provided change time.
   * @param csn The provided change time.
   */
  public void storeReceivedCTHeartbeat(ChangeNumber cn)
  public void storeReceivedCTHeartbeat(CSN csn)
  {
    // TODO:May be we can spare processing by only storing CN (timestamp)
    // TODO:May be we can spare processing by only storing CSN (timestamp)
    // instead of a server state.
    getChangeTimeHeartbeatState().update(cn);
    getChangeTimeHeartbeatState().update(csn);
  }
  /**
   * This methods count the changes, server by server :
   * - from a serverState start point
   * - to (inclusive) an end point (the provided endCN).
   * - to (inclusive) an end point (the provided endCSN).
   * @param startState The provided start server state.
   * @param endCN The provided end change number.
   * @return The number of changes between startState and endCN.
   * @param endCSN The provided end CSN.
   * @return The number of changes between startState and endCSN.
   */
  public long getEligibleCount(ServerState startState, ChangeNumber endCN)
  public long getEligibleCount(ServerState startState, CSN endCSN)
  {
    long res = 0;
    for (int serverId : getDbServerState())
    {
      ChangeNumber startCN = startState.getChangeNumber(serverId);
      long serverIdRes = getCount(serverId, startCN, endCN);
      CSN startCSN = startState.getCSN(serverId);
      long serverIdRes = getCount(serverId, startCSN, endCSN);
      // The startPoint is excluded when counting the ECL eligible changes
      if (startCN != null && serverIdRes > 0)
      if (startCSN != null && serverIdRes > 0)
      {
        serverIdRes--;
      }
@@ -2912,20 +2915,20 @@
  }
  /**
   * This methods count the changes, server by server :
   * - from a start CN
   * - to (inclusive) an end point (the provided endCN).
   * @param startCN The provided start changeNumber.
   * @param endCN The provided end change number.
   * @return The number of changes between startTime and endCN.
   * This methods count the changes, server by server:
   * - from a start CSN
   * - to (inclusive) an end point (the provided endCSN).
   * @param startCSN The provided start CSN.
   * @param endCSN The provided end CSN.
   * @return The number of changes between startTime and endCSN.
   */
  public long getEligibleCount(ChangeNumber startCN, ChangeNumber endCN)
  public long getEligibleCount(CSN startCSN, CSN endCSN)
  {
    long res = 0;
    for (int serverId : getDbServerState()) {
      ChangeNumber lStartCN =
          new ChangeNumber(startCN.getTime(), startCN.getSeqnum(), serverId);
      res += getCount(serverId, lStartCN, endCN);
      CSN lStartCSN =
          new CSN(startCSN.getTime(), startCSN.getSeqnum(), serverId);
      res += getCount(serverId, lStartCSN, endCSN);
    }
    return res;
  }
opends/src/server/org/opends/server/replication/server/SafeDataExpectedAcksInfo.java
@@ -31,13 +31,14 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.AckMsg;
import static org.opends.server.loggers.debug.DebugLogger.*;
/**
 * This class holds every info needed about the expected acks for a received
 * update message requesting assured replication with Safe Data sub-mode.
@@ -51,27 +52,29 @@
   */
  private static final DebugTracer TRACER = getTracer();
  // Requested level of safe data when the update message was received.
  private byte safeDataLevel = (byte)-1;
  /** Requested level of safe data when the update message was received. */
  private byte safeDataLevel = -1;
  // Number of received acks for the matching update message, up to now
  // Already set to 1 as the local RS receiving the message from a DS counts.
  private byte numReceivedAcks = (byte)1;
  /**
   * Number of received acks for the matching update message, up to now Already
   * set to 1 as the local RS receiving the message from a DS counts.
   */
  private byte numReceivedAcks = 1;
  /**
   * Creates a new SafeDataExpectedAcksInfo.
   * @param changeNumber The change number of the assured update message
   * @param csn The CSN of the assured update message
   * @param requesterServerHandler The server that sent the assured update
   * message
   * @param safeDataLevel The Safe Data level requested for the assured
   * update message
   * @param expectedServers The list of servers we want an ack from
   */
  public SafeDataExpectedAcksInfo(ChangeNumber changeNumber,
  public SafeDataExpectedAcksInfo(CSN csn,
    ServerHandler requesterServerHandler, byte safeDataLevel,
    List<Integer> expectedServers)
  {
    super(changeNumber, requesterServerHandler, AssuredMode.SAFE_DATA_MODE,
    super(csn, requesterServerHandler, AssuredMode.SAFE_DATA_MODE,
      expectedServers);
    this.safeDataLevel = safeDataLevel;
  }
@@ -79,7 +82,8 @@
  /**
   * {@inheritDoc}
   */
   public boolean processReceivedAck(ServerHandler ackingServer, AckMsg ackMsg)
  @Override
  public boolean processReceivedAck(ServerHandler ackingServer, AckMsg ackMsg)
  {
    /*
     * Security: although a DS should not respond to an update message sent to
@@ -117,9 +121,10 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public AckMsg createAck(boolean timeout)
  {
    AckMsg ack = new AckMsg(changeNumber);
    AckMsg ack = new AckMsg(csn);
    if (timeout)
    {
opends/src/server/org/opends/server/replication/server/SafeReadExpectedAcksInfo.java
@@ -23,20 +23,21 @@
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.server;
import java.util.ArrayList;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import java.util.List;
import java.util.Set;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.AckMsg;
import static org.opends.server.loggers.debug.DebugLogger.*;
/**
 * This class holds every info needed about the expected acks for a received
 * update message requesting assured replication with Safe Read sub-mode.
@@ -50,18 +51,20 @@
   */
  private static final DebugTracer TRACER = getTracer();
  // Did some servers go in timeout when the matching update was sent ?
  /** Did some servers go in timeout when the matching update was sent ?. */
  private boolean hasTimeout = false;
  // Were some servers in wrong status when the matching update was sent ?
  /** Were some servers in wrong status when the matching update was sent ?. */
  private boolean hasWrongStatus = false;
  // Did some servers make an error replaying the sent matching update ?
  /** Did some servers make an error replaying the sent matching update ?. */
  private boolean hasReplayError = false;
  // The list of server ids that had errors for the sent matching update
  // Each server id of the list had one of the
  // 3 possible errors (timeout, wrong status or replay error)
  /**
   * The list of server ids that had errors for the sent matching update Each
   * server id of the list had one of the 3 possible errors (timeout, wrong
   * status or replay error).
   */
  private List<Integer> failedServers = new ArrayList<Integer>();
  /**
@@ -75,7 +78,7 @@
  /**
   * Creates a new SafeReadExpectedAcksInfo.
   * @param changeNumber The change number of the assured update message
   * @param csn The CSN of the assured update message
   * @param requesterServerHandler The server that sent the assured update
   * message
   * @param expectedServers The list of servers we want an ack from (they are
@@ -84,11 +87,11 @@
   * wrongStatus (degraded status) to keep trace of the error for the future
   * returning ack we gonna compute
   */
  public SafeReadExpectedAcksInfo(ChangeNumber changeNumber,
  public SafeReadExpectedAcksInfo(CSN csn,
    ServerHandler requesterServerHandler, List<Integer> expectedServers,
    List<Integer> wrongStatusServers)
  {
    super(changeNumber, requesterServerHandler, AssuredMode.SAFE_READ_MODE,
    super(csn, requesterServerHandler, AssuredMode.SAFE_READ_MODE,
      expectedServers);
    // Keep track of potential servers detected in wrong status
@@ -156,6 +159,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean processReceivedAck(ServerHandler ackingServer, AckMsg ackMsg)
  {
    // Get the ack status for the matching server
@@ -204,9 +208,10 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public AckMsg createAck(boolean timeout)
  {
    AckMsg ack = new AckMsg(changeNumber);
    AckMsg ack = new AckMsg(csn);
    // Fill collected errors info
    ack.setHasTimeout(hasTimeout);
opends/src/server/org/opends/server/replication/server/ServerHandler.java
@@ -39,7 +39,7 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.protocol.*;
@@ -383,13 +383,13 @@
   */
  public long getApproxFirstMissingDate()
  {
    // Get the older CN received
    ChangeNumber olderUpdateCN = getOlderUpdateCN();
    if (olderUpdateCN != null)
    // Get the older CSN received
    CSN olderUpdateCSN = getOlderUpdateCSN();
    if (olderUpdateCSN != null)
    {
      // If not present in the local RS db,
      // then approximate with the older update time
      return olderUpdateCN.getTime();
      return olderUpdateCSN.getTime();
    }
    return 0;
  }
opends/src/server/org/opends/server/replication/server/ServerReader.java
@@ -142,7 +142,7 @@
                if (dsStatus == BAD_GEN_ID_STATUS)
                  logError(WARN_IGNORING_UPDATE_FROM_DS_BADGENID.get(
                      handler.getReplicationServerId(),
                      updateMsg.getChangeNumber().toString(),
                      updateMsg.getCSN().toString(),
                      handler.getBaseDN(), handler.getServerId(),
                      session.getReadableRemoteAddress(),
                      handler.getGenerationId(),
@@ -150,7 +150,7 @@
                if (dsStatus == FULL_UPDATE_STATUS)
                  logError(WARN_IGNORING_UPDATE_FROM_DS_FULLUP.get(
                      handler.getReplicationServerId(),
                      updateMsg.getChangeNumber().toString(),
                      updateMsg.getCSN().toString(),
                      handler.getBaseDN(), handler.getServerId(),
                      session.getReadableRemoteAddress()));
                filtered = true;
@@ -168,7 +168,7 @@
                logError(
                    WARN_IGNORING_UPDATE_FROM_RS.get(
                        handler.getReplicationServerId(),
                        updateMsg.getChangeNumber().toString(),
                        updateMsg.getCSN().toString(),
                        handler.getBaseDN(),
                        handler.getServerId(),
                        session.getReadableRemoteAddress(),
opends/src/server/org/opends/server/replication/server/ServerWriter.java
@@ -137,7 +137,7 @@
            if (dsStatus == ServerStatus.BAD_GEN_ID_STATUS)
              logError(WARN_IGNORING_UPDATE_TO_DS_BADGENID.get(
                  handler.getReplicationServerId(),
                  update.getChangeNumber().toString(),
                  update.getCSN().toString(),
                  handler.getBaseDN(), handler.getServerId(),
                  session.getReadableRemoteAddress(),
                  handler.getGenerationId(),
@@ -145,7 +145,7 @@
            if (dsStatus == ServerStatus.FULL_UPDATE_STATUS)
              logError(WARN_IGNORING_UPDATE_TO_DS_FULLUP.get(
                  handler.getReplicationServerId(),
                  update.getChangeNumber().toString(),
                  update.getCSN().toString(),
                  handler.getBaseDN(), handler.getServerId(),
                  session.getReadableRemoteAddress()));
            continue;
@@ -164,7 +164,7 @@
            logError(
                WARN_IGNORING_UPDATE_TO_RS.get(
                    handler.getReplicationServerId(),
                    update.getChangeNumber().toString(),
                    update.getCSN().toString(),
                    handler.getBaseDN(),
                    handler.getServerId(),
                    session.getReadableRemoteAddress(),
opends/src/server/org/opends/server/replication/server/UpdateComparator.java
@@ -23,12 +23,13 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.server;
import java.util.Comparator;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
/**
@@ -58,8 +59,9 @@
   *          0 if msg1 == msg2
   *          1 if msg1 > msg2
   */
  @Override
  public int compare(UpdateMsg msg1, UpdateMsg msg2)
  {
    return ChangeNumber.compare(msg1.getChangeNumber(), msg2.getChangeNumber());
    return CSN.compare(msg1.getCSN(), msg2.getCSN());
  }
}
opends/src/server/org/opends/server/replication/server/changelog/api/ChangelogDB.java
@@ -26,7 +26,7 @@
 */
package org.opends.server.replication.server.changelog.api;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class stores the changelog information into a database.
@@ -39,13 +39,13 @@
{
  /**
   * Get the CN associated to a provided draft change number.
   * Get the CSN associated to a provided draft change number.
   *
   * @param draftCN
   *          the provided draft change number.
   * @return the associated CN, null when none.
   * @return the associated CSN, null when none.
   */
  public ChangeNumber getChangeNumber(int draftCN);
  public CSN getCSN(int draftCN);
  /**
   * Get the baseDN associated to a provided draft change number.
@@ -92,11 +92,10 @@
   *          The value of the previous cookie.
   * @param baseDN
   *          The associated baseDN.
   * @param changeNumber
   *          The associated replication change number.
   * @param csn
   *          The associated replication CSN.
   */
  void add(int draftCN, String previousCookie, String baseDN,
      ChangeNumber changeNumber);
  void add(int draftCN, String previousCookie, String baseDN, CSN csn);
  /**
   * Generate a new {@link ChangelogDBIterator} that allows to browse the db
opends/src/server/org/opends/server/replication/server/changelog/api/ChangelogDBIterator.java
@@ -28,7 +28,7 @@
import java.io.Closeable;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * Iterator into the changelog database. Once it is not used anymore, a
@@ -39,11 +39,11 @@
{
  /**
   * Getter for the replication change number field.
   * Getter for the replication CSN field.
   *
   * @return The replication change number field.
   * @return The replication CSN field.
   */
  ChangeNumber getChangeNumber();
  CSN getCSN();
  /**
   * Getter for the baseDN field.
opends/src/server/org/opends/server/replication/server/changelog/api/ReplicaDBCursorComparator.java
@@ -29,17 +29,17 @@
import java.util.Comparator;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
/**
 * This class defines a {@link Comparator} that allows to know which
 * {@link ReplicaDBCursor} contain the next {@link UpdateMsg} in the order
 * defined by the {@link ChangeNumber} of the {@link UpdateMsg}.
 * defined by the {@link CSN} of the {@link UpdateMsg}.
 */
public class ReplicaDBCursorComparator implements Comparator<ReplicaDBCursor>
{
  /**
   * Compare the {@link ChangeNumber} of the {@link ReplicaDBCursor}.
   * Compare the {@link CSN} of the {@link ReplicaDBCursor}.
   *
   * @param o1
   *          first cursor.
@@ -50,9 +50,9 @@
  @Override
  public int compare(ReplicaDBCursor o1, ReplicaDBCursor o2)
  {
    ChangeNumber csn1 = o1.getChange().getChangeNumber();
    ChangeNumber csn2 = o2.getChange().getChangeNumber();
    CSN csn1 = o1.getChange().getCSN();
    CSN csn2 = o2.getChange().getCSN();
    return ChangeNumber.compare(csn1, csn2);
    return CSN.compare(csn1, csn2);
  }
}
opends/src/server/org/opends/server/replication/server/changelog/je/DbHandler.java
@@ -38,7 +38,7 @@
import org.opends.server.api.MonitorProvider;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.ReplicationServerDomain;
@@ -60,7 +60,7 @@
 * It is responsible for efficiently saving the updates that is received from
 * each master server into stable storage.
 * This class is also able to generate a {@link ReplicaDBCursor} that can be
 * used to read all changes from a given {@link ChangeNumber}.
 * used to read all changes from a given {@link CSN}.
 *
 * This class publish some monitoring information below cn=monitor.
 */
@@ -110,8 +110,8 @@
  private int queueByteSize = 0;
  private ReplicationDB db;
  private ChangeNumber firstChange = null;
  private ChangeNumber lastChange = null;
  private CSN firstChange = null;
  private CSN lastChange = null;
  private int serverId;
  private String baseDn;
  private DbMonitorProvider dbMonitor = new DbMonitorProvider();
@@ -201,13 +201,13 @@
      queueByteSize += update.size();
      msgQueue.add(update);
      if (lastChange == null || lastChange.older(update.getChangeNumber()))
      if (lastChange == null || lastChange.older(update.getCSN()))
      {
        lastChange = update.getChangeNumber();
        lastChange = update.getCSN();
      }
      if (firstChange == null)
      {
        firstChange = update.getChangeNumber();
        firstChange = update.getCSN();
      }
    }
  }
@@ -231,7 +231,7 @@
   * Get the firstChange.
   * @return Returns the firstChange.
   */
  public ChangeNumber getFirstChange()
  public CSN getFirstChange()
  {
    return firstChange;
  }
@@ -240,7 +240,7 @@
   * Get the lastChange.
   * @return Returns the lastChange.
   */
  public ChangeNumber getLastChange()
  public CSN getLastChange()
  {
    return lastChange;
  }
@@ -260,26 +260,25 @@
  }
  /**
   * Generate a new {@link ReplicaDBCursor} that allows to browse the db
   * managed by this dbHandler and starting at the position defined by a given
   * changeNumber.
   * Generate a new {@link ReplicaDBCursor} that allows to browse the db managed
   * by this dbHandler and starting at the position defined by a given CSN.
   *
   * @param startAfterCN
   * @param startAfterCSN
   *          The position where the cursor must start.
   * @return a new {@link ReplicaDBCursor} that allows to browse the db
   *         managed by this dbHandler and starting at the position defined by a
   *         given changeNumber.
   * @return a new {@link ReplicaDBCursor} that allows to browse the db managed
   *         by this dbHandler and starting at the position defined by a given
   *         CSN.
   * @throws ChangelogException
   *           if a database problem happened.
   */
  public ReplicaDBCursor generateCursorFrom(ChangeNumber startAfterCN)
  public ReplicaDBCursor generateCursorFrom(CSN startAfterCSN)
      throws ChangelogException
  {
    if (startAfterCN == null)
    if (startAfterCSN == null)
    {
      flush();
    }
    return new JEReplicaDBCursor(db, startAfterCN, this);
    return new JEReplicaDBCursor(db, startAfterCSN, this);
  }
  /**
@@ -427,11 +426,10 @@
    latestTrimDate = TimeThread.getTime() - trimAge;
    ChangeNumber trimDate = new ChangeNumber(latestTrimDate, 0, 0);
    CSN trimDate = new CSN(latestTrimDate, 0, 0);
    // Find the last changeNumber before the trimDate, in the Database.
    ChangeNumber lastBeforeTrimDate = db
        .getPreviousChangeNumber(trimDate);
    // Find the last CSN before the trimDate, in the Database.
    CSN lastBeforeTrimDate = db.getPreviousCSN(trimDate);
    if (lastBeforeTrimDate != null)
    {
      // If we found it, we want to stop trimming when reaching it.
@@ -451,22 +449,21 @@
        {
          for (int j = 0; j < 50; j++)
          {
            ChangeNumber changeNumber = cursor.nextChangeNumber();
            if (changeNumber == null)
            CSN csn = cursor.nextCSN();
            if (csn == null)
            {
              cursor.close();
              done = true;
              return;
            }
            if (!changeNumber.equals(lastChange)
                && changeNumber.older(trimDate))
            if (!csn.equals(lastChange) && csn.older(trimDate))
            {
              cursor.delete();
            }
            else
            {
              firstChange = changeNumber;
              firstChange = csn;
              cursor.close();
              done = true;
              return;
@@ -552,9 +549,9 @@
      return attributes;
    }
    private String encode(ChangeNumber changeNumber)
    private String encode(CSN csn)
    {
      return changeNumber + " " + new Date(changeNumber.getTime());
      return csn + " " + new Date(csn.getTime());
    }
    /**
@@ -646,19 +643,18 @@
  }
  /**
   * Return the number of changes between 2 provided change numbers.
   * Return the number of changes between 2 provided CSNs.
   * This a alternative to traverseAndCount, expected to be much more efficient
   * when there is a huge number of changes in the Db.
   * @param from The lower (older) change number.
   * @param to   The upper (newer) change number.
   * @param from The lower (older) CSN.
   * @param to   The upper (newer) CSN.
   * @return The computed number of changes.
   */
  public long getCount(ChangeNumber from, ChangeNumber to)
  public long getCount(CSN from, CSN to)
  {
    // Now that we always keep the last ChangeNumber in the DB to avoid
    // expiring cookies too quickly, we need to check if the "to"
    // is older than the trim date.
    if (to == null || !to.older(new ChangeNumber(latestTrimDate, 0, 0)))
    // Now that we always keep the last CSN in the DB to avoid expiring cookies
    // too quickly, we need to check if the "to" is older than the trim date.
    if (to == null || !to.older(new CSN(latestTrimDate, 0, 0)))
    {
      flush();
      return db.count(from, to);
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDB.java
@@ -34,7 +34,7 @@
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.types.DebugLogLevel;
@@ -89,16 +89,16 @@
   *                     with this draftCN.
   * @param domainBaseDN the provided domainBaseDn to be stored associated
   *                     with this draftCN.
   * @param changeNumber the provided replication change number to be
   * @param csn the provided replication CSN to be
   *                     stored associated with this draftCN.
   */
  public void addEntry(int draftCN, String value, String domainBaseDN,
      ChangeNumber changeNumber)
      CSN csn)
  {
    try
    {
      DatabaseEntry key = new ReplicationDraftCNKey(draftCN);
      DatabaseEntry data = new DraftCNData(value, domainBaseDN, changeNumber);
      DatabaseEntry data = new DraftCNData(value, domainBaseDN, csn);
      // Use a transaction so that we can override durability.
      Transaction txn = null;
@@ -388,7 +388,7 @@
        {
          if (localCursor.getSearchKey(key, entry, LockMode.DEFAULT) != SUCCESS)
          {
            // We could not move the cursor to the expected startingChangeNumber
            // We could not move the cursor to the expected startingDraftCN
            if (localCursor.getSearchKeyRange(key, entry, DEFAULT) != SUCCESS)
            {
              // We could not even move the cursor closed to it => failure
@@ -618,10 +618,10 @@
    }
    /**
     * Returns the replication changeNumber associated with the current key.
     * @return the replication changeNumber
     * Returns the replication CSN associated with the current key.
     * @return the replication CSN
     */
    public ChangeNumber currentChangeNumber()
    public CSN currentCSN()
    {
      if (isClosed)
      {
@@ -632,7 +632,7 @@
      {
        if (seqnumData != null)
        {
          return seqnumData.getChangeNumber();
          return seqnumData.getCSN();
        }
      }
      catch(Exception e)
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNData.java
@@ -30,7 +30,7 @@
import java.io.UnsupportedEncodingException;
import org.opends.messages.Message;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import com.sleepycat.je.DatabaseEntry;
@@ -48,19 +48,17 @@
  private String value;
  private String baseDN;
  private ChangeNumber changeNumber;
  private CSN csn;
  /**
   * Creates a record to be stored in the DraftCNDB.
   * @param value The value (cookie).
   * @param baseDN The baseDN (domain DN).
   * @param changeNumber The replication change number.
   * @param csn The replication CSN.
   */
  public DraftCNData(String value, String baseDN, ChangeNumber changeNumber)
  public DraftCNData(String value, String baseDN, CSN csn)
  {
    String record = value
                   + FIELD_SEPARATOR + baseDN
                   + FIELD_SEPARATOR + changeNumber;
    String record = value + FIELD_SEPARATOR + baseDN + FIELD_SEPARATOR + csn;
    setData(getBytes(record));
  }
@@ -88,7 +86,7 @@
      String[] str = stringData.split(FIELD_SEPARATOR, 3);
      value = str[0];
      baseDN = str[1];
      changeNumber = new ChangeNumber(str[2]);
      csn = new CSN(str[2]);
    }
    catch (UnsupportedEncodingException e)
    {
@@ -125,16 +123,17 @@
  }
  /**
   * Getter for the replication change number.
   * Getter for the replication CSN.
   *
   * @return the replication change number.
   * @throws ChangelogException when a problem occurs.
   * @return the replication CSN.
   * @throws ChangelogException
   *           when a problem occurs.
   */
  public ChangeNumber getChangeNumber() throws ChangelogException
  public CSN getCSN() throws ChangelogException
  {
    if (value == null)
      decodeData(getData());
    return this.changeNumber;
    return this.csn;
  }
  /**
@@ -157,6 +156,6 @@
  {
    buffer.append("DraftCNData : [value=").append(value);
    buffer.append("] [serviceID=").append(baseDN);
    buffer.append("] [changeNumber=").append(changeNumber).append("]");
    buffer.append("] [csn=").append(csn).append("]");
  }
}
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbHandler.java
@@ -39,7 +39,7 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.server.ReplicationServer;
@@ -62,8 +62,8 @@
 * server in the topology.
 * It is responsible for efficiently saving the updates that is received from
 * each master server into stable storage.
 * This class is also able to generate a ChangelogDBIterator that can be
 * used to read all changes from a given ChangeNumber.
 * This class is also able to generate a {@link ChangelogDBIterator} that can be
 * used to read all changes from a given draft ChangeNumber.
 * <p>
 * This class publishes some monitoring information below <code>
 * cn=monitor</code>.
@@ -140,9 +140,9 @@
  /** {@inheritDoc} */
  @Override
  public synchronized void add(int draftCN, String value, String baseDN,
      ChangeNumber cn)
      CSN csn)
  {
    db.addEntry(draftCN, value, baseDN, cn);
    db.addEntry(draftCN, value, baseDN, csn);
    if (debugEnabled())
      TRACER.debugInfo(
@@ -150,7 +150,7 @@
        + " key=" + draftCN
        + " value=" + value
        + " baseDN=" + baseDN
        + " cn=" + cn);
        + " csn=" + csn);
  }
  /** {@inheritDoc} */
@@ -331,8 +331,8 @@
            return;
          }
          // From the draftCNDb change record, get the domain and changeNumber
          final ChangeNumber cn = cursor.currentChangeNumber();
          // From the draftCNDb change record, get the domain and CSN
          final CSN csn = cursor.currentCSN();
          final String baseDN = cursor.currentBaseDN();
          if (baseDNToClear != null && baseDNToClear.equalsIgnoreCase(baseDN))
          {
@@ -352,27 +352,27 @@
          }
          final ServerState startState = domain.getStartState();
          final ChangeNumber fcn = startState.getChangeNumber(cn.getServerId());
          final CSN fcsn = startState.getCSN(csn.getServerId());
          final int currentDraftCN = cursor.currentKey();
          if (cn.older(fcn))
          if (csn.older(fcsn))
          {
            cursor.delete();
            continue;
          }
          ServerState cnVector;
          ServerState csnVector;
          try
          {
            Map<String,ServerState> cnStartStates =
            Map<String, ServerState> csnStartStates =
                MultiDomainServerState.splitGenStateToServerStates(
                        cursor.currentValue());
            cnVector = cnStartStates.get(baseDN);
            csnVector = csnStartStates.get(baseDN);
            if (debugEnabled())
              TRACER.debugInfo("DraftCNDBHandler:clear() - ChangeVector:" +
                      cnVector + " -- StartState:" + startState);
              TRACER.debugInfo("DraftCNDBHandler:clear() - ChangeVector:"
                  + csnVector + " -- StartState:" + startState);
          }
          catch(Exception e)
          {
@@ -381,14 +381,14 @@
            continue;
          }
          if ((cnVector == null)
                  || (cnVector.getChangeNumber(cn.getServerId()) != null
                      && !cnVector.cover(startState)))
          if ((csnVector == null)
              || (csnVector.getCSN(csn.getServerId()) != null && !csnVector
                  .cover(startState)))
          {
            cursor.delete();
            if (debugEnabled())
              TRACER.debugInfo("DraftCNDBHandler:clear() - deleted " +
                      cn + "Not covering startState");
              TRACER.debugInfo("DraftCNDBHandler:clear() - deleted " + csn
                  + "Not covering startState");
            continue;
          }
@@ -538,13 +538,13 @@
  /** {@inheritDoc} */
  @Override
  public ChangeNumber getChangeNumber(int draftCN)
  public CSN getCSN(int draftCN)
  {
    DraftCNDBCursor draftCNDBCursor = null;
    try
    {
      draftCNDBCursor = db.openReadCursor(draftCN);
      return draftCNDBCursor.currentChangeNumber();
      return draftCNDBCursor.currentCSN();
    }
    catch(Exception e)
    {
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbIterator.java
@@ -29,7 +29,7 @@
import org.opends.messages.Message;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.replication.server.changelog.api.ChangelogDBIterator;
import org.opends.server.replication.server.changelog.je.DraftCNDB
@@ -84,11 +84,11 @@
  /** {@inheritDoc} */
  @Override
  public ChangeNumber getChangeNumber()
  public CSN getCSN()
  {
    try
    {
      return this.draftCNDbCursor.currentChangeNumber();
      return this.draftCNDbCursor.currentCSN();
    }
    catch(Exception e)
    {
opends/src/server/org/opends/server/replication/server/changelog/je/JEReplicaDBCursor.java
@@ -28,7 +28,7 @@
package org.opends.server.replication.server.changelog.je;
import org.opends.messages.Message;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.replication.server.changelog.api.ReplicaDBCursor;
@@ -43,7 +43,7 @@
  private ReplServerDBCursor cursor = null;
  private DbHandler dbHandler;
  private ReplicationDB db;
  private ChangeNumber lastNonNullCurrentCN;
  private CSN lastNonNullCurrentCSN;
  /**
   * Creates a new {@link JEReplicaDBCursor}. All created cursor must be
@@ -51,23 +51,23 @@
   *
   * @param db
   *          The db where the cursor must be created.
   * @param startAfterCN
   *          The ChangeNumber after which the cursor must start.
   * @param startAfterCSN
   *          The CSN after which the cursor must start.
   * @param dbHandler
   *          The associated DbHandler.
   * @throws ChangelogException
   *           if a database problem happened.
   */
  public JEReplicaDBCursor(ReplicationDB db, ChangeNumber startAfterCN,
  public JEReplicaDBCursor(ReplicationDB db, CSN startAfterCSN,
      DbHandler dbHandler) throws ChangelogException
  {
    this.db = db;
    this.dbHandler = dbHandler;
    this.lastNonNullCurrentCN = startAfterCN;
    this.lastNonNullCurrentCSN = startAfterCSN;
    try
    {
      cursor = db.openReadCursor(startAfterCN);
      cursor = db.openReadCursor(startAfterCSN);
    }
    catch(Exception e)
    {
@@ -81,7 +81,7 @@
      dbHandler.flush();
      // look again in the db
      cursor = db.openReadCursor(startAfterCN);
      cursor = db.openReadCursor(startAfterCSN);
      if (cursor == null)
      {
        throw new ChangelogException(Message.raw("no new change"));
@@ -104,7 +104,7 @@
    if (currentChange != null)
    {
      lastNonNullCurrentCN = currentChange.getChangeNumber();
      lastNonNullCurrentCSN = currentChange.getCSN();
    }
    else
    {
@@ -118,11 +118,11 @@
        dbHandler.flush();
        try
        {
          cursor = db.openReadCursor(lastNonNullCurrentCN);
          cursor = db.openReadCursor(lastNonNullCurrentCSN);
          currentChange = cursor.next();
          if (currentChange != null)
          {
            lastNonNullCurrentCN = currentChange.getChangeNumber();
            lastNonNullCurrentCSN = currentChange.getCSN();
          }
        }
        catch(Exception e)
opends/src/server/org/opends/server/replication/server/changelog/je/ReplicationDB.java
@@ -35,7 +35,7 @@
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.ReplicationServerDomain;
@@ -61,8 +61,8 @@
  private static final int START = 0;
  private static final int STOP = 1;
  private Database db = null;
  private ReplicationDbEnv dbenv = null;
  private Database db;
  private ReplicationDbEnv dbenv;
  private ReplicationServer replicationServer;
  private int serverId;
  private String baseDn;
@@ -76,7 +76,7 @@
  // Change counter management
  // The Db itself does not allow to count records between a start and an end
  // change. And we cannot rely on the replication seqnum that is part of the
  // changenumber, since there can be holes (when an operation is canceled).
  // CSN, since there can be holes (when an operation is canceled).
  // And traversing all the records from the start one to the end one works
  // fine but can be very long (ECL:lastChangeNumber).
  //
@@ -87,9 +87,9 @@
  // - a counter value : count of changes since previous counter record.
  //
  // A counter record has to follow the order of the db, so it needs to have
  // a changenumber key that follows the order.
  // A counter record must have its own changenumber key since the Db does not
  // support duplicate keys (it is a compatibility breaker character of the DB).
  // a CSN key that follows the order.
  // A counter record must have its own CSN key since the Db does not support
  // duplicate keys (it is a compatibility breaker character of the DB).
  //
  // We define 2 conditions to store a counter record :
  // 1/- at least 'counterWindowSize' changes have been stored in the Db
@@ -156,11 +156,11 @@
      OperationStatus status = cursor.getLast(key, data, LockMode.DEFAULT);
      while (status == OperationStatus.SUCCESS)
      {
        ChangeNumber cn = toChangeNumber(key.getData());
        if (isACounterRecord(cn))
        CSN csn = toCSN(key.getData());
        if (isACounterRecord(csn))
        {
          counterCurrValue = decodeCounterValue(data.getData()) + 1;
          counterTsLimit = cn.getTime();
          counterTsLimit = csn.getTime();
          break;
        }
@@ -179,9 +179,9 @@
    }
  }
  private static ChangeNumber toChangeNumber(byte[] data)
  private static CSN toCSN(byte[] data)
  {
    return new ChangeNumber(decodeUTF8(data));
    return new CSN(decodeUTF8(data));
  }
@@ -204,10 +204,10 @@
      for (UpdateMsg change : changes)
      {
        final DatabaseEntry key =
            createReplicationKey(change.getChangeNumber());
            createReplicationKey(change.getCSN());
        final DatabaseEntry data = new ReplicationData(change);
        insertCounterRecordIfNeeded(change.getChangeNumber());
        insertCounterRecordIfNeeded(change.getCSN());
        db.put(null, key, data);
        counterCurrValue++;
      }
@@ -222,19 +222,18 @@
    }
  }
  private void insertCounterRecordIfNeeded(ChangeNumber changeNumber)
      throws DatabaseException
  private void insertCounterRecordIfNeeded(CSN csn) throws DatabaseException
  {
    if (counterCurrValue != 0 && (counterCurrValue % counterWindowSize == 0))
    {
      // enough changes to generate a counter record
      // wait for the next change of time
      counterTsLimit = changeNumber.getTime();
      counterTsLimit = csn.getTime();
    }
    if (counterTsLimit != 0 && changeNumber.getTime() != counterTsLimit)
    if (counterTsLimit != 0 && csn.getTime() != counterTsLimit)
    {
      // Write the counter record
      final ChangeNumber counterRecord = newCounterRecord(changeNumber);
      final CSN counterRecord = newCounterRecord(csn);
      DatabaseEntry counterKey = createReplicationKey(counterRecord);
      DatabaseEntry counterValue = encodeCounterValue(counterCurrValue - 1);
      db.put(null, counterKey, counterValue);
@@ -242,12 +241,12 @@
    }
  }
  private DatabaseEntry createReplicationKey(ChangeNumber changeNumber)
  private DatabaseEntry createReplicationKey(CSN csn)
  {
    DatabaseEntry key = new DatabaseEntry();
    try
    {
      key.setData(changeNumber.toString().getBytes("UTF-8"));
      key.setData(csn.toString().getBytes("UTF-8"));
    }
    catch (UnsupportedEncodingException e)
    {
@@ -285,15 +284,16 @@
   * Create a cursor that can be used to search or iterate on this
   * ReplicationServer DB.
   *
   * @param changeNumber The ChangeNumber from which the cursor must start.
   * @param startCSN
   *          The CSN from which the cursor must start.
   * @throws ChangelogException
   *           When a problem occurs or the startingChangeNumber does not exist.
   *           When a problem occurs or the startCSN does not exist.
   * @return The ReplServerDBCursor.
   */
  public ReplServerDBCursor openReadCursor(ChangeNumber changeNumber)
  public ReplServerDBCursor openReadCursor(CSN startCSN)
      throws ChangelogException
  {
    return new ReplServerDBCursor(changeNumber);
    return new ReplServerDBCursor(startCSN);
  }
  /**
@@ -326,9 +326,10 @@
  /**
   * Read the first Change from the database.
   * @return the first ChangeNumber.
   *
   * @return the first CSN.
   */
  public ChangeNumber readFirstChange()
  public CSN readFirstChange()
  {
    dbCloseLock.readLock().lock();
@@ -351,10 +352,10 @@
        return null;
      }
      final ChangeNumber cn = toChangeNumber(key.getData());
      if (!isACounterRecord(cn))
      final CSN csn = toCSN(key.getData());
      if (!isACounterRecord(csn))
      {
        return cn;
        return csn;
      }
      // First record is a counter record .. go next
@@ -365,7 +366,7 @@
      }
      // There cannot be 2 counter record next to each other,
      // it is safe to return this record
      return toChangeNumber(key.getData());
      return toCSN(key.getData());
    }
    catch (DatabaseException e)
    {
@@ -383,9 +384,9 @@
  /**
   * Read the last Change from the database.
   *
   * @return the last ChangeNumber.
   * @return the last CSN.
   */
  public ChangeNumber readLastChange()
  public CSN readLastChange()
  {
    dbCloseLock.readLock().lock();
@@ -408,10 +409,10 @@
        return null;
      }
      final ChangeNumber cn = toChangeNumber(key.getData());
      if (!isACounterRecord(cn))
      final CSN csn = toCSN(key.getData());
      if (!isACounterRecord(csn))
      {
        return cn;
        return csn;
      }
      if (cursor.getPrev(key, data, LockMode.DEFAULT) != SUCCESS)
@@ -424,7 +425,7 @@
      }
      // There cannot be 2 counter record next to each other,
      // it is safe to return this record
      return toChangeNumber(key.getData());
      return toCSN(key.getData());
    }
    catch (DatabaseException e)
    {
@@ -438,17 +439,16 @@
  }
  /**
   * Try to find in the DB, the change number right before the one
   * passed as a parameter.
   * Try to find in the DB, the CSN right before the one passed as a parameter.
   *
   * @param changeNumber
   *          The changeNumber from which we start searching.
   * @return the changeNumber right before the one passed as a parameter.
   *         Can return null if there is none.
   * @param csn
   *          The CSN from which we start searching.
   * @return the CSN right before the one passed as a parameter. Can return null
   *         if there is none.
   */
  public ChangeNumber getPreviousChangeNumber(ChangeNumber changeNumber)
  public CSN getPreviousCSN(CSN csn)
  {
    if (changeNumber == null)
    if (csn == null)
    {
      return null;
    }
@@ -464,23 +464,23 @@
        return null;
      }
      DatabaseEntry key = createReplicationKey(changeNumber);
      DatabaseEntry key = createReplicationKey(csn);
      DatabaseEntry data = new DatabaseEntry();
      cursor = db.openCursor(null, null);
      if (cursor.getSearchKeyRange(key, data, LockMode.DEFAULT) == SUCCESS)
      {
        // We can move close to the changeNumber.
        // We can move close to the CSN.
        // Let's move to the previous change.
        if (cursor.getPrev(key, data, LockMode.DEFAULT) == SUCCESS)
        {
          return getRegularRecord(cursor, key, data);
        }
        // else, there was no change previous to our changeNumber.
        // else, there was no change previous to our CSN.
      }
      else
      {
        // We could not move the cursor past to the changeNumber
        // Check if the last change is older than changeNumber
        // We could not move the cursor past to the CSN
        // Check if the last change is older than CSN
        if (cursor.getLast(key, data, LockMode.DEFAULT) == SUCCESS)
        {
          return getRegularRecord(cursor, key, data);
@@ -498,24 +498,24 @@
    return null;
  }
  private ChangeNumber getRegularRecord(Cursor cursor, DatabaseEntry key,
  private CSN getRegularRecord(Cursor cursor, DatabaseEntry key,
      DatabaseEntry data) throws DatabaseException
  {
    final ChangeNumber cn = toChangeNumber(key.getData());
    if (!isACounterRecord(cn))
    final CSN csn = toCSN(key.getData());
    if (!isACounterRecord(csn))
    {
      return cn;
      return csn;
    }
    // There cannot be 2 counter record next to each other,
    // it is safe to return previous record which must exist
    if (cursor.getPrev(key, data, LockMode.DEFAULT) == SUCCESS)
    {
      return toChangeNumber(key.getData());
      return toCSN(key.getData());
    }
    // database only contain a counter record, which should not be possible
    // let's just say no changeNumber
    // let's just say no CSN
    return null;
  }
@@ -553,17 +553,16 @@
     * Creates a ReplServerDBCursor that can be used for browsing a
     * replicationServer db.
     *
     * @param startingChangeNumber
     *          The ChangeNumber from which the cursor must start.
     * @param startCSN
     *          The CSN from which the cursor must start.
     * @throws ChangelogException
     *           When the startingChangeNumber does not exist.
     *           When the startCSN does not exist.
     */
    private ReplServerDBCursor(ChangeNumber startingChangeNumber)
        throws ChangelogException
    private ReplServerDBCursor(CSN startCSN) throws ChangelogException
    {
      if (startingChangeNumber != null)
      if (startCSN != null)
      {
        key = createReplicationKey(startingChangeNumber);
        key = createReplicationKey(startCSN);
      }
      else
      {
@@ -590,19 +589,18 @@
        }
        localCursor = db.openCursor(txn, null);
        if (startingChangeNumber != null)
        if (startCSN != null)
        {
          if (localCursor.getSearchKey(key, data, LockMode.DEFAULT) != SUCCESS)
          {
            // We could not move the cursor to the expected startingChangeNumber
            // We could not move the cursor to the expected startCSN
            if (localCursor.getSearchKeyRange(key, data, DEFAULT) != SUCCESS)
            {
              // We could not even move the cursor closed to it => failure
              throw new ChangelogException(
                  Message.raw("ChangeNumber not available"));
              // We could not even move the cursor close to it => failure
              throw new ChangelogException(Message.raw("CSN not available"));
            }
            // We can move close to the startingChangeNumber.
            // We can move close to the startCSN.
            // Let's create a cursor from that point.
            DatabaseEntry aKey = new DatabaseEntry();
            DatabaseEntry aData = new DatabaseEntry();
@@ -752,12 +750,13 @@
    }
    /**
     * Get the next ChangeNumber in the database from this Cursor.
     * Get the next CSN in the database from this Cursor.
     *
     * @return The next ChangeNumber in the database from this cursor.
     * @throws ChangelogException In case of underlying database problem.
     * @return The next CSN in the database from this cursor.
     * @throws ChangelogException
     *           In case of underlying database problem.
     */
    public ChangeNumber nextChangeNumber() throws ChangelogException
    public CSN nextCSN() throws ChangelogException
    {
      if (isClosed)
      {
@@ -770,7 +769,7 @@
        {
          return null;
        }
        return toChangeNumber(key.getData());
        return toCSN(key.getData());
      }
      catch (DatabaseException e)
      {
@@ -804,11 +803,11 @@
          return null;
        }
        ChangeNumber cn = null;
        CSN csn = null;
        try
        {
          cn = toChangeNumber(key.getData());
          if (isACounterRecord(cn))
          csn = toCSN(key.getData());
          if (isACounterRecord(csn))
          {
            continue;
          }
@@ -827,7 +826,7 @@
           */
          Message message = ERR_REPLICATIONDB_CANNOT_PROCESS_CHANGE_RECORD
              .get(replicationServer.getServerId(),
                  (cn == null ? "" : cn.toString()),
                  (csn == null ? "" : csn.toString()),
                  e.getMessage());
          logError(message);
        }
@@ -908,10 +907,10 @@
   * Count the number of changes between 2 changes numbers (inclusive).
   * @param start The lower limit of the count.
   * @param stop The higher limit of the count.
   * @return The number of changes between provided start and stop changeNumber.
   * @return The number of changes between provided start and stop CSN.
   * Returns 0 when an error occurs.
   */
  public long count(ChangeNumber start, ChangeNumber stop)
  public long count(CSN start, CSN stop)
  {
    dbCloseLock.readLock().lock();
    try
@@ -962,8 +961,8 @@
  }
  private void findFirstCounterRecordAfterStartPoint(ChangeNumber start,
      ChangeNumber stop, int[] counterValues, int[] distanceToCounterRecords)
  private void findFirstCounterRecordAfterStartPoint(CSN start,
      CSN stop, int[] counterValues, int[] distanceToCounterRecords)
      throws DatabaseException
  {
    Cursor cursor = db.openCursor(null, null);
@@ -988,8 +987,8 @@
      while (status == OperationStatus.SUCCESS)
      {
        // test whether the record is a regular change or a counter
        final ChangeNumber cn = toChangeNumber(key.getData());
        if (isACounterRecord(cn))
        final CSN csn = toCSN(key.getData());
        if (isACounterRecord(csn))
        {
          // we have found the counter record
          counterValues[START] = decodeCounterValue(data.getData());
@@ -998,7 +997,7 @@
        // reached a regular change record
        // test whether we reached the 'stop' target
        if (!cn.newer(stop))
        if (!csn.newer(stop))
        {
          // let's loop
          distanceToCounterRecords[START]++;
@@ -1017,8 +1016,8 @@
    }
  }
  private boolean findFirstCounterRecordBeforeStopPoint(ChangeNumber start,
      ChangeNumber stop, int[] counterValues, int[] distanceToCounterRecords)
  private boolean findFirstCounterRecordBeforeStopPoint(CSN start,
      CSN stop, int[] counterValues, int[] distanceToCounterRecords)
      throws DatabaseException
  {
    Cursor cursor = db.openCursor(null, null);
@@ -1040,8 +1039,8 @@
      while (status == OperationStatus.SUCCESS)
      {
        final ChangeNumber cn = toChangeNumber(key.getData());
        if (isACounterRecord(cn))
        final CSN csn = toCSN(key.getData());
        if (isACounterRecord(csn))
        {
          // we have found the counter record
          counterValues[STOP] = decodeCounterValue(data.getData());
@@ -1049,7 +1048,7 @@
        }
        // it is a regular change record
        if (!cn.older(start))
        if (!csn.older(start))
        {
          distanceToCounterRecords[STOP]++;
          status = cursor.getPrev(key, data, LockMode.DEFAULT);
@@ -1067,7 +1066,7 @@
  /**
   * The diagram below shows a visual description of how the distance between
   * two change numbers in the database is computed.
   * two CSNs in the database is computed.
   *
   * <pre>
   *     +--------+                        +--------+
@@ -1102,9 +1101,9 @@
   * Explanation of the terms used:
   * <dl>
   * <dt>START</dt>
   * <dd>Start change number for the count</dd>
   * <dd>Start CSN for the count</dd>
   * <dt>STOP</dt>
   * <dd>Stop change number for the count</dd>
   * <dd>Stop CSN for the count</dd>
   * <dt>dist</dt>
   * <dd>Distance from START (or STOP) to the counter record</dd>
   * <dt>CSN</dt>
@@ -1113,9 +1112,9 @@
   * database is ordered.</dd>
   * <dt>CR</dt>
   * <dd>Stands for "Counter Record". Counter Records are inserted in the
   * database along with real change numbers, but they are not real changes.
   * They are only used to speed up calculating the distance between 2 change
   * numbers without the need to scan the whole database in between.</dd>
   * database along with real CSNs, but they are not real changes. They are only
   * used to speed up calculating the distance between 2 CSNs without the need
   * to scan the whole database in between.</dd>
   * </dl>
   */
  private long computeDistance(int[] counterValues,
@@ -1137,21 +1136,21 @@
  }
  /**
   * Whether a provided changeNumber represents a counter record. A counter
   * record is used to store TODO.
   * Whether a provided CSN represents a counter record. A counter record is
   * used to store the time.
   *
   * @param cn
   *          The changeNumber to test
   * @return true if the provided changenumber is a counter, false otherwise
   * @param csn
   *          The CSN to test
   * @return true if the provided CSN is a counter, false otherwise
   */
  private static boolean isACounterRecord(ChangeNumber cn)
  private static boolean isACounterRecord(CSN csn)
  {
    return cn.getServerId() == 0 && cn.getSeqnum() == 0;
    return csn.getServerId() == 0 && csn.getSeqnum() == 0;
  }
  private static ChangeNumber newCounterRecord(ChangeNumber changeNumber)
  private static CSN newCounterRecord(CSN csn)
  {
    return new ChangeNumber(changeNumber.getTime(), 0, 0);
    return new CSN(csn.getTime(), 0, 0);
  }
  /**
opends/src/server/org/opends/server/replication/service/CTHeartbeatPublisherThread.java
@@ -25,20 +25,19 @@
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions Copyright 2011-2013 ForgeRock AS
 */
package org.opends.server.replication.service;
import org.opends.server.api.DirectoryThread;
import static org.opends.server.loggers.debug.DebugLogger.*;
import java.io.IOException;
import org.opends.server.api.DirectoryThread;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.ChangeTimeHeartbeatMsg;
import org.opends.server.replication.protocol.Session;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.util.TimeThread;
import java.io.IOException;
import static org.opends.server.loggers.debug.DebugLogger.*;
/**
 * This thread publishes a heartbeat message on a given protocol session at
@@ -105,7 +104,7 @@
        long now = System.currentTimeMillis();
        ChangeTimeHeartbeatMsg ctHeartbeatMsg =
         new ChangeTimeHeartbeatMsg(
             new ChangeNumber(TimeThread.getTime(),0, serverId));
             new CSN(TimeThread.getTime(),0, serverId));
        if (now > session.getLastPublishTime() + heartbeatInterval)
        {
opends/src/server/org/opends/server/replication/service/ReplicationBroker.java
@@ -27,32 +27,12 @@
 */
package org.opends.server.replication.service;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import static org.opends.server.replication.protocol.ProtocolVersion.*;
import static org.opends.server.replication.server.ReplicationServer.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
@@ -62,17 +42,19 @@
import org.opends.messages.MessageBuilder;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.DSInfo;
import org.opends.server.replication.common.MutableBoolean;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.common.*;
import org.opends.server.replication.plugin.MultimasterReplication;
import org.opends.server.replication.protocol.*;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.util.ServerConstants;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.replication.protocol.ProtocolVersion.*;
import static org.opends.server.replication.server.ReplicationServer.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * The broker for Multi-master Replication.
 */
@@ -91,7 +73,7 @@
  private volatile Collection<String> replicationServerUrls;
  private volatile boolean connected = false;
  /**
   * String reported under cn=monitor when there is no connected RS.
   * String reported under CSN=monitor when there is no connected RS.
   */
  public final static String NO_CONNECTED_SERVER = "Not connected";
  private volatile String replicationServer = NO_CONNECTED_SERVER;
@@ -223,7 +205,7 @@
   * @param groupId The group id of our domain.
   * @param changeTimeHeartbeatInterval The interval (in ms) between Change
   *        time  heartbeats are sent to the RS,
   *        or zero if no CN heartbeat should be sent.
   *        or zero if no CSN heartbeat should be sent.
   */
  public ReplicationBroker(ReplicationDomain replicationDomain,
    ServerState state, String baseDn, int serverID2, int window,
@@ -1583,8 +1565,11 @@
    /**
     * Now apply the choice base on the weight to the best servers list
     */
    if (bestServers.size() > 1)
    if (bestServers.size() == 1)
    {
      return bestServers.values().iterator().next();
    }
      if (firstConnection)
      {
        // We are not connected to a server yet
@@ -1599,10 +1584,6 @@
        return computeBestServerForWeight(bestServers, rsServerId,
          localServerId);
      }
    } else
    {
      return bestServers.values().iterator().next();
    }
  }
  /**
@@ -1738,12 +1719,11 @@
    Map<Integer, ReplicationServerInfo> moreUpToDateServers =
      new HashMap<Integer, ReplicationServerInfo>();
    // Extract the change number of the latest change generated by the local
    // server
    ChangeNumber myChangeNumber = localState.getChangeNumber(localServerId);
    if (myChangeNumber == null)
    // Extract the CSN of the latest change generated by the local server
    CSN myCSN = localState.getCSN(localServerId);
    if (myCSN == null)
    {
      myChangeNumber = new ChangeNumber(0, 0, localServerId);
      myCSN = new CSN(0, 0, localServerId);
    }
    /**
@@ -1751,23 +1731,23 @@
     * if for instance we failed and restarted, having sent some changes to the
     * RS but without having time to store our own state) regarding our own
     * server id. If some servers more up to date, prefer this list but take
     * only the latest change number.
     * only the latest CSN.
     */
    ChangeNumber latestRsChangeNumber = null;
    CSN latestRsCSN = null;
    for (Integer rsId : bestServers.keySet())
    {
      ReplicationServerInfo replicationServerInfo = bestServers.get(rsId);
      ServerState rsState = replicationServerInfo.getServerState();
      ChangeNumber rsChangeNumber = rsState.getChangeNumber(localServerId);
      if (rsChangeNumber == null)
      CSN rsCSN = rsState.getCSN(localServerId);
      if (rsCSN == null)
      {
        rsChangeNumber = new ChangeNumber(0, 0, localServerId);
        rsCSN = new CSN(0, 0, localServerId);
      }
      // Has this replication server the latest local change ?
      if (myChangeNumber.olderOrEqual(rsChangeNumber))
      if (myCSN.olderOrEqual(rsCSN))
      {
        if (myChangeNumber.equals(rsChangeNumber))
        if (myCSN.equals(rsCSN))
        {
          // This replication server has exactly the latest change from the
          // local server
@@ -1776,14 +1756,14 @@
        {
          // This replication server is even more up to date than the local
          // server
          if (latestRsChangeNumber == null)
          if (latestRsCSN == null)
          {
            // Initialize the latest change number
            latestRsChangeNumber = rsChangeNumber;
            // Initialize the latest CSN
            latestRsCSN = rsCSN;
          }
          if (rsChangeNumber.newerOrEquals(latestRsChangeNumber))
          if (rsCSN.newerOrEquals(latestRsCSN))
          {
            if (rsChangeNumber.equals(latestRsChangeNumber))
            if (rsCSN.equals(latestRsCSN))
            {
              moreUpToDateServers.put(rsId, replicationServerInfo);
            } else
@@ -1792,7 +1772,7 @@
              // new RS
              moreUpToDateServers.clear();
              moreUpToDateServers.put(rsId, replicationServerInfo);
              latestRsChangeNumber = rsChangeNumber;
              latestRsCSN = rsCSN;
            }
          }
        }
@@ -1802,10 +1782,8 @@
    {
      // Prefer servers more up to date than local server
      return moreUpToDateServers;
    } else
    {
      return upToDateServers;
    }
    return upToDateServers;
  }
@@ -3041,7 +3019,7 @@
   */
  public void startChangeTimeHeartBeatPublishing()
  {
    // Start a CN heartbeat thread.
    // Start a CSN heartbeat thread.
    if (changeTimeHeartbeatSendInterval > 0)
    {
      String threadName = "Replica DS("
@@ -3058,7 +3036,7 @@
    {
      if (debugEnabled())
        TRACER.debugInfo(this
          + " is not configured to send CN heartbeat interval");
          + " is not configured to send CSN heartbeat interval");
    }
  }
opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
@@ -27,11 +27,6 @@
 */
package org.opends.server.replication.service;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.replication.common.StatusMachine.*;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -58,6 +53,11 @@
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ResultCode;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.replication.common.StatusMachine.*;
/**
 * This class should be used as a base for Replication implementations.
 * <p>
@@ -141,8 +141,8 @@
   * to be able to correlate all the coming back acks to the original
   * operation.
   */
  private final Map<ChangeNumber, UpdateMsg> waitingAckMsgs =
    new ConcurrentHashMap<ChangeNumber, UpdateMsg>();
  private final Map<CSN, UpdateMsg> waitingAckMsgs =
    new ConcurrentHashMap<CSN, UpdateMsg>();
  /**
@@ -291,10 +291,10 @@
  private final ServerState state;
  /**
   * The generator that will be used to generate {@link ChangeNumber}
   * The generator that will be used to generate {@link CSN}
   * for this domain.
   */
  private final ChangeNumberGenerator generator;
  private final CSNGenerator generator;
  private final Object eclIncludesLock = new Object();
  private final Map<Integer, Set<String>> eclIncludesByServer =
@@ -313,13 +313,13 @@
  private final Object sessionLock = new Object();
  /**
   * Returns the {@link ChangeNumberGenerator} that will be used to
   * generate {@link ChangeNumber} for this domain.
   * Returns the {@link CSNGenerator} that will be used to
   * generate {@link CSN} for this domain.
   *
   * @return The {@link ChangeNumberGenerator} that will be used to
   *         generate {@link ChangeNumber} for this domain.
   * @return The {@link CSNGenerator} that will be used to
   *         generate {@link CSN} for this domain.
   */
  public ChangeNumberGenerator getGenerator()
  public CSNGenerator getGenerator()
  {
    return generator;
  }
@@ -341,7 +341,7 @@
    this.serverID = serverID;
    this.initWindow = initWindow;
    this.state = new ServerState();
    this.generator = new ChangeNumberGenerator(serverID, state);
    this.generator = new CSNGenerator(serverID, state);
    domains.put(baseDN, this);
  }
@@ -364,7 +364,7 @@
    this.baseDN = baseDN;
    this.serverID = serverID;
    this.state = serverState;
    this.generator = new ChangeNumberGenerator(serverID, state);
    this.generator = new CSNGenerator(serverID, state);
    domains.put(baseDN, this);
  }
@@ -830,7 +830,7 @@
        else if (msg instanceof UpdateMsg)
        {
          update = (UpdateMsg) msg;
          generator.adjust(update.getChangeNumber());
          generator.adjust(update.getCSN());
        }
        else if (msg instanceof InitializeRcvAckMsg)
        {
@@ -915,12 +915,11 @@
   */
  private void receiveAck(AckMsg ack)
  {
    UpdateMsg update;
    ChangeNumber changeNumber = ack.getChangeNumber();
    CSN csn = ack.getCSN();
    // Remove the message for pending ack list (this may already make the thread
    // that is waiting for the ack be aware of its reception)
    update = waitingAckMsgs.remove(changeNumber);
    UpdateMsg update = waitingAckMsgs.remove(csn);
    // Signal waiting thread ack has been received
    if (update != null)
@@ -2705,7 +2704,7 @@
    is used the ack is sent without error at replay flag.
    */
    processUpdateDone(msg, null);
    state.update(msg.getChangeNumber());
    state.update(msg.getCSN());
  }
  /**
@@ -3212,7 +3211,7 @@
          if (rsGroupId == groupId)
          {
            // Send the ack
            AckMsg ackMsg = new AckMsg(msg.getChangeNumber());
            AckMsg ackMsg = new AckMsg(msg.getCSN());
            if (replayErrorMsg != null)
            {
              // Mark the error in the ack
@@ -3287,7 +3286,7 @@
        msg.setSafeDataLevel(assuredSdLevel);
      // Add the assured message to the list of update that are waiting for acks
      waitingAckMsgs.put(msg.getChangeNumber(), msg);
      waitingAckMsgs.put(msg.getCSN(), msg);
    }
  }
@@ -3332,8 +3331,8 @@
    long startTime = System.currentTimeMillis();
    synchronized (msg)
    {
      ChangeNumber cn = msg.getChangeNumber();
      while (waitingAckMsgs.containsKey(cn))
      CSN csn = msg.getCSN();
      while (waitingAckMsgs.containsKey(csn))
      {
        try
        {
@@ -3359,8 +3358,7 @@
          remove the update from the wait list, log the timeout error and
          also update assured monitoring counters
          */
          UpdateMsg update;
          update = waitingAckMsgs.remove(cn);
          UpdateMsg update = waitingAckMsgs.remove(csn);
          if (update != null)
          {
@@ -3386,9 +3384,9 @@
              // Should not happen
            }
            throw new TimeoutException("No ack received for message cn: " + cn +
              " and replication servceID: " + baseDN + " after " +
              assuredTimeout + " ms.");
            throw new TimeoutException("No ack received for message csn: "
                + csn + " and replication servceID: " + baseDN + " after "
                + assuredTimeout + " ms.");
          } else
          {
            // Ack received just before timeout limit: we can exit
@@ -3413,7 +3411,7 @@
  {
    // Publish the update
    broker.publish(msg);
    state.update(msg.getChangeNumber());
    state.update(msg.getCSN());
    numSentUpdates.incrementAndGet();
  }
@@ -3428,7 +3426,7 @@
    UpdateMsg update;
    synchronized (this)
    {
      update = new UpdateMsg(generator.newChangeNumber(), msg);
      update = new UpdateMsg(generator.newCSN(), msg);
      /*
      If assured replication is configured, this will prepare blocking
      mechanism. If assured replication is disabled, this returns
@@ -3672,17 +3670,15 @@
    }
  }
  /**
   * Returns the ChangeNUmber of the last Change that was fully processed
   * by this ReplicationDomain.
   * Returns the CSN of the last Change that was fully processed by this
   * ReplicationDomain.
   *
   * @return The ChangeNUmber of the last Change that was fully processed
   *         by this ReplicationDomain.
   * @return The CSN of the last Change that was fully processed by this
   *         ReplicationDomain.
   */
  public ChangeNumber getLastLocalChange()
  public CSN getLastLocalChange()
  {
    return state.getChangeNumber(serverID);
    return state.getCSN(serverID);
  }
}
opends/src/server/org/opends/server/tasks/PurgeConflictsHistoricalTask.java
@@ -27,21 +27,21 @@
 */
package org.opends.server.tasks;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.core.DirectoryServer.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import java.util.List;
import org.opends.messages.*;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskState;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.types.*;
import org.opends.server.util.TimeThread;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.core.DirectoryServer.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
/**
 * This class provides an implementation of a Directory Server task that can
 * be used to purge the replication historical informations stored in the
@@ -59,8 +59,8 @@
   */
  private static final DebugTracer TRACER = getTracer();
  private String  domainString = null;
  private LDAPReplicationDomain domain = null;
  private String domainString;
  private LDAPReplicationDomain domain;
  /**
   *                 current historical purge delay
@@ -68,21 +68,18 @@
   * -----------------------------------------------------------------> t
   *               |                           |            |
   *           current                      task           task
   *           CN being purged           start date    max end date
   *           CSN being purged           start date    max end date
   *                                           <------------>
   *                                          config.purgeMaxDuration
   *
   * The task will start purging the change with the oldest CN found.
   * The task will start purging the change with the oldest CSN found.
   * The task run as long as :
   *  - the end date (computed from the configured max duration) is not reached
   *  - the CN purged is oldest than the configured historical purge delay
   *
   *
   *  - the CSN purged is oldest than the configured historical purge delay
   */
  private int purgeTaskMaxDurationInSec = DEFAULT_MAX_DURATION;
  TaskState initState;
  private TaskState initState;
  private static final void debugInfo(String s)
@@ -210,8 +207,8 @@
        // sets in the attributes the last stats values
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COUNT,
            String.valueOf(this.purgeCount));
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CN,
            this.lastCN.toStringUI());
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CSN,
            this.lastCSN.toStringUI());
        debugInfo("[PURGE] PurgeConflictsHistoricalTask write  attrs ");
      }
      catch(Exception e)
@@ -231,34 +228,37 @@
    return initState;
  }
  int updateAttrPeriod = 0;
  ChangeNumber lastCN;
  int purgeCount;
  private int updateAttrPeriod = 0;
  private CSN lastCSN;
  private int purgeCount;
  /**
   * Set the last changenumber purged and the count of purged values in order
   * to monitor the historical purge.
   * @param lastCN the last changeNumber purged.
   * @param purgeCount the count of purged values.
   * Set the last CSN purged and the count of purged values in order to monitor
   * the historical purge.
   *
   * @param lastCSN
   *          the last CSN purged.
   * @param purgeCount
   *          the count of purged values.
   */
  public void setProgressStats(ChangeNumber lastCN, int purgeCount)
  public void setProgressStats(CSN lastCSN, int purgeCount)
  {
    try
    {
      if (purgeCount == 0)
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_FIRST_CN,
            lastCN.toStringUI());
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_FIRST_CSN,
            lastCSN.toStringUI());
      // we don't want the update of the task to overload too much task duration
      this.purgeCount = purgeCount;
      this.lastCN = lastCN;
      this.lastCSN = lastCSN;
      if (++updateAttrPeriod % 100 == 0)
      {
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COUNT,
            String.valueOf(purgeCount));
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CN,
            lastCN.toStringUI());
        replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_LAST_CSN,
            lastCSN.toStringUI());
        debugInfo("[PURGE] PurgeConflictsHistoricalTask write  attrs "
            + purgeCount);
      }
opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -539,7 +539,7 @@
            {
              out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get(operationType,
                  ((ChangeNumberControlPlugin.ChangeNumberControl)c).
                      getChangeNumber().toString()));
                      getCSN().toString()));
            }
          }
        }
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -27,14 +27,6 @@
 */
package org.opends.server.workflowelement.externalchangelog;
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.LDIFWriter.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -47,7 +39,7 @@
import org.opends.server.controls.*;
import org.opends.server.core.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ExternalChangeLogSession;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.plugin.MultimasterReplication;
@@ -60,6 +52,14 @@
import org.opends.server.types.operation.SearchReferenceSearchOperation;
import org.opends.server.util.ServerConstants;
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.LDIFWriter.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class defines an operation used to search for entries in a local backend
 * of the Directory Server.
@@ -791,7 +791,7 @@
      clEntry = createChangelogEntry(eclmsg.getBaseDN(), eclmsg
          .getCookie().toString(), DN.decode(addMsg.getDn()),
          addMsg.getChangeNumber(), ldifChanges, // entry as created (in LDIF
          addMsg.getCSN(), ldifChanges, // entry as created (in LDIF
                                                 // format)
          addMsg.getEntryUUID(),
          eclAttributes, // entry attributes
@@ -858,7 +858,7 @@
      clEntry = createChangelogEntry(eclmsg.getBaseDN(), eclmsg
          .getCookie().toString(), DN.decode(modifyMsg.getDn()),
          modifyMsg.getChangeNumber(), ldifChanges,
          modifyMsg.getCSN(), ldifChanges,
          modifyMsg.getEntryUUID(),
          modifyMsg.getEclIncludes(), // entry attributes
          eclmsg.getDraftChangeNumber(), changeType,
@@ -889,7 +889,7 @@
      clEntry = createChangelogEntry(eclmsg.getBaseDN(), eclmsg
          .getCookie().toString(), DN.decode(delMsg.getDn()),
          delMsg.getChangeNumber(),
          delMsg.getCSN(),
          null, // no changes
          delMsg.getEntryUUID(),
          delMsg.getEclIncludes(), // entry attributes
@@ -988,7 +988,7 @@
   * @param baseDN          The provided baseDN value.
   * @param cookie          The provided cookie value.
   * @param targetDN        The provided targetDN.
   * @param changeNumber    The provided replication changeNumber.
   * @param csn    The provided replication CSN.
   * @param clearLDIFchanges     The provided LDIF changes for ADD and MODIFY
   * @param targetUUID      The provided targetUUID.
   * @param includedAttributes The provided attributes to include
@@ -1003,7 +1003,7 @@
      String baseDN,
      String cookie,
      DN targetDN,
      ChangeNumber changeNumber,
      CSN csn,
      String clearLDIFchanges,
      String targetUUID,
      List<RawAttribute> includedAttributes,
@@ -1016,7 +1016,7 @@
    if (draftChangenumber == 0)
    {
      // Draft uncompat mode
      dnString = "replicationCSN=" + changeNumber + "," + baseDN + ","
      dnString = "replicationCSN=" + csn + "," + baseDN + ","
          + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
    }
    else
@@ -1056,7 +1056,7 @@
    SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); // ??
    String format = dateFormat.format(new Date(changeNumber.getTime()));
    String format = dateFormat.format(new Date(csn.getTime()));
    addAttributeByType("changetime", "changeTime", format, uAttrs,
        operationalAttrs);
@@ -1068,11 +1068,11 @@
    // NON REQUESTED attributes
    addAttributeByType("replicationcsn", "replicationCSN", changeNumber
    addAttributeByType("replicationcsn", "replicationCSN", csn
        .toString(), uAttrs, operationalAttrs);
    addAttributeByType("replicaidentifier", "replicaIdentifier", Integer
        .toString(changeNumber.getServerId()), uAttrs, operationalAttrs);
        .toString(csn.getServerId()), uAttrs, operationalAttrs);
    if (clearLDIFchanges != null)
    {
@@ -1205,7 +1205,7 @@
    StartECLSessionMsg msg = evaluateSearchParameters2(sf);
    startCLmsg.setFirstDraftChangeNumber(msg.getFirstDraftChangeNumber());
    startCLmsg.setLastDraftChangeNumber(msg.getLastDraftChangeNumber());
    startCLmsg.setChangeNumber(msg.getChangeNumber());
    startCLmsg.setCSN(msg.getCSN());
  }
  private static StartECLSessionMsg evaluateSearchParameters2(SearchFilter sf)
@@ -1214,7 +1214,7 @@
    StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
    startCLmsg.setFirstDraftChangeNumber(-1);
    startCLmsg.setLastDraftChangeNumber(-1);
    startCLmsg.setChangeNumber(new ChangeNumber(0,0,(short)0));
    startCLmsg.setCSN(new CSN(0, 0, 0));
    // If there's no filter, just return
    if (sf == null)
@@ -1239,9 +1239,8 @@
    }
    else if (matches(sf, FilterType.EQUALITY, "replicationcsn"))
    {
      // == exact changenumber
      ChangeNumber cn = new ChangeNumber(sf.getAssertionValue().toString());
      startCLmsg.setChangeNumber(cn);
      // == exact CSN
      startCLmsg.setCSN(new CSN(sf.getAssertionValue().toString()));
      return startCLmsg;
    }
    else if (matches(sf, FilterType.EQUALITY, "changenumber"))
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/DependencyTest.java
@@ -40,7 +40,7 @@
import org.opends.server.TestCaseUtils;
import org.opends.server.backends.MemoryBackend;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.plugin.DomainFakeCfg;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.replication.plugin.MultimasterReplication;
@@ -134,7 +134,7 @@
      // send a sequence of add operation
      String addDn = TEST_ROOT_DN_STRING;
      ChangeNumberGenerator gen = new ChangeNumberGenerator(brokerId, 0L);
      CSNGenerator gen = new CSNGenerator(brokerId, 0L);
      int sequence;
      for (sequence = 1; sequence<=AddSequenceLength; sequence ++)
@@ -144,14 +144,14 @@
                           new LinkedList<AttributeValue>());
        addDn = "dc=dependency" + sequence + "," + addDn;
        AddMsg addMsg =
          new AddMsg(gen.newChangeNumber(), addDn, stringUID(sequence+1),
          new AddMsg(gen.newCSN(), addDn, stringUID(sequence+1),
                     stringUID(sequence),
                     entry.getObjectClassAttribute(),
                     entry.getAttributes(), null );
        broker.publish(addMsg);
        ModifyMsg modifyMsg =
          new ModifyMsg(gen.newChangeNumber(), DN.decode(addDn),
          new ModifyMsg(gen.newCSN(), DN.decode(addDn),
                        generatemods("description", "test"),
                        stringUID(sequence+1));
        broker.publish(modifyMsg);
@@ -207,7 +207,7 @@
      while (sequence-->1)
      {
        DeleteMsg delMsg = new DeleteMsg(deleteDN.toString(),
                                         gen.newChangeNumber(),
                                         gen.newCSN(),
                                         stringUID(sequence + 1));
        broker.publish(delMsg);
        deleteDN = deleteDN.getParent();
@@ -264,7 +264,7 @@
      Entry entry = TestCaseUtils.entryFromLdifString(entryldif);
      AttributeType uidType =
        DirectoryServer.getSchema().getAttributeType("entryuuid");
      ChangeNumberGenerator gen = new ChangeNumberGenerator(brokerId, 0L);
      CSNGenerator gen = new CSNGenerator(brokerId, 0L);
      int renamedEntryUuid = 100;
      int replServerPort = TestCaseUtils.findFreePort();
@@ -297,7 +297,7 @@
                         new LinkedList<AttributeValue>());
      String addDn = "dc=moddndel" + "," + TEST_ROOT_DN_STRING;
      AddMsg addMsg =
        new AddMsg(gen.newChangeNumber(), addDn, stringUID(renamedEntryUuid),
        new AddMsg(gen.newCSN(), addDn, stringUID(renamedEntryUuid),
                   stringUID(1),
                   entry.getObjectClassAttribute(),
                   entry.getAttributes(), null );
@@ -319,13 +319,13 @@
      // rename and delete the entry.
      ModifyDNMsg moddnMsg =
        new ModifyDNMsg(addDn, gen.newChangeNumber(),
        new ModifyDNMsg(addDn, gen.newCSN(),
                        stringUID(renamedEntryUuid),
                        stringUID(1), true, null, "dc=new_name");
      broker.publish(moddnMsg);
      DeleteMsg delMsg =
        new DeleteMsg("dc=new_name" + "," + TEST_ROOT_DN_STRING,
                      gen.newChangeNumber(), stringUID(renamedEntryUuid));
                      gen.newCSN(), stringUID(renamedEntryUuid));
      broker.publish(delMsg);
      // enable back the domain to trigger message replay.
@@ -425,7 +425,7 @@
                               false, CLEAN_DB_GENERATION_ID);
      // send a sequence of add/del/add operations
      ChangeNumberGenerator gen = new ChangeNumberGenerator(brokerId, 0L);
      CSNGenerator gen = new CSNGenerator(brokerId, 0L);
      int sequence;
      for (sequence = 1; sequence<=AddSequenceLength; sequence ++)
@@ -436,14 +436,14 @@
                           new LinkedList<AttributeValue>());
        String addDn = "dc=dependency" + sequence + "," + TEST_ROOT_DN_STRING;
        AddMsg addMsg =
          new AddMsg(gen.newChangeNumber(), addDn, stringUID(sequence+1),
          new AddMsg(gen.newCSN(), addDn, stringUID(sequence+1),
                     stringUID(1),
                     entry.getObjectClassAttribute(),
                     entry.getAttributes(), null );
        broker.publish(addMsg);
        // delete the entry
        DeleteMsg delMsg = new DeleteMsg(addDn, gen.newChangeNumber(),
        DeleteMsg delMsg = new DeleteMsg(addDn, gen.newCSN(),
                                         stringUID(sequence+1));
        broker.publish(delMsg);
@@ -452,7 +452,7 @@
        entry.addAttribute(Attributes.create("entryuuid", stringUID(sequence+1025)),
                           new LinkedList<AttributeValue>());
        addMsg =
          new AddMsg(gen.newChangeNumber(), addDn, stringUID(sequence+1025),
          new AddMsg(gen.newCSN(), addDn, stringUID(sequence+1025),
                     stringUID(1),
                     entry.getObjectClassAttribute(),
                     entry.getAttributes(), null );
@@ -488,7 +488,7 @@
      {
        String deleteDN = "dc=dependency" + sequence + "," + TEST_ROOT_DN_STRING;
        DeleteMsg delMsg = new DeleteMsg(deleteDN,
                                         gen.newChangeNumber(),
                                         gen.newCSN(),
                                         stringUID(sequence + 1025));
        broker.publish(delMsg);
      }
@@ -553,7 +553,7 @@
      String addDn = TEST_ROOT_DN_STRING;
      ChangeNumberGenerator gen = new ChangeNumberGenerator(brokerId, 0L);
      CSNGenerator gen = new CSNGenerator(brokerId, 0L);
      // send a sequence of add/modrdn operations
      int sequence;
@@ -565,7 +565,7 @@
                           new LinkedList<AttributeValue>());
        addDn = "dc=dependency" + sequence + "," + TEST_ROOT_DN_STRING;
        AddMsg addMsg =
          new AddMsg(gen.newChangeNumber(), addDn, stringUID(sequence+1),
          new AddMsg(gen.newCSN(), addDn, stringUID(sequence+1),
                     stringUID(1),
                     entry.getObjectClassAttribute(),
                     entry.getAttributes(), null );
@@ -573,7 +573,7 @@
        // rename the entry
        ModifyDNMsg moddnMsg =
          new ModifyDNMsg(addDn, gen.newChangeNumber(), stringUID(sequence+1),
          new ModifyDNMsg(addDn, gen.newCSN(), stringUID(sequence+1),
                          stringUID(1), true, null, "dc=new_dep" + sequence);
        broker.publish(moddnMsg);
      }
@@ -602,7 +602,7 @@
      {
        addDn = "dc=new_dep" + sequence + "," + TEST_ROOT_DN_STRING;
        DeleteMsg delMsg = new DeleteMsg(addDn.toString(),
                                         gen.newChangeNumber(),
                                         gen.newCSN(),
                                         stringUID(sequence + 1));
        broker.publish(delMsg);
      }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -44,8 +44,8 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.*;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.plugin.DomainFakeCfg;
@@ -110,7 +110,7 @@
  /** The LDAPStatistics object associated with the LDAP connection handler. */
  private LDAPStatistics ldapStatistics;
  private ChangeNumber gblCN;
  private CSN gblCSN;
  private List<Control> NO_CONTROL = null;
@@ -497,15 +497,17 @@
      // create and publish 1 change on each suffix
      long time = TimeThread.getTime();
      int ts = 1;
      ChangeNumber cn1 = new ChangeNumber(time, ts++, SERVER_ID_1);
      CSN csn1 = new CSN(time, ts++, SERVER_ID_1);
      DeleteMsg delMsg1 =
        new DeleteMsg("o=" + tn + "1," + TEST_ROOT_DN_STRING, cn1, "ECLBasicMsg1uid");
          new DeleteMsg("o=" + tn + "1," + TEST_ROOT_DN_STRING, csn1,
              "ECLBasicMsg1uid");
      server01.publish(delMsg1);
      debugInfo(tn, "publishes:" + delMsg1);
      ChangeNumber cn2 = new ChangeNumber(time, ts++, SERVER_ID_2);
      CSN csn2 = new CSN(time, ts++, SERVER_ID_2);
      DeleteMsg delMsg2 =
        new DeleteMsg("o=" + tn + "2," + TEST_ROOT_DN_STRING2, cn2, "ECLBasicMsg2uid");
          new DeleteMsg("o=" + tn + "2," + TEST_ROOT_DN_STRING2, csn2,
              "ECLBasicMsg2uid");
      server02.publish(delMsg2);
      debugInfo(tn, "publishes:" + delMsg2);
@@ -523,20 +525,20 @@
      msg = serverECL.receive();
      ECLUpdateMsg eclu = (ECLUpdateMsg)msg;
      UpdateMsg u = eclu.getUpdateMsg();
      debugInfo(tn, "RESULT:" + u.getChangeNumber() + " " + eclu.getCookie());
      assertTrue(u.getChangeNumber().equals(cn1), "RESULT:" + u.getChangeNumber());
      debugInfo(tn, "RESULT:" + u.getCSN() + " " + eclu.getCookie());
      assertTrue(u.getCSN().equals(csn1), "RESULT:" + u.getCSN());
      assertTrue(eclu.getCookie().equalsTo(new MultiDomainServerState(
          "o=test:"+delMsg1.getChangeNumber()+";o=test2:;")));
          "o=test:"+delMsg1.getCSN()+";o=test2:;")));
      // receive change 2 from suffix 2
      msg = serverECL.receive();
      eclu = (ECLUpdateMsg)msg;
      u = eclu.getUpdateMsg();
      debugInfo(tn, "RESULT:" + u.getChangeNumber());
      assertTrue(u.getChangeNumber().equals(cn2), "RESULT:" + u.getChangeNumber());
      debugInfo(tn, "RESULT:" + u.getCSN());
      assertTrue(u.getCSN().equals(csn2), "RESULT:" + u.getCSN());
      assertTrue(eclu.getCookie().equalsTo(new MultiDomainServerState(
          "o=test2:"+delMsg2.getChangeNumber()+";"+
          "o=test:"+delMsg1.getChangeNumber()+";")));
          "o=test2:"+delMsg2.getCSN()+";"+
          "o=test:"+delMsg1.getCSN()+";")));
      // receive Done
      msg = serverECL.receive();
@@ -642,9 +644,10 @@
      // create and publish 1 change on each suffix
      long time = TimeThread.getTime();
      ChangeNumber cn1 = new ChangeNumber(time, 1, SERVER_ID_1);
      CSN csn1 = new CSN(time, 1, SERVER_ID_1);
      DeleteMsg delMsg1 =
        new DeleteMsg("o=" + tn + "1," + TEST_ROOT_DN_STRING, cn1, "ECLBasicMsg1uid");
          new DeleteMsg("o=" + tn + "1," + TEST_ROOT_DN_STRING, csn1,
              "ECLBasicMsg1uid");
      server01.publish(delMsg1);
      debugInfo(tn, "publishes:" + delMsg1);
@@ -688,7 +691,7 @@
      // Test lastExternalChangelogCookie attribute of the ECL
      // (does only refer to non private backend)
      MultiDomainServerState expectedLastCookie =
        new MultiDomainServerState("o=test:"+cn1+";");
          new MultiDomainServerState("o=test:" + csn1 + ";");
      String lastCookie = readLastCookie();
@@ -742,17 +745,17 @@
      // Produce updates
      long time = TimeThread.getTime();
      int ts = 1;
      ChangeNumber cn = new ChangeNumber(time, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, cn, tn, 1);
      CSN csn = new CSN(time, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, csn, tn, 1);
      cn = new ChangeNumber(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest2(s2test2, cn, tn, 2);
      csn = new CSN(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest2(s2test2, csn, tn, 2);
      ChangeNumber cn3 = new ChangeNumber(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest2(s2test2, cn3, tn, 3);
      CSN csn3 = new CSN(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest2(s2test2, csn3, tn, 3);
      cn = new ChangeNumber(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, cn, tn, 4);
      csn = new CSN(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, csn, tn, 4);
      sleep(1500);
      // Changes are :
@@ -788,8 +791,8 @@
      cookie = getCookie(searchOp.getSearchEntries(), 1, tn, ldifWriter, cookie);
      // Now publishes a new change and search from the previous cookie
      ChangeNumber cn5 = new ChangeNumber(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, cn5, tn, 5);
      CSN csn5 = new CSN(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, csn5, tn, 5);
      sleep(500);
      // Changes are :
@@ -817,33 +820,34 @@
      sleep(500);
      time = TimeThread.getTime();
      cn = new ChangeNumber(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, cn, tn, 6);
      csn = new CSN(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, csn, tn, 6);
      cn = new ChangeNumber(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, cn, tn, 7);
      csn = new CSN(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, csn, tn, 7);
      ChangeNumber cn8 = new ChangeNumber(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, cn8, tn, 8);
      CSN csn8 = new CSN(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, csn8, tn, 8);
      ChangeNumber cn9 = new ChangeNumber(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, cn9, tn, 9);
      CSN csn9 = new CSN(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, csn9, tn, 9);
      sleep(500);
      ReplicationServerDomain rsd = replicationServer.getReplicationServerDomain(TEST_ROOT_DN_STRING);
      ServerState startState = rsd.getStartState();
      assertEquals(startState.getChangeNumber(s1test.getServerId()).getSeqnum(), 1);
      assertTrue(startState.getChangeNumber(s2test.getServerId()) != null);
      assertEquals(startState.getChangeNumber(s2test.getServerId()).getSeqnum(), 7);
      assertEquals(startState.getCSN(s1test.getServerId()).getSeqnum(), 1);
      assertTrue(startState.getCSN(s2test.getServerId()) != null);
      assertEquals(startState.getCSN(s2test.getServerId()).getSeqnum(), 7);
      rsd = replicationServer.getReplicationServerDomain(TEST_ROOT_DN_STRING2);
      startState = rsd.getStartState();
      assertEquals(startState.getChangeNumber(s2test2.getServerId()).getSeqnum(), 2);
      assertEquals(startState.getChangeNumber(s1test2.getServerId()).getSeqnum(), 6);
      assertEquals(startState.getCSN(s2test2.getServerId()).getSeqnum(), 2);
      assertEquals(startState.getCSN(s1test2.getServerId()).getSeqnum(), 6);
      // Test lastExternalChangelogCookie attribute of the ECL
      MultiDomainServerState expectedLastCookie =
        new MultiDomainServerState("o=test:"+cn5+" "+cn9+";o=test2:"+cn3+" "+cn8+";");
          new MultiDomainServerState("o=test:" + csn5 + " " + csn9
              + ";o=test2:" + csn3 + " " + csn8 + ";");
      String lastCookie = readLastCookie();
@@ -914,25 +918,25 @@
    return cookie;
  }
  private void publishDeleteMsgInOTest(ReplicationBroker broker,
      ChangeNumber cn, String tn, int i)
  private void publishDeleteMsgInOTest(ReplicationBroker broker, CSN csn,
      String tn, int i)
  {
    publishDeleteMsg(broker, cn, tn, i, TEST_ROOT_DN_STRING);
    publishDeleteMsg(broker, csn, tn, i, TEST_ROOT_DN_STRING);
  }
  private void publishDeleteMsgInOTest2(ReplicationBroker broker,
      ChangeNumber cn, String tn, int i)
  private void publishDeleteMsgInOTest2(ReplicationBroker broker, CSN csn,
      String tn, int i)
  {
    publishDeleteMsg(broker, cn, tn, i, TEST_ROOT_DN_STRING2);
    publishDeleteMsg(broker, csn, tn, i, TEST_ROOT_DN_STRING2);
  }
  private void publishDeleteMsg(ReplicationBroker broker, ChangeNumber cn,
      String tn, int i, String baseDn)
  private void publishDeleteMsg(ReplicationBroker broker, CSN csn, String tn,
      int i, String baseDn)
  {
    String dn = "uid=" + tn + i + "," + baseDn;
    DeleteMsg delMsg = new DeleteMsg(dn, cn, tn + "uuid" + i);
    DeleteMsg delMsg = new DeleteMsg(dn, csn, tn + "uuid" + i);
    broker.publish(delMsg);
    debugInfo(tn, " publishes " + delMsg.getChangeNumber());
    debugInfo(tn, " publishes " + delMsg.getCSN());
  }
  private InternalSearchOperation searchOnCookieChangelog(String filterString,
@@ -993,8 +997,8 @@
          DN.decode(TEST_ROOT_DN_STRING), SERVER_ID_1,
          100, replicationServerPort, brokerSessionTimeout, true);
      final ChangeNumber[] cns = generateChangeNumbers(4, SERVER_ID_1);
      publishDeleteMsgInOTest(server01, cns[0], tn, 1);
      final CSN[] csns = generateCSNs(4, SERVER_ID_1);
      publishDeleteMsgInOTest(server01, csns[0], tn, 1);
      Thread.sleep(1000);
@@ -1002,8 +1006,8 @@
      String cookieNotEmpty = readLastCookie();
      debugInfo(tn, "Store cookie not empty=\"" + cookieNotEmpty + "\"");
      publishDeleteMsgInOTest(server01, cns[1], tn, 2);
      publishDeleteMsgInOTest(server01, cns[2], tn, 3);
      publishDeleteMsgInOTest(server01, csns[1], tn, 2);
      publishDeleteMsgInOTest(server01, csns[2], tn, 3);
      // Sleep longer than this delay - the changelog will be trimmed
      Thread.sleep(1000);
@@ -1046,7 +1050,7 @@
      // 5. Assert that a request with an "old" cookie - one that refers to
      //    changes that have been removed by the replication changelog trimming
      //    returns the appropriate error.
      publishDeleteMsgInOTest(server01, cns[3], tn, 1);
      publishDeleteMsgInOTest(server01, csns[3], tn, 1);
      debugInfo(tn, "d1 trimdate" + d1.getStartState());
      debugInfo(tn, "d2 trimdate" + d2.getStartState());
@@ -1142,20 +1146,20 @@
      String user1entryUUID = "11111111-1111-1111-1111-111111111111";
      String baseUUID       = "22222222-2222-2222-2222-222222222222";
      ChangeNumber[] cns = generateChangeNumbers(4, SERVER_ID_1);
      CSN[] csns = generateCSNs(4, SERVER_ID_1);
      // Publish DEL
      int cnCounter = 0;
      publishDeleteMsgInOTest(server01, cns[cnCounter], tn, cnCounter + 1);
      int csnCounter = 0;
      publishDeleteMsgInOTest(server01, csns[csnCounter], tn, csnCounter + 1);
      // Publish ADD
      cnCounter++;
      csnCounter++;
      String lentry = "dn: uid="+tn+"2," + TEST_ROOT_DN_STRING + "\n"
          + "objectClass: top\n" + "objectClass: domain\n"
          + "entryUUID: "+user1entryUUID+"\n";
      Entry entry = TestCaseUtils.entryFromLdifString(lentry);
      AddMsg addMsg = new AddMsg(
          cns[cnCounter],
          csns[csnCounter],
          "uid="+tn+"2," + TEST_ROOT_DN_STRING,
          user1entryUUID,
          baseUUID,
@@ -1163,30 +1167,30 @@
          entry.getAttributes(),
          new ArrayList<Attribute>());
      server01.publish(addMsg);
      debugInfo(tn, " publishes " + addMsg.getChangeNumber());
      debugInfo(tn, " publishes " + addMsg.getCSN());
      // Publish MOD
      cnCounter++;
      csnCounter++;
      DN baseDN = DN.decode("uid=" + tn + "3," + TEST_ROOT_DN_STRING);
      List<Modification> mods = createMods("description", "new value");
      ModifyMsg modMsg = new ModifyMsg(cns[cnCounter], baseDN, mods, tn + "uuid3");
      ModifyMsg modMsg = new ModifyMsg(csns[csnCounter], baseDN, mods, tn + "uuid3");
      server01.publish(modMsg);
      debugInfo(tn, " publishes " + modMsg.getChangeNumber());
      debugInfo(tn, " publishes " + modMsg.getCSN());
      // Publish modDN
      cnCounter++;
      csnCounter++;
      final DN newSuperior = DN.decode(TEST_ROOT_DN_STRING2);
      ModifyDNOperation op = new ModifyDNOperationBasis(connection, 1, 1, null,
          DN.decode("uid="+tn+"4," + TEST_ROOT_DN_STRING), // entryDN
          RDN.decode("uid="+tn+"new4"), // new rdn
          true,  // deleteoldrdn
          newSuperior);
      op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cns[cnCounter],
      op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(csns[csnCounter],
          tn + "uuid4", "newparentId"));
      LocalBackendModifyDNOperation localOp = new LocalBackendModifyDNOperation(op);
      ModifyDNMsg modDNMsg = new ModifyDNMsg(localOp);
      server01.publish(modDNMsg);
      debugInfo(tn, " publishes " + modDNMsg.getChangeNumber());
      debugInfo(tn, " publishes " + modDNMsg.getCSN());
      sleep(1000);
      String cookie= "";
@@ -1197,7 +1201,7 @@
      final String[] cookies = new String[4];
      for (int j = 0; j < cookies.length; j++)
      {
        cookies[j] = "o=test:" + cns[j] + ";";
        cookies[j] = "o=test:" + csns[j] + ";";
      }
      assertEquals(searchOp.getSearchEntries().size(), 4);
@@ -1207,9 +1211,9 @@
      for (SearchResultEntry resultEntry : entries)
      {
        i++;
        checkDn(cns[i - 1], resultEntry);
        checkDn(csns[i - 1], resultEntry);
        checkValue(resultEntry, "targetdn", "uid=" + tn + i + "," + TEST_ROOT_DN_STRING);
        checkValue(resultEntry, "replicationcsn", cns[i - 1].toString());
        checkValue(resultEntry, "replicationcsn", csns[i - 1].toString());
        checkValue(resultEntry, "replicaidentifier", String.valueOf(SERVER_ID_1));
        checkValue(resultEntry, "changelogcookie", cookies[i - 1]);
        checkValue(resultEntry, "changenumber", "0");
@@ -1262,24 +1266,24 @@
    debugInfo(tn, "Ending test with success");
  }
  private ChangeNumber[] generateChangeNumbers(int nb, int serverId)
  private CSN[] generateCSNs(int nb, int serverId)
  {
    long startTime = TimeThread.getTime();
    ChangeNumber[] cns = new ChangeNumber[nb];
    CSN[] csns = new CSN[nb];
    for (int i = 0; i < nb; i++)
    {
      // seqNum must be greater than 0, so start at 1
      cns[i] = new ChangeNumber(startTime + i, i + 1, serverId);
      csns[i] = new CSN(startTime + i, i + 1, serverId);
    }
    return cns;
    return csns;
  }
  private void checkDn(ChangeNumber cn, SearchResultEntry resultEntry)
  private void checkDn(CSN csn, SearchResultEntry resultEntry)
  {
    String actualDN = resultEntry.getDN().toNormalizedString();
    String expectedDN =
        "replicationcsn=" + cn + "," + TEST_ROOT_DN_STRING + ",cn=changelog";
        "replicationcsn=" + csn + "," + TEST_ROOT_DN_STRING + ",cn=changelog";
    assertThat(actualDN).isEqualToIgnoringCase(expectedDN);
  }
@@ -1423,13 +1427,13 @@
          DN.decode(TEST_ROOT_DN_STRING), SERVER_ID_1,
          100, replicationServerPort, brokerSessionTimeout, true);
      ChangeNumber[] cns = generateChangeNumbers(2, SERVER_ID_1);
      CSN[] csns = generateCSNs(2, SERVER_ID_1);
      // Produce update on this suffix
      DeleteMsg delMsg =
          new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, cns[0],
          new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, csns[0],
            "11111111-1112-1113-1114-111111111114");
      debugInfo(tn, " publishing " + delMsg.getChangeNumber());
      debugInfo(tn, " publishing " + delMsg.getCSN());
      server01.publish(delMsg);
      sleep(500); // let's be sure the message is in the RS
@@ -1535,16 +1539,16 @@
      }
      // Produces change 2
      final ChangeNumber cn = cns[1];
      final CSN csn = csns[1];
      String expectedDn = "uid=" + tn + "2," +  TEST_ROOT_DN_STRING;
      delMsg = new DeleteMsg(expectedDn, cn,
      delMsg = new DeleteMsg(expectedDn, csn,
         "11111111-1112-1113-1114-111111111115");
      debugInfo(tn, " publishing " + delMsg.getChangeNumber());
      debugInfo(tn, " publishing " + delMsg.getCSN());
      server01.publish(delMsg);
      this.gblCN = cn;
      this.gblCSN = csn;
      sleep(1000);
      debugInfo(tn, delMsg.getChangeNumber() +
      debugInfo(tn, delMsg.getCSN() +
      " published , psearch will now wait for new entries");
      // wait for the 1 new entry
@@ -1711,30 +1715,30 @@
      server02.setChangeTimeHeartbeatInterval(100); //ms
      // Produce update 1
      ChangeNumber cn1 =
        new ChangeNumber(TimeThread.getTime(), ts++, SERVER_ID_1);
      CSN csn1 =
        new CSN(TimeThread.getTime(), ts++, SERVER_ID_1);
      DeleteMsg delMsg1 =
        new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, cn1,
        new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, csn1,
            "11111111-1111-1111-1111-111111111111");
      debugInfo(tn, " publishing " + delMsg1);
      server01.publish(delMsg1);
      sleep(500); // let's be sure the message is in the RS
      // Produce update 2
      ChangeNumber cn2 =
        new ChangeNumber(TimeThread.getTime(), ts++, SERVER_ID_2);
      CSN csn2 =
        new CSN(TimeThread.getTime(), ts++, SERVER_ID_2);
      DeleteMsg delMsg2 =
        new DeleteMsg("uid=" + tn + "2," + TEST_ROOT_DN_STRING2, cn2,
        new DeleteMsg("uid=" + tn + "2," + TEST_ROOT_DN_STRING2, csn2,
            "22222222-2222-2222-2222-222222222222");
      debugInfo(tn, " publishing " + delMsg2);
      server02.publish(delMsg2);
      sleep(500); // let's be sure the message is in the RS
      // Produce update 3
      ChangeNumber cn3 =
        new ChangeNumber(TimeThread.getTime(), ts++, SERVER_ID_2);
      CSN csn3 =
        new CSN(TimeThread.getTime(), ts++, SERVER_ID_2);
      DeleteMsg delMsg3 =
        new DeleteMsg("uid=" + tn + "3," + TEST_ROOT_DN_STRING2, cn3,
        new DeleteMsg("uid=" + tn + "3," + TEST_ROOT_DN_STRING2, csn3,
            "33333333-3333-3333-3333-333333333333");
      debugInfo(tn, " publishing " + delMsg3);
      server02.publish(delMsg3);
@@ -1828,9 +1832,9 @@
      InvocationCounterPlugin.resetAllCounters();
      long searchRequests   = ldapStatistics.getSearchRequests();
      ldapStatistics.getSearchRequests();
      long searchEntries    = ldapStatistics.getSearchResultEntries();
      long searchReferences = ldapStatistics.getSearchResultReferences();
      ldapStatistics.getSearchResultReferences();
      long searchesDone     = ldapStatistics.getSearchResultsDone();
      LDAPMessage message;
@@ -1852,7 +1856,7 @@
      if (!changesOnly)
      {
        debugInfo(tn, "Search1  Persistent filter=" + searchRequest1.getFilter()
                  + " expected to return change " + cn1);
                  + " expected to return change " + csn1);
        searchEntries = 0;
        message = null;
@@ -1868,14 +1872,13 @@
              searchEntries++;
              if (searchEntries==1)
              {
                checkValue(searchResultEntry.toSearchResultEntry(),"replicationcsn",cn1.toString());
                checkValue(searchResultEntry.toSearchResultEntry(),"replicationcsn",csn1.toString());
                checkValue(searchResultEntry.toSearchResultEntry(),"changenumber",
                    (compatMode?"10":"0"));
              }
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
              searchReferences++;
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -1896,7 +1899,7 @@
        message = null;
        {
          debugInfo(tn, "Search 2  Persistent filter=" + searchRequest2.getFilter()
              + " expected to return change " + cn2 + " & " + cn3);
              + " expected to return change " + csn2 + " & " + csn3);
          while (searchEntries < 2 && (message = r2.readMessage()) != null)
          {
            debugInfo(tn, "Search 2 Result=" +
@@ -1911,7 +1914,6 @@
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
              searchReferences++;
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -1933,7 +1935,7 @@
        message = null;
        {
          debugInfo(tn, "Search3  Persistent filter=" + searchRequest3.getFilter()
              + " expected to return change top + " + cn1 + " & " + cn2 + " & " + cn3);
              + " expected to return change top + " + csn1 + " & " + csn2 + " & " + csn3);
          while (searchEntries < 4 && (message = r3.readMessage()) != null)
          {
            debugInfo(tn, "Search3 Result=" +
@@ -1947,7 +1949,6 @@
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
              searchReferences++;
              break;
            case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -1967,34 +1968,34 @@
      }
      // Produces additional change
      ChangeNumber cn11 = new ChangeNumber(TimeThread.getTime(), 11, SERVER_ID_1);
      CSN csn11 = new CSN(TimeThread.getTime(), 11, SERVER_ID_1);
      String expectedDn11 = "uid=" + tn + "11," +  TEST_ROOT_DN_STRING;
      DeleteMsg delMsg11 = new DeleteMsg(expectedDn11, cn11,
      DeleteMsg delMsg11 = new DeleteMsg(expectedDn11, csn11,
         "44444444-4444-4444-4444-444444444444");
      debugInfo(tn, " publishing " + delMsg11);
      server01.publish(delMsg11);
      sleep(500);
      debugInfo(tn, delMsg11.getChangeNumber() + " published additionally ");
      debugInfo(tn, delMsg11.getCSN() + " published additionally ");
      // Produces additional change
      ChangeNumber cn12 = new ChangeNumber(TimeThread.getTime(), 12, SERVER_ID_2);
      CSN csn12 = new CSN(TimeThread.getTime(), 12, SERVER_ID_2);
      String expectedDn12 = "uid=" + tn + "12," +  TEST_ROOT_DN_STRING2;
      DeleteMsg delMsg12 = new DeleteMsg(expectedDn12, cn12,
      DeleteMsg delMsg12 = new DeleteMsg(expectedDn12, csn12,
         "55555555-5555-5555-5555-555555555555");
      debugInfo(tn, " publishing " + delMsg12 );
      server02.publish(delMsg12);
      sleep(500);
      debugInfo(tn, delMsg12.getChangeNumber()  + " published additionally ");
      debugInfo(tn, delMsg12.getCSN()  + " published additionally ");
      // Produces additional change
      ChangeNumber cn13 = new ChangeNumber(TimeThread.getTime(), 13, SERVER_ID_2);
      CSN csn13 = new CSN(TimeThread.getTime(), 13, SERVER_ID_2);
      String expectedDn13 = "uid=" + tn + "13," +  TEST_ROOT_DN_STRING2;
      DeleteMsg delMsg13 = new DeleteMsg(expectedDn13, cn13,
      DeleteMsg delMsg13 = new DeleteMsg(expectedDn13, csn13,
         "66666666-6666-6666-6666-666666666666");
      debugInfo(tn, " publishing " + delMsg13);
      server02.publish(delMsg13);
      sleep(500);
      debugInfo(tn, delMsg13.getChangeNumber()  + " published additionally ");
      debugInfo(tn, delMsg13.getCSN()  + " published additionally ");
      // wait 11
      searchEntries = 0;
@@ -2013,7 +2014,6 @@
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
          searchReferences++;
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -2047,7 +2047,6 @@
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
          searchReferences++;
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -2081,7 +2080,6 @@
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
          searchReferences++;
          break;
        case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
@@ -2292,17 +2290,17 @@
      // Produce updates
      long time = TimeThread.getTime();
      int ts = 1;
      ChangeNumber cn = new ChangeNumber(time, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, cn, tn, 1);
      CSN csn = new CSN(time, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, csn, tn, 1);
      cn = new ChangeNumber(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest(s2test2, cn, tn, 2);
      csn = new CSN(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest(s2test2, csn, tn, 2);
      ChangeNumber cn3 = new ChangeNumber(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest(s2test2, cn3, tn, 3);
      CSN csn3 = new CSN(time++, ts++, s2test2.getServerId());
      publishDeleteMsgInOTest(s2test2, csn3, tn, 3);
      cn = new ChangeNumber(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, cn, tn, 4);
      csn = new CSN(time++, ts++, s1test.getServerId());
      publishDeleteMsgInOTest(s1test, csn, tn, 4);
      sleep(500);
      // --
@@ -2317,17 +2315,17 @@
      // Test startState ("first cookie") of the ECL
      time = TimeThread.getTime();
      cn = new ChangeNumber(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, cn, tn, 6);
      csn = new CSN(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, csn, tn, 6);
      cn = new ChangeNumber(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, cn, tn, 7);
      csn = new CSN(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, csn, tn, 7);
      ChangeNumber cn8 = new ChangeNumber(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, cn8, tn, 8);
      CSN csn8 = new CSN(time++, ts++, s1test2.getServerId());
      publishDeleteMsgInOTest2(s1test2, csn8, tn, 8);
      ChangeNumber cn9 = new ChangeNumber(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, cn9, tn, 9);
      CSN csn9 = new CSN(time++, ts++, s2test.getServerId());
      publishDeleteMsgInOTest(s2test, csn9, tn, 9);
      sleep(500);
      ReplicationServerDomain rsd1 = replicationServer.getReplicationServerDomain(TEST_ROOT_DN_STRING);
@@ -2336,8 +2334,8 @@
      debugInfo(tn, rsd1.getBaseDn()
          + " DbServerState=" + rsd1.getDbServerState()
          + " ChangeTimeHeartBeatState=" + rsd1.getChangeTimeHeartbeatState()
          + " eligibleCN=" + rsd1.getEligibleCN()
          + " rs eligibleCN=" + replicationServer.getEligibleCN());
          + " eligibleCSN=" + rsd1.getEligibleCSN()
          + " rs eligibleCSN=" + replicationServer.getEligibleCSN());
      // FIXME:ECL Enable this test by adding an assert on the right value
      ReplicationServerDomain rsd2 = replicationServer.getReplicationServerDomain(TEST_ROOT_DN_STRING2);
@@ -2346,8 +2344,8 @@
      debugInfo(tn, rsd2.getBaseDn()
          + " DbServerState=" + rsd2.getDbServerState()
          + " ChangeTimeHeartBeatState=" + rsd2.getChangeTimeHeartbeatState()
          + " eligibleCN=" + rsd2.getEligibleCN()
          + " rs eligibleCN=" + replicationServer.getEligibleCN());
          + " eligibleCSN=" + rsd2.getEligibleCSN()
          + " rs eligibleCSN=" + replicationServer.getEligibleCSN());
      // FIXME:ECL Enable this test by adding an assert on the right value
    }
    finally
@@ -2403,15 +2401,15 @@
      String user1entryUUID = "11111111-1112-1113-1114-111111111115";
      String baseUUID       = "22222222-2222-2222-2222-222222222222";
      ChangeNumber[] cns = generateChangeNumbers(nbChanges, SERVER_ID_1);
      gblCN = cns[1];
      CSN[] csns = generateCSNs(nbChanges, SERVER_ID_1);
      gblCSN = csns[1];
      // Publish DEL
      DeleteMsg delMsg =
          new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, cns[0],
          new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, csns[0],
            user1entryUUID);
      server01.publish(delMsg);
      debugInfo(tn, " publishes " + delMsg.getChangeNumber());
      debugInfo(tn, " publishes " + delMsg.getCSN());
      // Publish ADD
      String lentry =
@@ -2421,7 +2419,7 @@
          + "entryUUID: "+user1entryUUID+"\n";
      Entry entry = TestCaseUtils.entryFromLdifString(lentry);
      AddMsg addMsg = new AddMsg(
          gblCN,
          gblCSN,
          "uid="+tn+"2," + TEST_ROOT_DN_STRING,
          user1entryUUID,
          baseUUID,
@@ -2429,14 +2427,14 @@
          entry.getAttributes(),
          new ArrayList<Attribute>());
      server01.publish(addMsg);
      debugInfo(tn, " publishes " + addMsg.getChangeNumber());
      debugInfo(tn, " publishes " + addMsg.getCSN());
      // Publish MOD
      DN baseDN = DN.decode("uid="+tn+"3," + TEST_ROOT_DN_STRING);
      List<Modification> mods = createMods("description", "new value");
      ModifyMsg modMsg = new ModifyMsg(cns[2], baseDN, mods, user1entryUUID);
      ModifyMsg modMsg = new ModifyMsg(csns[2], baseDN, mods, user1entryUUID);
      server01.publish(modMsg);
      debugInfo(tn, " publishes " + modMsg.getChangeNumber());
      debugInfo(tn, " publishes " + modMsg.getCSN());
      // Publish modDN
      ModifyDNOperation op = new ModifyDNOperationBasis(connection, 1, 1, null,
@@ -2444,11 +2442,11 @@
          RDN.decode("uid="+tn+"new4"), // new rdn
          true,  // deleteoldrdn
          DN.decode(TEST_ROOT_DN_STRING2)); // new superior
      op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cns[3], user1entryUUID, "newparentId"));
      op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(csns[3], user1entryUUID, "newparentId"));
      LocalBackendModifyDNOperation localOp = new LocalBackendModifyDNOperation(op);
      ModifyDNMsg modDNMsg = new ModifyDNMsg(localOp);
      server01.publish(modDNMsg);
      debugInfo(tn, " publishes " + modDNMsg.getChangeNumber());
      debugInfo(tn, " publishes " + modDNMsg.getCSN());
      sleep(1000);
      String filter = "(targetdn=*"+tn.toLowerCase()+"*,o=test)";
@@ -2456,7 +2454,7 @@
      // test 4 entries returned
      assertEntries(searchOp.getSearchEntries(), firstDraftChangeNumber, tn,
          ldifWriter, user1entryUUID, cns[0], gblCN, cns[2], cns[3]);
          ldifWriter, user1entryUUID, csns[0], gblCSN, csns[2], csns[3]);
      stop(server01);
@@ -2466,7 +2464,7 @@
      searchOp = searchOnChangelog(filter, tn, SUCCESS);
      assertEntries(searchOp.getSearchEntries(), firstDraftChangeNumber, tn,
          ldifWriter, user1entryUUID, cns[0], gblCN, cns[2], cns[3]);
          ldifWriter, user1entryUUID, csns[0], gblCSN, csns[2], csns[3]);
      assertEquals(searchOp.getSearchEntries().size(), nbChanges);
    }
    debugInfo(tn, "Ending test with success");
@@ -2475,7 +2473,7 @@
  private void assertEntries(List<SearchResultEntry> entries,
      int firstDraftChangeNumber, String tn, LDIFWriter ldifWriter,
      String user1entryUUID, ChangeNumber... cns) throws Exception
      String user1entryUUID, CSN... csns) throws Exception
  {
    debugAndWriteEntries(ldifWriter, entries, tn);
    assertEquals(entries.size(), 4);
@@ -2489,9 +2487,9 @@
      checkValue(resultEntry, "changenumber", String.valueOf(firstDraftChangeNumber + i - 1));
      checkValue(resultEntry, "targetentryuuid", user1entryUUID);
      checkValue(resultEntry, "replicaidentifier", String.valueOf(SERVER_ID_1));
      final ChangeNumber cn = cns[i - 1];
      checkValue(resultEntry, "replicationcsn", cn.toString());
      checkValue(resultEntry, "changelogcookie", "o=test:" + cn + ";");
      final CSN csn = csns[i - 1];
      checkValue(resultEntry, "replicationcsn", csn.toString());
      checkValue(resultEntry, "changelogcookie", "o=test:" + csn + ";");
      checkValue(resultEntry, "targetdn", "uid=" + tn + i + "," + TEST_ROOT_DN_STRING);
      if (i==1)
@@ -2556,10 +2554,10 @@
    // check the entry has the right content
    SearchResultEntry resultEntry = entries.get(0);
    assertTrue("changenumber=6,cn=changelog".equalsIgnoreCase(resultEntry.getDN().toNormalizedString()));
    checkValue(resultEntry, "replicationcsn", gblCN.toString());
    checkValue(resultEntry, "replicationcsn", gblCSN.toString());
    checkValue(resultEntry, "replicaidentifier", String.valueOf(SERVER_ID_1));
    checkValue(resultEntry, "changetype", "add");
    checkValue(resultEntry, "changelogcookie", "o=test:" + gblCN + ";");
    checkValue(resultEntry, "changelogcookie", "o=test:" + gblCSN + ";");
    checkValue(resultEntry, "targetentryuuid", user1entryUUID);
    checkValue(resultEntry, "changenumber", "6");
@@ -2644,7 +2642,7 @@
    LDIFWriter ldifWriter = getLDIFWriter();
    String filter = "(replicationcsn=" + this.gblCN + ")";
    String filter = "(replicationcsn=" + this.gblCSN + ")";
    InternalSearchOperation searchOp = searchOnChangelog(filter, tn, SUCCESS);
    assertEquals(searchOp.getSearchEntries().size(), 1);
@@ -2654,7 +2652,7 @@
    // check the DEL entry has the right content
    SearchResultEntry resultEntry = entries.get(0);
    checkValue(resultEntry, "replicationcsn", gblCN.toString());
    checkValue(resultEntry, "replicationcsn", gblCSN.toString());
    // TODO:ECL check values of the other attributes
    debugInfo(tn, "Ending test with success");
@@ -2698,12 +2696,12 @@
      evaluateSearchParameters(baseDN, 8, 8, "(changenumber=8)");
      //
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
      ChangeNumber changeNumber1 = gen.newChangeNumber();
      CSNGenerator gen = new CSNGenerator( 1, 0);
      CSN changeNumber1 = gen.newCSN();
      final StartECLSessionMsg startCLmsg =
          evaluateSearchParameters(baseDN, -1, -1,
              "(replicationcsn=" + changeNumber1 + ")");
      assertEquals(startCLmsg.getChangeNumber(), changeNumber1);
      assertEquals(startCLmsg.getCSN(), changeNumber1);
      // Use change number as base object.
      baseDN = DN.decode("changeNumber=8,cn=changelog");
@@ -2718,8 +2716,7 @@
  }
  private StartECLSessionMsg evaluateSearchParameters(DN baseDN,
      int firstDraftCN,
      int lastDraftCN, String filterString) throws Exception
      int firstDraftCN, int lastDraftCN, String filterString) throws Exception
  {
    final StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
    ECLSearchOperation.evaluateSearchParameters(startCLmsg, baseDN,
@@ -2872,11 +2869,11 @@
    String user1entryUUID = "11111111-1112-1113-1114-111111111115";
    // Publish DEL
    ChangeNumber cn1 = new ChangeNumber(TimeThread.getTime(), ts++, SERVER_ID_1);
    CSN csn1 = new CSN(TimeThread.getTime(), ts++, SERVER_ID_1);
    DeleteMsg delMsg = new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING,
        cn1, user1entryUUID);
        csn1, user1entryUUID);
    server01.publish(delMsg);
    debugInfo(tn, " publishes " + delMsg.getChangeNumber());
    debugInfo(tn, " publishes " + delMsg.getCSN());
    sleep(500);
    stop(server01);
@@ -2892,17 +2889,17 @@
    debugInfo(tn, "Starting test\n\n");
    String user1entryUUID = "11111111-1112-1113-1114-111111111115";
    final ChangeNumber[] cns = generateChangeNumbers(4, SERVER_ID_1);
    final ChangeNumber cn1 = cns[0];
    final ChangeNumber cn2 = cns[1];
    final ChangeNumber cn3 = cns[2];
    final CSN[] csns = generateCSNs(4, SERVER_ID_1);
    final CSN csn1 = csns[0];
    final CSN csn2 = csns[1];
    final CSN csn3 = csns[2];
    ReplicationServerDomain rsdtest = replicationServer.getReplicationServerDomain(TEST_ROOT_DN_STRING);
    // this empty state will force to count from the start of the DB
    final ServerState fromStart = new ServerState();
    // The replication changelog is empty
    assertEquals(rsdtest.getEligibleCount(fromStart, cns[0]), 0);
    assertEquals(rsdtest.getEligibleCount(fromStart, csns[0]), 0);
    // Creates broker on o=test
    ReplicationBroker server01 = openReplicationSession(
@@ -2910,54 +2907,52 @@
        1000, replicationServerPort, brokerSessionTimeout, true);
    // Publish one first message
    DeleteMsg delMsg = new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, cn1,
    DeleteMsg delMsg = new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, csn1,
            user1entryUUID);
    server01.publish(delMsg);
    debugInfo(tn, " publishes " + delMsg.getChangeNumber());
    debugInfo(tn, " publishes " + delMsg.getCSN());
    sleep(300);
    // From begin to now : 1 change
    assertEquals(rsdtest.getEligibleCount(fromStart, now()), 1);
    // Publish one second message
    delMsg = new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, cn2,
        user1entryUUID);
    delMsg = new DeleteMsg("uid=" + tn + "1," + TEST_ROOT_DN_STRING, csn2, user1entryUUID);
    server01.publish(delMsg);
    debugInfo(tn, " publishes " + delMsg.getChangeNumber());
    debugInfo(tn, " publishes " + delMsg.getCSN());
    sleep(300);
    // From begin to now : 2 changes
    assertEquals(rsdtest.getEligibleCount(fromStart, now()), 2);
    // From begin to first change (inclusive) : 1 change = cn1
    assertEquals(rsdtest.getEligibleCount(fromStart, cn1), 1);
    // From begin to first change (inclusive) : 1 change = csn1
    assertEquals(rsdtest.getEligibleCount(fromStart, csn1), 1);
    final ServerState fromStateBeforeCN1 = new ServerState();
    fromStateBeforeCN1.update(cn1);
    final ServerState fromStateBeforeCSN1 = new ServerState();
    fromStateBeforeCSN1.update(csn1);
    // From state/cn1(exclusive) to cn1 (inclusive) : 0 change
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCN1, cn1), 0);
    // From state/csn1(exclusive) to csn1 (inclusive) : 0 change
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCSN1, csn1), 0);
    // From state/cn1(exclusive) to cn2 (inclusive) : 1 change = cn2
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCN1, cn2), 1);
    // From state/csn1(exclusive) to csn2 (inclusive) : 1 change = csn2
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCSN1, csn2), 1);
    final ServerState fromStateBeforeCN2 = new ServerState();
    fromStateBeforeCN2.update(cn2);
    final ServerState fromStateBeforeCSN2 = new ServerState();
    fromStateBeforeCSN2.update(csn2);
    // From state/cn2(exclusive) to now (inclusive) : 0 change
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCN2, now()), 0);
    // From state/csn2(exclusive) to now (inclusive) : 0 change
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCSN2, now()), 0);
    // Publish one third message
    delMsg = new DeleteMsg("uid="+tn+"1," + TEST_ROOT_DN_STRING, cn3,
        user1entryUUID);
    delMsg = new DeleteMsg("uid="+tn+"1," + TEST_ROOT_DN_STRING, csn3, user1entryUUID);
    server01.publish(delMsg);
    debugInfo(tn, " publishes " + delMsg.getChangeNumber());
    debugInfo(tn, " publishes " + delMsg.getCSN());
    sleep(300);
    fromStateBeforeCN2.update(cn2);
    fromStateBeforeCSN2.update(csn2);
    // From state/cn2(exclusive) to now : 1 change = cn3
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCN2, now()), 1);
    // From state/csn2(exclusive) to now : 1 change = csn3
    assertEquals(rsdtest.getEligibleCount(fromStateBeforeCSN2, now()), 1);
    boolean perfs=false;
    if (perfs)
@@ -2971,9 +2966,8 @@
      debugInfo(tn, "Perf test in compat mode - will generate " + maxMsg + " msgs.");
      for (int i=4; i<=maxMsg; i++)
      {
        ChangeNumber cnx = new ChangeNumber(TimeThread.getTime(), i, SERVER_ID_1);
        delMsg = new DeleteMsg("uid="+tn+i+"," + TEST_ROOT_DN_STRING, cnx,
              user1entryUUID);
        CSN csnx = new CSN(TimeThread.getTime(), i, SERVER_ID_1);
        delMsg = new DeleteMsg("uid="+tn+i+"," + TEST_ROOT_DN_STRING, csnx, user1entryUUID);
        server01.publish(delMsg);
      }
      sleep(1000);
@@ -2987,7 +2981,7 @@
      rs.disableEligibility(excludedDomains);
      long t1 = TimeThread.getTime();
      int[] limitss = replicationServer.getECLDraftCNLimits(
          replicationServer.getEligibleCN(), excludedDomains);
          replicationServer.getEligibleCSN(), excludedDomains);
      assertEquals(limitss[1], maxMsg);
      long t2 = TimeThread.getTime();
      debugInfo(tn, "Perfs - " + maxMsg + " counted in (ms):" + (t2 - t1));
@@ -3015,9 +3009,9 @@
    debugInfo(tn, "Ending test with success");
  }
  private ChangeNumber now()
  private CSN now()
  {
    return new ChangeNumber(TimeThread.getTime(), 1, SERVER_ID_1);
    return new CSN(TimeThread.getTime(), 1, SERVER_ID_1);
  }
  /**
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java
@@ -41,7 +41,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.replication.protocol.*;
@@ -596,10 +596,10 @@
    String user1dn;
    /*
     * Create a Change number generator to generate new changenumbers
     * when we need to send operation messages to the replicationServer.
     * Create a CSN generator to generate new CSNs when we need to send
     * operation messages to the replicationServer.
     */
    ChangeNumberGenerator gen = new ChangeNumberGenerator(2, 0);
    CSNGenerator gen = new CSNGenerator(2, 0);
    user1entryUUID = "33333333-3333-3333-3333-333333333333";
    user1dn = "uid=user1,ou=People," + baseDnStr;
@@ -629,7 +629,7 @@
    }
    // Create and publish an update message to add an entry.
    return new AddMsg(gen.newChangeNumber(),
    return new AddMsg(gen.newCSN(),
        personWithUUIDEntry.getDN().toString(),
        user1entryUUID,
        baseUUID,
@@ -1050,7 +1050,7 @@
        /* expected */
        AddMsg rcvmsg = (AddMsg)msg;
        assertEquals(rcvmsg.getChangeNumber(), emsg.getChangeNumber());
        assertEquals(rcvmsg.getCSN(), emsg.getCSN());
      }
      catch(SocketTimeoutException e)
      {
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java
@@ -27,9 +27,6 @@
 */
package org.opends.server.replication;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
@@ -45,7 +42,7 @@
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.plugin.EntryHistorical;
import org.opends.server.replication.protocol.ModifyMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
@@ -54,13 +51,17 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
/**
 * Test for the schema replication.
 */
@SuppressWarnings("javadoc")
public class SchemaReplicationTest extends ReplicationTestCase
{
  private ArrayList<Modification> rcvdMods = null;
  private List<Modification> rcvdMods;
  private int replServerPort;
@@ -217,9 +218,9 @@
    try
    {
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 2, 0);
      CSNGenerator gen = new CSNGenerator( 2, 0);
      ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(), baseDn, rcvdMods,
      ModifyMsg modMsg = new ModifyMsg(gen.newCSN(), baseDn, rcvdMods,
          EntryHistorical.getEntryUUID(DirectoryServer.getEntry(baseDn)));
      broker.publish(modMsg);
@@ -297,11 +298,11 @@
        "The received mod does not contain the original change");
      // check that the schema files were updated with the new ServerState.
      // by checking that the ChangeNUmber of msg we just received has been
      // by checking that the CSN of msg we just received has been
      // added to the user schema file.
      // build the string to find in the schema file
      String stateStr = modMsg.getChangeNumber().toString();
      String stateStr = modMsg.getCSN().toString();
      // open the schema file
      String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
@@ -325,15 +326,13 @@
        if (fileStr.indexOf(stateStr) != -1)
        {
          break;
        } else
        {
          if (count++ > 50)
          {
            fail("The Schema persistentState (changenumber:" + stateStr +
              ") has not been saved to " + path + " : " + fileStr);
          } else
            TestCaseUtils.sleep(100);
        }
        if (count++ > 50)
        {
          fail("The Schema persistentState (CSN:" + stateStr
              + ") has not been saved to " + path + " : " + fileStr);
        }
        TestCaseUtils.sleep(100);
      }
    } finally
    {
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -27,10 +27,6 @@
 */
package org.opends.server.replication;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.List;
@@ -44,8 +40,8 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.replication.protocol.*;
import org.opends.server.replication.service.ReplicationBroker;
@@ -57,6 +53,10 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
/**
 * Test synchronization of update operations on the directory server and through
 * the replication server broker interface.
@@ -245,7 +245,7 @@
   * Add an entry in the database
   *
   */
  private ChangeNumber addEntry(Entry entry) throws Exception
  private CSN addEntry(Entry entry) throws Exception
  {
    AddOperationBasis addOp = new AddOperationBasis(connection,
        InternalClientConnection.nextOperationID(), InternalClientConnection
@@ -256,7 +256,7 @@
    assertEquals(addOp.getResultCode(), ResultCode.SUCCESS);
    assertNotNull(getEntry(entry.getDN(), 1000, true));
    return OperationContext.getChangeNumber((Operation) addOp);
    return OperationContext.getCSN((Operation) addOp);
  }
  /**
@@ -297,10 +297,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new changenumbers
       * when we need to send operation messages to the replicationServer.
       * Create a CSN generator to generate new CSNs when we need to send
       * operation messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(2, 0);
      CSNGenerator gen = new CSNGenerator(2, 0);
      // Disable the directory server receive status.
@@ -308,7 +308,7 @@
      // Create and publish an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
          personWithUUIDEntry.getDN().toString(),
          user1entryUUID,
          baseUUID,
@@ -328,7 +328,7 @@
      setReceiveStatus(synchroServerEntry.getDN().toString(), true);
      // Create and publish another update message to add an entry.
      addMsg = new AddMsg(gen.newChangeNumber(),
      addMsg = new AddMsg(gen.newCSN(),
          personWithUUIDEntry.getDN().toString(),
          user1entryUUID,
          baseUUID,
@@ -345,7 +345,7 @@
      // Delete the entries to clean the database.
      DeleteMsg delMsg =
          new DeleteMsg(personWithUUIDEntry.getDN().toString(),
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
      broker.publish(delMsg);
      resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
@@ -384,14 +384,14 @@
    try
    {
      /*
       * Create a Change number generator to generate new changenumbers
       * when we need to send operation messages to the replicationServer.
       * Create a CSN generator to generate new CSNs when we need to send
       * operation messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(2, 0);
      CSNGenerator gen = new CSNGenerator(2, 0);
      // Create and publish an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
          personWithUUIDEntry.getDN().toString(),
          user1entryUUID,
          baseUUID,
@@ -408,7 +408,7 @@
      // Send a first modify operation message.
      List<Modification> mods = generatemods("telephonenumber", "01 02 45");
      ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(),
      ModifyMsg modMsg = new ModifyMsg(gen.newCSN(),
          personWithUUIDEntry.getDN(), mods,
          user1entryUUID);
      broker.publish(modMsg);
@@ -428,7 +428,7 @@
      // Send a second modify operation message.
      mods = generatemods("description", "Description was changed");
      modMsg = new ModifyMsg(gen.newChangeNumber(),
      modMsg = new ModifyMsg(gen.newCSN(),
          personWithUUIDEntry.getDN(), mods,
          user1entryUUID);
      broker.publish(modMsg);
@@ -445,7 +445,7 @@
      // Delete the entries to clean the database.
      DeleteMsg delMsg =
          new DeleteMsg(personWithUUIDEntry.getDN().toString(),
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
      broker.publish(delMsg);
      resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
@@ -512,11 +512,11 @@
      // A change on a first server.
      long changeTime = TimeThread.getTime();
      ChangeNumber t1 = new ChangeNumber(changeTime, 0, 3);
      CSN t1 = new CSN(changeTime, 0, 3);
      // A change on a second server.
      changeTime++;
      ChangeNumber t2 = new ChangeNumber(changeTime, 0, 4);
      CSN t2 = new CSN(changeTime, 0, 4);
      // Simulate the ordering t2:replace:B followed by t1:add:A that
      updateMonitorCount(baseDn, monitorAttr);
@@ -555,11 +555,11 @@
      // t1:replace:displayname
      // A change on a first server.
      changeTime++;
      t1 = new ChangeNumber(changeTime, 0, 3);
      t1 = new CSN(changeTime, 0, 3);
      // A change on a second server.
      changeTime++;
      t2 = new ChangeNumber(changeTime, 0, 4);
      t2 = new CSN(changeTime, 0, 4);
      // Simulate the ordering t2:delete:displayname followed by t1:replace:A
      updateMonitorCount(baseDn, monitorAttr);
@@ -631,11 +631,11 @@
    try
    {
    /*
     * Create a Change number generator to generate new changenumbers
     * when we need to send operations messages to the replicationServer.
     */
    ChangeNumberGenerator gen = new ChangeNumberGenerator( 2, 0);
      /*
       * Create a CSN generator to generate new CSNs when we need to send
       * operations messages to the replicationServer.
       */
    CSNGenerator gen = new CSNGenerator( 2, 0);
    /*
     * Test that the conflict resolution code is able to find entries
@@ -645,7 +645,7 @@
     * Finally check that the modify operation has been applied.
     */
    // create the entry with a given DN
    AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
    AddMsg addMsg = new AddMsg(gen.newCSN(),
        personWithUUIDEntry.getDN().toString(),
        user1entryUUID,
        baseUUID,
@@ -660,7 +660,7 @@
    // send a modify operation with the correct unique ID but another DN
    List<Modification> mods = generatemods("telephonenumber", "01 02 45");
    ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(),
    ModifyMsg modMsg = new ModifyMsg(gen.newCSN(),
        DN.decode("cn=something,ou=People," + TEST_ROOT_DN_STRING), mods,
        user1entryUUID);
    updateMonitorCount(baseDn, resolvedMonitorAttr);
@@ -688,7 +688,7 @@
    // send a modify operation attempting to replace the RDN entry
    // with a new value
    mods = generatemods("uid", "AnotherUid");
    modMsg = new ModifyMsg(gen.newChangeNumber(),
    modMsg = new ModifyMsg(gen.newCSN(),
        personWithUUIDEntry.getDN(), mods,
        user1entryUUID);
@@ -715,7 +715,7 @@
     */
    //  create the entry with a given DN and unique ID
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        personWithUUIDEntry.getDN().toString(),
        user1entryUUID, baseUUID,
        personWithUUIDEntry.getObjectClassAttribute(),
@@ -729,7 +729,7 @@
    // send a modify operation with a wrong unique ID but the same DN
    mods = generatemods("telephonenumber", "02 01 03 05");
    modMsg = new ModifyMsg(gen.newChangeNumber(),
    modMsg = new ModifyMsg(gen.newCSN(),
        DN.decode(user1dn), mods, "10000000-9abc-def0-1234-1234567890ab");
    updateMonitorCount(baseDn, resolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
@@ -761,7 +761,7 @@
    // used above
    DeleteMsg delMsg =
      new DeleteMsg("cn=anotherdn,ou=People," + TEST_ROOT_DN_STRING,
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
    updateMonitorCount(baseDn, resolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
    broker.publish(delMsg);
@@ -783,7 +783,7 @@
     */
    //  create an entry with a given DN and unique ID
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        personWithUUIDEntry.getDN().toString(),
        user1entryUUID, baseUUID,
        personWithUUIDEntry.getObjectClassAttribute(),
@@ -796,7 +796,7 @@
        "The ADD replication message was not applied");
    //  create an entry with the same DN and another unique ID
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        personWithSecondUniqueID.getDN().toString(),
        user1entrysecondUUID, baseUUID,
        personWithSecondUniqueID.getObjectClassAttribute(),
@@ -822,11 +822,11 @@
    //  delete the entries to clean the database.
    delMsg =
      new DeleteMsg(personWithUUIDEntry.getDN().toString(),
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
    broker.publish(delMsg);
    delMsg =
      new DeleteMsg(personWithSecondUniqueID.getDN().toString(),
          gen.newChangeNumber(), user1entrysecondUUID);
          gen.newCSN(), user1entrysecondUUID);
    broker.publish(delMsg);
    resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
    resultEntry = getEntry(personWithSecondUniqueID.getDN(), 10000, false);
@@ -841,7 +841,7 @@
     * Simulate this by trying to add an entry below a DN that does not
     * exist but with a parent ID that exist.
     */
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        "uid=new person,o=nothere,o=below,ou=People," + TEST_ROOT_DN_STRING,
        user1entryUUID,
        baseUUID,
@@ -874,7 +874,7 @@
    delMsg =
      new DeleteMsg("uid=new person,ou=People," + TEST_ROOT_DN_STRING,
          gen.newChangeNumber(), "11111111-9abc-def0-1234-1234567890ab");
          gen.newCSN(), "11111111-9abc-def0-1234-1234567890ab");
    updateMonitorCount(baseDn, resolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
    broker.publish(delMsg);
@@ -902,7 +902,7 @@
     */
    ModifyDNMsg  modDnMsg = new ModifyDNMsg(
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newCSN(),
        user1entryUUID, baseUUID, false,
        "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
        "uid=newrdn");
@@ -929,7 +929,7 @@
     */
     modDnMsg = new ModifyDNMsg(
        "uid=wrong,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
        "uid=wrong,ou=People," + TEST_ROOT_DN_STRING, gen.newCSN(),
        user1entryUUID, null, false, null, "uid=reallynewrdn");
    updateMonitorCount(baseDn, resolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
@@ -955,7 +955,7 @@
     */
    // add a second entry
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        user1dn,
        user1entrysecondUUID,
        baseUUID,
@@ -970,7 +970,7 @@
    assertNotNull(resultEntry, "The add operation was not replayed");
    // try to rename the first entry
    modDnMsg = new ModifyDNMsg(user1dn, gen.newChangeNumber(),
    modDnMsg = new ModifyDNMsg(user1dn, gen.newCSN(),
                               user1entrysecondUUID, baseUUID, false,
                               baseDn.toString(), "uid=reallynewrdn");
    updateMonitorCount(baseDn, unresolvedMonitorAttr);
@@ -996,7 +996,7 @@
      new DeleteMsg("entryUUID = " + user1entrysecondUUID + "+" +
          DN.decode(user1dn).getRDN().toString() +
          ",ou=People," + TEST_ROOT_DN_STRING,
          gen.newChangeNumber(), user1entrysecondUUID);
          gen.newCSN(), user1entrysecondUUID);
    broker.publish(delMsg);
    resultEntry = getEntry(
          DN.decode("entryUUID = " + user1entrysecondUUID + "+" +
@@ -1009,7 +1009,7 @@
    delMsg =
      new DeleteMsg("uid=reallynewrdn,ou=People," + TEST_ROOT_DN_STRING,
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
    broker.publish(delMsg);
    resultEntry = getEntry(
        DN.decode("uid=reallynewrdn,ou=People," + TEST_ROOT_DN_STRING), 10000, false);
@@ -1057,7 +1057,7 @@
        "Entry not added: ou=baseDn1,"+baseDn);
    // - create Add Msg for user1 with parent entry 1 UUID
    addMsg = new AddMsg(gen.newChangeNumber(),
    addMsg = new AddMsg(gen.newCSN(),
        "uid=new person,ou=baseDn1,"+baseDn,
        user1entryUUID,
        getEntryUUID(DN.decode("ou=baseDn1,"+baseDn)),
@@ -1122,7 +1122,7 @@
    // add domain1 entry with 2 children : domain2 and domain3
    addEntry(domain1);
    ChangeNumber olderCn = gen.newChangeNumber();
    CSN olderCSN = gen.newCSN();
    Thread.sleep(1000);
    domain1uid = getEntryUUID(DN.decode(domain1dn));
    addEntry(domain2);
@@ -1138,7 +1138,7 @@
    AlertCount = DummyAlertHandler.getAlertCount();
    // delete domain1
    delMsg = new DeleteMsg(domain1dn, olderCn, domain1uid);
    delMsg = new DeleteMsg(domain1dn, olderCSN, domain1uid);
    broker.publish(delMsg);
    // check that the domain1 has correctly been deleted
@@ -1180,15 +1180,15 @@
    domain1uid = getEntryUUID(DN.decode(domain1dn));
    addEntry(domain2);
    domain2uid = getEntryUUID(DN.decode(domain2dn));
    ChangeNumber addCn =  addEntry(domain3);
    gen.adjust(addCn);
    CSN addCSN = addEntry(domain3);
    gen.adjust(addCSN);
    domain3uid = getEntryUUID(DN.decode(domain3dn));
    updateMonitorCount(baseDn, unresolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
    // delete domain1
    delMsg = new DeleteMsg(domain1dn, gen.newChangeNumber(), domain1uid);
    delMsg = new DeleteMsg(domain1dn, gen.newCSN(), domain1uid);
    broker.publish(delMsg);
    // check that the domain1 has correctly been deleted
@@ -1213,7 +1213,7 @@
    // that is currently deleted on another master, the replay of the
    // add on the second master cause the added entry to be renamed
    //
    addMsg = new AddMsg(gen.newChangeNumber(), domain2dn, domain2uid,
    addMsg = new AddMsg(gen.newCSN(), domain2dn, domain2uid,
        domain1uid,
        domain2.getObjectClassAttribute(),
        domain2.getAttributes(), new ArrayList<Attribute>());
@@ -1235,7 +1235,7 @@
    // this is correctly detected as a resolved conflict.
    // To simulate this simply try a modifyDN on a non existent uid.
    modDnMsg = new ModifyDNMsg(
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newCSN(),
        "33343333-3533-3633-3373-333333833333", baseUUID, false,
        "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
        "uid=newrdn");
@@ -1270,7 +1270,7 @@
    updateMonitorCount(baseDn, unresolvedMonitorAttr);
    AlertCount = DummyAlertHandler.getAlertCount();
    modDnMsg = new ModifyDNMsg(
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
        "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newCSN(),
        "33333333-3333-3333-3333-333333333333",
        "12343333-3533-3633-3333-333333833333" , false,
        "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
@@ -1352,7 +1352,7 @@
      openReplicationSession(baseDn,  27, 100, replServerPort, 2000, true);
    try {
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 27, 0);
      CSNGenerator gen = new CSNGenerator( 27, 0);
      /*
       * Test that operations done on this server are sent to the
@@ -1453,7 +1453,7 @@
       *
       * Start by testing the Add message reception
       */
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
          personWithUUIDEntry.getDN().toString(),
          user1entryUUID, baseUUID,
          personWithUUIDEntry.getObjectClassAttribute(),
@@ -1472,7 +1472,7 @@
      /*
       * Test the reception of Modify Msg
       */
      modMsg = new ModifyMsg(gen.newChangeNumber(), personWithUUIDEntry.getDN(),
      modMsg = new ModifyMsg(gen.newCSN(), personWithUUIDEntry.getDN(),
          mods, user1entryUUID);
      if (assured)
        modMsg.setAssured(true);
@@ -1487,7 +1487,7 @@
      // Test that replication is able to add attribute that do
      // not exist in the schema.
      List<Modification> invalidMods = generatemods("badattribute", "value");
      modMsg = new ModifyMsg(gen.newChangeNumber(), personWithUUIDEntry.getDN(),
      modMsg = new ModifyMsg(gen.newCSN(), personWithUUIDEntry.getDN(),
          invalidMods, user1entryUUID);
      if (assured)
        modMsg.setAssured(true);
@@ -1502,7 +1502,7 @@
       * Test the Reception of Modify Dn Msg
       */
      moddnMsg = new ModifyDNMsg(personWithUUIDEntry.getDN().toString(),
          gen.newChangeNumber(),
          gen.newCSN(),
          user1entryUUID, null,
          true, null, "uid= new person");
      if (assured)
@@ -1519,7 +1519,7 @@
       * Test the Reception of Delete Msg
       */
      delMsg = new DeleteMsg("uid= new person,ou=People," + TEST_ROOT_DN_STRING,
          gen.newChangeNumber(), user1entryUUID);
          gen.newCSN(), user1entryUUID);
      if (assured)
        delMsg.setAssured(true);
      broker.publish(delMsg);
@@ -1580,7 +1580,7 @@
      openReplicationSession(baseDn,  11, 100, replServerPort, 1000, true);
    try
    {
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 11, 0);
      CSNGenerator gen = new CSNGenerator( 11, 0);
      // Create a test entry.
      String personLdif = "dn: uid=user.2,ou=People," + TEST_ROOT_DN_STRING + "\n"
@@ -1626,7 +1626,7 @@
      {
        // Publish a delete message for this test entry.
        DeleteMsg delMsg = new DeleteMsg(tmp.getDN().toString(),
                                         gen.newChangeNumber(),
                                         gen.newCSN(),
                                         uuid);
        broker.publish(delMsg);
@@ -1697,21 +1697,20 @@
  }
  /**
   * Test that the ReplicationDomain (plugin inside LDAP server) adjust
   * its internal change number generator to the last change number
   * received. Steps:
   * - create a domain with the current date in the CN generator
   * - make it receive an update with a CN in the future
   * its internal CSN generator to the last CSN received. Steps:
   * - create a domain with the current date in the CSN generator
   * - make it receive an update with a CSN in the future
   * - do a local operation replicated on that domain
   * - check that the update generated for that operation has a CN in the
   * - check that the update generated for that operation has a CSN in the
   *   future.
   * @throws Exception
   */
  @Test(enabled=true)
  public void CNGeneratorAdjust() throws Exception
  public void csnGeneratorAdjust() throws Exception
  {
    int serverId = 88;
    logError(Message.raw(Category.SYNC, Severity.INFORMATION,
        "Starting synchronization test : CNGeneratorAdjust"));
        "Starting synchronization test : CSNGeneratorAdjust"));
    final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
@@ -1728,15 +1727,15 @@
    try
    {
      /*
       * Create a Change number generator to generate new changenumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operation messages to the replicationServer.
       */
      long inTheFutur = System.currentTimeMillis() + (3600 * 1000);
      ChangeNumberGenerator gen = new ChangeNumberGenerator(serverId, inTheFutur);
      CSNGenerator gen = new CSNGenerator(serverId, inTheFutur);
      // Create and publish an update message to add an entry.
      AddMsg addMsg = new AddMsg(
          gen.newChangeNumber(),
          gen.newCSN(),
          user3dn.toString(),
          user3UUID,
          baseUUID,
@@ -1768,15 +1767,15 @@
      assertTrue(msg instanceof ModifyMsg,
          "The received replication message is not a MODIFY msg");
      ModifyMsg modMsg = (ModifyMsg) msg;
      assertEquals(addMsg.getChangeNumber().getTimeSec(),
          modMsg.getChangeNumber().getTimeSec(),
      assertEquals(addMsg.getCSN().getTimeSec(),
          modMsg.getCSN().getTimeSec(),
          "The MOD timestamp should have been adjusted to the ADD one");
      // Delete the entries to clean the database.
      DeleteMsg delMsg =
          new DeleteMsg(
          user3Entry.getDN().toString(),
          gen.newChangeNumber(),
          gen.newCSN(),
          user3UUID);
      broker.publish(delMsg);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/CSNGeneratorTest.java
New file
@@ -0,0 +1,91 @@
/*
 * 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 2009 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.common;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.util.TimeThread;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@SuppressWarnings("javadoc")
public class CSNGeneratorTest extends ReplicationTestCase
{
  /**
   * Test the adjust method of CSNGenerator
   */
  @Test
  public void adjustTest()
  {
    CSNGenerator generator = new CSNGenerator(5, TimeThread.getTime());
    CSN csn = generator.newCSN();
    CSN csn1 = new CSN(csn.getTime() + 5000, csn.getSeqnum(), 6);
    generator.adjust(csn1);
    CSN csn2 = generator.newCSN();
    assertTrue(csn2.compareTo(csn1) > 0,
        "CSNGenerator generated an earlier CSN after calling the adjust method.");
  }
  @Test
  public void adjustSameMilliTest()
  {
    CSNGenerator generator = new CSNGenerator(5, TimeThread.getTime());
    CSN csn = generator.newCSN();
    CSN csn1 = new CSN(csn.getTime(), csn.getSeqnum() + 10, 6);
    generator.adjust(csn1);
    CSN csn2 = generator.newCSN();
    assertTrue(csn2.compareTo(csn1) > 0,
        "CSNGenerator generated an earlier CSN after calling the adjust method.");
  }
  /**
   * Test the correct behavior of the CSNGenerator when
   * the seqnum is rolling over its limit
   */
  @Test
  public void adjustRollingSeqnum()
  {
    ServerState state = new ServerState();
    CSN csn1 = new CSN(TimeThread.getTime(), Integer.MAX_VALUE, 5);
    state.update(csn1);
    CSNGenerator generator = new CSNGenerator(5, state);
    CSN csn2 = generator.newCSN();
    assertTrue(csn2.getSeqnum() == 0);
    assertTrue(csn2.getTime() > csn1.getTime());
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/CSNTest.java
New file
@@ -0,0 +1,383 @@
/*
 * 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 2013 ForgeRock AS
 */
package org.opends.server.replication.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.util.TimeThread;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
 * Test {@link CSN} and {@link CSNGenerator}
 */
@SuppressWarnings("javadoc")
public class CSNTest extends ReplicationTestCase
{
  /**
   * Create CSN Data
   */
  @DataProvider(name = "csnData")
  public Object[][] createConstructorData() {
    long time = 0x12ABC;
    return new Object[][] {
       {1, 0, 1, "0000000000000001000100000000"},
       {time, 123, 45, "0000000000012abc002d0000007b"},
       {time, 123456789, 32767, "0000000000012abc7fff075bcd15"},
       {time, 123456789, 32768, "0000000000012abc8000075bcd15"},
       {time, 123456789, 65000, "0000000000012abcfde8075bcd15"},
       {time, 123, 45678, "0000000000012abcb26e0000007b"}
    };
  }
  /** Test CSN constructor */
  @Test(dataProvider = "csnData")
  public void createCSN(long time, int seq, int id, String str) throws Exception
  {
    CSN csn = new CSN(time, seq, id);
    assertEquals(csn.toString(), str);
    new CSN(time,   seq,   id);
    new CSN(time+1, seq,   id);
    new CSN(time,   seq+1, id);
    new CSN(time,   seq,   id+1);
  }
  /**
   * Test toString and constructor from String
   */
 @Test(dataProvider = "csnData")
 public void csnEncodeDecode(long time, int seq, int id, String str) throws Exception
 {
   // Create 2 CSN with the same data and check equality
    CSN csn = new CSN(time, seq, id);
    CSN csn2 = new CSN(csn.toString());
   assertEquals(csn, csn2,
       "The encoding/decoding is not reversible");
   assertEquals(csn2.toString(), str,
       "The encoding/decoding of CSN is not reversible for toString()");
 }
  /**
   * Create CSN
   */
  @DataProvider(name = "createCSN")
  public Object[][] createCSNData()
  {
    long time[] = {1, TimeThread.getTime()};
    int seq[] = {0,  123};
    int id [] = {1,  45};
    Object[][] obj = new Object[time.length][5];
    for (int i=0; i<time.length; i++)
    {
      obj[i][0] = new CSN(time[i],   seq[i],   id[i]);
      obj[i][1] = new CSN(time[i],   seq[i],   id[i]);
      obj[i][2] = new CSN(time[i]+1, seq[i],   id[i]);
      obj[i][3] = new CSN(time[i],   seq[i]+1, id[i]);
      obj[i][4] = new CSN(time[i],   seq[i],   id[i]+1);
    }
    return obj;
  }
  /** Test {@link CSN#hashCode()} method */
  @Test(dataProvider = "createCSN")
  public void csnHashCode(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertEquals(csn1.hashCode(), csn2.hashCode());
  }
  /** Test {@link CSN#equals(Object)} method */
  @Test(dataProvider = "createCSN")
  public void csnEquals(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertFalse(csn1.equals(new Object()));
    assertTrue(csn1.equals(csn1));
    assertTrue(csn1.equals(csn2));
    assertFalse(csn1.equals(csn3));
    assertFalse(csn1.equals(csn4));
    assertFalse(csn1.equals(csn5));
  }
  /** Test {@link CSN#getTimeSec()} method */
  @Test(dataProvider = "createCSN")
  public void csnGetTimeSec(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    // Check time in sec
    assertEquals(csn1.getTime()/1000, csn1.getTimeSec());
    assertEquals(csn2.getTime()/1000, csn2.getTimeSec());
    assertEquals(csn3.getTime()/1000, csn3.getTimeSec());
    assertEquals(csn4.getTime()/1000, csn4.getTimeSec());
    assertEquals(csn5.getTime()/1000, csn5.getTimeSec());
  }
  /** Test {@link CSN#compare(CSN, CSN)} method */
  @Test(dataProvider = "createCSN")
  public void csnCompare(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertTrue(CSN.compare(null, null) == 0);
    assertTrue(CSN.compare(null, csn2) < 0);
    assertTrue(CSN.compare(csn1, null) > 0);
    assertTrue(CSN.compare(csn1, csn2) == 0);
    assertTrue(CSN.compare(csn1, csn3) < 0);
    assertTrue(CSN.compare(csn3, csn1) > 0);
    assertTrue(CSN.compare(csn1, csn4) < 0);
    assertTrue(CSN.compare(csn4, csn1) > 0);
    assertTrue(CSN.compare(csn1, csn5) < 0);
    assertTrue(CSN.compare(csn5, csn1) > 0);
  }
  /** Test {@link CSN#older(CSN)} method */
  @Test(dataProvider = "createCSN")
  public void csnOlder(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertFalse(csn1.older(null));
    assertFalse(csn1.older(csn1));
    assertTrue(csn1.older(csn3));
    assertTrue(csn1.older(csn4));
    assertTrue(csn1.older(csn5));
  }
  /** Test {@link CSN#olderOrEqual(CSN)} method */
  @Test(dataProvider = "createCSN")
  public void csnOlderOrEqual(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertFalse(csn1.olderOrEqual(null));
    assertTrue(csn1.olderOrEqual(csn1));
    assertTrue(csn1.olderOrEqual(csn3));
    assertTrue(csn1.olderOrEqual(csn4));
    assertTrue(csn1.olderOrEqual(csn5));
  }
  /** Test {@link CSN#newer(CSN)} method */
  @Test(dataProvider = "createCSN")
  public void csnNewer(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertTrue(csn1.newer(null));
    assertFalse(csn1.newer(csn1));
    assertFalse(csn1.newer(csn3));
    assertFalse(csn1.newer(csn4));
    assertFalse(csn1.newer(csn5));
  }
  /** Test {@link CSN#newerOrEquals(CSN)} method */
  @Test(dataProvider = "createCSN")
  public void csnNewerOrEquals(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception
  {
    assertTrue(csn1.newerOrEquals(null));
    assertTrue(csn1.newerOrEquals(csn1));
    assertFalse(csn1.newerOrEquals(csn3));
    assertFalse(csn1.newerOrEquals(csn4));
    assertFalse(csn1.newerOrEquals(csn5));
  }
  /**
   * Create a {@link CSNGenerator}, then call {@link CSNGenerator#newCSN()} and
   * {@link CSNGenerator#adjust()}
   * <p>
   * FIXME these tests are calling Thread.sleep() which makes them slow. We
   * should really have a way to control time (make it go slower or faster) for
   * the unit tests to avoid such waits.
   */
  @Test
  public void csnGenerator() throws Exception
  {
    CSN csn1;
    CSN csn2;
    CSNGenerator csng =
      new CSNGenerator( 0, TimeThread.getTime());
    // Generate 2 CSNs and check that they are different
    csn1 = csng.newCSN();
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0);
    // Generate a CSN separated by 10 milliseconds
      // and check that they are different
    Thread.sleep(10);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0);
    // Generate a CSN separated by 300 milliseconds
      // and check that they are different
    Thread.sleep(300);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0);
    // Adjust with the oldest CSN
    csng.adjust(csn1);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0 );
    // Adjust with the newest generated
    csng.adjust(csn2);
    csn1 = csn2;
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0 );
    //  Adjust with the newest generated (time + 300)
    csn1 = new CSN(csn2.getTime() +300 ,csn2.getSeqnum(), csn2.getServerId());
    csng.adjust(csn1);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0 );
    //  Adjust with the newest generated (seqmun + 10)
    csn1 = new CSN(csn2.getTime() ,csn2.getSeqnum() +10, csn2.getServerId());
    csng.adjust(csn1);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0 );
    //  Adjust with the newest generated (seqmun = 0XFFFF)
    csn1 = new CSN(csn2.getTime() ,0XFFFF +10,csn2.getServerId());
    csng.adjust(csn1);
    csn2 = csng.newCSN();
    assertTrue(csn1.compareTo(csn2) != 0 );
  }
  /**
   * Test the difference in seq num between 2 CSNs.
   */
  @Test
  public void csnDiffSeqNum() throws Exception
  {
    CSN csn1;
    CSN csn2;
    csn1 = new CSN(0, 3, 0);
    // 3-0 = 3
    csn2 = new CSN(0, 0, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 3);
    // 3-1 = 2
    csn2 = new CSN(0, 1, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 2);
    // 3-3 = 0
    csn2 = new CSN(0, 3, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 0);
    // 3-4 = 0 (csn1 must be newer otherwise 0 should be returned)
    csn2 = new CSN(0, 4, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 0);
    csn1 = new CSN(0, 0, 0);
    // 0-0 = 0
    csn2 = new CSN(0, 0, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 0);
    // 0-1 = 0 (csn1 must be newer otherwise 0 should be returned)
    csn2 = new CSN(0, 1, 0);
    assertEquals(CSN.diffSeqNum(csn1, csn2), 0);
    csn1 = new CSN(0, 5, 0);
    csn2 = new CSN(0, 2, 0);
    // 5-null = 5
    assertEquals(CSN.diffSeqNum(csn1, null), 5);
    // null-2 = 0
    assertEquals(CSN.diffSeqNum(null, csn2), 0);
    // null-null = 0
    assertEquals(CSN.diffSeqNum(null, null), 0);
    csn1 = new CSN(1111111, 2, 0);
    csn2 = new CSN(3333333, 4, 0);
    // csn1 older than csn2 -> 0
    assertEquals(CSN.diffSeqNum(csn1, csn2), 0);
    csn1 = new CSN(3333333, 1, 0);
    csn2 = new CSN(1111111, Integer.MAX_VALUE-1, 0);
    // csn1 seqnum looped
    assertEquals(CSN.diffSeqNum(csn1, csn2), 3);
  }
  @DataProvider
  public Iterator<Object[]> createCSNPairsToCompare()
  {
    final List<Object> allCSNs = new ArrayList<Object>();
    for (Object[] csnData : createCSNData())
    {
      allCSNs.addAll(Arrays.asList(csnData));
    }
    final List<Object[]> results = new ArrayList<Object[]>();
    for (Object csn1 : allCSNs)
    {
      for (Object csn2 : allCSNs)
      {
        /*
         * it is ok to compare to the exact same CSN to ensure operations are
         * reflexive, and it is also ok to compare csn1 to csn2, and csn2 to
         * csn1 to ensure operations are symmetric
         */
        results.add(new Object[] { csn1, csn2 });
      }
    }
    return results.iterator();
  }
  @Test(dataProvider = "createCSNPairsToCompare")
  public void compareToEquivalentToEquals(CSN csn1, CSN csn2) throws Exception
  {
    assertEquals(csn1.compareTo(csn2) == 0, csn1.equals(csn2));
  }
  @Test(dataProvider = "createCSNPairsToCompare")
  public void hashCodesEqualWhenCSNsEqual(CSN csn1, CSN csn2) throws Exception
  {
    if (csn1.equals(csn2))
    {
      assertEquals(csn1.hashCode(), csn2.hashCode());
    }
  }
  @Test(dataProvider = "createCSNPairsToCompare")
  public void hashCodesEqualWhenCompareToEqual(CSN csn1, CSN csn2) throws Exception
  {
    if (csn1.compareTo(csn2) == 0)
    {
      assertEquals(csn1.hashCode(), csn2.hashCode());
    }
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/ChangeNumberGeneratorTest.java
File was deleted
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/ChangeNumberTest.java
File was deleted
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/ServerStateTest.java
@@ -23,43 +23,45 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.common;
import static org.testng.Assert.*;
import java.util.Set;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.ServerState;
import org.opends.server.util.TimeThread;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
 * Test the ServerState
 */
@SuppressWarnings("javadoc")
public class ServerStateTest extends ReplicationTestCase
{
  /**
   * Create ChangeNumber Data
   * Create CSN Data
   */
  @DataProvider(name = "changeNumberData")
  public Object[][] createChangeNumberData() {
  @DataProvider(name = "csnData")
  public Object[][] createCSNData()
  {
    return new Object[][] {
       {new ChangeNumber(1, 0, 1)},
       {new ChangeNumber(TimeThread.getTime(),  123,  45)}
       {new CSN(1, 0, 1)},
       {new CSN(TimeThread.getTime(),  123,  45)}
    };
  }
  /**
   * Create a new ServerState object
   */
  @Test(dataProvider = "changeNumberData")
  public void serverStateTest(ChangeNumber cn)
         throws Exception
  @Test(dataProvider = "csnData")
  public void serverStateTest(CSN csn) throws Exception
  {
    // Check constructor
    ServerState serverState = new ServerState() ;
@@ -69,57 +71,53 @@
    // TODO Check result;
    // Check update
    assertFalse(serverState.update((ChangeNumber)null));
    assertTrue(serverState.update(cn));
    assertFalse(serverState.update(cn));
    ChangeNumber cn1, cn2, cn3;
    cn1 = new ChangeNumber(cn.getTime()+1,cn.getSeqnum(),cn.getServerId());
    cn2 = new ChangeNumber(cn1.getTime(),cn1.getSeqnum()+1,cn1.getServerId());
    cn3 = new ChangeNumber(cn2.getTime(),cn2.getSeqnum(),(cn2.getServerId()+1));
    assertFalse(serverState.update((CSN)null));
    assertTrue(serverState.update(csn));
    assertFalse(serverState.update(csn));
    CSN csn1, csn2, csn3;
    csn1 = new CSN(csn.getTime() + 1, csn.getSeqnum(), csn.getServerId());
    csn2 = new CSN(csn1.getTime(), csn1.getSeqnum() + 1, csn1.getServerId());
    csn3 = new CSN(csn2.getTime(), csn2.getSeqnum(), (csn2.getServerId() + 1));
    assertTrue(serverState.update(cn1)) ;
    assertTrue(serverState.update(cn2)) ;
    assertTrue(serverState.update(cn3)) ;
    assertTrue(serverState.update(csn1));
    assertTrue(serverState.update(csn2));
    assertTrue(serverState.update(csn3));
    // Check toStringSet
    ChangeNumber[] cns = {cn2,cn3};
    CSN[] csns = { csn2, csn3 };
    Set<String> stringSet = serverState.toStringSet();
    assertEquals(cns.length, stringSet.size());
    assertEquals(csns.length, stringSet.size());
    // TODO Check the value
    // Check getMaxChangeNumber
    assertEquals(cn2.compareTo(serverState.getChangeNumber(cn2.getServerId())),0);
    assertEquals(cn3.compareTo(serverState.getChangeNumber(cn3.getServerId())),0);
    // Check getMaxCSN
    assertEquals(csn2.compareTo(serverState.getCSN(csn2.getServerId())), 0);
    assertEquals(csn3.compareTo(serverState.getCSN(csn3.getServerId())), 0);
    // Check the toString
    String stringRep = serverState.toString();
    assertTrue(stringRep.contains(cn2.toString()));
    assertTrue(stringRep.contains(cn3.toString()));
    assertTrue(stringRep.contains(csn2.toString()));
    assertTrue(stringRep.contains(csn3.toString()));
    // Check getBytes
    byte[] b = serverState.getBytes();
    ServerState generatedServerState = new ServerState(b,0,b.length -1) ;
    assertEquals(b, generatedServerState.getBytes()) ;
  }
  /**
   * Create a new ServerState object
   */
  @Test(dataProvider = "changeNumberData")
  public void serverStateReloadTest(ChangeNumber cn)
  @Test(dataProvider = "csnData")
  public void serverStateReloadTest(CSN csn)
  throws Exception
  {
    ChangeNumber cn1, cn3;
    cn1 = new ChangeNumber(cn.getTime()+1,cn.getSeqnum(),cn.getServerId());
    cn3 = new ChangeNumber(cn1.getTime(),cn1.getSeqnum(),(cn1.getServerId()+1));
    CSN csn1, csn3;
    csn1 = new CSN(csn.getTime() + 1, csn.getSeqnum(), csn.getServerId());
    csn3 = new CSN(csn1.getTime(), csn1.getSeqnum(), (csn1.getServerId() + 1));
    ServerState state1 = new ServerState();
    state1.update(cn1);
    state1.update(cn3);
    state1.update(csn1);
    state1.update(csn3);
    ServerState state2 = new ServerState();
    state2.reload(state1);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
@@ -212,7 +212,6 @@
   */
  private Entry createNotAssuredDomain() throws Exception
  {
    // Create a not assured config entry ldif
    String configEntryLdif = "dn: cn=" + testName + ", cn=domains, " +
      SYNCHRO_PLUGIN_DN + "\n" + "objectClass: top\n" +
@@ -252,36 +251,40 @@
    // Parameters given at constructor time
    private final int port;
    private int serverId = -1;
    boolean isAssured = false; // Default value for config
    AssuredMode assuredMode = AssuredMode.SAFE_DATA_MODE; // Default value for config
    byte safeDataLevel = (byte) 1; // Default value for config
    private boolean isAssured = false;
    private AssuredMode assuredMode = AssuredMode.SAFE_DATA_MODE;
    private byte safeDataLevel = 1;
    // Predefined config parameters
    private final int degradedStatusThreshold = 5000;
    // Parameters set with received server start message
    private String baseDn = null;
    private String baseDn;
    private long generationId = -1L;
    private ServerState serverState = null;
    private ServerState serverState;
    private int windowSize = -1;
    private byte groupId = (byte) -1;
    private byte groupId = -1;
    private boolean sslEncryption = false;
    // The scenario this RS is expecting
    /** The scenario this RS is expecting */
    private int scenario = -1;
    // parameters at handshake are ok
    /** parameters at handshake are ok */
    private boolean handshakeOk = false;
    // signal that the current scenario the RS must execute reached the point
    // where the main code can perform test assertion
    /**
     * signal that the current scenario the RS must execute reached the point
     * where the main code can perform test assertion.
     */
    private boolean scenarioExecuted = false;
    private ChangeNumberGenerator gen = null;
    private CSNGenerator gen;
    private String testcase;
    // Constructor for RS receiving updates in SR assured mode or not assured
    // The assured boolean means:
    // - true: SR mode
    // - false: not assured
    /**
     * Constructor for RS receiving updates in SR assured mode or not assured
     * The assured boolean means:
     * - true: SR mode
     * - false: not assured
     */
    public FakeReplicationServer(byte groupId, int port, int serverId, boolean assured,
        String testcase)
    {
@@ -322,8 +325,7 @@
     */
    public void start(int scenario)
    {
      gen = new ChangeNumberGenerator(3, 0L);
      gen = new CSNGenerator(3, 0L);
      // Store expected test case
      this.scenario = scenario;
@@ -338,7 +340,6 @@
    @Override
    public void run()
    {
      // Create server socket
      try
      {
@@ -424,7 +425,6 @@
     */
    private boolean performHandshake()
    {
      try
      {
        // Receive server start
@@ -523,7 +523,7 @@
    private void handleClientConnection()
    {
      debugInfo("handleClientConnection " + testcase + " " + scenario);
      // Handle DS connexion
      // Handle DS connection
      if (!performHandshake())
      {
        session.close();
@@ -580,9 +580,8 @@
    {
      try
      {
        // Create add message
        AddMsg addMsg =
          new AddMsg(gen.newChangeNumber(), entry.getDN().toString(), UUID.randomUUID().toString(),
          new AddMsg(gen.newCSN(), entry.getDN().toString(), UUID.randomUUID().toString(),
                     parentUid,
                     entry.getObjectClassAttribute(),
                     entry.getAttributes(), null );
@@ -656,7 +655,6 @@
     */
    private void executeNoTimeoutScenario()
    {
      try
      {
        UpdateMsg updateMsg = (UpdateMsg) session.receive();
@@ -666,7 +664,7 @@
        sleep(NO_TIMEOUT_RS_SLEEP_TIME);
        // Send the ack without errors
        AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber());
        AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
        session.publish(ackMsg);
        scenarioExecuted = true;
@@ -685,7 +683,7 @@
    {
      assertEquals(updateMsg.isAssured(), isAssured,
          "msg=" + ((updateMsg instanceof AddMsg)?
              ((AddMsg)updateMsg).getDn():updateMsg.getChangeNumber()));
              ((AddMsg)updateMsg).getDn():updateMsg.getCSN()));
      if (isAssured)
      {
        assertEquals(updateMsg.getAssuredMode(), assuredMode);
@@ -699,7 +697,6 @@
     */
    private void executeSafeReadManyErrorsScenario()
    {
      try
      {
        // Read first update
@@ -715,7 +712,7 @@
        List<Integer> serversInError = new ArrayList<Integer>();
        serversInError.add(10);
        serversInError.add(20);
        AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber(), false, false, true, serversInError);
        AckMsg ackMsg = new AckMsg(updateMsg.getCSN(), false, false, true, serversInError);
        session.publish(ackMsg);
        // Read second update
@@ -734,7 +731,7 @@
        serversInError.add(10);
        serversInError.add(20);
        serversInError.add(30);
        ackMsg = new AckMsg(updateMsg.getChangeNumber(), true, true, true, serversInError);
        ackMsg = new AckMsg(updateMsg.getCSN(), true, true, true, serversInError);
        session.publish(ackMsg);
        // Read third update
@@ -757,7 +754,6 @@
     */
    private void executeSafeDataManyErrorsScenario()
    {
      try
      {
        // Read first update
@@ -772,7 +768,7 @@
        // - server 10 error
        List<Integer> serversInError = new ArrayList<Integer>();
        serversInError.add(10);
        AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber(), true, false, false, serversInError);
        AckMsg ackMsg = new AckMsg(updateMsg.getCSN(), true, false, false, serversInError);
        session.publish(ackMsg);
        // Read second update
@@ -788,7 +784,7 @@
        serversInError = new ArrayList<Integer>();
        serversInError.add(10);
        serversInError.add(20);
        ackMsg = new AckMsg(updateMsg.getChangeNumber(), true, false, false, serversInError);
        ackMsg = new AckMsg(updateMsg.getCSN(), true, false, false, serversInError);
        session.publish(ackMsg);
        // Read third update
@@ -1790,9 +1786,7 @@
  protected Map<Integer,Integer> getErrorsByServers(DN baseDn,
    AssuredMode assuredMode) throws Exception
  {
    /*
     * Find monitoring entry for requested base DN
     */
    // Find monitoring entry for requested base DN
    String monitorFilter =
         "(&(cn=Directory server*)(domain-name=" + baseDn + "))";
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java
@@ -27,14 +27,12 @@
 */
package org.opends.server.replication.plugin;
import static org.testng.Assert.*;
import java.util.Collections;
import java.util.Map;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
@@ -43,6 +41,8 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
 * Test AttrInfo and AttrInfoWithOptions
 */
@@ -62,13 +62,13 @@
    AttributeValue att2 = AttributeValues.create(type, "value");
    AttributeValue att3 = AttributeValues.create(type, "again");
    ChangeNumber del1 = new ChangeNumber(1,  0,  1);
    ChangeNumber del2 = new ChangeNumber(1,  1,  1);
    ChangeNumber del3 = new ChangeNumber(1,  0,  2);
    CSN del1 = new CSN(1,  0,  1);
    CSN del2 = new CSN(1,  1,  1);
    CSN del3 = new CSN(1,  0,  2);
    ChangeNumber upd1 = new ChangeNumber(TimeThread.getTime(), 123, 45);
    ChangeNumber upd2 = new ChangeNumber(TimeThread.getTime() + 1000, 123,  45);
    ChangeNumber upd3 = new ChangeNumber(TimeThread.getTime(), 321, 54);
    CSN upd1 = new CSN(TimeThread.getTime(), 123, 45);
    CSN upd2 = new CSN(TimeThread.getTime() + 1000, 123,  45);
    CSN upd3 = new CSN(TimeThread.getTime(), 321, 54);
    return new Object[][]
    {
@@ -83,13 +83,13 @@
   */
  @Test(dataProvider = "attrInfo")
  public void attrInfo(
      AttributeValue att, ChangeNumber deleteTime, ChangeNumber updateTime)
      AttributeValue att, CSN deleteTime, CSN updateTime)
      throws Exception
  {
    // Create an empty AttrInfo
    AttrHistoricalMultiple attrInfo1 = new AttrHistoricalMultiple();
    // Check add(AttributeValue val, ChangeNumber CN)
    // Check
    attrInfo1.add(att, updateTime);
    Map<AttrValueHistorical,AttrValueHistorical> values1 = attrInfo1.getValuesHistorical();
    assertEquals(values1.size(), 1);
@@ -118,16 +118,16 @@
    assertEquals(attrInfo4.getDeleteTime().compareTo(attrInfo3.getDeleteTime()), 0);
    assertEquals(values4.size(), values3.size());
    // Check delete(AttributeValue val, ChangeNumber CN)
    // Check
    attrInfo4.delete(att, updateTime);
    assertEquals(attrInfo4.getValuesHistorical().size(), 1);
    // Check delete(LinkedHashSet<AttributeValue> values, ChangeNumber CN)
    // Check
    AttributeType type = DirectoryServer.getAttributeType("description");
    attrInfo3.delete(Attributes.create(type, att), updateTime) ;
    assertEquals(attrInfo3.getValuesHistorical().size(), 1);
    // Check delete(ChangeNumber CN)
    // Check
    attrInfo2.delete(updateTime) ;
    assertEquals(attrInfo2.getValuesHistorical().size(), 0);
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ComputeBestServerTest.java
@@ -31,29 +31,31 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.opends.server.replication.service.ReplicationBroker.*;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import static org.testng.Assert.*;
import org.opends.messages.Category;
import org.opends.messages.Message;
import org.opends.messages.Severity;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.ReplServerStartMsg;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.service.ReplicationBroker.ReplicationServerInfo;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.replication.service.ReplicationBroker.*;
import static org.testng.Assert.*;
/**
 * Test the algorithm for finding the best replication server among the
 * configured ones.
 */
@SuppressWarnings("javadoc")
public class ComputeBestServerTest extends ReplicationTestCase
{
@@ -70,15 +72,13 @@
  }
  /**
   * Test with one replication server, nobody has a change number (simulates)
   * very first connection.
   *
   * @throws Exception If a problem occurred
   * Test with one replication server, nobody has a CSN (simulates) very first
   * connection.
   */
  @Test
  public void testNullCNBoth() throws Exception
  public void testNullCSNBoth() throws Exception
  {
    String testCase = "testNullCNBoth";
    String testCase = "testNullCSNBoth";
    debugInfo("Starting " + testCase);
@@ -92,21 +92,20 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(0L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(0L, 0, myId3);
    aState.update(cn);
    csn = new CSN(0L, 0, myId2);
    aState.update(csn);
    csn = new CSN(0L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -121,13 +120,12 @@
  /**
   * Test with one replication server, only replication server has a non null
   * changenumber for ds server id
   * @throws Exception If a problem occurred
   * CSN for ds server id
   */
  @Test
  public void testNullCNDS() throws Exception
  public void testNullCSNDS() throws Exception
  {
    String testCase = "testNullCNDS";
    String testCase = "testNullCSNDS";
    debugInfo("Starting " + testCase);
@@ -140,23 +138,22 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(0L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(0L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(0L, 0, myId3);
    aState.update(cn);
    csn = new CSN(0L, 0, myId1);
    aState.update(csn);
    csn = new CSN(0L, 0, myId2);
    aState.update(csn);
    csn = new CSN(0L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -170,15 +167,13 @@
  }
  /**
   * Test with one replication server, only ds server has a non null
   * changenumber for ds server id but rs has a null one.
   *
   * @throws Exception If a problem occurred
   * Test with one replication server, only ds server has a non null CSN for ds
   * server id but rs has a null one.
   */
  @Test
  public void testNullCNRS() throws Exception
  public void testNullCSNRS() throws Exception
  {
    String testCase = "testNullCNRS";
    String testCase = "testNullCSNRS";
    debugInfo("Starting " + testCase);
@@ -192,23 +187,22 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(0L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(0L, 0, myId3);
    aState.update(cn);
    csn = new CSN(0L, 0, myId2);
    aState.update(csn);
    csn = new CSN(0L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -242,25 +236,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -295,25 +288,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -321,12 +313,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(2L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(2L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -361,25 +353,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    // This server has less changes than the other one but it has the same
    // group id as us so he should be the winner
    ReplServerStartMsg replServerStartMsg =
@@ -389,12 +380,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(2L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(2L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, LOOSER1, null, 0, aState, 0L,
      false, (byte)2, 0);
@@ -429,25 +420,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, 0L,
      false, (byte)2, 0);
@@ -455,12 +445,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(2L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(2L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(2L, 0, myId3);
    aState.update(cn);
    csn = new CSN(2L, 0, myId1);
    aState.update(csn);
    csn = new CSN(2L, 0, myId2);
    aState.update(csn);
    csn = new CSN(2L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, WINNER, null, 0, aState, 0L,
      false, (byte)2, 0);
@@ -496,25 +486,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -522,12 +511,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(2L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(4L, 0, myId3);
    aState.update(cn);
    csn = new CSN(2L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(4L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, LOOSER2, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -535,12 +524,12 @@
    // State for server 3
    aState = new ServerState();
    cn = new ChangeNumber(3L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(2L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(3L, 0, myId1);
    aState.update(csn);
    csn = new CSN(2L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(13, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -576,25 +565,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(1L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(1L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -602,12 +590,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(2L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(3L, 0, myId3);
    aState.update(cn);
    csn = new CSN(2L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(3L, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, LOOSER2, null, 0, aState, 0L,
      false, (byte)2, 0);
@@ -615,12 +603,12 @@
    // State for server 3
    aState = new ServerState();
    cn = new ChangeNumber(3L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(2L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(3L, 0, myId1);
    aState.update(csn);
    csn = new CSN(2L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    // This server has less changes than looser2 but it has the same
    // group id as us so he should be the winner
    replServerStartMsg =
@@ -656,25 +644,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(1L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(1L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(0L, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(1L, 0, myId3);
    aState.update(cn);
    csn = new CSN(0L, 0, myId1);
    aState.update(csn);
    csn = new CSN(1L, 0, myId2);
    aState.update(csn);
    csn = new CSN(1L, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -746,25 +733,24 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(4L, 0, myId1);
    mySt.update(cn);
    cn = new ChangeNumber(2L, 0, myId2); // Should not be used inside algo
    mySt.update(cn);
    cn = new ChangeNumber(3L, 0, myId3); // Should not be used inside algo
    mySt.update(cn);
    CSN csn = new CSN(4L, 0, myId1);
    mySt.update(csn);
    csn = new CSN(2L, 0, myId2); // Should not be used inside algo
    mySt.update(csn);
    csn = new CSN(3L, 0, myId3); // Should not be used inside algo
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(looser1T1, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(looser1T2, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(looser1T3, 0, myId3);
    aState.update(cn);
    csn = new CSN(looser1T1, 0, myId1);
    aState.update(csn);
    csn = new CSN(looser1T2, 0, myId2);
    aState.update(csn);
    csn = new CSN(looser1T3, 0, myId3);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -774,12 +760,12 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(winnerT1, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(winnerT2, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(winnerT3, 0, myId3);
    aState.update(cn);
    csn = new CSN(winnerT1, 0, myId1);
    aState.update(csn);
    csn = new CSN(winnerT2, 0, myId2);
    aState.update(csn);
    csn = new CSN(winnerT3, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, WINNER, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -789,12 +775,12 @@
    // State for server 3
    aState = new ServerState();
    cn = new ChangeNumber(looser2T1, 0, myId1);
    aState.update(cn);
    cn = new ChangeNumber(looser2T2, 0, myId2);
    aState.update(cn);
    cn = new ChangeNumber(looser2T3, 0, myId3);
    aState.update(cn);
    csn = new CSN(looser2T1, 0, myId1);
    aState.update(csn);
    csn = new CSN(looser2T2, 0, myId2);
    aState.update(csn);
    csn = new CSN(looser2T3, 0, myId3);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(13, LOOSER2, null, 0, aState, 0L,
      false, (byte)1, 0);
@@ -845,9 +831,6 @@
    // definitions for server ids
    int myId1 = 1;
    int myId2 = 2;
    int myId3 = 3;
    // definitions for server names
    final String WINNER  = "localhost:123";
    final String LOOSER1 = "localhost:456";
@@ -855,17 +838,16 @@
    // Create my state
    ServerState mySt = new ServerState();
    ChangeNumber cn = new ChangeNumber(4L, 0, myId1);
    mySt.update(cn);
    CSN csn = new CSN(4L, 0, myId1);
    mySt.update(csn);
    // Create replication servers info list
    HashMap<Integer, ReplicationServerInfo> rsInfos =
    Map<Integer, ReplicationServerInfo> rsInfos =
      new HashMap<Integer, ReplicationServerInfo>();
    // State for server 1
    ServerState aState = new ServerState();
    cn = new ChangeNumber(looser1T1, 0, myId1);
    aState.update(cn);
    csn = new CSN(looser1T1, 0, myId1);
    aState.update(csn);
    ReplServerStartMsg replServerStartMsg =
      new ReplServerStartMsg(11, LOOSER1, null, 0, aState, looser1GenId,
      false, looser1GroupId, 0);
@@ -875,8 +857,8 @@
    // State for server 2
    aState = new ServerState();
    cn = new ChangeNumber(winnerT1, 0, myId1);
    aState.update(cn);
    csn = new CSN(winnerT1, 0, myId1);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(12, WINNER, null, 0, aState, winnerGenId,
      false, winnerGroupId, 0);
@@ -886,8 +868,8 @@
    // State for server 3
    aState = new ServerState();
    cn = new ChangeNumber(looser2T1, 0, myId1);
    aState.update(cn);
    csn = new CSN(looser2T1, 0, myId1);
    aState.update(csn);
    replServerStartMsg =
      new ReplServerStartMsg(13, LOOSER2, null, 0, aState, looser2GenId,
      false, looser2GroupId, 0);
@@ -910,7 +892,7 @@
    Object[][] testData = new Object[24][];
    HashMap<Integer, ReplicationServerInfo> rsInfos = null;
    Map<Integer, ReplicationServerInfo> rsInfos = null;
      new HashMap<Integer, ReplicationServerInfo>();
    RSInfo rsInfo = null;
    List<Integer> connectedDSs = null;
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/FractionalReplicationTest.java
@@ -46,7 +46,7 @@
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
@@ -94,7 +94,7 @@
  private static final int INCLUDE_FRAC_MODE = 1;
  int initWindow = 100;
  private ChangeNumberGenerator gen = null;
  private CSNGenerator gen = null;
  /** The tracer object for the debug logger */
  private static final DebugTracer TRACER = getTracer();
@@ -405,11 +405,9 @@
    fractionalDomainCfgEntry = null;
    replicationServer = null;
    // Initialize the test backend
    TestCaseUtils.initializeTestBackend(false);
    // initialize cn generator
    gen = new ChangeNumberGenerator(DS2_ID, 0L);
    gen = new CSNGenerator(DS2_ID, 0L);
  }
  private void endTest()
@@ -731,7 +729,7 @@
    Entry entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID,
        null,
@@ -777,7 +775,7 @@
      mods.add(mod);
      DN entryDn = DN.decode((firstBackend ? ENTRY_DN : ENTRY_DN2));
      ModifyMsg modifyMsg = new ModifyMsg(gen.newChangeNumber(), entryDn, mods,
      ModifyMsg modifyMsg = new ModifyMsg(gen.newCSN(), entryDn, mods,
        ENTRY_UUID);
      replicationDomain.publish(modifyMsg);
@@ -1392,7 +1390,7 @@
      Entry entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID,
        null,
@@ -1428,7 +1426,7 @@
      entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      addMsg = new AddMsg(gen.newChangeNumber(),
      addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID2,
        null,
@@ -1488,7 +1486,7 @@
      Entry entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID,
        null,
@@ -1526,7 +1524,7 @@
      entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      addMsg = new AddMsg(gen.newChangeNumber(),
      addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID2,
        null,
@@ -1585,7 +1583,7 @@
      Entry entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID,
        null,
@@ -1611,7 +1609,7 @@
      DN newEntryDn = DN.decode(newEntryName);
      // Create modify dn message to modify the entry.
      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newChangeNumber(),
      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newCSN(),
        ENTRY_UUID, ENTRY_UUID3, false, TEST_ROOT_DN_STRING,
        "displayName=ValueToBeKept", null);
@@ -1666,7 +1664,7 @@
      Entry entry = TestCaseUtils.entryFromLdifString(entryLdif);
      // Create an update message to add an entry.
      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
      AddMsg addMsg = new AddMsg(gen.newCSN(),
        entry.getDN().toString(),
        ENTRY_UUID,
        null,
@@ -1692,7 +1690,7 @@
      DN newEntryDn = DN.decode(newEntryName);
      // Create modify dn message to modify the entry.
      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newChangeNumber(),
      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newCSN(),
        ENTRY_UUID, ENTRY_UUID3, false, TEST_ROOT_DN_STRING,
        "displayName=ValueToBeKept", null);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java
@@ -27,10 +27,6 @@
 */
package org.opends.server.replication.plugin;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
@@ -45,7 +41,7 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.*;
import org.opends.server.replication.server.ReplServerFakeConfiguration;
import org.opends.server.replication.server.ReplicationServer;
@@ -55,6 +51,10 @@
import org.opends.server.util.TimeThread;
import org.testng.annotations.Test;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.testng.Assert.*;
/**
 * Test the usage of the historical data of the replication.
 */
@@ -69,7 +69,7 @@
  {
    List<ReplicationMsg> list = null;
    public TestBroker(LinkedList<ReplicationMsg> list)
    public TestBroker(List<ReplicationMsg> list)
    {
      super(null, null, null, 0, 0, 0, 0, null, (byte) 0, 0);
      this.list = list;
@@ -94,8 +94,8 @@
    HistoricalCsnOrderingMatchingRule r =
      new HistoricalCsnOrderingMatchingRule();
    ChangeNumber del1 = new ChangeNumber(1,  0,  1);
    ChangeNumber del2 = new ChangeNumber(1,  1,  1);
    CSN del1 = new CSN(1,  0,  1);
    CSN del2 = new CSN(1,  1,  1);
    ByteString v1 = ByteString.valueOf("a"+":"+del1.toString());
    ByteString v2 = ByteString.valueOf("a"+":"+del2.toString());
@@ -156,7 +156,7 @@
    "description: foo");
    assertEquals(resultCode, 0);
    // Read the entry back to get its historical and included changeNumber
    // Read the entry back to get its historical and included CSN
    Entry entry = DirectoryServer.getEntry(dn1);
    List<Attribute> attrs1 = entry.getAttribute(histType);
@@ -194,25 +194,22 @@
    boolean result =
      rd1.buildAndPublishMissingChanges(
          new ChangeNumber(startTime, 0, serverId),
          new CSN(startTime, 0, serverId),
          session);
    assertTrue(result, "buildAndPublishMissingChanges has failed");
    assertEquals(opList.size(), 3, "buildAndPublishMissingChanges should return 3 operations");
    assertTrue(opList.getFirst().getClass().equals(AddMsg.class));
    // Build a change number from the first modification
    // Build a CSN from the first modification
    String hv[] = histValue.split(":");
    logError(Message.raw(Category.SYNC, Severity.INFORMATION, hv[1]));
    ChangeNumber fromChangeNumber = new ChangeNumber(hv[1]);
    CSN fromCSN = new CSN(hv[1]);
    opList = new LinkedList<ReplicationMsg>();
    session = new TestBroker(opList);
    result =
      rd1.buildAndPublishMissingChanges(
          fromChangeNumber,
          session);
      result = rd1.buildAndPublishMissingChanges(fromCSN, session);
    assertTrue(result, "buildAndPublishMissingChanges has failed");
    assertEquals(opList.size(), 1, "buildAndPublishMissingChanges should return 1 operation");
    assertTrue(opList.getFirst().getClass().equals(ModifyMsg.class));
@@ -303,7 +300,7 @@
    // correctly generates the 4 operations in the correct order.
    boolean result =
      rd1.buildAndPublishMissingChanges(
          new ChangeNumber(startTime, 0, serverId),
          new CSN(startTime, 0, serverId),
          session);
    assertTrue(result, "buildAndPublishMissingChanges has failed");
    assertEquals(opList.size(), 5, "buildAndPublishMissingChanges should return 5 operations");
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java
@@ -36,7 +36,7 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.replication.protocol.ModifyMsg;
@@ -55,9 +55,9 @@
 * Tests the Historical class.
 */
@SuppressWarnings("javadoc")
public class HistoricalTest
     extends ReplicationTestCase
public class HistoricalTest extends ReplicationTestCase
{
  private int replServerPort;
  private String testName = "historicalTest";
@@ -288,10 +288,10 @@
    long now = System.currentTimeMillis();
    // A change on a first server.
    ChangeNumber t1 = new ChangeNumber(now,  0,  3);
    CSN t1 = new CSN(now,  0,  3);
    // A change on a second server.
    ChangeNumber t2 = new ChangeNumber(now+1,  0,  4);
    CSN t2 = new CSN(now+1,  0,  4);
    // Simulate the ordering t1:add:A followed by t2:add:B that would
    // happen on one server.
@@ -316,8 +316,8 @@
    // Simulate the reverse ordering t2:add:B followed by t1:add:A that
    // would happen on the other server.
    t1 = new ChangeNumber(now+3,  0,  3);
    t2 = new ChangeNumber(now+4,  0,  4);
    t1 = new CSN(now+3,  0,  3);
    t2 = new CSN(now+4,  0,  4);
    // Replay an add of a value B at time t2 on a second server.
    attr = Attributes.create(attrType.getNormalizedPrimaryName(), "B");
@@ -354,7 +354,7 @@
}
  private static
  void publishModify(ReplicationBroker broker, ChangeNumber changeNum,
  void publishModify(ReplicationBroker broker, CSN changeNum,
                     DN dn, String entryuuid, Modification mod)
  {
    List<Modification> mods = new ArrayList<Modification>(1);
@@ -473,7 +473,7 @@
        // - the dn should be dn1,
        // - the entry id and the parent id should match the ids from the entry
        FakeAddOperation addOp = (FakeAddOperation) op;
        assertTrue(addOp.getChangeNumber() != null);
        assertTrue(addOp.getCSN() != null);
        AddMsg addmsg = addOp.generateMessage();
        assertTrue(dn1.equals(DN.decode(addmsg.getDn())));
        assertTrue(addmsg.getEntryUUID().equals(EntryHistorical.getEntryUUID(entry)));
@@ -503,7 +503,7 @@
   *
   * TODO: another test should be written that configures the task no NOT have
   * the time to purge everything in 1 run .. and thus to relauch it to finish
   * the purge. And verify that the second run starts on the changeNumber where
   * the purge. And verify that the second run starts on the CSN where
   * the previous task run had stopped.
   */
  @Test(enabled=true)
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java
@@ -43,7 +43,7 @@
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.LDAPUpdateMsg;
import org.opends.server.replication.protocol.ModifyContext;
import org.opends.server.replication.protocol.ReplicationMsg;
@@ -1329,7 +1329,7 @@
  {
    InternalClientConnection aConnection =
      InternalClientConnection.getRootConnection();
    ChangeNumber t = new ChangeNumber(date, 0, 0);
    CSN t = new CSN(date, 0, 0);
    ModifyOperationBasis modOpBasis =
      new ModifyOperationBasis(aConnection, 1, 1, null, entry.getDN(), mods);
@@ -1349,7 +1349,7 @@
    InternalClientConnection aConnection =
      InternalClientConnection.getRootConnection();
    ChangeNumber t = new ChangeNumber(date, 0, 0);
    CSN t = new CSN(date, 0, 0);
    List<Modification> mods = new ArrayList<Modification>();
    mods.add(mod);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
@@ -27,9 +27,6 @@
 */
package org.opends.server.replication.plugin;
import static org.opends.server.TestCaseUtils.*;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -40,14 +37,17 @@
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
import org.opends.server.types.*;
import org.testng.annotations.Test;
import static org.opends.server.TestCaseUtils.*;
import static org.testng.Assert.*;
/**
 * Test the naming conflict resolution code.
 */
@@ -87,10 +87,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
@@ -111,12 +111,12 @@
      TestCaseUtils.addEntry(entry);
      String entryUUID = getEntryUUID(entry.getDN());
      // generate two consecutive ChangeNumber that will be used in backward order
      ChangeNumber cn1 = gen.newChangeNumber();
      ChangeNumber cn2 = gen.newChangeNumber();
      // generate two consecutive CSN that will be used in backward order
      CSN csn1 = gen.newCSN();
      CSN csn2 = gen.newCSN();
      ModifyDNMsg  modDnMsg = new ModifyDNMsg(
          entry.getDN().toNormalizedString(), cn2,
          entry.getDN().toNormalizedString(), csn2,
          entryUUID, parentUUID, false,
          TEST_ROOT_DN_STRING,
      "uid=simultaneous2");
@@ -130,7 +130,7 @@
      // This MODIFY DN uses an older DN and should therefore be cancelled
      // at replay time.
      modDnMsg = new ModifyDNMsg(
          entry.getDN().toNormalizedString(), cn1,
          entry.getDN().toNormalizedString(), csn1,
          entryUUID, parentUUID, false,
          TEST_ROOT_DN_STRING,
      "uid=simulatneouswrong");
@@ -176,10 +176,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      String entryldif =
        "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
@@ -200,12 +200,11 @@
      TestCaseUtils.addEntry(entry);
      String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
      ChangeNumber cn1 = gen.newChangeNumber();
      CSN csn1 = gen.newCSN();
      // Now try to add the same entry with same DN but a different
      // unique ID though the replication
      AddMsg  addMsg =
        new AddMsg(cn1,
      AddMsg addMsg = new AddMsg(csn1,
            entry.getDN().toNormalizedString(),
            "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
            entry.getObjectClasses(), entry.getUserAttributes(),
@@ -261,10 +260,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * when we need to send operations messages to the replicationServer.
       * Create a CSN generator to generate new CSNs when we need to send
       * operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      String entryldif =
        "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
@@ -285,12 +284,11 @@
      TestCaseUtils.addEntry(entry);
      String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
      ChangeNumber cn1 = gen.newChangeNumber();
      CSN csn1 = gen.newCSN();
      // Now try to add the same entry with same DN but a different
      // unique ID though the replication
      AddMsg  addMsg =
        new AddMsg(cn1,
      AddMsg addMsg = new AddMsg(csn1,
            entry.getDN().toNormalizedString(),
            "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
            entry.getObjectClasses(), entry.getUserAttributes(),
@@ -331,20 +329,20 @@
   *       ADD uid=xx,ou=parent,...          [SUBTREE] DEL ou=parent, ...
   *
   * 1/ removeParentConflict1 (on S1)
   *    - t1(cn1) ADD uid=xx,ou=parent,...
   *         - t2(cn2) replay SUBTREE DEL ou=parent, ....
   *    - t1(csn1) ADD uid=xx,ou=parent,...
   *         - t2(csn2) replay SUBTREE DEL ou=parent, ....
   *    => No conflict : expect the parent entry & subtree to be deleted
   *
   * 2/ removeParentConflict2 (on S1)
   *    - t1(cn1) ADD uid=xx,ou=parent,...
   *             - replay t2(cn2) DEL ou=parent, ....
   *    - t1(csn1) ADD uid=xx,ou=parent,...
   *             - replay t2(csn2) DEL ou=parent, ....
   *    => Conflict and no automatic resolution: expect
   *         - the child entry to be renamed under root entry
   *         - the parent entry to be deleted
   *
   * 3/ removeParentConflict3 (on S2)
   *                         - t2(cn2) DEL or SUBTREE DEL ou=parent, ....
   *                         - t1(cn1) replay ADD uid=xx,ou=parent,...
   *                         - t2(csn2) DEL or SUBTREE DEL ou=parent, ....
   *                         - t1(csn1) replay ADD uid=xx,ou=parent,...
   *                        => Conflict and no automatic resolution: expect
   *                           - the child entry to be renamed under root entry
   *
@@ -367,10 +365,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      Entry parentEntry = TestCaseUtils.entryFromLdifString(
          "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
@@ -397,11 +395,11 @@
      String parentUUID = getEntryUUID(parentEntry.getDN());
      ChangeNumber cn2 = gen.newChangeNumber();
      CSN csn2 = gen.newCSN();
      DeleteMsg  delMsg = new DeleteMsg(
          parentEntry.getDN().toNormalizedString(),
          cn2,
          csn2,
          parentUUID);
      delMsg.setSubtreeDelete(true);
@@ -440,10 +438,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      Entry parentEntry = TestCaseUtils.entryFromLdifString(
          "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
@@ -476,11 +474,11 @@
      String parentUUID = getEntryUUID(parentEntry.getDN());
      String childUUID = getEntryUUID(childEntry.getDN());
      ChangeNumber cn2 = gen.newChangeNumber();
      CSN csn2 = gen.newCSN();
      DeleteMsg  delMsg = new DeleteMsg(
          parentEntry.getDN().toNormalizedString(),
          cn2,
          csn2,
          parentUUID);
      // NOT SUBTREE
@@ -524,10 +522,10 @@
    try
    {
      /*
       * Create a Change number generator to generate new ChangeNumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operations messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
      CSNGenerator gen = new CSNGenerator(201, 0);
      Entry parentEntry = TestCaseUtils.entryFromLdifString(
          "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
@@ -554,12 +552,12 @@
      String parentUUID = getEntryUUID(parentEntry.getDN());
      TestCaseUtils.deleteEntry(parentEntry);
      ChangeNumber cn1 = gen.newChangeNumber();
      CSN csn1 = gen.newCSN();
      // Create and publish an update message to add the child entry.
      String childUUID = "44444444-4444-4444-4444-444444444444";
      AddMsg addMsg = new AddMsg(
          cn1,
          csn1,
          childEntry.getDN().toString(),
          childUUID,
          parentUUID,
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/PersistentServerStateTest.java
@@ -28,19 +28,20 @@
package org.opends.server.replication.plugin;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.ServerState;
import org.opends.server.types.DN;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING;
import static org.testng.Assert.assertEquals;
import static org.opends.server.TestCaseUtils.*;
import static org.testng.Assert.*;
/**
 * Test the PersistentServerState class.
 */
@SuppressWarnings("javadoc")
public class PersistentServerStateTest extends ReplicationTestCase
{
  /**
@@ -59,48 +60,44 @@
   * retrieve ServerState to persistent storage.
   */
  @Test(dataProvider = "suffix")
  public void persistentServerStateTest(String dn)
         throws Exception
  public void persistentServerStateTest(String dn) throws Exception
  {
    /*
     * Create a new PersistentServerState,
     * update it with 2 new ChangeNumbers with 2 different server Ids
     * update it with 2 new csns with 2 different server Ids
     * save it
     *
     * Then creates a new PersistentServerState and check that the
     * 2 ChangeNumbers have been saved in this new PersistentServerState.
     * 2 csns have been saved in this new PersistentServerState.
     */
    DN baseDn = DN.decode(dn);
    ServerState origState = new ServerState();
    PersistentServerState state =
      new PersistentServerState(baseDn,  1, origState);
    ChangeNumberGenerator gen1 =
      new ChangeNumberGenerator( 1, origState);
    ChangeNumberGenerator gen2 =
      new ChangeNumberGenerator( 2, origState);
    CSNGenerator gen1 = new CSNGenerator(1, origState);
    CSNGenerator gen2 = new CSNGenerator(2, origState);
    ChangeNumber cn1 = gen1.newChangeNumber();
    ChangeNumber cn2 = gen2.newChangeNumber();
    CSN csn1 = gen1.newCSN();
    CSN csn2 = gen2.newCSN();
    assertEquals(state.update(cn1), true);
    assertEquals(state.update(cn2), true);
    assertEquals(state.update(csn1), true);
    assertEquals(state.update(csn2), true);
    state.save();
    PersistentServerState stateSaved = new PersistentServerState(baseDn,  1);
    ChangeNumber cn1Saved = stateSaved.getMaxChangeNumber( 1);
    ChangeNumber cn2Saved = stateSaved.getMaxChangeNumber( 2);
    PersistentServerState stateSaved = new PersistentServerState(baseDn, 1);
    CSN csn1Saved = stateSaved.getMaxCSN(1);
    CSN csn2Saved = stateSaved.getMaxCSN(2);
    assertEquals(cn1Saved, cn1,
        "cn1 has not been saved or loaded correctly for " + dn);
    assertEquals(cn2Saved, cn2,
        "cn2 has not been saved or loaded correctly for " + dn);
    assertEquals(csn1Saved, csn1,
        "csn1 has not been saved or loaded correctly for " + dn);
    assertEquals(csn2Saved, csn2,
        "csn2 has not been saved or loaded correctly for " + dn);
    state.clear();
    stateSaved = new PersistentServerState(baseDn,  1);
    cn1Saved = stateSaved.getMaxChangeNumber( 1);
    assertEquals(cn1Saved, null,
        "cn1 has not been saved after clear for " + dn);
    csn1Saved = stateSaved.getMaxCSN(1);
    assertEquals(csn1Saved, null,
        "csn1 has not been saved after clear for " + dn);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/StateMachineTest.java
@@ -27,11 +27,6 @@
 */
package org.opends.server.replication.plugin;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import static org.testng.Assert.*;
import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
@@ -51,7 +46,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.DSInfo;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.common.ServerStatus;
@@ -69,6 +64,11 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import static org.testng.Assert.*;
/**
 * Some tests to go through the DS state machine and validate we get the
 * expected status according to the actions we perform.
@@ -953,7 +953,7 @@
    /** Number of sent changes */
    private int nChangesSent = 0;
    private int nChangesSentLimit = 0;
    ChangeNumberGenerator gen = null;
    CSNGenerator gen = null;
    private Object sleeper = new Object();
    /**
     * If the BrokerWriter is to be used for a lot of changes to send (which is
@@ -971,9 +971,9 @@
      super("BrokerWriter for broker " + serverId);
      this.rb = rb;
      this.serverId = serverId;
      // Create a Change number generator to generate new change numbers
      // Create a csn generator to generate new csns
      // when we need to send changes
      gen = new ChangeNumberGenerator(serverId, 0);
      gen = new CSNGenerator(serverId, 0);
      // Start thread (is paused by default so will have to call follow anyway)
      start();
@@ -1186,7 +1186,7 @@
      }
      // Create an update message to add an entry.
      return new AddMsg(gen.newChangeNumber(),
      return new AddMsg(gen.newCSN(),
        personWithUUIDEntry.getDN().toString(),
        userEntryUUID,
        null,
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java
@@ -23,27 +23,29 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.plugin.AttrValueHistorical;
import org.opends.server.replication.common.CSN;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.util.TimeThread;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import static org.testng.Assert.*;
/**
 * Test of ValueInfo
 */
@SuppressWarnings("javadoc")
public class ValueInfoTest extends ReplicationTestCase
{
  /**
   * Build some data for the ValueInfo test below.
   */
@@ -55,13 +57,13 @@
    AttributeValue att2 = AttributeValues.create(type, "value");
    AttributeValue att3 = AttributeValues.create(type, "again");
    ChangeNumber del1 = new ChangeNumber(1,  0,  1);
    ChangeNumber del2 = new ChangeNumber(1,  1,  1);
    ChangeNumber del3 = new ChangeNumber(1,  0,  2);
    CSN del1 = new CSN(1,  0,  1);
    CSN del2 = new CSN(1,  1,  1);
    CSN del3 = new CSN(1,  0,  2);
    ChangeNumber upd1 = new ChangeNumber(TimeThread.getTime(), 123, 45);
    ChangeNumber upd2 = new ChangeNumber(TimeThread.getTime()+ 1000, 123, 45);
    ChangeNumber upd3 = new ChangeNumber(TimeThread.getTime(), 321, 54);
    CSN upd1 = new CSN(TimeThread.getTime(), 123, 45);
    CSN upd2 = new CSN(TimeThread.getTime()+ 1000, 123, 45);
    CSN upd3 = new CSN(TimeThread.getTime(), 321, 54);
    return new Object[][] {
        {att1,null,null},
@@ -74,16 +76,13 @@
   * Create a ValueInfo and check the methods
   */
  @Test(dataProvider = "valueInfo")
  public void valueInfo(AttributeValue value,
      ChangeNumber CNupdate,
      ChangeNumber CNdelete)
         throws Exception
  public void valueInfo(AttributeValue value, CSN csnUpdate, CSN csnDelete) throws Exception
  {
    AttributeType type = DirectoryServer.getAttributeType("description");
    AttrValueHistorical valInfo1 = new AttrValueHistorical(value,CNupdate,CNdelete);
    AttrValueHistorical valInfo2 = new AttrValueHistorical(value,CNupdate,CNupdate);
    AttrValueHistorical valInfo1 = new AttrValueHistorical(value, csnUpdate, csnDelete);
    AttrValueHistorical valInfo2 = new AttrValueHistorical(value, csnUpdate, csnUpdate);
    AttrValueHistorical valInfo3 = new AttrValueHistorical(AttributeValues.create(type,"Test"),
        CNupdate,CNupdate);
            csnUpdate, csnUpdate);
    // Check equals
    assertFalse(valInfo1.equals(new Object())) ;
@@ -97,20 +96,20 @@
    // Check getValueDeleteTime
    if (valInfo1.getValueDeleteTime() != null)
    {
      assertTrue(valInfo1.getValueDeleteTime().compareTo(CNdelete) == 0);
      assertTrue(valInfo1.getValueDeleteTime().compareTo(csnDelete) == 0);
    }
    // Check getValueUpdateTime
    if (valInfo1.getValueUpdateTime() != null)
    {
      assertTrue(valInfo1.getValueUpdateTime().compareTo(CNupdate) == 0);
      assertTrue(valInfo1.getValueUpdateTime().compareTo(csnUpdate) == 0);
    }
    // Check getValue
    assertTrue(valInfo1.getAttributeValue().equals(value)) ;
    // Chek valueUpdateTime
    if (CNupdate == null)
    if (csnUpdate == null)
    {
      assertFalse(valInfo1.isUpdate());
    }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/ProtocolCompatibilityTest.java
@@ -25,7 +25,6 @@
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011-2013 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import java.io.UnsupportedEncodingException;
@@ -42,39 +41,24 @@
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.DSInfo;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.Operation;
import org.opends.server.types.RawAttribute;
import org.opends.server.replication.common.*;
import org.opends.server.types.*;
import org.opends.server.util.TimeThread;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.replication.protocol.OperationContext.SYNCHROCONTEXT;
import static org.opends.server.replication.protocol.ProtocolVersion.getCurrentVersion;
import static org.opends.server.util.StaticUtils.byteToHex;
import static org.opends.messages.ReplicationMessages.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.opends.server.replication.protocol.OperationContext.*;
import static org.opends.server.replication.protocol.ProtocolVersion.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.messages.ReplicationMessages.*;
import static org.testng.Assert.*;
/**
 * Test the conversions between the various protocol versions.
 */
@SuppressWarnings("javadoc")
public class ProtocolCompatibilityTest extends ReplicationTestCase {
  short REPLICATION_PROTOCOL_VLAST = ProtocolVersion.getCurrentVersion();
@@ -109,12 +93,12 @@
  {
    String baseDN = "o=test";
    ServerState state = new ServerState();
    state.update(new ChangeNumber((long)0, 0,0));
    state.update(new CSN(0, 0,0));
    Object[] set1 = new Object[] {1, baseDN, 0, "localhost:8989", state, 0L, (byte)0, 0};
    baseDN = "dc=example,dc=com";
    state = new ServerState();
    state.update(new ChangeNumber((long)75, 5,263));
    state.update(new CSN(75, 5,263));
    Object[] set2 = new Object[] {16, baseDN, 100, "anotherHost:1025", state, 1245L, (byte)25, 3456};
    return new Object [][] { set1, set2 };
@@ -154,8 +138,7 @@
    assertEquals(msg.getServerURL(), newMsg.getServerURL());
    assertEquals(msg.getBaseDn(), newMsg.getBaseDn());
    assertEquals(msg.getWindowSize(), newMsg.getWindowSize());
    assertEquals(msg.getServerState().getChangeNumber(1),
        newMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1), newMsg.getServerState().getCSN(1));
    assertEquals(msg.getSSLEncryption(), newMsg.getSSLEncryption());
    // Check default value for only post V1 fields
@@ -178,8 +161,7 @@
    assertEquals(msg.getServerURL(), vlastMsg.getServerURL());
    assertEquals(msg.getBaseDn(), vlastMsg.getBaseDn());
    assertEquals(msg.getWindowSize(), vlastMsg.getWindowSize());
    assertEquals(msg.getServerState().getChangeNumber(1),
        vlastMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1), vlastMsg.getServerState().getCSN(1));
    assertEquals(msg.getSSLEncryption(), vlastMsg.getSSLEncryption());
    assertEquals(msg.getGroupId(), vlastMsg.getGroupId());
    assertEquals(msg.getDegradedStatusThreshold(), vlastMsg.getDegradedStatusThreshold());
@@ -235,9 +217,9 @@
      new HashMap<AttributeType,List<Attribute>>();
    opList.put(attr.getAttributeType(), operationalAttributes);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123, 45);
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    AddMsg msg = new AddMsg(cn, rawDN, "thisIsaUniqueID", "parentUniqueId",
    AddMsg msg = new AddMsg(csn, rawDN, "thisIsaUniqueID", "parentUniqueId",
                            objectClass, userAttributes,
                            operationalAttributes);
@@ -266,7 +248,7 @@
    // Check fields common to both versions
    assertEquals(newMsg.getEntryUUID(), msg.getEntryUUID());
    assertEquals(newMsg.getDn(), msg.getDn());
    assertEquals(newMsg.getChangeNumber(), msg.getChangeNumber());
    assertEquals(newMsg.getCSN(), msg.getCSN());
    assertEquals(newMsg.isAssured(), msg.isAssured());
    assertEquals(newMsg.getParentEntryUUID(), msg.getParentEntryUUID());
@@ -309,7 +291,7 @@
    // Check we retrieve original VLAST message (VLAST fields)
    assertEquals(msg.getEntryUUID(), vlastMsg.getEntryUUID());
    assertEquals(msg.getDn(), vlastMsg.getDn());
    assertEquals(msg.getChangeNumber(), vlastMsg.getChangeNumber());
    assertEquals(msg.getCSN(), vlastMsg.getCSN());
    assertEquals(msg.getParentEntryUUID(), vlastMsg.getParentEntryUUID());
    assertEquals(msg.isAssured(), vlastMsg.isAssured());
    assertEquals(msg.getAssuredMode(), vlastMsg.getAssuredMode());
@@ -389,8 +371,8 @@
    byte safeDataLevel, List<Attribute> entryAttrList)
  throws Exception
  {
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123, 45);
    DeleteMsg msg = new DeleteMsg(rawDN, cn, "thisIsaUniqueID");
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    DeleteMsg msg = new DeleteMsg(rawDN, csn, "thisIsaUniqueID");
    msg.setAssured(isAssured);
    msg.setAssuredMode(assuredMode);
@@ -418,7 +400,7 @@
    // Check fields common to both versions
    assertEquals(newMsg.getEntryUUID(), msg.getEntryUUID());
    assertEquals(newMsg.getDn(), msg.getDn());
    assertEquals(newMsg.getChangeNumber(), msg.getChangeNumber());
    assertEquals(newMsg.getCSN(), msg.getCSN());
    assertEquals(newMsg.isAssured(), msg.isAssured());
    // Check default value for only VLAST fields
@@ -445,7 +427,7 @@
    // Check we retrieve original VLAST message (VLAST fields)
    assertEquals(msg.getEntryUUID(), vlastMsg.getEntryUUID());
    assertEquals(msg.getDn(), vlastMsg.getDn());
    assertEquals(msg.getChangeNumber(), vlastMsg.getChangeNumber());
    assertEquals(msg.getCSN(), vlastMsg.getCSN());
    assertEquals(msg.isAssured(), vlastMsg.isAssured());
    assertEquals(msg.getAssuredMode(), vlastMsg.getAssuredMode());
    assertEquals(msg.getSafeDataLevel(), vlastMsg.getSafeDataLevel());
@@ -473,8 +455,8 @@
   */
  @DataProvider(name = "createModifyData")
  public Object[][] createModifyData() {
    ChangeNumber cn1 = new ChangeNumber(1,  0,  1);
    ChangeNumber cn2 = new ChangeNumber(TimeThread.getTime(), 123, 45);
    CSN csn1 = new CSN(1, 0, 1);
    CSN csn2 = new CSN(TimeThread.getTime(), 123, 45);
    AttributeType type = DirectoryServer.getAttributeType("description");
@@ -520,16 +502,16 @@
    entryAttrList.add(eattr2);
    return new Object[][] {
        { cn1, "dc=test", mods1, false, AssuredMode.SAFE_DATA_MODE, (byte)0, null},
        { cn2, "dc=cn2", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)1, entryAttrList},
        { cn2, "dc=test with a much longer dn in case this would "
        { csn1, "dc=test", mods1, false, AssuredMode.SAFE_DATA_MODE, (byte) 0, null },
        { csn2, "dc=cn2", mods1, true, AssuredMode.SAFE_READ_MODE, (byte) 1, entryAttrList },
        { csn2, "dc=test with a much longer dn in case this would "
               + "make a difference", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test, cn=with a, o=more complex, ou=dn", mods1, false, AssuredMode.SAFE_READ_MODE, (byte)5, entryAttrList},
        { cn2, "cn=use\\, backslash", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test with several mod", mods2, false, AssuredMode.SAFE_DATA_MODE, (byte)16, entryAttrList},
        { cn2, "dc=test with several values", mods3, false, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test with long mod", mods4, true, AssuredMode.SAFE_READ_MODE, (byte)120, entryAttrList},
        { cn2, "dc=testDsaOperation", mods5, true, AssuredMode.SAFE_DATA_MODE, (byte)99, null},
        { csn2, "dc=test, cn=with a, o=more complex, ou=dn", mods1, false, AssuredMode.SAFE_READ_MODE, (byte) 5, entryAttrList },
        { csn2, "cn=use\\, backslash", mods1, true, AssuredMode.SAFE_READ_MODE, (byte) 3, null },
        { csn2, "dc=test with several mod", mods2, false, AssuredMode.SAFE_DATA_MODE, (byte) 16, entryAttrList },
        { csn2, "dc=test with several values", mods3, false, AssuredMode.SAFE_READ_MODE, (byte) 3, null },
        { csn2, "dc=test with long mod", mods4, true, AssuredMode.SAFE_READ_MODE, (byte) 120, entryAttrList },
        { csn2, "dc=testDsaOperation", mods5, true, AssuredMode.SAFE_DATA_MODE, (byte) 99, null },
        };
  }
@@ -538,7 +520,7 @@
   * using protocol V1 and V2 are working.
   */
  @Test(dataProvider = "createModifyData")
  public void modifyMsgTestVLASTV2(ChangeNumber changeNumber,
  public void modifyMsgTestVLASTV2(CSN csn,
                               String rawdn, List<Modification> mods,
                               boolean isAssured, AssuredMode assuredMode,
                               byte safeDataLevel,
@@ -553,7 +535,7 @@
   * using protocol V1 and VLAST are working.
   */
  @Test(enabled=false,dataProvider = "createModifyData")
  public void modifyMsgTestVLASTV1(ChangeNumber changeNumber,
  public void modifyMsgTestVLASTV1(CSN csn,
                               String rawdn, List<Modification> mods,
                               boolean isAssured, AssuredMode assuredMode,
                               byte safeDataLevel,
@@ -562,7 +544,7 @@
  {
    // Create VLAST message
    DN dn = DN.decode(rawdn);
    ModifyMsg origVlastMsg = new ModifyMsg(changeNumber, dn, mods, "fakeuniqueid");
    ModifyMsg origVlastMsg = new ModifyMsg(csn, dn, mods, "fakeuniqueid");
    origVlastMsg.setAssured(isAssured);
    origVlastMsg.setAssuredMode(assuredMode);
@@ -589,7 +571,7 @@
    // Check fields common to both versions
    assertEquals(newv1Msg.getEntryUUID(), origVlastMsg.getEntryUUID());
    assertEquals(newv1Msg.getDn(), origVlastMsg.getDn());
    assertEquals(newv1Msg.getChangeNumber(), origVlastMsg.getChangeNumber());
    assertEquals(newv1Msg.getCSN(), origVlastMsg.getCSN());
    assertEquals(newv1Msg.isAssured(), origVlastMsg.isAssured());
    // Create a modify operation from each message to compare mods (kept encoded in messages)
@@ -632,7 +614,7 @@
    // Check we retrieve original VLAST message (VLAST fields)
    assertEquals(origVlastMsg.getEntryUUID(), generatedVlastMsg.getEntryUUID());
    assertEquals(origVlastMsg.getDn(), generatedVlastMsg.getDn());
    assertEquals(origVlastMsg.getChangeNumber(), generatedVlastMsg.getChangeNumber());
    assertEquals(origVlastMsg.getCSN(), generatedVlastMsg.getCSN());
    assertEquals(origVlastMsg.isAssured(), generatedVlastMsg.isAssured());
    assertEquals(origVlastMsg.getAssuredMode(), generatedVlastMsg.getAssuredMode());
    assertEquals(origVlastMsg.getSafeDataLevel(), generatedVlastMsg.getSafeDataLevel());
@@ -750,8 +732,8 @@
         throws Exception
  {
    // Create VLAST message
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 596, 13);
    ModifyDNMsg msg = new ModifyDNMsg(rawDN, cn, uid,
    CSN csn = new CSN(TimeThread.getTime(), 596, 13);
    ModifyDNMsg msg = new ModifyDNMsg(rawDN, csn, uid,
                     newParentUid, deleteOldRdn,
                     newSuperior, newRdn, mods);
@@ -781,7 +763,7 @@
    // Check fields common to both versions
    assertEquals(newMsg.getEntryUUID(), msg.getEntryUUID());
    assertEquals(newMsg.getDn(), msg.getDn());
    assertEquals(newMsg.getChangeNumber(), msg.getChangeNumber());
    assertEquals(newMsg.getCSN(), msg.getCSN());
    assertEquals(newMsg.isAssured(), msg.isAssured());
    assertEquals(newMsg.getNewRDN(), msg.getNewRDN());
    assertEquals(newMsg.getNewSuperior(), msg.getNewSuperior());
@@ -827,7 +809,7 @@
    // Check we retrieve original VLAST message (VLAST fields)
    assertEquals(msg.getEntryUUID(), vlastMsg.getEntryUUID());
    assertEquals(msg.getDn(), vlastMsg.getDn());
    assertEquals(msg.getChangeNumber(), vlastMsg.getChangeNumber());
    assertEquals(msg.getCSN(), vlastMsg.getCSN());
    assertEquals(msg.isAssured(), vlastMsg.isAssured());
    assertEquals(msg.getAssuredMode(), vlastMsg.getAssuredMode());
    assertEquals(msg.getSafeDataLevel(), vlastMsg.getSafeDataLevel());
@@ -888,26 +870,26 @@
        {"1603303030303030303030303030303030313030303130303030303030300064633" +
         "d746573740066616b65756e69717565696400000200301f0a0102301a040b646573" +
         "6372697074696f6e310b04096e65772076616c756500",
          ModifyMsg.class, new ChangeNumber(1, 0, 1), "dc=test" },
          ModifyMsg.class, new CSN(1, 0, 1), "dc=test" },
        {"1803303030303031323366313238343132303030326430303030303037620064633" +
         "d636f6d00756e69717565696400000201",
            DeleteMsg.class, new ChangeNumber(0x123f1284120L,123,45), "dc=com"},
            DeleteMsg.class, new CSN(0x123f1284120L,123,45), "dc=com"},
        {"1803303030303031323366313238343132303030326430303030303037620064633" +
         "d64656c6574652c64633d616e2c64633d656e7472792c64633d776974682c64633d" +
         "612c64633d6c6f6e6720646e00756e69717565696400000201",
            DeleteMsg.class, new ChangeNumber(0x123f1284120L,123,45),
            DeleteMsg.class, new CSN(0x123f1284120L,123,45),
            "dc=delete,dc=an,dc=entry,dc=with,dc=a,dc=long dn"},
        {"1903303030303031323366313238613762333030326430303030303037620064633" +
         "d746573742c64633d636f6d00756e6971756569640000020164633d6e6577006463" +
         "3d6368616e6765006e6577706172656e7449640000301f0a0102301a040b6465736" +
         "372697074696f6e310b04096e65772076616c756500",
            ModifyDNMsg.class, new ChangeNumber(0x123f128a7b3L,123,45), "dc=test,dc=com"},
            ModifyDNMsg.class, new CSN(0x123f128a7b3L,123,45), "dc=test,dc=com"},
        {"1703303030303031323366313239333431323030326430303030303037620064633" +
         "d6578616d706c652c64633d636f6d0074686973497361556e697175654944000002" +
         "00706172656e74556e69717565496400301d040b6f626a656374436c617373310e0" +
         "40c6f7267616e697a6174696f6e300a04016f31050403636f6d301c040c63726561" +
         "746f72736e616d65310c040a64633d63726561746f72",
            AddMsg.class, new ChangeNumber(0x123f1293412L,123,45), "dc=example,dc=com"}
            AddMsg.class, new CSN(0x123f1293412L,123,45), "dc=example,dc=com"}
        };
  }
@@ -925,14 +907,14 @@
   */
  @Test(dataProvider = "createOldUpdateData")
  public void createOldUpdate(
      String encodedString, Class<?> msgType, ChangeNumber cn, String dn)
      String encodedString, Class<?> msgType, CSN csn, String dn)
      throws UnsupportedEncodingException, DataFormatException,
      NotSupportedOldVersionPDUException, DirectoryException
  {
    LDAPUpdateMsg msg = (LDAPUpdateMsg) ReplicationMsg.generateMsg(
        hexStringToByteArray(encodedString), ProtocolVersion.REPLICATION_PROTOCOL_V3);
    assertEquals(msg.getDn(), dn);
    assertEquals(msg.getChangeNumber(), cn);
    assertEquals(msg.getCSN(), csn);
    assertEquals(msg.getClass(), msgType);
    BigInteger bi = new BigInteger(msg.getBytes(ProtocolVersion.REPLICATION_PROTOCOL_V3));
    assertEquals(bi.toString(16), encodedString);
@@ -1001,15 +983,15 @@
    return new Object[][] {
        {"05303030303031323366316535383832383030326430303030303037" +
          "6200010101313030003230303000333030303000",
          new ChangeNumber(0x123f1e58828L, 123, 45), true, fservers4 }
          new CSN(0x123f1e58828L, 123, 45), true, fservers4 }
    };
  }
  @Test(dataProvider = "createoldAckMsgData")
  public void oldAckMsgPDUs(String oldPdu, ChangeNumber cn,
  public void oldAckMsgPDUs(String oldPdu, CSN csn,
      boolean hasTimeout, ArrayList<Integer> failedServers) throws Exception
  {
    AckMsg msg = new AckMsg(hexStringToByteArray(oldPdu));
    assertEquals(msg.getChangeNumber(), cn);
    assertEquals(msg.getCSN(), csn);
    assertEquals(msg.hasTimeout(), hasTimeout);
    assertEquals(msg.getFailedServers(), failedServers);
    // We use V4 here because these PDU have not changed since 2.0.
@@ -1064,16 +1046,16 @@
    urls4.add("ldaps://host:port/dc=foobar1??sub?(sn=Another Entry 1)");
    urls4.add("ldaps://host:port/dc=foobar2??sub?(sn=Another Entry 2)");
    DSInfo dsInfo1 = new DSInfo(13, "dsHost1:111", 26, (long)154631, ServerStatus.FULL_UPDATE_STATUS,
    DSInfo dsInfo1 = new DSInfo(13, "dsHost1:111", 26, 154631, ServerStatus.FULL_UPDATE_STATUS,
      false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo2 = new DSInfo(-436, "dsHost2:222", 493, (long)-227896, ServerStatus.DEGRADED_STATUS,
    DSInfo dsInfo2 = new DSInfo(-436, "dsHost2:222", 493, -227896, ServerStatus.DEGRADED_STATUS,
      true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo3 = new DSInfo(2436, "dsHost3:333", 591, (long)0, ServerStatus.NORMAL_STATUS,
    DSInfo dsInfo3 = new DSInfo(2436, "dsHost3:333", 591, 0, ServerStatus.NORMAL_STATUS,
      false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo4 = new DSInfo(415, "dsHost4:444", 146, (long)0, ServerStatus.BAD_GEN_ID_STATUS,
    DSInfo dsInfo4 = new DSInfo(415, "dsHost4:444", 146, 0, ServerStatus.BAD_GEN_ID_STATUS,
      true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, new HashSet<String>(), new HashSet<String>(), (short)-1);
    List<DSInfo> dsList1 = new ArrayList<DSInfo>();
@@ -1090,11 +1072,9 @@
    dsList4.add(dsInfo2);
    dsList4.add(dsInfo1);
    RSInfo rsInfo1 = new RSInfo(4527, null, (long)45316, (byte)103, 1);
    RSInfo rsInfo2 = new RSInfo(4527, null, (long)0, (byte)0, 1);
    RSInfo rsInfo3 = new RSInfo(0, null, (long)-21113, (byte)98, 1);
    RSInfo rsInfo1 = new RSInfo(4527, null, 45316, (byte)103, 1);
    RSInfo rsInfo2 = new RSInfo(4527, null, 0, (byte)0, 1);
    RSInfo rsInfo3 = new RSInfo(0, null, -21113, (byte)98, 1);
    List<RSInfo> rsList1 = new ArrayList<RSInfo>();
    rsList1.add(rsInfo1);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
@@ -76,9 +76,9 @@
   */
  @DataProvider(name = "createModifyData")
  public Object[][] createModifyData() {
    ChangeNumber cn1 = new ChangeNumber(1,  0,  1);
    ChangeNumber cn2 = new ChangeNumber(TimeThread.getTime(), 123,  45);
    ChangeNumber cn3 = new ChangeNumber(TimeThread.getTime(), 67894123,  45678);
    CSN csn1 = new CSN(1,  0,  1);
    CSN csn2 = new CSN(TimeThread.getTime(), 123,  45);
    CSN csn3 = new CSN(TimeThread.getTime(), 67894123,  45678);
    AttributeType type = DirectoryServer.getAttributeType("description");
@@ -113,17 +113,17 @@
    List<Attribute> eclIncludes = getEntryAttributes();
    return new Object[][] {
        { cn1, "dc=test", mods1, false, AssuredMode.SAFE_DATA_MODE, (byte)0, null},
        { cn2, "dc=cn2", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)1, eclIncludes},
        { cn2, "dc=test with a much longer dn in case this would "
        { csn1, "dc=test", mods1, false, AssuredMode.SAFE_DATA_MODE, (byte)0, null},
        { csn2, "dc=cn2", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)1, eclIncludes},
        { csn2, "dc=test with a much longer dn in case this would "
               + "make a difference", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test, cn=with a, o=more complex, ou=dn", mods1, false, AssuredMode.SAFE_READ_MODE, (byte)5, eclIncludes},
        { cn2, "cn=use\\, backslash", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test with several mod", mods2, false, AssuredMode.SAFE_DATA_MODE, (byte)16, eclIncludes},
        { cn2, "dc=test with several values", mods3, false, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { cn2, "dc=test with long mod", mods4, true, AssuredMode.SAFE_READ_MODE, (byte)120, eclIncludes},
        { cn2, "dc=testDsaOperation", mods5, true, AssuredMode.SAFE_DATA_MODE, (byte)99, null},
        { cn3, "dc=serverIdLargerThan32767", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)1, null},
        { csn2, "dc=test, cn=with a, o=more complex, ou=dn", mods1, false, AssuredMode.SAFE_READ_MODE, (byte)5, eclIncludes},
        { csn2, "cn=use\\, backslash", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { csn2, "dc=test with several mod", mods2, false, AssuredMode.SAFE_DATA_MODE, (byte)16, eclIncludes},
        { csn2, "dc=test with several values", mods3, false, AssuredMode.SAFE_READ_MODE, (byte)3, null},
        { csn2, "dc=test with long mod", mods4, true, AssuredMode.SAFE_READ_MODE, (byte)120, eclIncludes},
        { csn2, "dc=testDsaOperation", mods5, true, AssuredMode.SAFE_DATA_MODE, (byte)99, null},
        { csn3, "dc=serverIdLargerThan32767", mods1, true, AssuredMode.SAFE_READ_MODE, (byte)1, null},
        };
  }
@@ -134,7 +134,7 @@
   * Finally test that both Msg matches.
   */
  @Test(enabled=true,dataProvider = "createModifyData")
  public void modifyMsgTest(ChangeNumber changeNumber,
  public void modifyMsgTest(CSN csn,
                               String rawdn, List<Modification> mods,
                               boolean isAssured, AssuredMode assuredMode,
                               byte safeDataLevel,
@@ -144,7 +144,7 @@
    DN dn = DN.decode(rawdn);
    InternalClientConnection connection =
        InternalClientConnection.getRootConnection();
    ModifyMsg msg = new ModifyMsg(changeNumber, dn, mods, "fakeuniqueid");
    ModifyMsg msg = new ModifyMsg(csn, dn, mods, "fakeuniqueid");
    msg.setAssured(isAssured);
    msg.setAssuredMode(assuredMode);
@@ -164,7 +164,7 @@
    assertEquals(generatedMsg.getAssuredMode(), assuredMode);
    assertEquals(generatedMsg.getSafeDataLevel(), safeDataLevel);
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
    assertEquals(msg.getCSN(), generatedMsg.getCSN());
    // Get ECL entry attributes
    assertAttributesEqual(entryAttrList, generatedMsg.getEclIncludes());
@@ -191,7 +191,7 @@
   * Finally test that both Msgs match.
   */
  @Test(enabled=true,dataProvider = "createModifyData")
  public void updateMsgTest(ChangeNumber changeNumber,
  public void updateMsgTest(CSN csn,
                               String rawdn, List<Modification> mods,
                               boolean isAssured, AssuredMode assuredMode,
                               byte safeDataLevel ,
@@ -199,7 +199,7 @@
         throws Exception
  {
    DN dn = DN.decode(rawdn);
    ModifyMsg msg = new ModifyMsg(changeNumber, dn, mods, "fakeuniqueid");
    ModifyMsg msg = new ModifyMsg(csn, dn, mods, "fakeuniqueid");
    // Check isAssured
    assertFalse(msg.isAssured());
@@ -222,7 +222,7 @@
    assertFalse(msg.equals(null));
    assertFalse(msg.equals(new Object()));
    // Check change number
    // Check CSN
    assertTrue(msg.equals(generatedMsg));
    // Check hashCode
@@ -291,8 +291,8 @@
      deleteOp.addRequestControl(new SubtreeDeleteControl(false));
    }
    LocalBackendDeleteOperation op = new LocalBackendDeleteOperation(deleteOp);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),123,  45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn, "uniqueid"));
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn, "uniqueid"));
    DeleteMsg msg = new DeleteMsg(op);
    assertEquals(msg.isSubtreeDelete(), subtree);
    // Set ECL entry attributes
@@ -306,7 +306,7 @@
    assertEquals(msg.toString(), generatedMsg.toString());
    assertEquals(msg.getInitiatorsName(), generatedMsg.getInitiatorsName());
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
    assertEquals(msg.getCSN(), generatedMsg.getCSN());
    assertEquals(generatedMsg.isSubtreeDelete(), subtree);
    // Get ECL entry attributes
@@ -324,7 +324,7 @@
    // Create an update message from this op
    DeleteMsg updateMsg = (DeleteMsg) LDAPUpdateMsg.generateMsg(op);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
    assertEquals(msg.getCSN(), updateMsg.getCSN());
    assertEquals(msg.isSubtreeDelete(), updateMsg.isSubtreeDelete());
  }
@@ -384,9 +384,9 @@
                  DN.decode(rawDN), RDN.decode(newRdn), deleteOldRdn,
                  (newSuperior.length() != 0 ? DN.decode(newSuperior) : null));
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123,  45);
    CSN csn = new CSN(TimeThread.getTime(), 123,  45);
    op.setAttachment(SYNCHROCONTEXT,
        new ModifyDnContext(cn, "uniqueid", "newparentId"));
        new ModifyDnContext(csn, "uniqueid", "newparentId"));
    LocalBackendModifyDNOperation localOp =
      new LocalBackendModifyDNOperation(op);
    for (Modification mod : mods)
@@ -423,7 +423,7 @@
    ModifyDNOperation moddn1 = (ModifyDNOperation) oriOp;
    ModifyDNOperation moddn2 = (ModifyDNOperation) generatedOperation;
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
    assertEquals(msg.getCSN(), generatedMsg.getCSN());
    assertEquals(moddn1.getRawEntryDN(), moddn2.getRawEntryDN());
    assertEquals(moddn1.getRawNewRDN(), moddn2.getRawNewRDN());
    assertEquals(moddn1.deleteOldRDN(), moddn2.deleteOldRDN());
@@ -432,7 +432,7 @@
    // Create an update message from this op
    ModifyDNMsg updateMsg = (ModifyDNMsg) LDAPUpdateMsg.generateMsg(localOp);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
    assertEquals(msg.getCSN(), updateMsg.getCSN());
  }
  @DataProvider(name = "createAddData")
@@ -470,9 +470,9 @@
        new HashMap<AttributeType, List<Attribute>>();
    opList.put(attr.getAttributeType(), operationalAttributes);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123,  45);
    CSN csn = new CSN(TimeThread.getTime(), 123,  45);
    AddMsg msg = new AddMsg(cn, rawDN, "thisIsaUniqueID", "parentUniqueId",
    AddMsg msg = new AddMsg(csn, rawDN, "thisIsaUniqueID", "parentUniqueId",
                            objectClass, userAttributes,
                            operationalAttributes);
@@ -527,7 +527,7 @@
    AddOperation addOpB = new AddOperationBasis(connection,
        1, 1, null, dn, objectClassList, userAttList, opList);
    LocalBackendAddOperation localAddOp = new LocalBackendAddOperation(addOpB);
    OperationContext opCtx = new AddContext(cn, "thisIsaUniqueID",
    OperationContext opCtx = new AddContext(csn, "thisIsaUniqueID",
        "parentUniqueId");
    localAddOp.setAttachment(SYNCHROCONTEXT, opCtx);
@@ -549,7 +549,7 @@
    // Create an update message from this op
    AddMsg updateMsg = (AddMsg) LDAPUpdateMsg.generateMsg(localAddOp);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
    assertEquals(msg.getCSN(), updateMsg.getCSN());
  }
  private void assertAttributesEqual(List<Attribute> entryAttrList,
@@ -578,9 +578,9 @@
   */
  @DataProvider(name = "createAckData")
  public Object[][] createAckData() {
    ChangeNumber cn1 = new ChangeNumber(1,  0,  1);
    ChangeNumber cn2 = new ChangeNumber(TimeThread.getTime(), 123, 45);
    ChangeNumber cn3 = new ChangeNumber(TimeThread.getTime(), 1234567, 45678);
    CSN csn1 = new CSN(1,  0,  1);
    CSN csn2 = new CSN(TimeThread.getTime(), 123, 45);
    CSN csn3 = new CSN(TimeThread.getTime(), 1234567, 45678);
    List<Integer> fservers1 = newList(12345, -12345, 31657, -28456, 0);
    List<Integer> fservers2 = newList();
@@ -588,20 +588,20 @@
    List<Integer> fservers4 = newList(100, 2000, 30000, -100, -2000, -30000);
    return new Object[][] {
        {cn1, true, false, false, fservers1},
        {cn2, false, true, false, fservers2},
        {cn1, false, false, true, fservers3},
        {cn2, false, false, false, fservers4},
        {cn1, true, true, false, fservers1},
        {cn2, false, true, true, fservers2},
        {cn1, true, false, true, fservers3},
        {cn2, true, true, true, fservers4},
        {cn3, true, true, true, fservers4}
        {csn1, true, false, false, fservers1},
        {csn2, false, true, false, fservers2},
        {csn1, false, false, true, fservers3},
        {csn2, false, false, false, fservers4},
        {csn1, true, true, false, fservers1},
        {csn2, false, true, true, fservers2},
        {csn1, true, false, true, fservers3},
        {csn2, true, true, true, fservers4},
        {csn3, true, true, true, fservers4}
        };
  }
  @Test(enabled=true,dataProvider = "createAckData")
  public void ackMsgTest(ChangeNumber cn, boolean hasTimeout, boolean hasWrongStatus,
  public void ackMsgTest(CSN csn, boolean hasTimeout, boolean hasWrongStatus,
    boolean hasReplayError, List<Integer> failedServers)
         throws Exception
  {
@@ -609,8 +609,8 @@
    // Constructor test (with ChangeNumber)
    // Check that retrieved CN is OK
    msg1 = new  AckMsg(cn);
    assertEquals(msg1.getChangeNumber().compareTo(cn), 0);
    msg1 = new AckMsg(csn);
    assertEquals(msg1.getCSN().compareTo(csn), 0);
    // Check default values for error info
    assertFalse(msg1.hasTimeout());
@@ -619,8 +619,8 @@
    assertEquals(msg1.getFailedServers().size(), 0);
    // Check constructor with error info
    msg1 = new  AckMsg(cn, hasTimeout, hasWrongStatus, hasReplayError, failedServers);
    assertEquals(msg1.getChangeNumber().compareTo(cn), 0);
    msg1 = new  AckMsg(csn, hasTimeout, hasWrongStatus, hasReplayError, failedServers);
    assertEquals(msg1.getCSN().compareTo(csn), 0);
    assertEquals(msg1.hasTimeout(), hasTimeout);
    assertEquals(msg1.hasWrongStatus(), hasWrongStatus);
    assertEquals(msg1.hasReplayError(), hasReplayError);
@@ -628,7 +628,7 @@
    // Constructor test (with byte[])
    msg2 = new  AckMsg(msg1.getBytes(getCurrentVersion()));
    assertEquals(msg2.getChangeNumber().compareTo(cn), 0);
    assertEquals(msg2.getCSN().compareTo(csn), 0);
    assertEquals(msg1.hasTimeout(), msg2.hasTimeout());
    assertEquals(msg1.hasWrongStatus(), msg2.hasWrongStatus());
    assertEquals(msg1.hasReplayError(), msg2.hasReplayError());
@@ -648,7 +648,7 @@
      assertTrue(true);
    }
    // Check that retrieved CN is OK
    // Check that retrieved CSN is OK
    msg2 = (AckMsg) ReplicationMsg.generateMsg(
        msg1.getBytes(getCurrentVersion()), getCurrentVersion());
  }
@@ -663,8 +663,8 @@
    DeleteOperation deleteOp =
      new DeleteOperationBasis(connection, 1, 1,null, DN.decode("cn=t1"));
    LocalBackendDeleteOperation op = new LocalBackendDeleteOperation(deleteOp);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123,  45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn, "uniqueid"));
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn, "uniqueid"));
    DeleteMsg delmsg = new DeleteMsg(op);
    int draftcn = 21;
@@ -704,15 +704,15 @@
  {
    String baseDN = TEST_ROOT_DN_STRING;
    ServerState state = new ServerState();
    state.update(new ChangeNumber(0, 0,0));
    state.update(new CSN(0, 0,0));
    Object[] set1 = new Object[] {1, baseDN, 0, state, 0L, false, (byte)0};
    state = new ServerState();
    state.update(new ChangeNumber(75, 5,263));
    state.update(new CSN(75, 5,263));
    Object[] set2 = new Object[] {16, baseDN, 100, state, 1248L, true, (byte)31};
    state = new ServerState();
    state.update(new ChangeNumber(75, 98573895,45263));
    state.update(new CSN(75, 98573895,45263));
    Object[] set3 = new Object[] {16, baseDN, 100, state, 1248L, true, (byte)31};
    return new Object [][] { set1, set2, set3 };
@@ -736,8 +736,8 @@
    assertEquals(msg.getWindowSize(), newMsg.getWindowSize());
    assertEquals(msg.getHeartbeatInterval(), newMsg.getHeartbeatInterval());
    assertEquals(msg.getSSLEncryption(), newMsg.getSSLEncryption());
    assertEquals(msg.getServerState().getChangeNumber(1),
        newMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1),
        newMsg.getServerState().getCSN(1));
    assertEquals(newMsg.getVersion(), getCurrentVersion());
    assertEquals(msg.getGenerationId(), newMsg.getGenerationId());
    assertEquals(msg.getGroupId(), newMsg.getGroupId());
@@ -748,15 +748,15 @@
  {
    String baseDN = TEST_ROOT_DN_STRING;
    ServerState state = new ServerState();
    state.update(new ChangeNumber(0, 0,0));
    state.update(new CSN(0, 0,0));
    Object[] set1 = new Object[] {1, baseDN, 0, "localhost:8989", state, 0L, (byte)0, 0};
    state = new ServerState();
    state.update(new ChangeNumber(75, 5,263));
    state.update(new CSN(75, 5,263));
    Object[] set2 = new Object[] {16, baseDN, 100, "anotherHost:1025", state, 1245L, (byte)25, 3456};
    state = new ServerState();
    state.update(new ChangeNumber(75, 5, 45263));
    state.update(new CSN(75, 5, 45263));
    Object[] set3 = new Object[] {16, baseDN, 100, "anotherHost:1025", state, 1245L, (byte)25, 3456};
    return new Object [][] { set1, set2, set3 };
@@ -778,8 +778,8 @@
    assertEquals(msg.getServerURL(), newMsg.getServerURL());
    assertEquals(msg.getBaseDn(), newMsg.getBaseDn());
    assertEquals(msg.getWindowSize(), newMsg.getWindowSize());
    assertEquals(msg.getServerState().getChangeNumber(1),
        newMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1),
        newMsg.getServerState().getCSN(1));
    assertEquals(newMsg.getVersion(), getCurrentVersion());
    assertEquals(msg.getGenerationId(), newMsg.getGenerationId());
    assertEquals(msg.getSSLEncryption(), newMsg.getSSLEncryption());
@@ -793,15 +793,15 @@
  {
    String baseDN = TEST_ROOT_DN_STRING;
    ServerState state = new ServerState();
    state.update(new ChangeNumber(0, 0, 0));
    state.update(new CSN(0, 0, 0));
    Object[] set1 = new Object[] {1, baseDN, 0, "localhost:8989", state, 0L, (byte)0, 0, 0, 0};
    state = new ServerState();
    state.update(new ChangeNumber(75, 5, 263));
    state.update(new CSN(75, 5, 263));
    Object[] set2 = new Object[] {16, baseDN, 100, "anotherHost:1025", state, 1245L, (byte)25, 3456, 3, 31512};
    state = new ServerState();
    state.update(new ChangeNumber(123, 5, 98));
    state.update(new CSN(123, 5, 98));
    Object[] set3 = new Object[] {36, baseDN, 100, "anotherHostAgain:8017", state, 6841L, (byte)32, 2496, 630, 9524};
    return new Object [][] { set1, set2, set3 };
@@ -824,8 +824,8 @@
    assertEquals(msg.getServerURL(), newMsg.getServerURL());
    assertEquals(msg.getBaseDn(), newMsg.getBaseDn());
    assertEquals(msg.getWindowSize(), newMsg.getWindowSize());
    assertEquals(msg.getServerState().getChangeNumber(1),
        newMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1),
        newMsg.getServerState().getCSN(1));
    assertEquals(newMsg.getVersion(), getCurrentVersion());
    assertEquals(msg.getGenerationId(), newMsg.getGenerationId());
    assertEquals(msg.getSSLEncryption(), newMsg.getSSLEncryption());
@@ -1097,29 +1097,29 @@
    // RS State
    ServerState rsState = new ServerState();
    ChangeNumber rscn1 = new ChangeNumber(1,  1,  1);
    ChangeNumber rscn2 = new ChangeNumber(1,  1,  45678);
    rsState.update(rscn1);
    rsState.update(rscn2);
    CSN rsCSN1 = new CSN(1, 1, 1);
    CSN rsCSN2 = new CSN(1, 1, 45678);
    rsState.update(rsCSN1);
    rsState.update(rsCSN2);
    // LS1 state
    ServerState s1 = new ServerState();
    int sid1 = 111;
    ChangeNumber cn1 = new ChangeNumber(1,  1, sid1);
    s1.update(cn1);
    CSN csn1 = new CSN(1, 1, sid1);
    s1.update(csn1);
    // LS2 state
    ServerState s2 = new ServerState();
    int sid2 = 222;
    Long now = ((Integer)10).longValue();
    ChangeNumber cn2 = new ChangeNumber(now, 123, sid2);
    s2.update(cn2);
    CSN csn2 = new CSN(now, 123, sid2);
    s2.update(csn2);
    // LS3 state
    ServerState s3 = new ServerState();
    int sid3 = 56789;
    ChangeNumber cn3 = new ChangeNumber(now, 123, sid3);
    s3.update(cn3);
    CSN csn3 = new CSN(now, 123, sid3);
    s3.update(csn3);
    MonitorMsg msg =
      new MonitorMsg(sender, dest);
@@ -1280,8 +1280,8 @@
  public void UpdateMsgTest() throws Exception
  {
    final String test = "string used for test";
    ChangeNumber cn = new ChangeNumber(1, 2 , 39123);
    UpdateMsg msg = new UpdateMsg(cn, test.getBytes());
    CSN csn = new CSN(1, 2, 39123);
    UpdateMsg msg = new UpdateMsg(csn, test.getBytes());
    UpdateMsg newMsg = new UpdateMsg(msg.getBytes());
    assertEquals(test.getBytes(), newMsg.getPayload());
  }
@@ -1306,8 +1306,8 @@
    assertEquals(msg.getWindowSize(), newMsg.getWindowSize());
    assertEquals(msg.getHeartbeatInterval(), newMsg.getHeartbeatInterval());
    assertEquals(msg.getSSLEncryption(), newMsg.getSSLEncryption());
    assertEquals(msg.getServerState().getChangeNumber(1),
        newMsg.getServerState().getChangeNumber(1));
    assertEquals(msg.getServerState().getCSN(1),
        newMsg.getServerState().getCSN(1));
    assertEquals(newMsg.getVersion(), getCurrentVersion());
    assertEquals(msg.getGenerationId(), newMsg.getGenerationId());
    assertEquals(msg.getGroupId(), newMsg.getGroupId());
@@ -1321,13 +1321,13 @@
    throws Exception
  {
    // data
    ChangeNumber changeNumber = new ChangeNumber(TimeThread.getTime(), 123,  45);
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    ServerState state = new ServerState();
    assertTrue(state.update(new ChangeNumber(75, 5,263)));
    assertTrue(state.update(new CSN(75, 5,263)));
    // create original
    StartECLSessionMsg msg = new StartECLSessionMsg();
    msg.setChangeNumber(changeNumber);
    msg.setCSN(csn);
    msg.setCrossDomainServerState("fakegenstate");
    msg.setPersistent(StartECLSessionMsg.PERSISTENT);
    msg.setFirstDraftChangeNumber(13);
@@ -1341,7 +1341,7 @@
    // create copy
    StartECLSessionMsg newMsg = new StartECLSessionMsg(msg.getBytes(getCurrentVersion()));
    // test equality between the two copies
    assertEquals(msg.getChangeNumber(), newMsg.getChangeNumber());
    assertEquals(msg.getCSN(), newMsg.getCSN());
    assertEquals(msg.isPersistent(), newMsg.isPersistent());
    assertEquals(msg.getFirstDraftChangeNumber(), newMsg.getFirstDraftChangeNumber());
    assertEquals(msg.getECLRequestType(), newMsg.getECLRequestType());
@@ -1394,7 +1394,7 @@
      new HashMap<AttributeType,List<Attribute>>();
    opList.put(attr.getAttributeType(), operationalAttributes);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123, 45);
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    DN dn = DN.decode(rawDN);
    for (int i=1;i<perfRep;i++)
@@ -1405,7 +1405,7 @@
      AddOperation addOpB = new AddOperationBasis(connection,
          1, 1, null, dn, objectClassList, userAttList, opList);
      LocalBackendAddOperation addOp = new LocalBackendAddOperation(addOpB);
      OperationContext opCtx = new AddContext(cn, "thisIsaUniqueID",
      OperationContext opCtx = new AddContext(csn, "thisIsaUniqueID",
          "parentUniqueId");
      addOp.setAttachment(SYNCHROCONTEXT, opCtx);
      t2 = System.nanoTime();
@@ -1457,7 +1457,7 @@
  }
  @Test(enabled=false,dataProvider = "createModifyData")
  public void modMsgPerfs(ChangeNumber changeNumber,
  public void modMsgPerfs(CSN csn,
      String rawdn, List<Modification> mods,
      boolean isAssured, AssuredMode assuredMode,
      byte safeDataLevel, List<Attribute> entryAttrList)
@@ -1471,7 +1471,7 @@
    long buildnew = 0;
    long t1,t2,t3,t31,t4,t5,t6 = 0;
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123, 45);
    CSN csn2 = new CSN(TimeThread.getTime(), 123, 45);
    DN dn = DN.decode(rawdn);
    for (int i=1;i<perfRep;i++)
@@ -1483,7 +1483,7 @@
          connection, 1, 1, null, dn, mods);
      LocalBackendModifyOperation modifyOp =
        new LocalBackendModifyOperation(modifyOpB);
      OperationContext opCtx = new ModifyContext(cn, "thisIsaUniqueID");
      OperationContext opCtx = new ModifyContext(csn2, "thisIsaUniqueID");
      modifyOp.setAttachment(SYNCHROCONTEXT, opCtx);
      t2 = System.nanoTime();
      createop += (t2 - t1);
@@ -1557,8 +1557,8 @@
        new DeleteOperationBasis(connection, 1, 1,null, DN.decode(rawDN));
      LocalBackendDeleteOperation op =
          new LocalBackendDeleteOperation(deleteOp);
      ChangeNumber cn = new ChangeNumber(TimeThread.getTime(), 123, 45);
      op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn, "uniqueid"));
      CSN csn = new CSN(TimeThread.getTime(), 123, 45);
      op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn, "uniqueid"));
      t2 = System.nanoTime();
      createop += (t2 - t1);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/AssuredReplicationServerTest.java
@@ -576,7 +576,7 @@
    private int scenario = -1;
    private long generationId = -1;
    private ChangeNumberGenerator gen = null;
    private CSNGenerator gen = null;
    /** False if a received update had assured parameters not as expected */
    private boolean everyUpdatesAreOk = true;
@@ -620,7 +620,7 @@
      setAssuredTimeout(assuredTimeout);
      this.scenario = scenario;
      gen = new ChangeNumberGenerator(serverID, 0L);
      gen = new CSNGenerator(serverID, 0L);
    }
    public boolean receivedUpdatesOk()
@@ -691,7 +691,7 @@
          // be done when using asynchronous process update mechanism
          // (see processUpdate javadoc)
          processUpdateDone(updateMsg, null);
          getServerState().update(updateMsg.getChangeNumber());
          getServerState().update(updateMsg.getCSN());
          break;
        case TIMEOUT_DS_SCENARIO:
          // Let timeout occur
@@ -702,9 +702,8 @@
          // be done when using asynchronous process update mechanism
          // (see processUpdate javadoc)
          processUpdateDone(updateMsg, "This is the replay error message generated from fake DS " +
            getServerId() + " for update with change number " + updateMsg.
            getChangeNumber());
          getServerState().update(updateMsg.getChangeNumber());
            getServerId() + " for update with CSN " + updateMsg.getCSN());
          getServerState().update(updateMsg.getCSN());
          break;
        default:
          fail("Unknown scenario: " + scenario);
@@ -762,7 +761,7 @@
    {
      // Create a new delete update message (the simplest to create)
      DeleteMsg delMsg =
          new DeleteMsg(getBaseDNString(), gen.newChangeNumber(),
          new DeleteMsg(getBaseDNString(), gen.newCSN(),
        UUID.randomUUID().toString());
      // Send it (this uses the defined assured conf at constructor time)
@@ -802,7 +801,7 @@
    /** The scenario this RS is expecting */
    private int scenario = -1;
    private ChangeNumberGenerator gen = null;
    private CSNGenerator gen = null;
    /** False if a received update had assured parameters not as expected */
    private boolean everyUpdatesAreOk = true;
@@ -839,7 +838,7 @@
      this.assuredMode = assuredMode;
      this.safeDataLevel = (byte) safeDataLevel;
      gen = new ChangeNumberGenerator(serverId + 10, 0L);
      gen = new CSNGenerator(serverId + 10, 0L);
    }
    /**
@@ -849,7 +848,7 @@
    public AckMsg sendNewFakeUpdate() throws Exception
    {
        // Create a new delete update message (the simplest to create)
        DeleteMsg delMsg = new DeleteMsg(baseDn, gen.newChangeNumber(),
        DeleteMsg delMsg = new DeleteMsg(baseDn, gen.newCSN(),
        UUID.randomUUID().toString());
        // Send del message in assured mode
@@ -969,7 +968,7 @@
                if (updateMsg.isAssured())
                {
                  // Send the ack without errors
                  AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber());
                  AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
                  session.publish(ackMsg);
                  ackReplied = true;
                }
@@ -983,7 +982,7 @@
                  // Emulate RS waiting for virtual DS ack
                  sleep(MAX_SEND_UPDATE_TIME);
                  // Send the ack with timeout error from a virtual DS with id (ours + 10)
                  AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber());
                  AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
                  ackMsg.setHasTimeout(true);
                  List<Integer> failedServers = new ArrayList<Integer>();
                  failedServers.add(serverId + 10);
@@ -996,7 +995,7 @@
                if (updateMsg.isAssured())
                {
                  // Send the ack with wrong status error from a virtual DS with id (ours + 10)
                  AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber());
                  AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
                  ackMsg.setHasWrongStatus(true);
                  List<Integer> failedServers = new ArrayList<Integer>();
                  failedServers.add((serverId + 10));
@@ -1009,7 +1008,7 @@
                if (updateMsg.isAssured())
                {
                  // Send the ack with replay error from a virtual DS with id (ours + 10)
                  AckMsg ackMsg = new AckMsg(updateMsg.getChangeNumber());
                  AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
                  ackMsg.setHasReplayError(true);
                  List<Integer> failedServers = new ArrayList<Integer>();
                  failedServers.add((serverId + 10));
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/MonitorTest.java
@@ -34,8 +34,8 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
@@ -292,7 +292,7 @@
        + "userPassword: password\n" + "initials: AA\n";
  }
  static private ReplicationMsg createAddMsg(ChangeNumber cn)
  static private ReplicationMsg createAddMsg(CSN csn)
  {
    Entry personWithUUIDEntry = null;
    String user1entryUUID;
@@ -327,7 +327,7 @@
    }
    // Create and publish an update message to add an entry.
    return new AddMsg(cn,
    return new AddMsg(csn,
        personWithUUIDEntry.getDN().toString(),
        user1entryUUID,
        baseUUID,
@@ -405,14 +405,14 @@
      }
      /*
       * Create a Change number generator to generate new changenumbers
       * Create a CSN generator to generate new CSNs
       * when we need to send operation messages to the replicationServer.
       */
      ChangeNumberGenerator gen = new ChangeNumberGenerator(server3ID, 0);
      CSNGenerator gen = new CSNGenerator(server3ID, 0);
      for (int i = 0; i < 10; i++)
      {
        broker3.publish(createAddMsg(gen.newChangeNumber()));
        broker3.publish(createAddMsg(gen.newCSN()));
      }
      searchMonitor();
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
@@ -44,8 +44,8 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.plugin.MultimasterReplication;
@@ -91,12 +91,12 @@
   */
  private int replicationServerPort;
  private ChangeNumber firstChangeNumberServer1 = null;
  private ChangeNumber secondChangeNumberServer1 = null;
  private ChangeNumber firstChangeNumberServer2 = null;
  private ChangeNumber secondChangeNumberServer2 = null;
  private CSN firstCSNServer1 = null;
  private CSN secondCSNServer1 = null;
  private CSN firstCSNServer2 = null;
  private CSN secondCSNServer2 = null;
  private ChangeNumber unknownChangeNumberServer1;
  private CSN unknownCSNServer1;
  private static final String exportLDIFAllFile = "exportLDIF.ldif";
  private String exportLDIFDomainFile = null;
@@ -226,35 +226,34 @@
      assertTrue(server2.isConnected());
      /*
       * Create change numbers for the messages sent from server 1
       * with current time  sequence 1 and with current time + 2 sequence 2
       * Create CSNs for the messages sent from server 1 with current time
       * sequence 1 and with current time + 2 sequence 2
       */
      long time = TimeThread.getTime();
      firstChangeNumberServer1 = new ChangeNumber(time, 1,  1);
      secondChangeNumberServer1 = new ChangeNumber(time + 2, 2,  1);
      firstCSNServer1 = new CSN(time, 1, 1);
      secondCSNServer1 = new CSN(time + 2, 2, 1);
      /*
       * Create change numbers for the messages sent from server 2
       * with current time  sequence 1 and with current time + 3 sequence 2
       * Create CSNs for the messages sent from server 2 with current time
       * sequence 1 and with current time + 3 sequence 2
       */
      firstChangeNumberServer2 = new ChangeNumber(time+ 1, 1,  2);
      secondChangeNumberServer2 = new ChangeNumber(time + 3, 2,  2);
      firstCSNServer2 = new CSN(time + 1, 1, 2);
      secondCSNServer2 = new CSN(time + 3, 2, 2);
      /*
       * Create a ChangeNumber between firstChangeNumberServer1 and
       * secondChangeNumberServer1 that will not be used to create a
       * change sent to the replicationServer but that will be used
       * in the Server State when opening a connection to the
       * ReplicationServer to make sure that the ReplicationServer is
       * able to accept such clients.
       * Create a CSN between firstCSNServer1 and secondCSNServer1 that will not
       * be used to create a change sent to the replicationServer but that will
       * be used in the Server State when opening a connection to the
       * ReplicationServer to make sure that the ReplicationServer is able to
       * accept such clients.
       */
      unknownChangeNumberServer1 = new ChangeNumber(time+1, 1,  1);
      unknownCSNServer1 = new CSN(time + 1, 1, 1);
      /*
       * Send and receive a Delete Msg from server 1 to server 2
       */
      DeleteMsg msg =
        new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, firstChangeNumberServer1,
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, firstCSNServer1,
                      "uid");
      server1.publish(msg);
      ReplicationMsg msg2 = server2.receive();
@@ -264,7 +263,7 @@
      /*
       * Send and receive a second Delete Msg
       */
      msg = new DeleteMsg(TEST_ROOT_DN_STRING, secondChangeNumberServer1, "uid");
      msg = new DeleteMsg(TEST_ROOT_DN_STRING, secondCSNServer1, "uid");
      server1.publish(msg);
      msg2 = server2.receive();
      server2.updateWindowAfterReplay();
@@ -274,7 +273,7 @@
       * Send and receive a Delete Msg from server 2 to server 1
       */
      msg =
        new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, firstChangeNumberServer2,
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, firstCSNServer2,
                      "other-uid");
      server2.publish(msg);
      msg2 = server1.receive();
@@ -284,7 +283,7 @@
      /*
       * Send and receive a second Delete Msg
       */
      msg = new DeleteMsg(TEST_ROOT_DN_STRING, secondChangeNumberServer2, "uid");
      msg = new DeleteMsg(TEST_ROOT_DN_STRING, secondCSNServer2, "uid");
      server2.publish(msg);
      msg2 = server1.receive();
      server1.updateWindowAfterReplay();
@@ -326,8 +325,7 @@
      ReplicationMsg msg2 = broker.receive();
      broker.updateWindowAfterReplay();
      assertDeleteMsgChangeNumberEquals(msg2, firstChangeNumberServer1,
          "first");
      assertDeleteMsgCSNEquals(msg2, firstCSNServer1, "first");
      debugInfo("Ending newClient");
    }
    finally
@@ -342,14 +340,11 @@
   * Test that a client that has already seen some changes now receive
   * the correct next change.
   */
  private void newClientWithChanges(
      ServerState state, ChangeNumber nextChangeNumber) throws Exception
  private void newClientWithChanges(ServerState state, CSN nextCSN) throws Exception
  {
    ReplicationBroker broker = null;
    /*
     * Connect to the replicationServer using the state created above.
     */
    // Connect to the replicationServer using the state created above.
    try {
      broker =
        openReplicationSession(DN.decode(TEST_ROOT_DN_STRING),  3,
@@ -357,7 +352,7 @@
      ReplicationMsg msg2 = broker.receive();
      broker.updateWindowAfterReplay();
      assertDeleteMsgChangeNumberEquals(msg2, nextChangeNumber, "second");
      assertDeleteMsgCSNEquals(msg2, nextCSN, "second");
    }
    finally
    {
@@ -366,20 +361,14 @@
  }
  /**
   * Asserts that the change number for the passed in message matches the
   * supplied change number.
   *
   * @param msg
   * @param nextChangeNumber
   * @param msgNumber
   * Asserts that the CSN for the passed in message matches the supplied CSN.
   */
  private void assertDeleteMsgChangeNumberEquals(ReplicationMsg msg,
      ChangeNumber nextChangeNumber, String msgNumber)
  private void assertDeleteMsgCSNEquals(ReplicationMsg msg, CSN nextCSN, String msgNumber)
  {
    if (msg instanceof DeleteMsg)
    {
      DeleteMsg del = (DeleteMsg) msg;
      assertEquals(del.getChangeNumber(), nextChangeNumber, "The " + msgNumber
      assertEquals(del.getCSN(), nextCSN, "The " + msgNumber
          + " message received by a new client was the wrong one.");
    }
    else
@@ -400,10 +389,10 @@
     * done in test changelogBasic.
     */
    ServerState state = new ServerState();
    state.update(firstChangeNumberServer1);
    state.update(firstChangeNumberServer2);
    state.update(firstCSNServer1);
    state.update(firstCSNServer2);
    newClientWithChanges(state, secondChangeNumberServer1);
    newClientWithChanges(state, secondCSNServer1);
    debugInfo("Ending newClientWithFirstChanges");
  }
@@ -415,13 +404,13 @@
  {
    debugInfo("Starting newClientWithUnknownChanges");
    /*
     * Create a ServerState with wrongChangeNumberServer1
     * Create a ServerState with wrongCSNServer1
     */
    ServerState state = new ServerState();
    state.update(unknownChangeNumberServer1);
    state.update(secondChangeNumberServer2);
    state.update(unknownCSNServer1);
    state.update(secondCSNServer2);
    newClientWithChanges(state, secondChangeNumberServer1);
    newClientWithChanges(state, secondCSNServer1);
    debugInfo("Ending newClientWithUnknownChanges");
  }
@@ -436,9 +425,9 @@
     * Create a ServerState updated with the first change from server 1
     */
    ServerState state = new ServerState();
    state.update(firstChangeNumberServer1);
    state.update(firstCSNServer1);
    newClientWithChanges(state, firstChangeNumberServer2);
    newClientWithChanges(state, firstCSNServer2);
    debugInfo("Ending newClientWithChangefromServer1");
  }
@@ -453,9 +442,9 @@
     * Create a ServerState updated with the first change from server 1
     */
    ServerState state = new ServerState();
    state.update(firstChangeNumberServer2);
    state.update(firstCSNServer2);
    newClientWithChanges(state, firstChangeNumberServer1);
    newClientWithChanges(state, firstCSNServer1);
    debugInfo("Ending newClientWithChangefromServer2");
  }
@@ -470,10 +459,10 @@
     * Create a ServerState updated with the first change from server 1
     */
    ServerState state = new ServerState();
    state.update(secondChangeNumberServer2);
    state.update(firstChangeNumberServer1);
    state.update(secondCSNServer2);
    state.update(firstCSNServer1);
    newClientWithChanges(state, secondChangeNumberServer1);
    newClientWithChanges(state, secondCSNServer1);
    debugInfo("Ending newClientLateServer1");
  }
@@ -516,7 +505,7 @@
    int TOTAL_MSG = 1000;     // number of messages to send during the test
    int CLIENT_THREADS = 2;   // number of threads that will try to read
                              // the messages
    ChangeNumberGenerator gen = new ChangeNumberGenerator(5 , 0);
    CSNGenerator gen = new CSNGenerator(5 , 0);
    BrokerReader client[] = new BrokerReader[CLIENT_THREADS];
    ReplicationBroker clientBroker[] = new ReplicationBroker[CLIENT_THREADS];
@@ -559,7 +548,7 @@
      for (int i = 0; i< TOTAL_MSG; i++)
      {
        DeleteMsg msg =
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, gen.newCSN(),
          "uid");
        server.publish(msg);
      }
@@ -613,7 +602,7 @@
      for (int i = 0; i< THREADS; i++)
      {
        int serverId = 10 + i;
        ChangeNumberGenerator gen = new ChangeNumberGenerator(serverId , 0);
        CSNGenerator gen = new CSNGenerator(serverId , 0);
        broker[i] =
          openReplicationSession( DN.decode(TEST_ROOT_DN_STRING), serverId,
              100, replicationServerPort, 3000, 1000, 0, true);
@@ -755,9 +744,9 @@
        // - Delete
        long time = TimeThread.getTime();
        int ts = 1;
        ChangeNumber cn = new ChangeNumber(time, ts++, brokerIds[0]);
        CSN csn = new CSN(time, ts++, brokerIds[0]);
        DeleteMsg delMsg = new DeleteMsg("o=example" + itest + "," + TEST_ROOT_DN_STRING, cn, "uid");
        DeleteMsg delMsg = new DeleteMsg("o=example" + itest + "," + TEST_ROOT_DN_STRING, csn, "uid");
        broker1.publish(delMsg);
        String user1entryUUID = "33333333-3333-3333-3333-333333333333";
@@ -768,8 +757,8 @@
            + "objectClass: top\n" + "objectClass: domain\n"
            + "entryUUID: 11111111-1111-1111-1111-111111111111\n";
        Entry entry = TestCaseUtils.entryFromLdifString(lentry);
        cn = new ChangeNumber(time, ts++, brokerIds[0]);
        AddMsg addMsg = new AddMsg(cn, "o=example," + TEST_ROOT_DN_STRING,
        csn = new CSN(time, ts++, brokerIds[0]);
        AddMsg addMsg = new AddMsg(csn, "o=example," + TEST_ROOT_DN_STRING,
            user1entryUUID, baseUUID, entry.getObjectClassAttribute(), entry
            .getAttributes(), new ArrayList<Attribute>());
        broker1.publish(addMsg);
@@ -779,17 +768,17 @@
        Modification mod1 = new Modification(ModificationType.REPLACE, attr1);
        List<Modification> mods = new ArrayList<Modification>();
        mods.add(mod1);
        cn = new ChangeNumber(time, ts++, brokerIds[0]);
        ModifyMsg modMsg = new ModifyMsg(cn, DN
        csn = new CSN(time, ts++, brokerIds[0]);
        ModifyMsg modMsg = new ModifyMsg(csn, DN
            .decode("o=example," + TEST_ROOT_DN_STRING), mods, "fakeuniqueid");
        broker1.publish(modMsg);
        // - ModifyDN
        cn = new ChangeNumber(time, ts++, brokerIds[0]);
        csn = new CSN(time, ts++, brokerIds[0]);
        ModifyDNOperationBasis op = new ModifyDNOperationBasis(connection, 1, 1, null, DN
            .decode("o=example," + TEST_ROOT_DN_STRING), RDN.decode("o=example2"), true,
            null);
        op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn, "uniqueid",
        op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(csn, "uniqueid",
        "newparentId"));
        LocalBackendModifyDNOperation localOp =
          new LocalBackendModifyDNOperation(op);
@@ -1081,9 +1070,9 @@
  {
    int count;
    private ReplicationBroker broker;
    ChangeNumberGenerator gen;
    CSNGenerator gen;
    public BrokerWriter(ReplicationBroker broker, ChangeNumberGenerator gen,
    public BrokerWriter(ReplicationBroker broker, CSNGenerator gen,
        int count)
    {
      this.broker = broker;
@@ -1108,7 +1097,7 @@
        count--;
        DeleteMsg msg =
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
          new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, gen.newCSN(),
              "uid");
        broker.publish(msg);
@@ -1268,7 +1257,7 @@
     List<UpdateMsg> l = new ArrayList<UpdateMsg>();
     long time = TimeThread.getTime();
     int ts = 1;
     ChangeNumber cn;
     CSN csn;
     try
     {
@@ -1281,8 +1270,8 @@
           + "objectClass: domain\n"
           + "entryUUID: 11111111-1111-1111-1111-111111111111\n";
       Entry entry = TestCaseUtils.entryFromLdifString(lentry);
       cn = new ChangeNumber(time, ts++, serverId);
       AddMsg addMsg = new AddMsg(cn, "o=example,"+suffix,
       csn = new CSN(time, ts++, serverId);
       AddMsg addMsg = new AddMsg(csn, "o=example,"+suffix,
           user1entryUUID, baseUUID, entry.getObjectClassAttribute(), entry
           .getAttributes(), new ArrayList<Attribute>());
       l.add(addMsg);
@@ -1301,9 +1290,9 @@
           + "entryUUID: " + user1entryUUID +"\n"
           + "userpassword: fjen$$en" + "\n";
       Entry uentry = TestCaseUtils.entryFromLdifString(luentry);
       cn = new ChangeNumber(time, ts++, serverId);
       csn = new CSN(time, ts++, serverId);
       AddMsg addMsg2 = new AddMsg(
           cn,
           csn,
           "uid=new person,ou=People,"+suffix,
           user1entryUUID,
           baseUUID,
@@ -1325,24 +1314,24 @@
       mods.add(mod2);
       mods.add(mod3);
       cn = new ChangeNumber(time, ts++, serverId);
       csn = new CSN(time, ts++, serverId);
       DN dn = DN.decode("o=example,"+suffix);
       ModifyMsg modMsg = new ModifyMsg(cn, dn,
       ModifyMsg modMsg = new ModifyMsg(csn, dn,
           mods, "fakeuniqueid");
       l.add(modMsg);
       // Modify DN
       cn = new ChangeNumber(time, ts++, serverId);
       csn = new CSN(time, ts++, serverId);
       ModifyDNMsg  modDnMsg = new ModifyDNMsg(
           "uid=new person,ou=People,"+suffix, cn,
           "uid=new person,ou=People,"+suffix, csn,
           user1entryUUID, baseUUID, false,
           "uid=wrong, ou=people,"+suffix,
       "uid=newrdn");
       l.add(modDnMsg);
       // Del
       cn = new ChangeNumber(time, ts++, serverId);
       DeleteMsg delMsg = new DeleteMsg("o=example,"+suffix, cn, "uid");
       csn = new CSN(time, ts++, serverId);
       DeleteMsg delMsg = new DeleteMsg("o=example,"+suffix, csn, "uid");
       l.add(delMsg);
     }
     catch(Exception ignored) {}
@@ -1655,7 +1644,7 @@
         // - Test messages between clients by publishing now
         long time = TimeThread.getTime();
         int ts = 1;
         ChangeNumber cn;
         CSN csn;
         String user1entryUUID = "33333333-3333-3333-3333-333333333333";
         String baseUUID  = "22222222-2222-2222-2222-222222222222";
@@ -1664,8 +1653,8 @@
             + "objectClass: top\n" + "objectClass: domain\n"
             + "entryUUID: " + user1entryUUID + "\n";
         Entry entry = TestCaseUtils.entryFromLdifString(lentry);
         cn = new ChangeNumber(time, ts++, brokerIds[0]);
         AddMsg addMsg = new AddMsg(cn, "o=example," + TEST_ROOT_DN_STRING,
         csn = new CSN(time, ts++, brokerIds[0]);
         AddMsg addMsg = new AddMsg(csn, "o=example," + TEST_ROOT_DN_STRING,
             user1entryUUID, baseUUID, entry.getObjectClassAttribute(), entry
             .getAttributes(), new ArrayList<Attribute>());
         broker1.publish(addMsg);
@@ -1675,8 +1664,8 @@
         Modification mod1 = new Modification(ModificationType.REPLACE, attr1);
         List<Modification> mods = new ArrayList<Modification>();
         mods.add(mod1);
         cn = new ChangeNumber(time, ts++, brokerIds[0]);
         ModifyMsg modMsg = new ModifyMsg(cn, DN
         csn = new CSN(time, ts++, brokerIds[0]);
         ModifyMsg modMsg = new ModifyMsg(csn, DN
             .decode("o=example," + TEST_ROOT_DN_STRING), mods, "fakeuniqueid");
         broker1.publish(modMsg);
@@ -1736,8 +1725,8 @@
         try
         {
           // - Del
           cn = new ChangeNumber(time, ts++, brokerIds[0]);
           DeleteMsg delMsg = new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, cn, user1entryUUID);
           csn = new CSN(time, ts++, brokerIds[0]);
           DeleteMsg delMsg = new DeleteMsg("o=example," + TEST_ROOT_DN_STRING, csn, user1entryUUID);
           broker1.publish(delMsg);
           // Should receive some TopologyMsg messages for disconnection
           // between the 2 RSs
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/UpdateComparatorTest.java
@@ -23,36 +23,33 @@
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS
 */
package org.opends.server.replication.server;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.replication.protocol.OperationContext.SYNCHROCONTEXT;
import static org.testng.Assert.*;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.DeleteContext;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.UpdateComparator;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.util.TimeThread;
import org.opends.server.workflowelement.localbackend.LocalBackendDeleteOperation;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.replication.protocol.OperationContext.*;
import static org.testng.Assert.*;
/**
 * Test ChangeNumber and ChangeNumberGenerator
 * Test CSN and CSNGenerator
 */
@SuppressWarnings("javadoc")
public class UpdateComparatorTest extends ReplicationTestCase
{
@@ -61,11 +58,9 @@
   */
  @DataProvider(name = "updateMessageData")
  public Object[][] createUpdateMessageData() {
    CSN csn1 = new CSN(1, 0, 1);
    CSN csn2 = new CSN(TimeThread.getTime(), 123, 45);
    ChangeNumber cn1 = new ChangeNumber(1,  0,  1);
    ChangeNumber cn2 = new ChangeNumber(TimeThread.getTime(), 123,  45);
    //
    // Create the update message
    InternalClientConnection connection =
        InternalClientConnection.getRootConnection();
@@ -81,12 +76,11 @@
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn1, "uniqueid 1"));
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn1, "uniqueid 1"));
    DeleteMsg msg1 = new DeleteMsg(op);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn2, "uniqueid 2"));
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn2, "uniqueid 2"));
    DeleteMsg msg2 = new DeleteMsg(op);
    return new Object[][] {
       {msg1, msg1, 0},
       {msg1, msg2, -1},
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/changelog/je/DbHandlerTest.java
@@ -35,8 +35,8 @@
import org.opends.server.config.ConfigException;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.server.ReplServerFakeConfiguration;
import org.opends.server.replication.server.ReplicationServer;
@@ -88,17 +88,17 @@
      dbEnv = new ReplicationDbEnv(testRoot.getPath(), replicationServer);
      handler = new DbHandler(1, TEST_ROOT_DN_STRING, replicationServer, dbEnv, 5000);
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
      ChangeNumber changeNumber1 = gen.newChangeNumber();
      ChangeNumber changeNumber2 = gen.newChangeNumber();
      ChangeNumber changeNumber3 = gen.newChangeNumber();
      ChangeNumber changeNumber4 = gen.newChangeNumber();
      ChangeNumber changeNumber5 = gen.newChangeNumber();
      CSNGenerator gen = new CSNGenerator( 1, 0);
      CSN csn1 = gen.newCSN();
      CSN csn2 = gen.newCSN();
      CSN csn3 = gen.newCSN();
      CSN csn4 = gen.newCSN();
      CSN csn5 = gen.newCSN();
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber1, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber2, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber3, "uid"));
      DeleteMsg update4 = new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber4, "uid");
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn1, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn2, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn3, "uid"));
      DeleteMsg update4 = new DeleteMsg(TEST_ROOT_DN_STRING, csn4, "uid");
      //--
      // Iterator tests with memory queue only populated
@@ -106,8 +106,8 @@
      // verify that memory queue is populated
      assertEquals(handler.getQueueSize(),3);
      assertFoundInOrder(handler, changeNumber1, changeNumber2, changeNumber3);
      assertNotFound(handler, changeNumber5);
      assertFoundInOrder(handler, csn1, csn2, csn3);
      assertNotFound(handler, csn5);
      //--
      // Iterator tests with db only populated
@@ -116,12 +116,12 @@
      // verify that memory queue is empty (all changes flushed in the db)
      assertEquals(handler.getQueueSize(),0);
      assertFoundInOrder(handler, changeNumber1, changeNumber2, changeNumber3);
      assertNotFound(handler, changeNumber5);
      assertFoundInOrder(handler, csn1, csn2, csn3);
      assertNotFound(handler, csn5);
      // Test first and last
      assertEquals(changeNumber1, handler.getFirstChange());
      assertEquals(changeNumber3, handler.getLastChange());
      assertEquals(csn1, handler.getFirstChange());
      assertEquals(csn3, handler.getLastChange());
      //--
         // Cursor tests with db and memory queue populated
@@ -131,11 +131,11 @@
      // verify memory queue contains this one
      assertEquals(handler.getQueueSize(),1);
      assertFoundInOrder(handler, changeNumber1, changeNumber2, changeNumber3, changeNumber4);
         // Test cursor from existing CN at the limit between queue and db
      assertFoundInOrder(handler, changeNumber3, changeNumber4);
      assertFoundInOrder(handler, changeNumber4);
      assertNotFound(handler, changeNumber5);
      assertFoundInOrder(handler, csn1, csn2, csn3, csn4);
      // Test cursor from existing CSN at the limit between queue and db
      assertFoundInOrder(handler, csn3, csn4);
      assertFoundInOrder(handler, csn4);
      assertNotFound(handler, csn5);
      handler.setPurgeDelay(1);
@@ -143,10 +143,9 @@
      int count = 300;  // wait at most 60 seconds
      while (!purged && (count > 0))
      {
        ChangeNumber firstChange = handler.getFirstChange();
        ChangeNumber lastChange = handler.getLastChange();
        if ((!firstChange.equals(changeNumber4) ||
          (!lastChange.equals(changeNumber4))))
        CSN firstChange = handler.getFirstChange();
        CSN lastChange = handler.getLastChange();
        if (!firstChange.equals(csn4) || !lastChange.equals(csn4))
        {
          TestCaseUtils.sleep(100);
        } else
@@ -188,22 +187,21 @@
    return testRoot;
  }
  private void assertFoundInOrder(DbHandler handler,
      ChangeNumber... changeNumbers) throws Exception
  private void assertFoundInOrder(DbHandler handler, CSN... csns) throws Exception
  {
    if (changeNumbers.length == 0)
    if (csns.length == 0)
    {
      return;
    }
      ReplicaDBCursor cursor = handler.generateCursorFrom(changeNumbers[0]);
    ReplicaDBCursor cursor = handler.generateCursorFrom(csns[0]);
    try
    {
      for (int i = 1; i < changeNumbers.length; i++)
      for (int i = 1; i < csns.length; i++)
      {
            assertTrue(cursor.next());
            final ChangeNumber cn = cursor.getChange().getChangeNumber();
            assertEquals(cn, changeNumbers[i]);
        final CSN csn = cursor.getChange().getCSN();
        assertEquals(csn, csns[i]);
      }
         assertFalse(cursor.next());
         assertNull(cursor.getChange(), "Actual change number="
@@ -215,17 +213,17 @@
    }
  }
  private void assertNotFound(DbHandler handler, ChangeNumber changeNumber)
  private void assertNotFound(DbHandler handler, CSN csn)
  {
    ReplicaDBCursor cursor = null;
    try
    {
      cursor = handler.generateCursorFrom(changeNumber);
      cursor = handler.generateCursorFrom(csn);
      fail("Expected exception");
    }
    catch (Exception e)
    {
      assertEquals(e.getLocalizedMessage(), "ChangeNumber not available");
      assertEquals(e.getLocalizedMessage(), "CSN not available");
    }
    finally
    {
@@ -256,19 +254,19 @@
      handler = new DbHandler(1, TEST_ROOT_DN_STRING, replicationServer, dbEnv, 5000);
      // Creates changes added to the dbHandler
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
      ChangeNumber changeNumber1 = gen.newChangeNumber();
      ChangeNumber changeNumber2 = gen.newChangeNumber();
      ChangeNumber changeNumber3 = gen.newChangeNumber();
      CSNGenerator gen = new CSNGenerator( 1, 0);
      CSN csn1 = gen.newCSN();
      CSN csn2 = gen.newCSN();
      CSN csn3 = gen.newCSN();
      // Add the changes
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber1, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber2, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, changeNumber3, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn1, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn2, "uid"));
      handler.add(new DeleteMsg(TEST_ROOT_DN_STRING, csn3, "uid"));
      // Check they are here
      assertEquals(changeNumber1, handler.getFirstChange());
      assertEquals(changeNumber3, handler.getLastChange());
      assertEquals(csn1, handler.getFirstChange());
      assertEquals(csn3, handler.getLastChange());
      // Clear ...
      handler.clear();
@@ -354,84 +352,83 @@
      // Populate the db with 'max' msg
      int mySeqnum = 1;
      ChangeNumber cnarray[] = new ChangeNumber[2*(max+1)];
      CSN csnArray[] = new CSN[2 * (max + 1)];
      long now = System.currentTimeMillis();
      for (int i=1; i<=max; i++)
      {
        cnarray[i] = new ChangeNumber(now+i, mySeqnum, 1);
        csnArray[i] = new CSN(now + i, mySeqnum, 1);
        mySeqnum+=2;
        DeleteMsg update1 = new DeleteMsg(TEST_ROOT_DN_STRING, cnarray[i], "uid");
        DeleteMsg update1 = new DeleteMsg(TEST_ROOT_DN_STRING, csnArray[i], "uid");
        handler.add(update1);
      }
      handler.flush();
      // Test first and last
      ChangeNumber cn1 = handler.getFirstChange();
      assertEquals(cn1, cnarray[1], "First change");
      ChangeNumber cnlast = handler.getLastChange();
      assertEquals(cnlast, cnarray[max], "Last change");
      CSN csn1 = handler.getFirstChange();
      assertEquals(csn1, csnArray[1], "First change");
      CSN csnLast = handler.getLastChange();
      assertEquals(csnLast, csnArray[max], "Last change");
      // Test count in different subcases trying to handle all special cases
      // regarding the 'counter' record and 'count' algorithm
      testcase="FROM change1 TO change1 ";
      actualCnt = handler.getCount(cnarray[1], cnarray[1]);
      actualCnt = handler.getCount(csnArray[1], csnArray[1]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 1, testcase);
      testcase="FROM change1 TO change2 ";
      actualCnt = handler.getCount(cnarray[1], cnarray[2]);
      actualCnt = handler.getCount(csnArray[1], csnArray[2]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 2, testcase);
      testcase="FROM change1 TO counterWindow="+(counterWindow);
      actualCnt = handler.getCount(cnarray[1], cnarray[counterWindow]);
      actualCnt = handler.getCount(csnArray[1], csnArray[counterWindow]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, counterWindow, testcase);
      testcase="FROM change1 TO counterWindow+1="+(counterWindow+1);
      actualCnt = handler.getCount(cnarray[1], cnarray[counterWindow+1]);
      actualCnt = handler.getCount(csnArray[1], csnArray[counterWindow+1]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, counterWindow+1, testcase);
      testcase="FROM change1 TO 2*counterWindow="+(2*counterWindow);
      actualCnt = handler.getCount(cnarray[1], cnarray[2*counterWindow]);
      actualCnt = handler.getCount(csnArray[1], csnArray[2*counterWindow]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 2*counterWindow, testcase);
      testcase="FROM change1 TO 2*counterWindow+1="+((2*counterWindow)+1);
      actualCnt = handler.getCount(cnarray[1], cnarray[(2*counterWindow)+1]);
      actualCnt = handler.getCount(csnArray[1], csnArray[(2*counterWindow)+1]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, (2*counterWindow)+1, testcase);
      testcase="FROM change2 TO change5 ";
      actualCnt = handler.getCount(cnarray[2], cnarray[5]);
      actualCnt = handler.getCount(csnArray[2], csnArray[5]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 4, testcase);
      testcase="FROM counterWindow+2 TO counterWindow+5 ";
      actualCnt = handler.getCount(cnarray[(counterWindow+2)], cnarray[(counterWindow+5)]);
      actualCnt = handler.getCount(csnArray[(counterWindow+2)], csnArray[(counterWindow+5)]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 4, testcase);
      testcase="FROM change2 TO counterWindow+5 ";
      actualCnt = handler.getCount(cnarray[2], cnarray[(counterWindow+5)]);
      actualCnt = handler.getCount(csnArray[2], csnArray[(counterWindow+5)]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, counterWindow+4, testcase);
      testcase="FROM counterWindow+4 TO counterWindow+4 ";
      actualCnt = handler.getCount(cnarray[(counterWindow+4)], cnarray[(counterWindow+4)]);
      actualCnt = handler.getCount(csnArray[(counterWindow+4)], csnArray[(counterWindow+4)]);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, 1, testcase);
      // Now test with changes older than first or newer than last
      ChangeNumber olderThanFirst = null;
      ChangeNumber newerThanLast =
        new ChangeNumber(System.currentTimeMillis() + (2*(max+1)), 100, 1);
      CSN olderThanFirst = null;
      CSN newerThanLast = new CSN(System.currentTimeMillis() + (2*(max+1)), 100, 1);
      // Now we want to test with start and stop outside of the db
      testcase="FROM our first generated change TO now (> newest change in the db)";
      actualCnt = handler.getCount(cnarray[1], newerThanLast);
      actualCnt = handler.getCount(csnArray[1], newerThanLast);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, max, testcase);
@@ -450,34 +447,34 @@
      handler.setCounterWindowSize(counterWindow);
      // Test first and last
      cn1 = handler.getFirstChange();
      assertEquals(cn1, cnarray[1], "First change");
      cnlast = handler.getLastChange();
      assertEquals(cnlast, cnarray[max], "Last change");
      csn1 = handler.getFirstChange();
      assertEquals(csn1, csnArray[1], "First change");
      csnLast = handler.getLastChange();
      assertEquals(csnLast, csnArray[max], "Last change");
      testcase="FROM our first generated change TO now (> newest change in the db)";
      actualCnt = handler.getCount(cnarray[1], newerThanLast);
      actualCnt = handler.getCount(csnArray[1], newerThanLast);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, max, testcase);
      // Populate the db with 'max' msg
      for (int i=max+1; i<=(2*max); i++)
      {
        cnarray[i] = new ChangeNumber(now+i, mySeqnum, 1);
        csnArray[i] = new CSN(now+i, mySeqnum, 1);
        mySeqnum+=2;
        DeleteMsg update1 = new DeleteMsg(TEST_ROOT_DN_STRING, cnarray[i], "uid");
        DeleteMsg update1 = new DeleteMsg(TEST_ROOT_DN_STRING, csnArray[i], "uid");
        handler.add(update1);
      }
      handler.flush();
      // Test first and last
      cn1 = handler.getFirstChange();
      assertEquals(cn1, cnarray[1], "First change");
      cnlast = handler.getLastChange();
      assertEquals(cnlast, cnarray[2*max], "Last change");
      csn1 = handler.getFirstChange();
      assertEquals(csn1, csnArray[1], "First change");
      csnLast = handler.getLastChange();
      assertEquals(csnLast, csnArray[2 * max], "Last change");
      testcase="FROM our first generated change TO now (> newest change in the db)";
      actualCnt = handler.getCount(cnarray[1], newerThanLast);
      actualCnt = handler.getCount(csnArray[1], newerThanLast);
      debugInfo(tn,testcase + " actualCnt=" + actualCnt);
      assertEquals(actualCnt, (2*max), testcase);
@@ -490,10 +487,10 @@
      testcase="AFTER PURGE (first, last)=";
      debugInfo(tn,testcase + handler.getFirstChange() + handler.getLastChange());
      assertEquals(handler.getLastChange(), cnarray[2*max], "Last=");
      assertEquals(handler.getLastChange(), csnArray[2*max], "Last=");
      testcase="AFTER PURGE ";
      actualCnt = handler.getCount(cnarray[1], newerThanLast);
      actualCnt = handler.getCount(csnArray[1], newerThanLast);
      int expectedCnt;
      if (totalCount>1)
      {
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbHandlerTest.java
@@ -32,12 +32,12 @@
import org.opends.server.TestCaseUtils;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.server.ReplServerFakeConfiguration;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.replication.server.changelog.api.ChangelogDBIterator;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.replication.server.changelog.je.DraftCNDB.DraftCNDBCursor;
import org.opends.server.util.StaticUtils;
import org.testng.annotations.Test;
@@ -49,6 +49,7 @@
 * - periodic trim
 * - call to clear method()
 */
@SuppressWarnings("javadoc")
public class DraftCNDbHandlerTest extends ReplicationTestCase
{
  /**
@@ -59,8 +60,6 @@
   * - set a very short trim period
   * - wait for the db to be trimmed / here since the changes are not stored in
   *   the replication changelog, the draftCNDb will be cleared.
   *
   * @throws Exception
   */
  @Test()
  void testDraftCNDbHandlerTrim() throws Exception
@@ -100,15 +99,15 @@
      String baseDN2 = "baseDN2";
      String baseDN3 = "baseDN3";
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
      ChangeNumber changeNumber1 = gen.newChangeNumber();
      ChangeNumber changeNumber2 = gen.newChangeNumber();
      ChangeNumber changeNumber3 = gen.newChangeNumber();
      CSNGenerator gen = new CSNGenerator( 1, 0);
      CSN csn1 = gen.newCSN();
      CSN csn2 = gen.newCSN();
      CSN csn3 = gen.newCSN();
      // Add records
      handler.add(sn1, value1, baseDN1, changeNumber1);
      handler.add(sn2, value2, baseDN2, changeNumber2);
      handler.add(sn3, value3, baseDN3, changeNumber3);
      handler.add(sn1, value1, baseDN1, csn1);
      handler.add(sn2, value2, baseDN2, csn2);
      handler.add(sn3, value3, baseDN3, csn3);
      // The ChangeNumber should not get purged
      final int firstDraftCN = handler.getFirstDraftCN();
@@ -118,20 +117,20 @@
      DraftCNDBCursor dbc = handler.getReadCursor(firstDraftCN);
      try
      {
        assertEquals(dbc.currentChangeNumber(), changeNumber1);
        assertEquals(dbc.currentCSN(), csn1);
        assertEquals(dbc.currentBaseDN(), baseDN1);
        assertEquals(dbc.currentValue(), value1);
        assertTrue(dbc.toString().length() != 0);
        assertTrue(dbc.next());
        assertEquals(dbc.currentChangeNumber(), changeNumber2);
        assertEquals(dbc.currentCSN(), csn2);
        assertEquals(dbc.currentBaseDN(), baseDN2);
        assertEquals(dbc.currentValue(), value2);
        assertTrue(dbc.next());
        assertEquals(dbc.currentChangeNumber(), changeNumber3);
        assertEquals(dbc.currentCSN(), csn3);
        assertEquals(dbc.currentBaseDN(), baseDN3);
        assertEquals(dbc.currentValue(), value3);
@@ -227,15 +226,15 @@
      String baseDN2 = "baseDN2";
      String baseDN3 = "baseDN3";
      ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
      ChangeNumber changeNumber1 = gen.newChangeNumber();
      ChangeNumber changeNumber2 = gen.newChangeNumber();
      ChangeNumber changeNumber3 = gen.newChangeNumber();
      CSNGenerator gen = new CSNGenerator( 1, 0);
      CSN csn1 = gen.newCSN();
      CSN csn2 = gen.newCSN();
      CSN csn3 = gen.newCSN();
      // Add records
      handler.add(sn1, value1, baseDN1, changeNumber1);
      handler.add(sn2, value2, baseDN2, changeNumber2);
      handler.add(sn3, value3, baseDN3, changeNumber3);
      handler.add(sn1, value1, baseDN1, csn1);
      handler.add(sn2, value2, baseDN2, csn2);
      handler.add(sn3, value3, baseDN3, csn3);
      Thread.sleep(500);
      // Checks