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    }