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.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 public abstract class Chore extends HasThread { 38 private final Log LOG = LogFactory.getLog(this.getClass()); 39 private final Sleeper sleeper; 40 protected final Stoppable stopper; 41 42 /** 43 * @param p Period at which we should run. Will be adjusted appropriately 44 * should we find work and it takes time to complete. 45 * @param stopper When {@link Stoppable#isStopped()} is true, this thread will 46 * cleanup and exit cleanly. 47 */ 48 public Chore(String name, final int p, final Stoppable stopper) { 49 super(name); 50 this.sleeper = new Sleeper(p, stopper); 51 this.stopper = stopper; 52 } 53 54 /** 55 * @see java.lang.Thread#run() 56 */ 57 @Override 58 public void run() { 59 try { 60 boolean initialChoreComplete = false; 61 while (!this.stopper.isStopped()) { 62 long startTime = System.currentTimeMillis(); 63 try { 64 if (!initialChoreComplete) { 65 initialChoreComplete = initialChore(); 66 } else { 67 chore(); 68 } 69 } catch (Exception e) { 70 LOG.error("Caught exception", e); 71 if (this.stopper.isStopped()) { 72 continue; 73 } 74 } 75 this.sleeper.sleep(startTime); 76 } 77 } catch (Throwable t) { 78 LOG.fatal(getName() + "error", t); 79 } finally { 80 LOG.info(getName() + " exiting"); 81 cleanup(); 82 } 83 } 84 85 /** 86 * If the thread is currently sleeping, trigger the core to happen immediately. 87 * If it's in the middle of its operation, will begin another operation 88 * immediately after finishing this one. 89 */ 90 public void triggerNow() { 91 this.sleeper.skipSleepCycle(); 92 } 93 94 /* 95 * Exposed for TESTING! 96 * calls directly the chore method, from the current thread. 97 */ 98 public void choreForTesting() { 99 chore(); 100 } 101 102 /** 103 * Override to run a task before we start looping. 104 * @return true if initial chore was successful 105 */ 106 protected boolean initialChore() { 107 // Default does nothing. 108 return true; 109 } 110 111 /** 112 * Look for chores. If any found, do them else just return. 113 */ 114 protected abstract void chore(); 115 116 /** 117 * Sleep for period. 118 */ 119 protected void sleep() { 120 this.sleeper.sleep(); 121 } 122 123 /** 124 * Called when the chore has completed, allowing subclasses to cleanup any 125 * extra overhead 126 */ 127 protected void cleanup() { 128 } 129 }