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.hbase.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     * @return the sleep period in milliseconds
69     */
70    public final int getPeriod() {
71      return sleeper.getPeriod();
72    }
73  
74    /**
75     * @see java.lang.Thread#run()
76     */
77    @Override
78    public void run() {
79      try {
80        boolean initialChoreComplete = false;
81        while (!this.stopper.isStopped()) {
82          long startTime = System.currentTimeMillis();
83          try {
84            if (!initialChoreComplete) {
85              initialChoreComplete = initialChore();
86            } else {
87              chore();
88            }
89          } catch (Exception e) {
90            LOG.error("Caught exception", e);
91            if (this.stopper.isStopped()) {
92              continue;
93            }
94          }
95          this.sleeper.sleep(startTime);
96        }
97      } catch (Throwable t) {
98        LOG.fatal(getName() + "error", t);
99      } finally {
100       LOG.info(getName() + " exiting");
101       cleanup();
102     }
103   }
104 
105   /**
106    * If the thread is currently sleeping, trigger the core to happen immediately.
107    * If it's in the middle of its operation, will begin another operation
108    * immediately after finishing this one.
109    */
110   public void triggerNow() {
111     this.sleeper.skipSleepCycle();
112   }
113 
114   /*
115    * Exposed for TESTING!
116    * calls directly the chore method, from the current thread.
117    */
118   public void choreForTesting() {
119     chore();
120   }
121 
122   /**
123    * Override to run a task before we start looping.
124    * @return true if initial chore was successful
125    */
126   protected boolean initialChore() {
127     // Default does nothing.
128     return true;
129   }
130 
131   /**
132    * Look for chores.  If any found, do them else just return.
133    */
134   protected abstract void chore();
135 
136   /**
137    * Sleep for period.
138    */
139   protected void sleep() {
140     this.sleeper.sleep();
141   }
142 
143   /**
144    * Called when the chore has completed, allowing subclasses to cleanup any
145    * extra overhead
146    */
147   protected void cleanup() {
148   }
149 }