View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.util.HasThread;
25  import org.apache.hadoop.hbase.util.Sleeper;
26  
27  /**
28   * Chore is a task performed on a period in hbase.  The chore is run in its own
29   * thread. This base abstract class provides while loop and sleeping facility.
30   * If an unhandled exception, the threads exit is logged.
31   * Implementers just need to add checking if there is work to be done and if
32   * so, do it.  Its the base of most of the chore threads in hbase.
33   *
34   * <p>Don't subclass Chore if the task relies on being woken up for something to
35   * do, such as an entry being added to a queue, etc.
36   */
37  @InterfaceAudience.Private
38  public abstract class Chore extends HasThread {
39    private final Log LOG = LogFactory.getLog(this.getClass());
40    private final Sleeper sleeper;
41    protected final Stoppable stopper;
42  
43    /**
44     * @param p Period at which we should run.  Will be adjusted appropriately
45     * should we find work and it takes time to complete.
46     * @param stopper When {@link Stoppable#isStopped()} is true, this thread will
47     * cleanup and exit cleanly.
48     */
49    public Chore(String name, final int p, final Stoppable stopper) {
50      super(name);
51      if (stopper == null){
52        throw new NullPointerException("stopper cannot be null");
53      }
54      this.sleeper = new Sleeper(p, stopper);
55      this.stopper = stopper;
56    }
57  
58    /**
59     * This constructor is for test only. It allows to create an object and to call chore() on
60     *  it. There is no sleeper nor stoppable.
61     */
62    protected Chore(){
63      sleeper = null;
64      stopper = null;
65    }
66  
67    /**
68     * @see java.lang.Thread#run()
69     */
70    @Override
71    public void run() {
72      try {
73        boolean initialChoreComplete = false;
74        while (!this.stopper.isStopped()) {
75          long startTime = System.currentTimeMillis();
76          try {
77            if (!initialChoreComplete) {
78              initialChoreComplete = initialChore();
79            } else {
80              chore();
81            }
82          } catch (Exception e) {
83            LOG.error("Caught exception", e);
84            if (this.stopper.isStopped()) {
85              continue;
86            }
87          }
88          this.sleeper.sleep(startTime);
89        }
90      } catch (Throwable t) {
91        LOG.fatal(getName() + "error", t);
92      } finally {
93        LOG.info(getName() + " exiting");
94        cleanup();
95      }
96    }
97  
98    /**
99     * If the thread is currently sleeping, trigger the core to happen immediately.
100    * If it's in the middle of its operation, will begin another operation
101    * immediately after finishing this one.
102    */
103   public void triggerNow() {
104     this.sleeper.skipSleepCycle();
105   }
106 
107   /*
108    * Exposed for TESTING!
109    * calls directly the chore method, from the current thread.
110    */
111   public void choreForTesting() {
112     chore();
113   }
114 
115   /**
116    * Override to run a task before we start looping.
117    * @return true if initial chore was successful
118    */
119   protected boolean initialChore() {
120     // Default does nothing.
121     return true;
122   }
123 
124   /**
125    * Look for chores.  If any found, do them else just return.
126    */
127   protected abstract void chore();
128 
129   /**
130    * Sleep for period.
131    */
132   protected void sleep() {
133     this.sleeper.sleep();
134   }
135 
136   /**
137    * Called when the chore has completed, allowing subclasses to cleanup any
138    * extra overhead
139    */
140   protected void cleanup() {
141   }
142 }