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