View Javadoc
1   package org.apache.commons.jcs.auxiliary;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.concurrent.atomic.AtomicBoolean;
23  import java.util.concurrent.locks.Condition;
24  import java.util.concurrent.locks.Lock;
25  import java.util.concurrent.locks.ReentrantLock;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  /**
31   * Used to monitor and repair any failed connection for the lateral cache service. By default the
32   * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
33   * error. Upon the notification of a connection error, the monitor changes to operate in a time
34   * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
35   * connections are restored, it changes back to the failure driven mode.
36   */
37  public abstract class AbstractAuxiliaryCacheMonitor extends Thread
38  {
39      /** The logger */
40      protected final Log log = LogFactory.getLog( this.getClass() );
41  
42      /** How long to wait between runs */
43      protected static long idlePeriod = 20 * 1000;
44  
45      /**
46       * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected!
47       */
48      protected AtomicBoolean allright = new AtomicBoolean(true);
49  
50      /**
51       * shutdown flag
52       */
53      private AtomicBoolean shutdown = new AtomicBoolean(false);
54  
55      /** Synchronization helper lock */
56      private Lock lock = new ReentrantLock();
57  
58      /** Synchronization helper condition */
59      private Condition trigger = lock.newCondition();
60  
61      /**
62       * Constructor
63       *
64       * @param name the thread name
65       */
66      public AbstractAuxiliaryCacheMonitor(String name)
67      {
68          super(name);
69      }
70  
71      /**
72       * Configures the idle period between repairs.
73       * <p>
74       * @param idlePeriod The new idlePeriod value
75       */
76      public static void setIdlePeriod( long idlePeriod )
77      {
78          if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod )
79          {
80              AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod;
81          }
82      }
83  
84      /**
85       * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
86       */
87      public void notifyError()
88      {
89          if (allright.compareAndSet(true, false))
90          {
91              signalTrigger();
92          }
93      }
94  
95      /**
96       * Notifies the cache monitor that the service shall shut down
97       */
98      public void notifyShutdown()
99      {
100         if (shutdown.compareAndSet(false, true))
101         {
102             signalTrigger();
103         }
104     }
105 
106     // Trigger continuation of loop
107     private void signalTrigger()
108     {
109         try
110         {
111             lock.lock();
112             trigger.signal();
113         }
114         finally
115         {
116             lock.unlock();
117         }
118     }
119 
120     /**
121      * Clean up all resources before shutdown
122      */
123     protected abstract void dispose();
124 
125     /**
126      * do actual work
127      */
128     protected abstract void doWork();
129 
130     /**
131      * Main processing method for the AbstractAuxiliaryCacheMonitor object
132      */
133     @Override
134     public void run()
135     {
136         do
137         {
138             if ( log.isDebugEnabled() )
139             {
140                 if ( allright.get() )
141                 {
142                     log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." );
143                 }
144                 else
145                 {
146                     log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." );
147                 }
148             }
149 
150             if ( allright.get() )
151             {
152                 // Failure driven mode.
153                 try
154                 {
155                     lock.lock();
156                     trigger.await();
157                     // wake up only if there is an error.
158                 }
159                 catch ( InterruptedException ignore )
160                 {
161                     //no op, this is expected
162                 }
163                 finally
164                 {
165                     lock.unlock();
166                 }
167             }
168 
169             // check for requested shutdown
170             if ( shutdown.get() )
171             {
172                 log.info( "Shutting down cache monitor" );
173                 dispose();
174                 return;
175             }
176 
177             // The "allright" flag must be false here.
178             // Simply presume we can fix all the errors until proven otherwise.
179             allright.set(true);
180 
181             if ( log.isDebugEnabled() )
182             {
183                 log.debug( "Cache monitor running." );
184             }
185 
186             doWork();
187 
188             try
189             {
190                 // don't want to sleep after waking from an error
191                 // run immediately and sleep here.
192                 if ( log.isDebugEnabled() )
193                 {
194                     log.debug( "Cache monitor sleeping for " + idlePeriod + " between runs." );
195                 }
196 
197                 Thread.sleep( idlePeriod );
198             }
199             catch ( InterruptedException ex )
200             {
201                 // ignore;
202             }
203         }
204         while ( true );
205     }
206 }