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

Jean-Noel Rouvignac
04.43.2013 fe9b2994e042be96cb148e52fc58653fcf09aa9d
opends/src/server/org/opends/server/replication/common/FirstChangeNumberVirtualAttributeProvider.java
@@ -142,7 +142,7 @@
        ReplicationServer rs = eclwe.getReplicationServer();
        rs.disableEligibility(excludedDomains);
        int[] limits = rs.getECLDraftCNLimits(
        int[] limits = rs.getECLChangeNumberLimits(
            rs.getEligibleCSN(), excludedDomains);
        first = String.valueOf(limits[0]);
opends/src/server/org/opends/server/replication/common/LastChangeNumberVirtualAttributeProvider.java
@@ -142,7 +142,7 @@
        ReplicationServer rs = eclwe.getReplicationServer();
        rs.disableEligibility(excludedDomains);
        int[] limits = rs.getECLDraftCNLimits(
        int[] limits = rs.getECLChangeNumberLimits(
            rs.getEligibleCSN(), excludedDomains);
        last = String.valueOf(limits[1]);
opends/src/server/org/opends/server/replication/protocol/ECLUpdateMsg.java
@@ -49,22 +49,22 @@
  private MultiDomainServerState cookie;
  /** The changeNumber as specified by draft-good-ldap-changelog. */
  private int draftChangeNumber;
  private int changeNumber;
  /**
   * Creates a new message.
   * @param updateMsg The provided update message.
   * @param cookie    The provided cookie value
   * @param baseDN    The provided baseDN.
   * @param draftChangeNumber The provided draft change number.
   * @param changeNumber The provided change number.
   */
  public ECLUpdateMsg(LDAPUpdateMsg updateMsg, MultiDomainServerState cookie,
      String baseDN, int draftChangeNumber)
      String baseDN, int changeNumber)
  {
    this.cookie = cookie;
    this.baseDN = baseDN;
    this.updateMsg = updateMsg;
    this.draftChangeNumber = draftChangeNumber;
    this.changeNumber = changeNumber;
  }
  /**
@@ -101,10 +101,9 @@
      this.baseDN = new String(in, pos, length, "UTF-8");
      pos += length + 1;
      // Decode the draft changeNumber
      // Decode the changeNumber
      length = getNextLength(in, pos);
      this.draftChangeNumber = Integer.valueOf(
          new String(in, pos, length, "UTF-8"));
      this.changeNumber = Integer.valueOf(new String(in, pos, length, "UTF-8"));
      pos += length + 1;
      // Decode the msg
@@ -112,8 +111,7 @@
      length = in.length - pos - 1;
      byte[] encodedMsg = new byte[length];
      System.arraycopy(in, pos, encodedMsg, 0, length);
      ReplicationMsg rmsg =
        ReplicationMsg.generateMsg(
      ReplicationMsg rmsg = ReplicationMsg.generateMsg(
            encodedMsg, ProtocolVersion.getCurrentVersion());
      this.updateMsg = (LDAPUpdateMsg)rmsg;
    }
@@ -173,7 +171,7 @@
    return "ECLUpdateMsg:[" +
    " updateMsg: " + updateMsg +
    " cookie: " + cookie +
    " draftChangeNumber: " + draftChangeNumber +
    " changeNumber: " + changeNumber +
    " serviceId: " + baseDN + "]";
  }
@@ -186,13 +184,12 @@
  {
    byte[] byteCookie = String.valueOf(cookie).getBytes("UTF-8");
    byte[] byteBaseDN = String.valueOf(baseDN).getBytes("UTF-8");
    byte[] byteDraftChangeNumber =
      Integer.toString(draftChangeNumber).getBytes("UTF-8");
    byte[] byteChangeNumber = Integer.toString(changeNumber).getBytes("UTF-8");
    byte[] byteUpdateMsg = updateMsg.getBytes(protocolVersion);
    int length = 1 + byteCookie.length +
                 1 + byteBaseDN.length +
                 1 + byteDraftChangeNumber.length +
                 1 + byteChangeNumber.length +
                 1 + byteUpdateMsg.length + 1;
    byte[] resultByteArray = new byte[length];
@@ -204,28 +201,28 @@
    // Encode all fields
    pos = addByteArray(byteCookie, resultByteArray, pos);
    pos = addByteArray(byteBaseDN, resultByteArray, pos);
    pos = addByteArray(byteDraftChangeNumber, resultByteArray, pos);
    pos = addByteArray(byteChangeNumber, resultByteArray, pos);
    pos = addByteArray(byteUpdateMsg, resultByteArray, pos);
    return resultByteArray;
  }
  /**
   * Setter for the draftChangeNumber of this change.
   * @param draftChangeNumber the provided draftChangeNumber for this change.
   * Setter for the changeNumber of this change.
   * @param changeNumber the provided changeNumber for this change.
   */
  public void setDraftChangeNumber(int draftChangeNumber)
  public void setChangeNumber(int changeNumber)
  {
    this.draftChangeNumber = draftChangeNumber;
    this.changeNumber = changeNumber;
  }
  /**
   * Getter for the draftChangeNumber of this change.
   * @return the draftChangeNumber of this change.
   * Getter for the changeNumber of this change.
   * @return the changeNumber of this change.
   */
  public int getDraftChangeNumber()
  public int getChangeNumber()
  {
    return this.draftChangeNumber;
    return this.changeNumber;
  }
}
opends/src/server/org/opends/server/replication/protocol/StartECLSessionMsg.java
@@ -56,7 +56,7 @@
   * and NOT replication CSNs).
   * TODO: not yet implemented
   */
  public final static short REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER = 1;
  public final static short REQUEST_TYPE_FROM_CHANGE_NUMBER = 1;
  /**
   * This specifies that the ECL is requested only for the entry that have
@@ -94,8 +94,8 @@
   * When eclRequestType = FROM_CHANGE_NUMBER, specifies the provided change
   * number first and last - [CHANGELOG].
   */
  private int    firstDraftChangeNumber = -1;
  private int    lastDraftChangeNumber = -1;
  private int firstChangeNumber = -1;
  private int lastChangeNumber = -1;
  /**
   * When eclRequestType = EQUALS_REPL_CHANGE_NUMBER, specifies the provided
@@ -133,10 +133,10 @@
    try
    {
      /* first bytes are the header */
      // first bytes are the header
      int pos = 0;
      /* first byte is the type */
      // first byte is the type
      if (in.length < 1 || in[pos++] != MSG_TYPE_START_ECL_SESSION)
      {
        throw new DataFormatException(
@@ -150,14 +150,12 @@
      // sequenceNumber
      length = getNextLength(in, pos);
      firstDraftChangeNumber =
        Integer.valueOf(new String(in, pos, length, "UTF-8"));
      firstChangeNumber = Integer.valueOf(new String(in, pos, length, "UTF-8"));
      pos += length +1;
      // stopSequenceNumber
      length = getNextLength(in, pos);
      lastDraftChangeNumber =
        Integer.valueOf(new String(in, pos, length, "UTF-8"));
      lastChangeNumber = Integer.valueOf(new String(in, pos, length, "UTF-8"));
      pos += length +1;
      // replication CSN
@@ -207,8 +205,8 @@
  {
    eclRequestType = REQUEST_TYPE_FROM_COOKIE;
    crossDomainServerState = "";
    firstDraftChangeNumber = -1;
    lastDraftChangeNumber = -1;
    firstChangeNumber = -1;
    lastChangeNumber = -1;
    csn = new CSN(0, 0, 0);
    isPersistent = NON_PERSISTENT;
    operationId = "-1";
@@ -227,8 +225,8 @@
    try
    {
      byte[] byteMode = toBytes(eclRequestType);
      byte[] byteSequenceNumber = toBytes(firstDraftChangeNumber);
      byte[] byteStopSequenceNumber = toBytes(lastDraftChangeNumber);
      byte[] byteChangeNumber = toBytes(firstChangeNumber);
      byte[] byteStopChangeNumber = toBytes(lastChangeNumber);
      byte[] byteCSN = csn.toString().getBytes("UTF-8");
      byte[] bytePsearch = toBytes(isPersistent);
      byte[] byteGeneralizedState = toBytes(crossDomainServerState);
@@ -237,8 +235,8 @@
      int length =
        byteMode.length + 1 +
        byteSequenceNumber.length + 1 +
        byteStopSequenceNumber.length + 1 +
        byteChangeNumber.length + 1 +
        byteStopChangeNumber.length + 1 +
        byteCSN.length + 1 +
        bytePsearch.length + 1 +
        byteGeneralizedState.length + 1 +
@@ -250,8 +248,8 @@
      int pos = 0;
      resultByteArray[pos++] = MSG_TYPE_START_ECL_SESSION;
      pos = addByteArray(byteMode, resultByteArray, pos);
      pos = addByteArray(byteSequenceNumber, resultByteArray, pos);
      pos = addByteArray(byteStopSequenceNumber, resultByteArray, pos);
      pos = addByteArray(byteChangeNumber, resultByteArray, pos);
      pos = addByteArray(byteStopChangeNumber, resultByteArray, pos);
      pos = addByteArray(byteCSN, resultByteArray, pos);
      pos = addByteArray(bytePsearch, resultByteArray, pos);
      pos = addByteArray(byteGeneralizedState, resultByteArray, pos);
@@ -284,9 +282,9 @@
    return getClass().getCanonicalName() + " [" +
            " requestType="+ eclRequestType +
            " persistentSearch="       + isPersistent +
            " csn=" + csn +
            " firstDraftChangeNumber=" + firstDraftChangeNumber +
            " lastDraftChangeNumber="  + lastDraftChangeNumber +
            " csn="                    + csn +
            " firstChangeNumber="      + firstChangeNumber +
            " lastChangeNumber="       + lastChangeNumber +
            " generalizedState="       + crossDomainServerState +
            " operationId="            + operationId +
            " excludedDNs="            + excludedBaseDNs + "]";
@@ -296,36 +294,36 @@
   * Getter on the changer number start.
   * @return the changer number start.
   */
  public int getFirstDraftChangeNumber()
  public int getFirstChangeNumber()
  {
    return firstDraftChangeNumber;
    return firstChangeNumber;
  }
  /**
   * Getter on the changer number stop.
   * @return the change number stop.
   */
  public int getLastDraftChangeNumber()
  public int getLastChangeNumber()
  {
    return lastDraftChangeNumber;
    return lastChangeNumber;
  }
  /**
   * Setter on the first changer number (as defined by [CHANGELOG]).
   * @param firstDraftChangeNumber the provided first change number.
   * @param firstChangeNumber the provided first change number.
   */
  public void setFirstDraftChangeNumber(int firstDraftChangeNumber)
  public void setFirstChangeNumber(int firstChangeNumber)
  {
    this.firstDraftChangeNumber = firstDraftChangeNumber;
    this.firstChangeNumber = firstChangeNumber;
  }
  /**
   * Setter on the last changer number (as defined by [CHANGELOG]).
   * @param lastDraftChangeNumber the provided last change number.
   * @param lastChangeNumber the provided last change number.
   */
  public void setLastDraftChangeNumber(int lastDraftChangeNumber)
  public void setLastChangeNumber(int lastChangeNumber)
  {
    this.lastDraftChangeNumber = lastDraftChangeNumber;
    this.lastChangeNumber = lastChangeNumber;
  }
  /**
opends/src/server/org/opends/server/replication/server/ECLServerHandler.java
@@ -69,14 +69,13 @@
  private boolean draftCompat = false;
  /**
   * Specifies the last draft changer number (seqnum) requested.
   * Specifies the last changer number requested.
   */
  private int lastDraftCN = 0;
  private int lastChangeNumber = 0;
  /**
   * Specifies whether the draft change number (seqnum) db has been read until
   * its end.
   * Specifies whether the change number db has been read until its end.
   */
  private boolean isEndOfDraftCNReached = false;
  private boolean isEndOfCNIndexDBReached = false;
  /**
   * Specifies whether the current search has been requested to be persistent
   * or not.
@@ -118,8 +117,8 @@
           "[" +
           "[draftCompat=" + draftCompat +
           "] [persistent=" + isPersistent +
           "] [lastDraftCN=" + lastDraftCN +
           "] [isEndOfDraftCNReached=" + isEndOfDraftCNReached +
           "] [startChangeNumber=" + lastChangeNumber +
           "] [isEndOfDraftCNReached=" + isEndOfCNIndexDBReached +
           "] [searchPhase=" + searchPhase +
           "] [startCookie=" + startCookie +
           "] [previousCookie=" + previousCookie +
@@ -516,18 +515,21 @@
  }
  /**
   * Initialize the handler from a provided draft first change number.
   * @param startDraftCN The provided draft first change number.
   * @throws DirectoryException When an error is raised.
   * Initialize the handler from a provided first change number.
   *
   * @param startChangeNumber
   *          The provided first change number.
   * @throws DirectoryException
   *           When an error is raised.
   */
  private void initializeCLSearchFromDraftCN(int startDraftCN)
  private void initializeCLSearchFromChangeNumber(int startChangeNumber)
      throws DirectoryException
  {
    try
    {
      this.draftCompat = true;
      final String providedCookie = findCookie(startDraftCN);
      final String providedCookie = findCookie(startChangeNumber);
      initializeChangelogDomainCtxts(providedCookie, true);
    }
    catch(DirectoryException de)
@@ -548,91 +550,93 @@
  }
  /**
   * Finds in the draft changelog DB the cookie corresponding to the passed in
   * startDraftCN.
   * Finds in the {@link ChangeNumberIndexDB} the cookie corresponding to the
   * passed in startChangeNumber.
   *
   * @param startDraftCN
   *          the start draftCN coming from the request filter.
   * @return the cookie corresponding to the passed in startDraftCN.
   * @param startChangeNumber
   *          the start change number coming from the request filter.
   * @return the cookie corresponding to the passed in startChangeNumber.
   * @throws Exception
   *           if a database problem occurred
   * @throws DirectoryException
   *           if a database problem occurred
   */
  private String findCookie(final int startDraftCN) throws ChangelogException,
  private String findCookie(final int startChangeNumber)
      throws ChangelogException,
      DirectoryException
  {
    final ChangeNumberIndexDB cnIndexDB =
        replicationServer.getChangeNumberIndexDB();
    if (startDraftCN <= 1)
    if (startChangeNumber <= 1)
    {
      // Request filter DOES NOT contain any firstDraftCN
      // So we'll generate from the first DraftCN in the DraftCNdb
      // Request filter DOES NOT contain any first change number
      // So we'll generate from the first change number in the DraftCNdb
      if (cnIndexDB.isEmpty())
      {
        // FIXME JNR if we find a way to make draftCNDb.isEmpty() a non costly
        // operation, then I think we can move this check to the top of this
        // method
        isEndOfDraftCNReached = true;
        isEndOfCNIndexDBReached = true;
        return null;
      }
      final int firstDraftCN = cnIndexDB.getFirstDraftCN();
      final int firstChangeNumber = cnIndexDB.getFirstChangeNumber();
      final String crossDomainStartState =
          cnIndexDB.getPreviousCookie(firstDraftCN);
      cnIndexDBCursor = cnIndexDB.getCursorFrom(firstDraftCN);
          cnIndexDB.getPreviousCookie(firstChangeNumber);
      cnIndexDBCursor = cnIndexDB.getCursorFrom(firstChangeNumber);
      return crossDomainStartState;
    }
    // Request filter DOES contain a startDraftCN
    // Request filter DOES contain a startChangeNumber
    // Read the draftCNDb to see whether it contains startDraftCN
    String crossDomainStartState = cnIndexDB.getPreviousCookie(startDraftCN);
    // Read the draftCNDb to see whether it contains startChangeNumber
    String crossDomainStartState =
        cnIndexDB.getPreviousCookie(startChangeNumber);
    if (crossDomainStartState != null)
    {
      // found the provided startDraftCN, let's return it
      cnIndexDBCursor = cnIndexDB.getCursorFrom(startDraftCN);
      // found the provided startChangeNumber, let's return it
      cnIndexDBCursor = cnIndexDB.getCursorFrom(startChangeNumber);
      return crossDomainStartState;
    }
    // startDraftCN provided in the request IS NOT in the DraftCNDb
    // startChangeNumber provided in the request IS NOT in the DraftCNDb
    /*
     * Get the draftLimits (from the eligibleCSN got at the beginning of the
     * operation) in order to have the first and possible last DraftCN.
     * operation) in order to have the first and possible last change number.
     */
    final int[] limits =
        replicationServer.getECLDraftCNLimits(eligibleCSN, excludedBaseDNs);
    final int firstDraftCN = limits[0];
    final int lastDraftCN = limits[1];
    final int[] limits = replicationServer.getECLChangeNumberLimits(
        eligibleCSN, excludedBaseDNs);
    final int firstChangeNumber = limits[0];
    final int lastChangeNumber = limits[1];
    // If the startDraftCN provided is lower than the first Draft CN in
    // If the startChangeNumber provided is lower than the firstChangeNumber in
    // the DB, let's use the lower limit.
    if (startDraftCN < firstDraftCN)
    if (startChangeNumber < firstChangeNumber)
    {
      crossDomainStartState = cnIndexDB.getPreviousCookie(firstDraftCN);
      crossDomainStartState = cnIndexDB.getPreviousCookie(firstChangeNumber);
      if (crossDomainStartState != null)
      {
        cnIndexDBCursor = cnIndexDB.getCursorFrom(firstDraftCN);
        cnIndexDBCursor = cnIndexDB.getCursorFrom(firstChangeNumber);
        return crossDomainStartState;
      }
      // This should not happen
      isEndOfDraftCNReached = true;
      isEndOfCNIndexDBReached = true;
      return null;
    }
    else if (startDraftCN <= lastDraftCN)
    else if (startChangeNumber <= lastChangeNumber)
    {
      // startDraftCN is between first and potential last and has never
      // startChangeNumber is between first and potential last and has never
      // been returned yet
      if (cnIndexDB.isEmpty())
      {
        isEndOfDraftCNReached = true;
        isEndOfCNIndexDBReached = true;
        return null;
      }
      final int lastKey = cnIndexDB.getLastDraftCN();
      final int lastKey = cnIndexDB.getLastChangeNumber();
      crossDomainStartState = cnIndexDB.getPreviousCookie(lastKey);
      cnIndexDBCursor = cnIndexDB.getCursorFrom(lastKey);
      return crossDomainStartState;
@@ -641,7 +645,7 @@
      // this may be very long. Work on perf improvement here.
    }
    // startDraftCN is greater than the potential last DraftCN
    // startChangeNumber is greater than the potential lastChangeNumber
    throw new DirectoryException(ResultCode.SUCCESS, Message.raw(""));
  }
@@ -999,7 +1003,7 @@
    this.operationId = startECLSessionMsg.getOperationId();
    isPersistent  = startECLSessionMsg.isPersistent();
    lastDraftCN   = startECLSessionMsg.getLastDraftChangeNumber();
    lastChangeNumber = startECLSessionMsg.getLastChangeNumber();
    searchPhase   = INIT_PHASE;
    try
    {
@@ -1117,9 +1121,9 @@
    {
      initializeCLSearchFromGenState(msg.getCrossDomainServerState());
    }
    else if (requestType == REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER)
    else if (requestType == REQUEST_TYPE_FROM_CHANGE_NUMBER)
    {
      initializeCLSearchFromDraftCN(msg.getFirstDraftChangeNumber());
      initializeCLSearchFromChangeNumber(msg.getFirstChangeNumber());
    }
  }
@@ -1131,8 +1135,7 @@
   *         ServerHandler.
   * @exception DirectoryException when an error occurs.
   */
  public ECLUpdateMsg takeECLUpdate()
  throws DirectoryException
  public ECLUpdateMsg takeECLUpdate() throws DirectoryException
  {
    ECLUpdateMsg msg = getNextECLUpdate();
@@ -1235,18 +1238,18 @@
            (LDAPUpdateMsg) oldestContext.nextMsg,
            null, // cookie will be set later
            oldestContext.rsd.getBaseDn(),
            0); //  draftChangeNumber may be set later
            0); // changeNumber may be set later
        oldestContext.nextMsg = null;
        // Default is not to loop, with one exception
        continueLooping = false;
        if (draftCompat)
        {
          continueLooping = !assignDraftCN(change);
          continueLooping = !assignChangeNumber(change);
        }
        // here we have the right oldest change
        // and in the draft case, we have its draft changenumber
        // and in the draft case, we have its change number
        // Set and test the domain of the oldestChange see if we reached
        // the end of the phase for this domain
@@ -1257,8 +1260,9 @@
        {
          oldestContext.active = false;
        }
        if (draftCompat && (lastDraftCN>0) &&
            (change.getDraftChangeNumber()>lastDraftCN))
        if (draftCompat
            && lastChangeNumber > 0
            && change.getChangeNumber() > lastChangeNumber)
        {
          oldestContext.active = false;
        }
@@ -1334,17 +1338,17 @@
  }
  /**
   * Either retrieves a draftCN from the draftCNDb, or assign a new draftCN and
   * store in the db.
   * Either retrieves a change number from the DB, or assign a new change number
   * and store in the DB.
   *
   * @param oldestChange
   *          the oldestChange where to assign the draftCN
   * @return <code>true</code> if a draftCN has been assigned to the provided
   *         oldestChange, <code>false</code> otherwise
   *          the oldestChange where to assign the change number
   * @return <code>true</code> if a change number has been assigned to the
   *         provided oldestChange, <code>false</code> otherwise
   * @throws DirectoryException
   *           if any problem occur
   */
  private boolean assignDraftCN(final ECLUpdateMsg oldestChange)
  private boolean assignChangeNumber(final ECLUpdateMsg oldestChange)
      throws DirectoryException
  {
    // We also need to check if the draftCNdb is consistent with
@@ -1361,7 +1365,7 @@
    while (true)
    {
      if (isEndOfDraftCNReached)
      if (isEndOfCNIndexDBReached)
      {
        // we are at the end of the DraftCNdb in the append mode
        assignNewDraftCNAndStore(oldestChange);
@@ -1369,12 +1373,12 @@
      }
      // the next change from the DraftCN db
      // the next change from the CNIndexDB
      CSN csnFromDraftCNDb = cnIndexDBCursor.getCSN();
      String dnFromDraftCNDb = cnIndexDBCursor.getBaseDN();
      if (debugEnabled())
        TRACER.debugInfo("getNextECLUpdate generating draftCN "
        TRACER.debugInfo("assignChangeNumber() generating change number "
            + " comparing the 2 db DNs :" + dnFromChangelogDb + "?="
            + csnFromChangelogDb + " timestamps:"
            + new Date(csnFromChangelogDb.getTime()) + " ?older"
@@ -1385,11 +1389,11 @@
          csnFromDraftCNDb, dnFromDraftCNDb))
      {
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
              + " assigning draftCN=" + cnIndexDBCursor.getDraftCN()
          TRACER.debugInfo("assignChangeNumber() generating change number "
              + " assigning changeNumber=" + cnIndexDBCursor.getChangeNumber()
              + " to change=" + oldestChange);
        oldestChange.setDraftChangeNumber(cnIndexDBCursor.getDraftCN());
        oldestChange.setChangeNumber(cnIndexDBCursor.getChangeNumber());
        return true;
      }
@@ -1400,7 +1404,8 @@
        // it should have been stored lately
        // let's continue to traverse the changelogdb
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate: will skip " + csnFromChangelogDb
          TRACER.debugInfo("assignChangeNumber(): will skip "
              + csnFromChangelogDb
              + " and read next from the regular changelog.");
        return false; // TO BE CHECKED
      }
@@ -1414,17 +1419,17 @@
        // let's traverse the DraftCNdb searching for the change
        // found in the changelogDb.
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
          TRACER.debugInfo("assignChangeNumber() generating change number "
              + " will skip " + csnFromDraftCNDb
              + " and read next change from the DraftCNDb.");
              + " and read next change from the CNIndexDB.");
        isEndOfDraftCNReached = !cnIndexDBCursor.next();
        isEndOfCNIndexDBReached = !cnIndexDBCursor.next();
        if (debugEnabled())
          TRACER.debugInfo("getNextECLUpdate generating draftCN "
              + " has skipped to " + " sn=" + cnIndexDBCursor.getDraftCN()
              + " csn=" + cnIndexDBCursor.getCSN()
              + " End of draftCNDb ?" + isEndOfDraftCNReached);
          TRACER.debugInfo("assignChangeNumber() generating change number has"
              + "skipped to  changeNumber=" + cnIndexDBCursor.getChangeNumber()
              + " csn=" + cnIndexDBCursor.getCSN() + " End of CNIndexDB ?"
              + isEndOfCNIndexDBReached);
      }
      catch (ChangelogException e)
      {
@@ -1448,13 +1453,13 @@
  private void assignNewDraftCNAndStore(ECLUpdateMsg change)
      throws DirectoryException
  {
    // generate a new draftCN and assign to this change
    change.setDraftChangeNumber(replicationServer.getNewDraftCN());
    // generate a new change number and assign to this change
    change.setChangeNumber(replicationServer.getNewChangeNumber());
    // store in changelogDB the pair
    // (DraftCN of the current change, state before this change)
    // store in CNIndexDB the pair
    // (change number of the current change, state before this change)
    replicationServer.getChangeNumberIndexDB().add(
        change.getDraftChangeNumber(),
        change.getChangeNumber(),
        previousCookie.toString(),
        change.getBaseDN(),
        change.getUpdateMsg().getCSN());
opends/src/server/org/opends/server/replication/server/ReplicationServer.java
@@ -153,11 +153,11 @@
  private ChangeNumberIndexDB cnIndexDB;
  /**
   * The last value generated of the draft change number.
   * The last value generated of the change number.
   * <p>
   * Guarded by cnIndexDBLock
   **/
  private int lastGeneratedDraftCN = 0;
  private int lastGeneratedChangeNumber = 0;
  /** Used for protecting {@link ChangeNumberIndexDB} related state. */
  private final Object cnIndexDBLock = new Object();
@@ -908,7 +908,7 @@
        try
        {
          lastGeneratedDraftCN = cnIndexDB.getLastDraftCN();
          lastGeneratedChangeNumber = cnIndexDB.getLastChangeNumber();
        }
        catch (Exception ignored)
        {
@@ -1397,7 +1397,7 @@
          }
        }
        lastGeneratedDraftCN = 0;
        lastGeneratedChangeNumber = 0;
        cnIndexDB = null;
      }
    }
@@ -1639,7 +1639,7 @@
        if (cnIndexDB == null)
        {
          cnIndexDB = new DraftCNDbHandler(this, this.dbEnv);
          lastGeneratedDraftCN = getLastDraftChangeNumber();
          lastGeneratedChangeNumber = getLastChangeNumber();
        }
        return cnIndexDB;
      }
@@ -1654,113 +1654,116 @@
  }
  /**
   * Get the value of the first draft change number, 0 when db is empty.
   * Get the value of the first change number, 0 when db is empty.
   *
   * @return the first value.
   */
  public int getFirstDraftChangeNumber()
  public int getFirstChangeNumber()
  {
    synchronized (cnIndexDBLock)
    {
      if (cnIndexDB != null)
      {
        return cnIndexDB.getFirstDraftCN();
        return cnIndexDB.getFirstChangeNumber();
      }
      return 0;
    }
  }
  /**
   * Get the value of the last draft change number, 0 when db is empty.
   * Get the value of the last change number, 0 when db is empty.
   *
   * @return the last value.
   */
  public int getLastDraftChangeNumber()
  public int getLastChangeNumber()
  {
    synchronized (cnIndexDBLock)
    {
      if (cnIndexDB != null)
      {
        return cnIndexDB.getLastDraftCN();
        return cnIndexDB.getLastChangeNumber();
      }
      return 0;
    }
  }
  /**
   * Generate a new Draft ChangeNumber.
   * @return The generated Draft ChangeNUmber
   * Generate a new change number.
   *
   * @return The generated change number
   */
  public int getNewDraftCN()
  public int getNewChangeNumber()
  {
    synchronized (cnIndexDBLock)
    {
      return ++lastGeneratedDraftCN;
      return ++lastGeneratedChangeNumber;
    }
  }
  /**
   * Get first and last DraftCN.
   * Get first and last change number.
   *
   * @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.
   * @param crossDomainEligibleCSN
   *          The provided crossDomainEligibleCSN used as the upper limit for
   *          the last change number
   * @param excludedBaseDNs
   *          The baseDNs that are excluded from the ECL.
   * @return The first and last change numbers.
   * @throws DirectoryException
   *           When it happens.
   */
  public int[] getECLDraftCNLimits(CSN crossDomainEligibleCSN,
  public int[] getECLChangeNumberLimits(CSN crossDomainEligibleCSN,
      Set<String> excludedBaseDNs) throws DirectoryException
  {
    /* The content of the DraftCNdb depends on the SEARCH operations done before
     * requesting the DraftCN. If no operations, DraftCNdb is empty.
     * requesting the change number. If no operations, DraftCNdb is empty.
     * The limits we want to get are the "potential" limits if a request was
     * done, the DraftCNdb is probably not complete to do that.
     *
     * The first DraftCN is :
     * The first change number is :
     *  - the first record from the DraftCNdb
     *  - if none because DraftCNdb empty,
     *      then
     *        if no change in replchangelog then return 0
     *        else return 1 (DraftCN that WILL be returned to next search)
     *        else return 1 (change number that WILL be returned to next search)
     *
     * The last DraftCN is :
     * The last change number is :
     *  - 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 crossDomainEligibleCSN
     *  - to the last change number, we add the count of updates in the
     *     replchangelog FROM that genState TO the crossDomainEligibleCSN
     *     (this diff is done domain by domain)
     */
    int lastDraftCN;
    int lastChangeNumber;
    boolean dbEmpty = false;
    final ChangeNumberIndexDB cnIndexDB = getChangeNumberIndexDB();
    int firstDraftCN = cnIndexDB.getFirstDraftCN();
    Map<String,ServerState> domainsServerStateForLastSeqnum = null;
    CSN csnForLastSeqnum = null;
    String domainForLastSeqnum = null;
    if (firstDraftCN < 1)
    int firstChangeNumber = cnIndexDB.getFirstChangeNumber();
    Map<String, ServerState> domainsServerStateForLastCN = null;
    CSN csnForLastCN = null;
    String domainForLastCN = null;
    if (firstChangeNumber < 1)
    {
      dbEmpty = true;
      firstDraftCN = 0;
      lastDraftCN = 0;
      firstChangeNumber = 0;
      lastChangeNumber = 0;
    }
    else
    {
      lastDraftCN = cnIndexDB.getLastDraftCN();
      lastChangeNumber = cnIndexDB.getLastChangeNumber();
      // Get the generalized state associated with the current last DraftCN
      // and initializes from it the startStates table
      String lastSeqnumGenState = cnIndexDB.getPreviousCookie(lastDraftCN);
      if ((lastSeqnumGenState != null) && (lastSeqnumGenState.length()>0))
      // Get the generalized state associated with the current last change
      // number and initializes from it the startStates table
      String lastCNGenState = cnIndexDB.getPreviousCookie(lastChangeNumber);
      if (lastCNGenState != null && lastCNGenState.length() > 0)
      {
        domainsServerStateForLastSeqnum = MultiDomainServerState.
          splitGenStateToServerStates(lastSeqnumGenState);
        domainsServerStateForLastCN =
            MultiDomainServerState.splitGenStateToServerStates(lastCNGenState);
      }
      // Get the CSN associated with the current last DraftCN
      csnForLastSeqnum = cnIndexDB.getCSN(lastDraftCN);
      // Get the domain associated with the current last DraftCN
      domainForLastSeqnum = cnIndexDB.getBaseDN(lastDraftCN);
      csnForLastCN = cnIndexDB.getCSN(lastChangeNumber);
      domainForLastCN = cnIndexDB.getBaseDN(lastChangeNumber);
    }
    long newestDate = 0;
@@ -1770,9 +1773,9 @@
        continue;
      // for this domain, have the state in the replchangelog
      // where the last DraftCN update is
      // where the last change number update is
      long ec;
      if (domainsServerStateForLastSeqnum == null)
      if (domainsServerStateForLastCN == null)
      {
        // Count changes of this domain from the beginning of the changelog
        CSN trimCSN = new CSN(rsd.getLatestDomainTrimDate(), 0, 0);
@@ -1790,35 +1793,35 @@
        //  the date of the most recent change from this last draft record
        if (newestDate == 0)
        {
          newestDate = csnForLastSeqnum.getTime();
          newestDate = csnForLastCN.getTime();
        }
        // And count changes of this domain from the date of the
        // lastseqnum record (that does not refer to this domain)
        CSN csnx = new CSN(newestDate, csnForLastSeqnum.getSeqnum(), 0);
        CSN csnx = new CSN(newestDate, csnForLastCN.getSeqnum(), 0);
        ec = rsd.getEligibleCount(csnx, crossDomainEligibleCSN);
        if (domainForLastSeqnum.equalsIgnoreCase(rsd.getBaseDn()))
        if (domainForLastCN.equalsIgnoreCase(rsd.getBaseDn()))
          ec--;
      }
      // cumulates on domains
      lastDraftCN += ec;
      lastChangeNumber += ec;
      // DraftCN Db is empty and there are eligible updates in the replication
      // changelog then init first DraftCN
      if ((ec>0) && (firstDraftCN==0))
        firstDraftCN = 1;
      // CNIndexDB is empty and there are eligible updates in the replication
      // changelog then init first change number
      if (ec > 0 && firstChangeNumber == 0)
        firstChangeNumber = 1;
    }
    if (dbEmpty)
    {
      // The database was empty, just keep increasing numbers since last time
      // we generated one DraftCN.
      firstDraftCN += lastGeneratedDraftCN;
      lastDraftCN += lastGeneratedDraftCN;
      // we generated one change number.
      firstChangeNumber += lastGeneratedChangeNumber;
      lastChangeNumber += lastGeneratedChangeNumber;
    }
    return new int[]{firstDraftCN, lastDraftCN};
    return new int[]{firstChangeNumber, lastChangeNumber};
  }
  /**
opends/src/server/org/opends/server/replication/server/changelog/api/ChangeNumberIndexDB.java
@@ -44,55 +44,55 @@
{
  /**
   * Get the CSN associated to a provided draft change number.
   * Get the CSN associated to a provided change number.
   *
   * @param draftCN
   *          the provided draft change number.
   * @param changeNumber
   *          the provided change number.
   * @return the associated CSN, null when none.
   */
  public CSN getCSN(int draftCN);
  public CSN getCSN(int changeNumber);
  /**
   * Get the baseDN associated to a provided draft change number.
   * Get the baseDN associated to a provided change number.
   *
   * @param draftCN
   *          the provided draft change number.
   * @param changeNumber
   *          the provided change number.
   * @return the baseDN, null when none.
   */
  public String getBaseDN(int draftCN);
  public String getBaseDN(int changeNumber);
  /**
   * Get the previous cookie associated to a provided draft change number.
   * Get the previous cookie associated to a provided change number.
   *
   * @param draftCN
   *          the provided draft change number.
   * @param changeNumber
   *          the provided change number.
   * @return the previous cookie, null when none.
   */
  String getPreviousCookie(int draftCN);
  String getPreviousCookie(int changeNumber);
  /**
   * Get the firstChange.
   * Get the first change number stored in this DB.
   *
   * @return Returns the first draftCN in the DB.
   * @return Returns the first change number in this DB.
   */
  int getFirstDraftCN();
  int getFirstChangeNumber();
  /**
   * Get the lastChange.
   * Get the last change number stored in this DB.
   *
   * @return Returns the last draftCN in the DB
   * @return Returns the last change number in this DB
   */
  int getLastDraftCN();
  int getLastChangeNumber();
  /**
   * Add an update to the list of messages that must be saved to the db managed
   * by this db handler.
   * Add an update to the list of messages that must be saved to this DB managed
   * by this DB.
   * <p>
   * This method is blocking if the size of the list of message is larger than
   * its maximum.
   *
   * @param draftCN
   *          The draft change number for this record in the db.
   * @param changeNumber
   *          The change number for this record in this DB.
   * @param previousCookie
   *          The value of the previous cookie.
   * @param baseDN
@@ -100,22 +100,22 @@
   * @param csn
   *          The associated replication CSN.
   */
  void add(int draftCN, String previousCookie, String baseDN, CSN csn);
  void add(int changeNumber, String previousCookie, String baseDN, CSN csn);
  /**
   * Generate a new {@link ChangeNumberIndexDBCursor} that allows to browse the
   * db managed by this dbHandler and starting at the position defined by a
   * db managed by this DBHandler and starting at the position defined by a
   * given changeNumber.
   *
   * @param startDraftCN
   * @param startChangeNumber
   *          The position where the iterator must start.
   * @return a new ReplicationIterator that allows to browse the db managed by
   *         this dbHandler and starting at the position defined by a given
   * @return a new ReplicationIterator that allows to browse this DB managed by
   *         this DBHandler and starting at the position defined by a given
   *         changeNumber.
   * @throws ChangelogException
   *           if a database problem happened.
   */
  ChangeNumberIndexDBCursor getCursorFrom(int startDraftCN)
  ChangeNumberIndexDBCursor getCursorFrom(int startChangeNumber)
      throws ChangelogException;
  /**
@@ -130,7 +130,7 @@
   * Clear the changes from this DB (from both memory cache and DB storage).
   *
   * @throws ChangelogException
   *           When an exception occurs while removing the changes from the DB.
   *           When an exception occurs while removing the changes from this DB.
   */
  void clear() throws ChangelogException;
@@ -139,15 +139,15 @@
   * the provided baseDN.
   *
   * @param baseDNToClear
   *          The baseDN for which we want to remove all records from the
   *          DraftCNDb - null means all.
   *          The baseDN for which we want to remove all records from this DB,
   *          null means all.
   * @throws ChangelogException
   *           When an exception occurs while removing the changes from the DB.
   *           When an exception occurs while removing the changes from this DB.
   */
  void clear(String baseDNToClear) throws ChangelogException;
  /**
   * Shutdown this dbHandler.
   * Shutdown this DB.
   */
  void shutdown();
opends/src/server/org/opends/server/replication/server/changelog/api/ChangeNumberIndexDBCursor.java
@@ -53,11 +53,11 @@
  String getBaseDN();
  /**
   * Getter for the draftCN field.
   * Getter for the change number field.
   *
   * @return The draft CN field.
   * @return The change number field.
   */
  int getDraftCN();
  int getChangeNumber();
  /**
   * Skip to the next record of the database.
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDB.java
@@ -83,21 +83,21 @@
  /**
   * Add an entry to the database.
   * @param draftCN      the provided draftCN.
   * @param changeNumber the provided change number.
   *
   * @param value        the provided value to be stored associated
   *                     with this draftCN.
   *                     with this change number.
   * @param domainBaseDN the provided domainBaseDn to be stored associated
   *                     with this draftCN.
   *                     with this change number.
   * @param csn the provided replication CSN to be
   *                     stored associated with this draftCN.
   *                     stored associated with this change number.
   */
  public void addEntry(int draftCN, String value, String domainBaseDN,
  public void addEntry(int changeNumber, String value, String domainBaseDN,
      CSN csn)
  {
    try
    {
      DatabaseEntry key = new ReplicationDraftCNKey(draftCN);
      DatabaseEntry key = new ReplicationDraftCNKey(changeNumber);
      DatabaseEntry data = new DraftCNData(value, domainBaseDN, csn);
      // Use a transaction so that we can override durability.
@@ -182,14 +182,15 @@
  /**
   * Create a cursor that can be used to search or iterate on this DB.
   *
   * @param draftCN The draftCN from which the cursor must start.
   * @param changeNumber The change number from which the cursor must start.
   * @throws ChangelogException If a database error prevented the cursor
   *                           creation.
   * @return The ReplServerDBCursor.
   */
  public DraftCNDBCursor openReadCursor(int draftCN) throws ChangelogException
  public DraftCNDBCursor openReadCursor(int changeNumber)
      throws ChangelogException
  {
    return new DraftCNDBCursor(draftCN);
    return new DraftCNDBCursor(changeNumber);
  }
  /**
@@ -219,9 +220,9 @@
  /**
   * Read the first Change from the database, 0 when none.
   * @return the first draftCN.
   * @return the first change number.
   */
  public int readFirstDraftCN()
  public int readFirstChangeNumber()
  {
    try
    {
@@ -286,10 +287,10 @@
  }
  /**
   * Read the last draftCN from the database.
   * @return the last draftCN.
   * Read the last change number from the database.
   * @return the last change number.
   */
  public int readLastDraftCN()
  public int readLastChangeNumber()
  {
    try
    {
@@ -349,22 +350,21 @@
    private final Transaction txn;
    private final DatabaseEntry key;
    private final DatabaseEntry entry;
    private DraftCNData seqnumData;
    private DraftCNData cnData;
    private boolean isClosed = false;
    /**
     * Creates a cursor that can be used for browsing the db.
     *
     * @param startingDraftCN
     *          the draftCN from which the cursor must start.
     * @param startChangeNumber
     *          the change number from which the cursor must start.
     * @throws ChangelogException
     *           when the startingDraftCN does not exist.
     *           when the startChangeNumber does not exist.
     */
    private DraftCNDBCursor(int startingDraftCN) throws ChangelogException
    private DraftCNDBCursor(int startChangeNumber) throws ChangelogException
    {
      this.key = new ReplicationDraftCNKey(startingDraftCN);
      this.key = new ReplicationDraftCNKey(startChangeNumber);
      this.entry = new DatabaseEntry();
      // Take the lock. From now on, whatever error that happen in the life
@@ -385,16 +385,16 @@
        }
        localCursor = db.openCursor(null, null);
        if (startingDraftCN >= 0)
        if (startChangeNumber >= 0)
        {
          if (localCursor.getSearchKey(key, entry, LockMode.DEFAULT) != SUCCESS)
          {
            // We could not move the cursor to the expected startingDraftCN
            // We could not move the cursor to the expected startChangeNumber
            if (localCursor.getSearchKeyRange(key, entry, DEFAULT) != SUCCESS)
            {
              // We could not even move the cursor closed to it => failure
              throw new ChangelogException(
                  Message.raw("ChangeLog Draft Change Number " + startingDraftCN
                  Message.raw("ChangeLog Change Number " + startChangeNumber
                      + " is not available"));
            }
@@ -405,12 +405,12 @@
            }
            else
            {
              seqnumData = new DraftCNData(entry.getData());
              cnData = new DraftCNData(entry.getData());
            }
          }
          else
          {
            seqnumData = new DraftCNData(entry.getData());
            cnData = new DraftCNData(entry.getData());
          }
        }
@@ -556,9 +556,9 @@
      try
      {
        if (seqnumData != null)
        if (cnData != null)
        {
          return seqnumData.getValue();
          return cnData.getValue();
        }
      }
      catch(Exception e)
@@ -581,9 +581,9 @@
      try
      {
        if (seqnumData != null)
        if (cnData != null)
        {
          return seqnumData.getBaseDN();
          return cnData.getBaseDN();
        }
      }
      catch(Exception e)
@@ -595,9 +595,9 @@
    /**
     * Getter for the integer value of the current cursor, representing
     * the current DraftChangeNumber being processed.
     * the current change number being processed.
     *
     * @return the current DraftCN as an integer.
     * @return the current change number as an integer.
     */
    public int currentKey()
    {
@@ -631,9 +631,9 @@
      try
      {
        if (seqnumData != null)
        if (cnData != null)
        {
          return seqnumData.getCSN();
          return cnData.getCSN();
        }
      }
      catch(Exception e)
@@ -659,10 +659,10 @@
        OperationStatus status = cursor.getNext(key, entry, LockMode.DEFAULT);
        if (status != OperationStatus.SUCCESS)
        {
          seqnumData = null;
          cnData = null;
          return false;
        }
        seqnumData = new DraftCNData(entry.getData());
        cnData = new DraftCNData(entry.getData());
      }
      catch(Exception e)
      {
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNData.java
@@ -52,13 +52,14 @@
  /**
   * Creates a record to be stored in the DraftCNDB.
   * @param value The value (cookie).
   * @param previousCookie The previous cookie.
   * @param baseDN The baseDN (domain DN).
   * @param csn The replication CSN.
   */
  public DraftCNData(String value, String baseDN, CSN csn)
  public DraftCNData(String previousCookie, String baseDN, CSN csn)
  {
    String record = value + FIELD_SEPARATOR + baseDN + FIELD_SEPARATOR + csn;
    String record =
        previousCookie + FIELD_SEPARATOR + baseDN + FIELD_SEPARATOR + csn;
    setData(getBytes(record));
  }
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbHandler.java
@@ -57,11 +57,10 @@
/**
 * This class is used for managing the replicationServer database for each
 * 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 {@link ChangeNumberIndexDBCursor} that
 * can be used to read all changes from a given draft ChangeNumber.
 * 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 {@link ChangeNumberIndexDBCursor} that can be used to
 * read all changes from a given change number.
 * <p>
 * This class publishes some monitoring information below <code>
 * cn=monitor</code>.
@@ -76,15 +75,15 @@
  private DraftCNDB db;
  /**
   * FIXME Is this field that useful? {@link #getFirstDraftCN()} does not even
   * use it!
   * FIXME Is this field that useful? {@link #getFirstChangeNumber()} does not
   * even use it!
   */
  private int firstDraftCN = NO_KEY;
  private int firstChangeNumber = NO_KEY;
  /**
   * FIXME Is this field that useful? {@link #getLastDraftCN()} does not even
   * use it! It is not even updated.
   * FIXME Is this field that useful? {@link #getLastChangeNumber()} does not
   * even use it!
   */
  private int lastDraftCN = NO_KEY;
  private int lastChangeNumber = NO_KEY;
  private DbMonitorProvider dbMonitor = new DbMonitorProvider();
  private boolean shutdown = false;
  private boolean trimDone = false;
@@ -123,8 +122,8 @@
    // DB initialization
    db = new DraftCNDB(dbenv);
    firstDraftCN = db.readFirstDraftCN();
    lastDraftCN = db.readLastDraftCN();
    firstChangeNumber = db.readFirstChangeNumber();
    lastChangeNumber = db.readLastChangeNumber();
    // Trimming thread
    thread = new DirectoryThread(this, "Replication DraftCN db");
@@ -137,32 +136,32 @@
  /** {@inheritDoc} */
  @Override
  public synchronized void add(int draftCN, String value, String baseDN,
      CSN csn)
  public synchronized void add(int changeNumber, String previousCookie,
      String baseDN, CSN csn)
  {
    db.addEntry(draftCN, value, baseDN, csn);
    db.addEntry(changeNumber, previousCookie, baseDN, csn);
    if (debugEnabled())
      TRACER.debugInfo(
          "In DraftCNDbhandler.add, added: "
        + " key=" + draftCN
        + " value=" + value
        + " key=" + changeNumber
        + " previousCookie=" + previousCookie
        + " baseDN=" + baseDN
        + " csn=" + csn);
  }
  /** {@inheritDoc} */
  @Override
  public int getFirstDraftCN()
  public int getFirstChangeNumber()
  {
    return db.readFirstDraftCN();
    return db.readFirstChangeNumber();
  }
  /** {@inheritDoc} */
  @Override
  public int getLastDraftCN()
  public int getLastChangeNumber()
  {
    return db.readLastDraftCN();
    return db.readLastChangeNumber();
  }
  /**
@@ -187,7 +186,7 @@
   * <ul>
   * <li>open a cursor, check if the next entry exits, then close the cursor
   * </li>
   * <li>call <code>db.readFirstDraftCN() != 0</code></li>
   * <li>call <code>db.readFirstChangeNumber() != 0</code></li>
   * </ul>
   */
  @Override
@@ -202,23 +201,24 @@
   * <p>
   * This method is only used by unit tests.
   *
   * @param startingDraftCN
   *          The draft change number from where to start.
   * @param startChangeNumber
   *          The change number from where to start.
   * @return the new cursor.
   * @throws ChangelogException
   *           if a database problem occurs.
   */
  DraftCNDBCursor getReadCursor(int startingDraftCN) throws ChangelogException
  DraftCNDBCursor getReadCursor(int startChangeNumber)
      throws ChangelogException
  {
    return db.openReadCursor(startingDraftCN);
    return db.openReadCursor(startChangeNumber);
  }
  /** {@inheritDoc} */
  @Override
  public ChangeNumberIndexDBCursor getCursorFrom(int startDraftCN)
  public ChangeNumberIndexDBCursor getCursorFrom(int startChangeNumber)
      throws ChangelogException
  {
    return new DraftCNDbIterator(db, startDraftCN);
    return new DraftCNDbIterator(db, startChangeNumber);
  }
  /** {@inheritDoc} */
@@ -353,7 +353,7 @@
          final ServerState startState = domain.getStartState();
          final CSN fcsn = startState.getCSN(csn.getServerId());
          final int currentDraftCN = cursor.currentKey();
          final int currentChangeNumber = cursor.currentKey();
          if (csn.older(fcsn))
          {
@@ -391,7 +391,7 @@
            continue;
          }
          firstDraftCN = currentDraftCN;
          firstChangeNumber = currentChangeNumber;
          cursor.close();
          return;
        }
@@ -431,9 +431,9 @@
    {
      List<Attribute> attributes = new ArrayList<Attribute>();
      attributes.add(Attributes.create("first-draft-changenumber",
          Integer.toString(db.readFirstDraftCN())));
          Integer.toString(db.readFirstChangeNumber())));
      attributes.add(Attributes.create("last-draft-changenumber",
          Integer.toString(db.readLastDraftCN())));
          Integer.toString(db.readLastChangeNumber())));
      attributes.add(Attributes.create("count",
          Long.toString(count())));
      return attributes;
@@ -445,7 +445,7 @@
    @Override
    public String getMonitorInstanceName()
    {
      return "Draft Changelog";
      return "ChangeNumber Index Database";
    }
    /**
@@ -465,7 +465,7 @@
  @Override
  public String toString()
  {
    return "draftCNdb:" + " " + firstDraftCN + " " + lastDraftCN;
    return "draftCNdb:" + " " + firstChangeNumber + " " + lastChangeNumber;
  }
  /**
@@ -482,8 +482,8 @@
  public void clear() throws ChangelogException
  {
    db.clear();
    firstDraftCN = db.readFirstDraftCN();
    lastDraftCN = db.readLastDraftCN();
    firstChangeNumber = db.readFirstChangeNumber();
    lastChangeNumber = db.readLastChangeNumber();
  }
  private ReentrantLock lock = new ReentrantLock();
@@ -516,74 +516,74 @@
  /** {@inheritDoc} */
  @Override
  public String getPreviousCookie(int draftCN)
  public String getPreviousCookie(int changeNumber)
  {
    DraftCNDBCursor draftCNDBCursor = null;
    DraftCNDBCursor cursor = null;
    try
    {
      draftCNDBCursor = db.openReadCursor(draftCN);
      return draftCNDBCursor.currentValue();
      cursor = db.openReadCursor(changeNumber);
      return cursor.currentValue();
    }
    catch(Exception e)
    {
      debugException("getValue", draftCN, e);
      debugException("getValue", changeNumber, e);
      return null;
    }
    finally
    {
      close(draftCNDBCursor);
      close(cursor);
    }
  }
  /** {@inheritDoc} */
  @Override
  public CSN getCSN(int draftCN)
  public CSN getCSN(int changeNumber)
  {
    DraftCNDBCursor draftCNDBCursor = null;
    DraftCNDBCursor cursor = null;
    try
    {
      draftCNDBCursor = db.openReadCursor(draftCN);
      return draftCNDBCursor.currentCSN();
      cursor = db.openReadCursor(changeNumber);
      return cursor.currentCSN();
    }
    catch(Exception e)
    {
      debugException("getCSN", draftCN, e);
      debugException("getCSN", changeNumber, e);
      return null;
    }
    finally
    {
      close(draftCNDBCursor);
      close(cursor);
    }
  }
  /**{@inheritDoc}*/
  @Override
  public String getBaseDN(int draftCN)
  public String getBaseDN(int changeNumber)
  {
    DraftCNDBCursor draftCNDBCursor = null;
    DraftCNDBCursor cursor = null;
    try
    {
      draftCNDBCursor = db.openReadCursor(draftCN);
      return draftCNDBCursor.currentBaseDN();
      cursor = db.openReadCursor(changeNumber);
      return cursor.currentBaseDN();
    }
    catch(Exception e)
    {
      debugException("getBaseDN", draftCN, e);
      debugException("getBaseDN", changeNumber, e);
      return null;
    }
    finally
    {
      close(draftCNDBCursor);
      close(cursor);
    }
  }
  private void debugException(String methodName, int draftCN, Exception e)
  private void debugException(String methodName, int changeNumber, Exception e)
  {
    if (debugEnabled())
      TRACER.debugInfo("In DraftCNDbHandler." + methodName + "(), read: "
          + " key=" + draftCN + " value returned is null"
          + " first="+ db.readFirstDraftCN()
          + " last=" + db.readLastDraftCN()
          + " key=" + changeNumber + " value returned is null"
          + " first="+ db.readFirstChangeNumber()
          + " last=" + db.readLastChangeNumber()
          + " count=" + db.count()
          + " exception " + e + " " + e.getMessage());
  }
opends/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbIterator.java
@@ -46,19 +46,20 @@
  private DraftCNDBCursor draftCNDbCursor;
  /**
   * Creates a new ReplicationIterator.
   * All created iterator must be released by the caller using the
   * releaseCursor() method.
   * Creates a new ReplicationIterator. All created iterator must be released by
   * the caller using the {@link #close()} method.
   *
   * @param db           The db where the iterator must be created.
   * @param startDraftCN The draft CN  after which the iterator
   *                     must start.
   * @throws ChangelogException If a database problem happened.
   * @param db
   *          The db where the iterator must be created.
   * @param startChangeNumber
   *          The change number after which the iterator must start.
   * @throws ChangelogException
   *           If a database problem happened.
   */
  public DraftCNDbIterator(DraftCNDB db, int startDraftCN)
  public DraftCNDbIterator(DraftCNDB db, int startChangeNumber)
      throws ChangelogException
  {
    draftCNDbCursor = db.openReadCursor(startDraftCN);
    draftCNDbCursor = db.openReadCursor(startChangeNumber);
    if (draftCNDbCursor == null)
    {
      throw new ChangelogException(Message.raw("no new change"));
@@ -97,11 +98,9 @@
  /** {@inheritDoc} */
  @Override
  public int getDraftCN()
  public int getChangeNumber()
  {
    ReplicationDraftCNKey sk = (ReplicationDraftCNKey) draftCNDbCursor.getKey();
    int currentSeqnum = sk.getDraftCN();
    return currentSeqnum;
    return ((ReplicationDraftCNKey) draftCNDbCursor.getKey()).getChangeNumber();
  }
  /** {@inheritDoc} */
opends/src/server/org/opends/server/replication/server/changelog/je/ReplicationDbEnv.java
@@ -529,7 +529,7 @@
    {
      try
      {
        // Opens the database for seqnum associated to this domain.
        // Opens the database for change number associated to this domain.
        // Create it if it does not already exist.
        return openDatabase("draftcndb");
      }
opends/src/server/org/opends/server/replication/server/changelog/je/ReplicationDraftCNKey.java
@@ -39,18 +39,18 @@
  private static final long serialVersionUID = 1L;
  /**
   * Creates a new ReplicationKey from the given draft ChangeNumber.
   * @param draftCN The draft change number to use.
   * Creates a new ReplicationKey from the given change number.
   * @param changeNumber The change number to use.
   */
  public ReplicationDraftCNKey(int draftCN)
  public ReplicationDraftCNKey(int changeNumber)
  {
    try
    {
      String s = String.valueOf(draftCN);
      String s = String.valueOf(changeNumber);
      int a = 16-s.length();
      String sscn = "0000000000000000".substring(0, a) + s;
      // Should it use StaticUtils.getBytes() to increase performances?
      this.setData(sscn.getBytes("UTF-8"));
      setData(sscn.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException e)
    {
      // Should never happens, UTF-8 is always supported
@@ -59,12 +59,11 @@
  }
  /**
   * Getter for the draft change number associated with this key.
   * @return the draft change number associated with this key.
   * Getter for the change number associated with this key.
   * @return the change number associated with this key.
   */
  public int getDraftCN()
  public int getChangeNumber()
  {
    String s = new String(this.getData());
    return Integer.valueOf(s);
    return Integer.valueOf(new String(getData()));
  }
}
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -209,10 +209,10 @@
      clientConnection   = getClientConnection();
      startECLSessionMsg = new StartECLSessionMsg();
      // Set default behavior as "from draft change number".
      // Set default behavior as "from change number".
      // "from cookie" is set only when cookie is provided.
      startECLSessionMsg.setECLRequestType(
          StartECLSessionMsg.REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER);
          StartECLSessionMsg.REQUEST_TYPE_FROM_CHANGE_NUMBER);
      // Set a string operationid that will help correlate any error message
      // logged for this operation with the 'real' client operation.
@@ -795,7 +795,7 @@
                                                 // format)
          addMsg.getEntryUUID(),
          eclAttributes, // entry attributes
          eclmsg.getDraftChangeNumber(), "add", changeInitiatorsName);
          eclmsg.getChangeNumber(), "add", changeInitiatorsName);
    }
    else if (msg instanceof ModifyCommonMsg)
    {
@@ -861,7 +861,7 @@
          modifyMsg.getCSN(), ldifChanges,
          modifyMsg.getEntryUUID(),
          modifyMsg.getEclIncludes(), // entry attributes
          eclmsg.getDraftChangeNumber(), changeType,
          eclmsg.getChangeNumber(), changeType,
          changeInitiatorsName);
      if (modifyMsg instanceof ModifyDNMsg)
@@ -893,7 +893,7 @@
          null, // no changes
          delMsg.getEntryUUID(),
          delMsg.getEclIncludes(), // entry attributes
          eclmsg.getDraftChangeNumber(), "delete",
          eclmsg.getChangeNumber(), "delete",
          delMsg.getInitiatorsName());
    }
@@ -992,7 +992,7 @@
   * @param clearLDIFchanges     The provided LDIF changes for ADD and MODIFY
   * @param targetUUID      The provided targetUUID.
   * @param includedAttributes The provided attributes to include
   * @param draftChangenumber The provided draft change number (integer)
   * @param changenumber    The provided change number (integer)
   * @param changetype      The provided change type (add, ...)
   * @param changeInitiatorsName The provided initiators name
   * @return                The created ECL entry.
@@ -1007,13 +1007,13 @@
      String clearLDIFchanges,
      String targetUUID,
      List<RawAttribute> includedAttributes,
      int draftChangenumber,
      int changenumber,
      String changetype,
      String changeInitiatorsName)
  throws DirectoryException
  {
    String dnString;
    if (draftChangenumber == 0)
    if (changenumber == 0)
    {
      // Draft uncompat mode
      dnString = "replicationCSN=" + csn + "," + baseDN + ","
@@ -1022,7 +1022,7 @@
    else
    {
      // Draft compat mode
      dnString = "changeNumber=" + draftChangenumber + ","
      dnString = "changeNumber=" + changenumber + ","
          + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
    }
@@ -1050,9 +1050,9 @@
    // REQUIRED attributes
    // ECL Changelog draft change number
    // ECL Changelog change number
    addAttributeByType("changenumber", "changeNumber", String
        .valueOf(draftChangenumber), uAttrs, operationalAttrs);
        .valueOf(changenumber), uAttrs, operationalAttrs);
    SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); // ??
@@ -1203,8 +1203,8 @@
    }
    StartECLSessionMsg msg = evaluateSearchParameters2(sf);
    startCLmsg.setFirstDraftChangeNumber(msg.getFirstDraftChangeNumber());
    startCLmsg.setLastDraftChangeNumber(msg.getLastDraftChangeNumber());
    startCLmsg.setFirstChangeNumber(msg.getFirstChangeNumber());
    startCLmsg.setLastChangeNumber(msg.getLastChangeNumber());
    startCLmsg.setCSN(msg.getCSN());
  }
@@ -1212,8 +1212,8 @@
  throws DirectoryException
  {
    StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
    startCLmsg.setFirstDraftChangeNumber(-1);
    startCLmsg.setLastDraftChangeNumber(-1);
    startCLmsg.setFirstChangeNumber(-1);
    startCLmsg.setLastChangeNumber(-1);
    startCLmsg.setCSN(new CSN(0, 0, 0));
    // If there's no filter, just return
@@ -1227,14 +1227,14 @@
    {
      int sn = Integer.decode(
          sf.getAssertionValue().getNormalizedValue().toString());
      startCLmsg.setFirstDraftChangeNumber(sn);
      startCLmsg.setFirstChangeNumber(sn);
      return startCLmsg;
    }
    else if (matches(sf, FilterType.LESS_OR_EQUAL, "changeNumber"))
    {
      int sn = Integer.decode(
          sf.getAssertionValue().getNormalizedValue().toString());
      startCLmsg.setLastDraftChangeNumber(sn);
      startCLmsg.setLastChangeNumber(sn);
      return startCLmsg;
    }
    else if (matches(sf, FilterType.EQUALITY, "replicationcsn"))
@@ -1247,8 +1247,8 @@
    {
      int sn = Integer.decode(
          sf.getAssertionValue().getNormalizedValue().toString());
      startCLmsg.setFirstDraftChangeNumber(sn);
      startCLmsg.setLastDraftChangeNumber(sn);
      startCLmsg.setFirstChangeNumber(sn);
      startCLmsg.setLastChangeNumber(sn);
      return startCLmsg;
    }
    else if (sf.getFilterType() == FilterType.AND)
@@ -1265,23 +1265,23 @@
      if (sfs.length > 0)
      {
        m1 = evaluateSearchParameters2(sfs[0]);
        l1 = m1.getLastDraftChangeNumber();
        f1 = m1.getFirstDraftChangeNumber();
        l1 = m1.getLastChangeNumber();
        f1 = m1.getFirstChangeNumber();
      }
      if (sfs.length > 1)
      {
        m2 = evaluateSearchParameters2(sfs[1]);
        l2 = m2.getLastDraftChangeNumber();
        f2 = m2.getFirstDraftChangeNumber();
        l2 = m2.getLastChangeNumber();
        f2 = m2.getFirstChangeNumber();
      }
      if (l1 == -1)
        startCLmsg.setLastDraftChangeNumber(l2);
        startCLmsg.setLastChangeNumber(l2);
      else if (l2 == -1)
        startCLmsg.setLastDraftChangeNumber(l1);
        startCLmsg.setLastChangeNumber(l1);
      else
        startCLmsg.setLastDraftChangeNumber(Math.min(l1, l2));
        startCLmsg.setLastChangeNumber(Math.min(l1, l2));
      startCLmsg.setFirstDraftChangeNumber(Math.max(f1,f2));
      startCLmsg.setFirstChangeNumber(Math.max(f1,f2));
      return startCLmsg;
    }
    else
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -211,7 +211,7 @@
    ECLCompatNoControl(1);
    // Write additional changes and read ECL from a provided draft change number
    // Write additional changes and read ECL from a provided change number
    ECLCompatWriteReadAllOps(5);
    replicationServer.clearDb();
  }
@@ -352,7 +352,7 @@
  @Test(enabled=true, groups="slow", dependsOnMethods = { "ECLReplicationServerTest"})
  public void ECLReplicationServerFullTest14() throws Exception
  {
    // Request from an invalid draft change number
    // Request from an invalid change number
    ECLCompatBadSeqnum();
  }
@@ -362,7 +362,7 @@
    // Write 4 changes and read ECL from start
    ECLCompatWriteReadAllOps(1);
    // Write 4 additional changes and read ECL from a provided draft change number
    // Write 4 additional changes and read ECL from a provided change number
    int ts = ECLCompatWriteReadAllOps(5);
    // Test request from a provided change number - read 6
@@ -371,10 +371,10 @@
    // Test request from a provided change number interval - read 5-7
    ECLCompatReadFromTo(5,7);
    // Test first and last draft changenumber
    // Test first and last change number
    ECLCompatTestLimits(1,8, true);
    // Test first and last draft changenumber, a dd a new change, do not
    // Test first and last change number, a dd a new change, do not
    // search again the ECL, but search for first and last
    ECLCompatTestLimitsAndAdd(1,8, ts);
@@ -2327,10 +2327,10 @@
    debugInfo(tn, "Ending test successfully");
  }
  private int ECLCompatWriteReadAllOps(int firstDraftChangeNumber)
  private int ECLCompatWriteReadAllOps(int firstChangeNumber)
      throws Exception
  {
    String tn = "ECLCompatWriteReadAllOps/" + firstDraftChangeNumber;
    String tn = "ECLCompatWriteReadAllOps/" + firstChangeNumber;
    debugInfo(tn, "Starting test\n\n");
    final int nbChanges = 4;
@@ -2397,17 +2397,19 @@
      InternalSearchOperation searchOp = searchOnChangelog(filter, tn, SUCCESS);
      // test 4 entries returned
      assertEntries(searchOp.getSearchEntries(), firstDraftChangeNumber, tn,
      assertEntries(searchOp.getSearchEntries(), firstChangeNumber, tn,
          ldifWriter, user1entryUUID, csns[0], gblCSN, csns[2], csns[3]);
      stop(server01);
      // Test with filter on draft changenumber
      filter = "(&(targetdn=*"+tn.toLowerCase()+"*,o=test)(&(changenumber>="+
          firstDraftChangeNumber+")(changenumber<="+(firstDraftChangeNumber+3)+")))";
      // Test with filter on change number
      filter =
          "(&(targetdn=*" + tn.toLowerCase() + "*,o=test)" +
               "(&(changenumber>=" + firstChangeNumber + ")" +
                     "(changenumber<=" + (firstChangeNumber + 3) + ")))";
      searchOp = searchOnChangelog(filter, tn, SUCCESS);
      assertEntries(searchOp.getSearchEntries(), firstDraftChangeNumber, tn,
      assertEntries(searchOp.getSearchEntries(), firstChangeNumber, tn,
          ldifWriter, user1entryUUID, csns[0], gblCSN, csns[2], csns[3]);
      assertEquals(searchOp.getSearchEntries().size(), nbChanges);
    }
@@ -2416,7 +2418,7 @@
  }
  private void assertEntries(List<SearchResultEntry> entries,
      int firstDraftChangeNumber, String tn, LDIFWriter ldifWriter,
      int firstChangeNumber, String tn, LDIFWriter ldifWriter,
      String user1entryUUID, CSN... csns) throws Exception
  {
    debugAndWriteEntries(ldifWriter, entries, tn);
@@ -2427,8 +2429,8 @@
    {
      i++;
      assertDnEquals(resultEntry, firstDraftChangeNumber, i - 1);
      checkValue(resultEntry, "changenumber", String.valueOf(firstDraftChangeNumber + i - 1));
      assertDnEquals(resultEntry, firstChangeNumber, i - 1);
      checkValue(resultEntry, "changenumber", String.valueOf(firstChangeNumber + i - 1));
      checkValue(resultEntry, "targetentryuuid", user1entryUUID);
      checkValue(resultEntry, "replicaidentifier", String.valueOf(SERVER_ID_1));
      final CSN csn = csns[i - 1];
@@ -2467,16 +2469,16 @@
    }
  }
  private void assertDnEquals(SearchResultEntry resultEntry, int draftCN, int i)
  private void assertDnEquals(SearchResultEntry resultEntry, int changeNumber, int i)
  {
    String actualDN = resultEntry.getDN().toNormalizedString();
    String expectedDN = "changenumber=" + (draftCN + i) + ",cn=changelog";
    String expectedDN = "changenumber=" + (changeNumber + i) + ",cn=changelog";
    assertThat(actualDN).isEqualToIgnoringCase(expectedDN);
  }
  private void ECLCompatReadFrom(int firstDraftChangeNumber) throws Exception
  private void ECLCompatReadFrom(int firstChangeNumber) throws Exception
  {
    String tn = "ECLCompatReadFrom/" + firstDraftChangeNumber;
    String tn = "ECLCompatReadFrom/" + firstChangeNumber;
    debugInfo(tn, "Starting test\n\n");
    LDIFWriter ldifWriter = getLDIFWriter();
@@ -2488,7 +2490,7 @@
    String user1entryUUID = "11111111-1112-1113-1114-111111111115";
    String filter = "(changenumber=" + firstDraftChangeNumber + ")";
    String filter = "(changenumber=" + firstChangeNumber + ")";
    InternalSearchOperation searchOp = searchOnChangelog(filter, tn, SUCCESS);
    List<SearchResultEntry> entries = searchOp.getSearchEntries();
@@ -2514,9 +2516,9 @@
   * Process similar search as but only check that there's no control returned
   * as part of the entry.
   */
  private void ECLCompatNoControl(int firstDraftChangeNumber) throws Exception
  private void ECLCompatNoControl(int firstChangeNumber) throws Exception
  {
    String tn = "ECLCompatNoControl/" + firstDraftChangeNumber;
    String tn = "ECLCompatNoControl/" + firstChangeNumber;
    debugInfo(tn, "Starting test\n\n");
    // Creates broker on o=test
@@ -2524,7 +2526,7 @@
        openReplicationSession(DN.decode(TEST_ROOT_DN_STRING), SERVER_ID_1, 100,
            replicationServerPort, brokerSessionTimeout, true);
    String filter = "(changenumber=" + firstDraftChangeNumber + ")";
    String filter = "(changenumber=" + firstChangeNumber + ")";
    InternalSearchOperation searchOp = searchOnChangelog(filter, tn, SUCCESS);
    List<SearchResultEntry> entries = searchOp.getSearchEntries();
@@ -2539,30 +2541,29 @@
  }
  /**
   * Read the ECL in compat mode from firstDraftChangeNumber and to
   * lastDraftChangeNumber.
   * Read the ECL in compat mode from firstChangeNumber and to lastChangeNumber.
   *
   * @param firstDraftChangeNumber the lower limit
   * @param lastDraftChangeNumber  the higher limit
   * @param firstChangeNumber
   *          the lower limit
   * @param lastChangeNumber
   *          the higher limit
   */
  private void ECLCompatReadFromTo(int firstDraftChangeNumber,
      int lastDraftChangeNumber) throws Exception
  private void ECLCompatReadFromTo(int firstChangeNumber, int lastChangeNumber) throws Exception
  {
    String tn = "ECLCompatReadFromTo/" + firstDraftChangeNumber + "/" + lastDraftChangeNumber;
    String tn = "ECLCompatReadFromTo/" + firstChangeNumber + "/" + lastChangeNumber;
    debugInfo(tn, "Starting test\n\n");
    String filter = "(&(changenumber>=" + firstDraftChangeNumber + ")" +
        "(changenumber<="+ lastDraftChangeNumber + "))";
    String filter =
        "(&(changenumber>=" + firstChangeNumber + ")" + "(changenumber<=" + lastChangeNumber + "))";
    InternalSearchOperation searchOp = searchOnChangelog(filter, tn, SUCCESS);
    assertEquals(searchOp.getSearchEntries().size(),
        lastDraftChangeNumber - firstDraftChangeNumber + 1);
    assertEquals(searchOp.getSearchEntries().size(), lastChangeNumber - firstChangeNumber + 1);
    debugAndWriteEntries(null, searchOp.getSearchEntries(), tn);
    debugInfo(tn, "Ending test with success");
  }
  /**
   * Read the ECL in compat mode providing an unknown draft changenumber.
   * Read the ECL in compat mode providing an unknown change number.
   */
  private void ECLCompatBadSeqnum() throws Exception
  {
@@ -2577,7 +2578,7 @@
  }
  /**
   * Read the ECL in compat mode providing an unknown draft changenumber.
   * Read the ECL in compat mode providing an unknown change number.
   */
  private void ECLFilterOnReplicationCsn() throws Exception
  {
@@ -2603,9 +2604,8 @@
  }
  /**
   * Test that different values of filter are correctly decoded
   * to find if the search op on the ECL can be optimized
   * regarding the Draft changenumbers.
   * Test that different values of filter are correctly decoded to find if the
   * search op on the ECL can be optimized regarding the change numbers.
   */
  private void ECLFilterTest() throws Exception
  {
@@ -2624,7 +2624,7 @@
        final StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
        ECLSearchOperation.evaluateSearchParameters(startCLmsg,
            baseDN, SearchFilter.createFilterFromString("(&(changenumber>=2)(changenumber<+5))"));
        assertEquals(startCLmsg.getFirstDraftChangeNumber(), 1);
        assertEquals(startCLmsg.getFirstChangeNumber(), 1);
      }
      catch (DirectoryException expected)
      {
@@ -2659,13 +2659,13 @@
  }
  private StartECLSessionMsg evaluateSearchParameters(DN baseDN,
      int firstDraftCN, int lastDraftCN, String filterString) throws Exception
      int firstChangeNumber, int lastChangeNumber, String filterString) throws Exception
  {
    final StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
    ECLSearchOperation.evaluateSearchParameters(startCLmsg, baseDN,
        SearchFilter.createFilterFromString(filterString));
    assertEquals(startCLmsg.getFirstDraftChangeNumber(), firstDraftCN);
    assertEquals(startCLmsg.getLastDraftChangeNumber(), lastDraftCN);
    assertEquals(startCLmsg.getFirstChangeNumber(), firstChangeNumber);
    assertEquals(startCLmsg.getLastChangeNumber(), lastChangeNumber);
    return startCLmsg;
  }
@@ -2924,9 +2924,9 @@
      ReplicationServer rs = eclwe.getReplicationServer();
      rs.disableEligibility(excludedDomains);
      long t1 = TimeThread.getTime();
      int[] limitss = replicationServer.getECLDraftCNLimits(
      int[] limits = replicationServer.getECLChangeNumberLimits(
          replicationServer.getEligibleCSN(), excludedDomains);
      assertEquals(limitss[1], maxMsg);
      assertEquals(limits[1], maxMsg);
      long t2 = TimeThread.getTime();
      debugInfo(tn, "Perfs - " + maxMsg + " counted in (ms):" + (t2 - t1));
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
@@ -666,7 +666,7 @@
    CSN csn = new CSN(TimeThread.getTime(), 123, 45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(csn, "uniqueid"));
    DeleteMsg delmsg = new DeleteMsg(op);
    int draftCN = 21;
    int changeNumber = 21;
    String baseDN = "dc=example,dc=com";
@@ -677,10 +677,10 @@
          "o=test2:000001210b6f21e904b100000002 000001210b6f21e904b200000002;");
    // Constructor test
    ECLUpdateMsg msg1 = new ECLUpdateMsg(delmsg, cookie, baseDN, draftCN);
    ECLUpdateMsg msg1 = new ECLUpdateMsg(delmsg, cookie, baseDN, changeNumber);
    assertTrue(msg1.getCookie().equalsTo(cookie));
    assertTrue(msg1.getBaseDN().equalsIgnoreCase(baseDN));
    assertEquals(msg1.getDraftChangeNumber(), draftCN);
    assertEquals(msg1.getChangeNumber(), changeNumber);
    DeleteMsg delmsg2 = (DeleteMsg)msg1.getUpdateMsg();
    assertEquals(delmsg.compareTo(delmsg2), 0);
@@ -690,8 +690,8 @@
    assertTrue(msg2.getCookie().equalsTo(cookie));
    assertTrue(msg2.getBaseDN().equalsIgnoreCase(msg1.getBaseDN()));
    assertTrue(msg2.getBaseDN().equalsIgnoreCase(baseDN));
    assertEquals(msg2.getDraftChangeNumber(), msg1.getDraftChangeNumber());
    assertEquals(msg2.getDraftChangeNumber(), draftCN);
    assertEquals(msg2.getChangeNumber(), msg1.getChangeNumber());
    assertEquals(msg2.getChangeNumber(), changeNumber);
    DeleteMsg delmsg1 = (DeleteMsg)msg1.getUpdateMsg();
    delmsg2 = (DeleteMsg)msg2.getUpdateMsg();
@@ -1330,8 +1330,8 @@
    msg.setCSN(csn);
    msg.setCrossDomainServerState("fakegenstate");
    msg.setPersistent(StartECLSessionMsg.PERSISTENT);
    msg.setFirstDraftChangeNumber(13);
    msg.setLastDraftChangeNumber(14);
    msg.setFirstChangeNumber(13);
    msg.setLastChangeNumber(14);
    msg.setECLRequestType((short) 3);
    msg.setOperationId("fakeopid");
    String dn1 = "cn=admin data";
@@ -1343,9 +1343,9 @@
    // test equality between the two copies
    assertEquals(msg.getCSN(), newMsg.getCSN());
    assertEquals(msg.isPersistent(), newMsg.isPersistent());
    assertEquals(msg.getFirstDraftChangeNumber(), newMsg.getFirstDraftChangeNumber());
    assertEquals(msg.getFirstChangeNumber(), newMsg.getFirstChangeNumber());
    assertEquals(msg.getECLRequestType(), newMsg.getECLRequestType());
    assertEquals(msg.getLastDraftChangeNumber(), newMsg.getLastDraftChangeNumber());
    assertEquals(msg.getLastChangeNumber(), newMsg.getLastChangeNumber());
    assertTrue(msg.getCrossDomainServerState().equalsIgnoreCase(newMsg.getCrossDomainServerState()));
    assertTrue(msg.getOperationId().equalsIgnoreCase(newMsg.getOperationId()));
    Set<String> dns2 = newMsg.getExcludedBaseDNs();
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/changelog/je/DraftCNDbHandlerTest.java
@@ -87,9 +87,9 @@
      handler.setPurgeDelay(0);
      // Prepare data to be stored in the db
      int sn1 = 3;
      int sn2 = 4;
      int sn3 = 5;
      int cn1 = 3;
      int cn2 = 4;
      int cn3 = 5;
      String value1 = "value1";
      String value2 = "value2";
@@ -105,16 +105,16 @@
      CSN csn3 = gen.newCSN();
      // Add records
      handler.add(sn1, value1, baseDN1, csn1);
      handler.add(sn2, value2, baseDN2, csn2);
      handler.add(sn3, value3, baseDN3, csn3);
      handler.add(cn1, value1, baseDN1, csn1);
      handler.add(cn2, value2, baseDN2, csn2);
      handler.add(cn3, value3, baseDN3, csn3);
      // The ChangeNumber should not get purged
      final int firstDraftCN = handler.getFirstDraftCN();
      assertEquals(firstDraftCN, sn1);
      assertEquals(handler.getLastDraftCN(), sn3);
      final int firstChangeNumber = handler.getFirstChangeNumber();
      assertEquals(firstChangeNumber, cn1);
      assertEquals(handler.getLastChangeNumber(), cn3);
      DraftCNDBCursor dbc = handler.getReadCursor(firstDraftCN);
      DraftCNDBCursor dbc = handler.getReadCursor(firstChangeNumber);
      try
      {
        assertEquals(dbc.currentCSN(), csn1);
@@ -148,11 +148,10 @@
      {
        Thread.sleep(200);
      }
      assertEquals(handler.getFirstDraftCN(), 0);
      assertEquals(handler.getLastDraftCN(), 0);
    } finally
      assertEquals(handler.getFirstChangeNumber(), 0);
      assertEquals(handler.getLastChangeNumber(), 0);
    }
    finally
    {
      if (handler != null)
        handler.shutdown();
@@ -214,9 +213,9 @@
      assertTrue(handler.isEmpty());
      // Prepare data to be stored in the db
      int sn1 = 3;
      int sn2 = 4;
      int sn3 = 5;
      int cn1 = 3;
      int cn2 = 4;
      int cn3 = 5;
      String value1 = "value1";
      String value2 = "value2";
@@ -232,37 +231,38 @@
      CSN csn3 = gen.newCSN();
      // Add records
      handler.add(sn1, value1, baseDN1, csn1);
      handler.add(sn2, value2, baseDN2, csn2);
      handler.add(sn3, value3, baseDN3, csn3);
      handler.add(cn1, value1, baseDN1, csn1);
      handler.add(cn2, value2, baseDN2, csn2);
      handler.add(cn3, value3, baseDN3, csn3);
      Thread.sleep(500);
      // Checks
      assertEquals(handler.getFirstDraftCN(), sn1);
      assertEquals(handler.getLastDraftCN(), sn3);
      assertEquals(handler.getFirstChangeNumber(), cn1);
      assertEquals(handler.getLastChangeNumber(), cn3);
      assertEquals(handler.count(), 3, "Db count");
      assertEquals(handler.getPreviousCookie(sn1),value1);
      assertEquals(handler.getPreviousCookie(sn2),value2);
      assertEquals(handler.getPreviousCookie(sn3),value3);
      assertEquals(handler.getPreviousCookie(cn1), value1);
      assertEquals(handler.getPreviousCookie(cn2), value2);
      assertEquals(handler.getPreviousCookie(cn3), value3);
      ChangeNumberIndexDBCursor cursor = handler.getCursorFrom(sn1);
      assertCursorReadsInOrder(cursor, sn1, sn2, sn3);
      ChangeNumberIndexDBCursor cursor = handler.getCursorFrom(cn1);
      assertCursorReadsInOrder(cursor, cn1, cn2, cn3);
      cursor = handler.getCursorFrom(sn2);
      assertCursorReadsInOrder(cursor, sn2, sn3);
      cursor = handler.getCursorFrom(cn2);
      assertCursorReadsInOrder(cursor, cn2, cn3);
      cursor = handler.getCursorFrom(sn3);
      assertCursorReadsInOrder(cursor, sn3);
      cursor = handler.getCursorFrom(cn3);
      assertCursorReadsInOrder(cursor, cn3);
      handler.clear();
      // Check the db is cleared.
      assertEquals(handler.getFirstDraftCN(), 0);
      assertEquals(handler.getLastDraftCN(), 0);
      assertEquals(handler.getFirstChangeNumber(), 0);
      assertEquals(handler.getLastChangeNumber(), 0);
      assertEquals(handler.count(), 0);
    } finally
    }
    finally
    {
      if (handler != null)
        handler.shutdown();
@@ -281,7 +281,7 @@
    {
      for (int i = 0; i < sns.length; i++)
      {
        assertEquals(cursor.getDraftCN(), sns[i]);
        assertEquals(cursor.getChangeNumber(), sns[i]);
        final boolean isNotLast = i + 1 < sns.length;
        assertEquals(cursor.next(), isNotLast);
      }