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 2007-2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.replication.plugin;
029    
030    import static org.opends.messages.ReplicationMessages.*;
031    import static org.opends.server.loggers.ErrorLogger.logError;
032    import static org.opends.server.loggers.debug.DebugLogger.*;
033    import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
034    
035    import org.opends.server.loggers.debug.DebugTracer;
036    
037    import java.io.IOException;
038    
039    import org.opends.server.api.DirectoryThread;
040    import org.opends.server.replication.protocol.ProtocolSession;
041    
042    /**
043     * This class implements a thread to monitor heartbeat messages from the
044     * replication server.  Each broker runs one of these threads.
045     */
046    public class HeartbeatMonitor extends DirectoryThread
047    {
048      /**
049       * The tracer object for the debug logger.
050       */
051      private static final DebugTracer TRACER = getTracer();
052    
053    
054    
055      /**
056       * The session on which heartbeats are to be monitored.
057       */
058      private ProtocolSession session;
059    
060    
061      /**
062       * The time in milliseconds between heartbeats from the replication
063       * server.  Zero means heartbeats are off.
064       */
065      private long heartbeatInterval;
066    
067    
068      /**
069       * Set this to stop the thread.
070       */
071      private boolean shutdown = false;
072    
073    
074      /**
075       * Create a heartbeat monitor thread.
076       * @param threadName The name of the heartbeat thread.
077       * @param session The session on which heartbeats are to be monitored.
078       * @param heartbeatInterval The expected interval between heartbeats in
079       * milliseconds.
080       */
081      public HeartbeatMonitor(String threadName, ProtocolSession session,
082                              long heartbeatInterval)
083      {
084        super(threadName);
085        this.session = session;
086        this.heartbeatInterval = heartbeatInterval;
087      }
088    
089      /**
090       * Call this method to stop the thread.
091       */
092      public void shutdown()
093      {
094        shutdown = true;
095      }
096    
097    
098      /**
099       * {@inheritDoc}
100       */
101      @Override
102      public void run()
103      {
104        boolean gotOneFailure = false;
105        if (debugEnabled())
106        {
107          TRACER.debugInfo("Heartbeat monitor is starting, expected interval is " +
108                    heartbeatInterval +
109              stackTraceToSingleLineString(new Exception()));
110        }
111        try
112        {
113          while (!shutdown)
114          {
115            long now = System.currentTimeMillis();
116            long lastReceiveTime = session.getLastReceiveTime();
117            if (now > lastReceiveTime + heartbeatInterval)
118            {
119              if (gotOneFailure == true)
120              {
121                // Heartbeat is well overdue so the server is assumed to be dead.
122                logError(NOTE_HEARTBEAT_FAILURE.get(currentThread().getName()));
123                session.close();
124                break;
125              }
126              else
127              {
128                gotOneFailure = true;
129              }
130            }
131            else
132            {
133              gotOneFailure = false;
134            }
135            try
136            {
137              Thread.sleep(heartbeatInterval);
138            }
139            catch (InterruptedException e)
140            {
141              // That's OK.
142            }
143          }
144        }
145        catch (IOException e)
146        {
147          // Hope that's OK.
148        }
149        finally
150        {
151          if (debugEnabled())
152          {
153            TRACER.debugInfo("Heartbeat monitor is exiting." +
154                stackTraceToSingleLineString(new Exception()));
155          }
156        }
157      }
158    }