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 java.util.concurrent.atomic.AtomicBoolean;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
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   * 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  public abstract class Chore extends Thread {
39    private final Log LOG = LogFactory.getLog(this.getClass());
40    private final Sleeper sleeper;
41    protected volatile AtomicBoolean stop;
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 s When this flag is set to true, this thread will cleanup and exit
47     * cleanly.
48     */
49    public Chore(String name, final int p, final AtomicBoolean s) {
50      super(name);
51      this.sleeper = new Sleeper(p, s);
52      this.stop = s;
53    }
54  
55    /**
56     * @see java.lang.Thread#run()
57     */
58    @Override
59    public void run() {
60      try {
61        boolean initialChoreComplete = false;
62        while (!this.stop.get()) {
63          long startTime = System.currentTimeMillis();
64          try {
65            if (!initialChoreComplete) {
66              initialChoreComplete = initialChore();
67            } else {
68              chore();
69            }
70          } catch (Exception e) {
71            LOG.error("Caught exception", e);
72            if (this.stop.get()) {
73              continue;
74            }
75          }
76          this.sleeper.sleep(startTime);
77        }
78      } catch (Throwable t) {
79        LOG.fatal("Caught error. Starting shutdown.", t);
80        this.stop.set(true);
81      } finally {
82        LOG.info(getName() + " exiting");
83      }
84    }
85  
86    /**
87     * If the thread is currently sleeping, trigger the core to happen immediately.
88     * If it's in the middle of its operation, will begin another operation
89     * immediately after finishing this one.
90     */
91    public void triggerNow() {
92      this.sleeper.skipSleepCycle();
93    }
94  
95    /**
96     * Override to run a task before we start looping.
97     * @return true if initial chore was successful
98     */
99    protected boolean initialChore() {
100     // Default does nothing.
101     return true;
102   }
103 
104   /**
105    * Look for chores.  If any found, do them else just return.
106    */
107   protected abstract void chore();
108 
109   /**
110    * Sleep for period.
111    */
112   protected void sleep() {
113     this.sleeper.sleep();
114   }
115 }