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 }