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 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.replication.server;
028
029 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
030 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
031
032 import java.util.Iterator;
033 import java.util.concurrent.ConcurrentHashMap;
034
035 import org.opends.server.loggers.debug.DebugTracer;
036 import org.opends.server.replication.common.ChangeNumber;
037 import org.opends.server.replication.common.ServerState;
038 import org.opends.server.util.TimeThread;
039
040 /**
041 * This class defines the Monitor Data that are consolidated across the
042 * whole replication topology.
043 */
044 public class MonitorData
045 {
046 /**
047 * The tracer object for the debug logger.
048 */
049 private static final DebugTracer TRACER = getTracer();
050
051 /**
052 *
053 * - For each server, the max (most recent) CN produced
054 *
055 * - For each server, its state i.e. the last processed from of each
056 * other LDAP server.
057 * The change latency (missing changes) will be
058 * the difference between the max above and the state here
059 *
060 * - For each server, the date of the first missing change.
061 * The time latency (delay) will be the difference between now and the
062 * date of the first missing change.
063 */
064
065 /* The date of the last time they have been elaborated */
066 private long buildDate = 0;
067
068 // For each LDAP server, its server state
069 private ConcurrentHashMap<Short, ServerState> LDAPStates =
070 new ConcurrentHashMap<Short, ServerState>();
071
072 // For each LDAP server, the last(max) CN it published
073 private ConcurrentHashMap<Short, ChangeNumber> maxCNs =
074 new ConcurrentHashMap<Short, ChangeNumber>();
075
076 // For each LDAP server, an approximation of the date of the first missing
077 // change
078 private ConcurrentHashMap<Short, Long> fmd =
079 new ConcurrentHashMap<Short, Long>();
080
081 private ConcurrentHashMap<Short, Long> missingChanges =
082 new ConcurrentHashMap<Short, Long>();
083
084 // For each RS server, an approximation of the date of the first missing
085 // change
086 private ConcurrentHashMap<Short, Long> fmRSDate =
087 new ConcurrentHashMap<Short, Long>();
088
089
090 /**
091 * Get an approximation of the latency delay of the replication.
092 * @param serverId The server ID.
093 * @return The delay
094 */
095 public long getApproxDelay(short serverId)
096 {
097 Long afmd = fmd.get(serverId);
098 if ((afmd != null) && (afmd>0))
099 return ((this.getBuildDate() - afmd)/1000);
100 else
101 return 0;
102 }
103
104 /**
105 * Get an approximation of the date of the first missing update.
106 * @param serverId The server ID.
107 * @return The date.
108 */
109 public long getApproxFirstMissingDate(short serverId)
110 {
111 Long res;
112 if ((res = fmd.get(serverId)) != null)
113 return res;
114 return 0;
115 }
116
117 /**
118 * Get the number of missing changes.
119 * @param serverId The server ID.
120 * @return The number of missing changes.
121 */
122 public long getMissingChanges(short serverId)
123 {
124 Long res = missingChanges.get(serverId);
125 if (res==null)
126 return 0;
127 else
128 return res;
129 }
130
131 /**
132 * Build the monitor data that are computed from the collected ones.
133 */
134 public void completeComputing()
135 {
136 String mds = "";
137
138 // Computes the missing changes counters
139 // For each LSi ,
140 // Regarding each other LSj
141 // Sum the difference : max(LSj) - state(LSi)
142
143 Iterator<Short> lsiStateItr = this.LDAPStates.keySet().iterator();
144 while (lsiStateItr.hasNext())
145 {
146 Short lsiSid = lsiStateItr.next();
147 ServerState lsiState = this.LDAPStates.get(lsiSid);
148 Long lsiMissingChanges = (long)0;
149 if (lsiState != null)
150 {
151 Iterator<Short> lsjMaxItr = this.maxCNs.keySet().iterator();
152 while (lsjMaxItr.hasNext())
153 {
154 Short lsjSid = lsjMaxItr.next();
155 ChangeNumber lsjMaxCN = this.maxCNs.get(lsjSid);
156 ChangeNumber lsiLastCN = lsiState.getMaxChangeNumber(lsjSid);
157
158 int missingChangesLsiLsj =
159 ChangeNumber.diffSeqNum(lsjMaxCN, lsiLastCN);
160
161 mds +=
162 "+ diff("+lsjMaxCN+"-"
163 +lsiLastCN+")="+missingChangesLsiLsj;
164
165 lsiMissingChanges += missingChangesLsiLsj;
166 }
167 }
168 mds += "=" + lsiMissingChanges;
169 this.missingChanges.put(lsiSid,lsiMissingChanges);
170
171 if (debugEnabled())
172 TRACER.debugInfo(
173 "Complete monitor data : Missing changes ("+ lsiSid +")=" + mds);
174 }
175 this.setBuildDate(TimeThread.getTime());
176 }
177
178 /**
179 * Returns a <code>String</code> object representing this
180 * object's value.
181 * @return a string representation of the value of this object in
182 */
183 public String toString()
184 {
185 String mds = "Monitor data=\n";
186
187 mds+= "Build date=" + this.getBuildDate();
188 // RS data
189 Iterator<Short> rsite = fmRSDate.keySet().iterator();
190 while (rsite.hasNext())
191 {
192 Short sid = rsite.next();
193 mds += "\nRSData(" + sid + ")=\t "+ "afmd=" + fmRSDate.get(sid);
194 }
195
196 // maxCNs
197 Iterator<Short> itc = maxCNs.keySet().iterator();
198 while (itc.hasNext())
199 {
200 Short sid = itc.next();
201 ChangeNumber cn = maxCNs.get(sid);
202 mds += "\nmaxCNs(" + sid + ")= " + cn.toString();
203 }
204
205 // LDAP data
206 Iterator<Short> lsite = LDAPStates.keySet().iterator();
207 while (lsite.hasNext())
208 {
209 Short sid = lsite.next();
210 ServerState ss = LDAPStates.get(sid);
211 mds += "\nLSData(" + sid + ")=\t" + "state=[" + ss.toString()
212 + "] afmd=" + this.getApproxFirstMissingDate(sid);
213 if (getBuildDate()>0)
214 {
215 mds += " missingDelay=" + this.getApproxDelay(sid);
216 }
217 mds +=" missingCount=" + missingChanges.get(sid);
218 }
219 //
220 mds += "--";
221 return mds;
222 }
223
224 /**
225 * Sets the build date of the data.
226 * @param buildDate The date.
227 */
228 public void setBuildDate(long buildDate)
229 {
230 this.buildDate = buildDate;
231 }
232
233 /**
234 * Returns the build date of the data.
235 * @return The date.
236 */
237 public long getBuildDate()
238 {
239 return buildDate;
240 }
241
242 /**
243 * From a provided state, sets the max CN of the monitor data.
244 * @param state the provided state.
245 */
246 public void setMaxCNs(ServerState state)
247 {
248 Iterator<Short> it = state.iterator();
249 while (it.hasNext())
250 {
251 short sid = it.next();
252 ChangeNumber newCN = state.getMaxChangeNumber(sid);
253 setMaxCN(sid, newCN);
254 }
255 }
256
257 /**
258 * For the provided serverId, sets the provided CN as the max if
259 * it is newer than the current max.
260 * @param serverId the provided serverId
261 * @param newCN the provided new CN
262 */
263 public void setMaxCN(short serverId, ChangeNumber newCN)
264 {
265 if (newCN==null) return;
266 ChangeNumber currentMaxCN = maxCNs.get(serverId);
267 if (currentMaxCN == null)
268 {
269 maxCNs.put(serverId, newCN);
270 }
271 else
272 {
273 if (newCN.newer(currentMaxCN))
274 maxCNs.replace(serverId, newCN);
275 }
276 }
277
278 /**
279 * Get the highest know change number of the LDAP server with the provided
280 * serverId.
281 * @param serverId The server ID.
282 * @return The highest change number.
283 */
284 public ChangeNumber getMaxCN(short serverId)
285 {
286 return maxCNs.get(serverId);
287 }
288
289 /**
290 * Get the state of the LDAP server with the provided serverId.
291 * @param serverId The server ID.
292 * @return The server state.
293 */
294 public ServerState getLDAPServerState(short serverId)
295 {
296 return LDAPStates.get(serverId);
297 }
298
299 /**
300 * Set the state of the LDAP server with the provided serverId.
301 * @param serverId The server ID.
302 * @param state The server state.
303 */
304 public void setLDAPServerState(short serverId, ServerState state)
305 {
306 LDAPStates.put(serverId, state);
307 }
308
309 /**
310 * Set the state of the LDAP server with the provided serverId.
311 * @param serverId The server ID.
312 * @param newFmd The first missing date.
313 */
314 public void setFirstMissingDate(short serverId, Long newFmd)
315 {
316 if (newFmd==null) return;
317 Long currentfmd = fmd.get(serverId);
318 if (currentfmd==null)
319 {
320 fmd.put(serverId, newFmd);
321 }
322 else
323 {
324 if ((newFmd!=0) && (newFmd<currentfmd))
325 fmd.replace(serverId, newFmd);
326 }
327 }
328
329 }