001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.replication.common;
028    
029    import org.opends.server.util.TimeThread;
030    
031    /**
032     * This class defines a structure that is used for storing the
033     * last change numbers generated on this server or received from other servers
034     * and generating new changenumbers that are guaranteed to be larger than
035     * all the previously seen or generated change numbers.
036     */
037    public class ChangeNumberGenerator
038    {
039      private long lastTime;
040      private int seqnum;
041      private short serverId;
042    
043      /**
044       * Create a new ChangeNumber Generator.
045       * @param id id to use when creating change numbers.
046       * @param timestamp time to start with.
047       */
048      public ChangeNumberGenerator(short id, long timestamp)
049      {
050        this.lastTime = timestamp;
051        this.serverId = id;
052        this.seqnum = 0;
053      }
054    
055      /**
056      * Create a new ChangeNumber Generator.
057      *
058      * @param id id to use when creating change numbers.
059      * @param state This generator will be created in a way that makes sure that
060      *              all change numbers generated will be larger than all the
061      *              changenumbers currently in state.
062      */
063     public ChangeNumberGenerator(short id, ServerState state)
064     {
065       this.lastTime = TimeThread.getTime();
066       for (short stateId : state)
067       {
068         if (this.lastTime < state.getMaxChangeNumber(stateId).getTime())
069           this.lastTime = state.getMaxChangeNumber(stateId).getTime();
070         if (stateId == id)
071           this.seqnum = state.getMaxChangeNumber(id).getSeqnum();
072       }
073       this.serverId = id;
074    
075     }
076    
077      /**
078       * Generate a new ChangeNumber.
079       *
080       * @return the generated ChangeNUmber
081       */
082      public ChangeNumber newChangeNumber()
083      {
084        long curTime = TimeThread.getTime();
085    
086        synchronized(this)
087        {
088          if (curTime > lastTime)
089          {
090            lastTime = curTime;
091          }
092    
093          if (seqnum++ == 0)
094          {
095            lastTime++;
096          }
097        }
098    
099        return new ChangeNumber(lastTime, seqnum, serverId);
100      }
101    
102      /**
103       * Adjust the lastTime of this Changenumber generator with
104       * a ChangeNumber that we have received from another server.
105       * This is necessary because we need that the changenumber generated
106       * after processing an update received from other hosts to be larger
107       * than the received changenumber
108       *
109       * @param number the ChangeNumber to adjust with
110       */
111      public void adjust(ChangeNumber number)
112      {
113        if (number==null)
114        {
115          lastTime = TimeThread.getTime();
116          seqnum = 0;
117          return;
118        }
119    
120        long rcvdTime = number.getTime();
121    
122        /* need to synchronize with NewChangeNumber method so that we
123         * protect writing lastTime fields
124         */
125        synchronized(this)
126        {
127          if (lastTime > rcvdTime)
128            return;
129          else
130            lastTime = rcvdTime++;
131        }
132      }
133    }