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.executor; 20 21 import java.io.IOException; 22 import java.util.concurrent.atomic.AtomicLong; 23 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 import org.apache.hadoop.hbase.classification.InterfaceAudience; 27 import org.apache.hadoop.hbase.Server; 28 import org.apache.htrace.Span; 29 import org.apache.htrace.Trace; 30 import org.apache.htrace.TraceScope; 31 32 /** 33 * Abstract base class for all HBase event handlers. Subclasses should 34 * implement the {@link #process()} and {@link #prepare()} methods. Subclasses 35 * should also do all necessary checks up in their prepare() if possible -- check 36 * table exists, is disabled, etc. -- so they fail fast rather than later when process 37 * is running. Do it this way because process be invoked directly but event 38 * handlers are also 39 * run in an executor context -- i.e. asynchronously -- and in this case, 40 * exceptions thrown at process time will not be seen by the invoker, not till 41 * we implement a call-back mechanism so the client can pick them up later. 42 * <p> 43 * Event handlers have an {@link EventType}. 44 * {@link EventType} is a list of ALL handler event types. We need to keep 45 * a full list in one place -- and as enums is a good shorthand for an 46 * implemenations -- because event handlers can be passed to executors when 47 * they are to be run asynchronously. The 48 * hbase executor, see ExecutorService, has a switch for passing 49 * event type to executor. 50 * <p> 51 * Event listeners can be installed and will be called pre- and post- process if 52 * this EventHandler is run in a Thread (its a Runnable so if its {@link #run()} 53 * method gets called). Implement 54 * {@link EventHandlerListener}s, and registering using 55 * {@link #setListener(EventHandlerListener)}. 56 * @see ExecutorService 57 */ 58 @InterfaceAudience.Private 59 public abstract class EventHandler implements Runnable, Comparable<Runnable> { 60 private static final Log LOG = LogFactory.getLog(EventHandler.class); 61 62 // type of event this object represents 63 protected EventType eventType; 64 65 protected Server server; 66 67 // sequence id generator for default FIFO ordering of events 68 protected static final AtomicLong seqids = new AtomicLong(0); 69 70 // sequence id for this event 71 private final long seqid; 72 73 // Listener to call pre- and post- processing. May be null. 74 private EventHandlerListener listener; 75 76 // Time to wait for events to happen, should be kept short 77 protected int waitingTimeForEvents; 78 79 private final Span parent; 80 81 /** 82 * This interface provides pre- and post-process hooks for events. 83 */ 84 public interface EventHandlerListener { 85 /** 86 * Called before any event is processed 87 * @param event The event handler whose process method is about to be called. 88 */ 89 void beforeProcess(EventHandler event); 90 /** 91 * Called after any event is processed 92 * @param event The event handler whose process method is about to be called. 93 */ 94 void afterProcess(EventHandler event); 95 } 96 97 /** 98 * Default base class constructor. 99 */ 100 public EventHandler(Server server, EventType eventType) { 101 this.parent = Trace.currentSpan(); 102 this.server = server; 103 this.eventType = eventType; 104 seqid = seqids.incrementAndGet(); 105 if (server != null) { 106 this.waitingTimeForEvents = server.getConfiguration(). 107 getInt("hbase.master.event.waiting.time", 1000); 108 } 109 } 110 111 /** 112 * Event handlers should do all the necessary checks in this method (rather than 113 * in the constructor, or in process()) so that the caller, which is mostly executed 114 * in the ipc context can fail fast. Process is executed async from the client ipc, 115 * so this method gives a quick chance to do some basic checks. 116 * Should be called after constructing the EventHandler, and before process(). 117 * @return the instance of this class 118 * @throws Exception when something goes wrong 119 */ 120 public EventHandler prepare() throws Exception { 121 return this; 122 } 123 124 @Override 125 public void run() { 126 TraceScope chunk = Trace.startSpan(this.getClass().getSimpleName(), parent); 127 try { 128 if (getListener() != null) getListener().beforeProcess(this); 129 process(); 130 if (getListener() != null) getListener().afterProcess(this); 131 } catch(Throwable t) { 132 handleException(t); 133 } finally { 134 chunk.close(); 135 } 136 } 137 138 /** 139 * This method is the main processing loop to be implemented by the various 140 * subclasses. 141 * @throws IOException 142 */ 143 public abstract void process() throws IOException; 144 145 /** 146 * Return the event type 147 * @return The event type. 148 */ 149 public EventType getEventType() { 150 return this.eventType; 151 } 152 153 /** 154 * Get the priority level for this handler instance. This uses natural 155 * ordering so lower numbers are higher priority. 156 * <p> 157 * Lowest priority is Integer.MAX_VALUE. Highest priority is 0. 158 * <p> 159 * Subclasses should override this method to allow prioritizing handlers. 160 * <p> 161 * Handlers with the same priority are handled in FIFO order. 162 * <p> 163 * @return Integer.MAX_VALUE by default, override to set higher priorities 164 */ 165 public int getPriority() { 166 return Integer.MAX_VALUE; 167 } 168 169 /** 170 * @return This events' sequence id. 171 */ 172 public long getSeqid() { 173 return this.seqid; 174 } 175 176 /** 177 * Default prioritized runnable comparator which implements a FIFO ordering. 178 * <p> 179 * Subclasses should not override this. Instead, if they want to implement 180 * priority beyond FIFO, they should override {@link #getPriority()}. 181 */ 182 @Override 183 public int compareTo(Runnable o) { 184 EventHandler eh = (EventHandler)o; 185 if(getPriority() != eh.getPriority()) { 186 return (getPriority() < eh.getPriority()) ? -1 : 1; 187 } 188 return (this.seqid < eh.seqid) ? -1 : 1; 189 } 190 191 /** 192 * @return Current listener or null if none set. 193 */ 194 public synchronized EventHandlerListener getListener() { 195 return listener; 196 } 197 198 /** 199 * @param listener Listener to call pre- and post- {@link #process()}. 200 */ 201 public synchronized void setListener(EventHandlerListener listener) { 202 this.listener = listener; 203 } 204 205 @Override 206 public String toString() { 207 return "Event #" + getSeqid() + 208 " of type " + eventType + 209 " (" + getInformativeName() + ")"; 210 } 211 212 /** 213 * Event implementations should override thie class to provide an 214 * informative name about what event they are handling. For example, 215 * event-specific information such as which region or server is 216 * being processed should be included if possible. 217 */ 218 public String getInformativeName() { 219 return this.getClass().toString(); 220 } 221 222 /** 223 * Event exception handler, may be overridden 224 * @param t Throwable object 225 */ 226 protected void handleException(Throwable t) { 227 String msg = "Caught throwable while processing event " + eventType; 228 LOG.error(msg, t); 229 if (server != null && (t instanceof Error || t instanceof RuntimeException)) { 230 server.abort(msg, t); 231 } 232 } 233 }