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.EnvironmentEdgeManager;
25  import org.apache.hadoop.hbase.util.HasThread;
26  import org.apache.hadoop.hbase.util.Sleeper;
27  
28  /**
29   * Chore is a task performed on a period in hbase.  The chore is run in its own
30   * thread. This base abstract class provides while loop and sleeping facility.
31   * If an unhandled exception, the threads exit is logged.
32   * Implementers just need to add checking if there is work to be done and if
33   * so, do it.  Its the base of most of the chore threads in hbase.
34   *
35   * <p>Don't subclass Chore if the task relies on being woken up for something to
36   * do, such as an entry being added to a queue, etc.
37   */
38  @InterfaceAudience.Private
39  public abstract class Chore extends HasThread {
40    private final Log LOG = LogFactory.getLog(this.getClass());
41    private final Sleeper sleeper;
42    protected final Stoppable stopper;
43  
44    /**
45     * @param p Period at which we should run.  Will be adjusted appropriately
46     * should we find work and it takes time to complete.
47     * @param stopper When {@link Stoppable#isStopped()} is true, this thread will
48     * cleanup and exit cleanly.
49     */
50    public Chore(String name, final int p, final Stoppable stopper) {
51      super(name);
52      if (stopper == null){
53        throw new NullPointerException("stopper cannot be null");
54      }
55      this.sleeper = new Sleeper(p, stopper);
56      this.stopper = stopper;
57    }
58  
59    /**
60     * This constructor is for test only. It allows to create an object and to call chore() on
61     *  it. There is no sleeper nor stoppable.
62     */
63    protected Chore(){
64      sleeper = null;
65      stopper = null;
66    }
67  
68    /**
69     * @see java.lang.Thread#run()
70     */
71    @Override
72    public void run() {
73      try {
74        boolean initialChoreComplete = false;
75        while (!this.stopper.isStopped()) {
76          long startTime = EnvironmentEdgeManager.currentTimeMillis();
77          try {
78            if (!initialChoreComplete) {
79              initialChoreComplete = initialChore();
80            } else {
81              chore();
82            }
83          } catch (Exception e) {
84            LOG.error("Caught exception", e);
85            if (this.stopper.isStopped()) {
86              continue;
87            }
88          }
89          this.sleeper.sleep(startTime);
90        }
91      } catch (Throwable t) {
92        LOG.fatal(getName() + "error", t);
93      } finally {
94        LOG.info(getName() + " exiting");
95        cleanup();
96      }
97    }
98  
99    /**
100    * If the thread is currently sleeping, trigger the core to happen immediately.
101    * If it's in the middle of its operation, will begin another operation
102    * immediately after finishing this one.
103    */
104   public void triggerNow() {
105     this.sleeper.skipSleepCycle();
106   }
107 
108   /*
109    * Exposed for TESTING!
110    * calls directly the chore method, from the current thread.
111    */
112   public void choreForTesting() {
113     chore();
114   }
115 
116   /**
117    * Override to run a task before we start looping.
118    * @return true if initial chore was successful
119    */
120   protected boolean initialChore() {
121     // Default does nothing.
122     return true;
123   }
124 
125   /**
126    * Look for chores.  If any found, do them else just return.
127    */
128   protected abstract void chore();
129 
130   /**
131    * Sleep for period.
132    */
133   protected void sleep() {
134     this.sleeper.sleep();
135   }
136 
137   /**
138    * Called when the chore has completed, allowing subclasses to cleanup any
139    * extra overhead
140    */
141   protected void cleanup() {
142   }
143 }