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.hbase.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 }