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 }