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.Sleeper;
25  
26  /**
27   * Chore is a task performed on a period in hbase.  The chore is run in its own
28   * thread. This base abstract class provides while loop and sleeping facility.
29   * If an unhandled exception, the threads exit is logged.
30   * Implementers just need to add checking if there is work to be done and if
31   * so, do it.  Its the base of most of the chore threads in hbase.
32   *
33   * <p>Don't subclass Chore if the task relies on being woken up for something to
34   * do, such as an entry being added to a queue, etc.
35   */
36  public abstract class Chore extends Thread {
37    private final Log LOG = LogFactory.getLog(this.getClass());
38    private final Sleeper sleeper;
39    protected final Stoppable stopper;
40  
41    /**
42     * @param p Period at which we should run.  Will be adjusted appropriately
43     * should we find work and it takes time to complete.
44     * @param stopper When {@link Stoppable#isStopped()} is true, this thread will
45     * cleanup and exit cleanly.
46     */
47    public Chore(String name, final int p, final Stoppable stopper) {
48      super(name);
49      this.sleeper = new Sleeper(p, stopper);
50      this.stopper = stopper;
51    }
52  
53    /**
54     * @see java.lang.Thread#run()
55     */
56    @Override
57    public void run() {
58      try {
59        boolean initialChoreComplete = false;
60        while (!this.stopper.isStopped()) {
61          long startTime = System.currentTimeMillis();
62          try {
63            if (!initialChoreComplete) {
64              initialChoreComplete = initialChore();
65            } else {
66              chore();
67            }
68          } catch (Exception e) {
69            LOG.error("Caught exception", e);
70            if (this.stopper.isStopped()) {
71              continue;
72            }
73          }
74          this.sleeper.sleep(startTime);
75        }
76      } catch (Throwable t) {
77        LOG.fatal(getName() + "error", t);
78      } finally {
79        LOG.info(getName() + " exiting");
80      }
81    }
82  
83    /**
84     * If the thread is currently sleeping, trigger the core to happen immediately.
85     * If it's in the middle of its operation, will begin another operation
86     * immediately after finishing this one.
87     */
88    public void triggerNow() {
89      this.sleeper.skipSleepCycle();
90    }
91  
92    /**
93     * Override to run a task before we start looping.
94     * @return true if initial chore was successful
95     */
96    protected boolean initialChore() {
97      // Default does nothing.
98      return true;
99    }
100 
101   /**
102    * Look for chores.  If any found, do them else just return.
103    */
104   protected abstract void chore();
105 
106   /**
107    * Sleep for period.
108    */
109   protected void sleep() {
110     this.sleeper.sleep();
111   }
112 }