View Javadoc

1   /**
2    * Copyright 2007 The Apache Software Foundation
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, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
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  public abstract class Chore extends HasThread {
38    private final Log LOG = LogFactory.getLog(this.getClass());
39    private final Sleeper sleeper;
40    protected final Stoppable stopper;
41  
42    /**
43     * @param p Period at which we should run.  Will be adjusted appropriately
44     * should we find work and it takes time to complete.
45     * @param stopper When {@link Stoppable#isStopped()} is true, this thread will
46     * cleanup and exit cleanly.
47     */
48    public Chore(String name, final int p, final Stoppable stopper) {
49      super(name);
50      this.sleeper = new Sleeper(p, stopper);
51      this.stopper = stopper;
52    }
53  
54    /**
55     * @see java.lang.Thread#run()
56     */
57    @Override
58    public void run() {
59      try {
60        boolean initialChoreComplete = false;
61        while (!this.stopper.isStopped()) {
62          long startTime = System.currentTimeMillis();
63          try {
64            if (!initialChoreComplete) {
65              initialChoreComplete = initialChore();
66            } else {
67              chore();
68            }
69          } catch (Exception e) {
70            LOG.error("Caught exception", e);
71            if (this.stopper.isStopped()) {
72              continue;
73            }
74          }
75          this.sleeper.sleep(startTime);
76        }
77      } catch (Throwable t) {
78        LOG.fatal(getName() + "error", t);
79      } finally {
80        LOG.info(getName() + " exiting");
81        cleanup();
82      }
83    }
84  
85    /**
86     * If the thread is currently sleeping, trigger the core to happen immediately.
87     * If it's in the middle of its operation, will begin another operation
88     * immediately after finishing this one.
89     */
90    public void triggerNow() {
91      this.sleeper.skipSleepCycle();
92    }
93  
94    /*
95     * Exposed for TESTING!
96     * calls directly the chore method, from the current thread.
97     */
98    public void choreForTesting() {
99      chore();
100   }
101 
102   /**
103    * Override to run a task before we start looping.
104    * @return true if initial chore was successful
105    */
106   protected boolean initialChore() {
107     // Default does nothing.
108     return true;
109   }
110 
111   /**
112    * Look for chores.  If any found, do them else just return.
113    */
114   protected abstract void chore();
115 
116   /**
117    * Sleep for period.
118    */
119   protected void sleep() {
120     this.sleeper.sleep();
121   }
122 
123   /**
124    * Called when the chore has completed, allowing subclasses to cleanup any
125    * extra overhead
126    */
127   protected void cleanup() {
128   }
129 }