001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.executor; 020 021import java.io.IOException; 022import java.util.concurrent.atomic.AtomicLong; 023 024import org.apache.hadoop.hbase.Server; 025import org.apache.hadoop.hbase.trace.TraceUtil; 026import org.apache.htrace.core.Span; 027import org.apache.htrace.core.TraceScope; 028import org.apache.htrace.core.Tracer; 029import org.apache.yetus.audience.InterfaceAudience; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * Abstract base class for all HBase event handlers. Subclasses should 035 * implement the {@link #process()} and {@link #prepare()} methods. Subclasses 036 * should also do all necessary checks up in their prepare() if possible -- check 037 * table exists, is disabled, etc. -- so they fail fast rather than later when process 038 * is running. Do it this way because process be invoked directly but event 039 * handlers are also 040 * run in an executor context -- i.e. asynchronously -- and in this case, 041 * exceptions thrown at process time will not be seen by the invoker, not till 042 * we implement a call-back mechanism so the client can pick them up later. 043 * <p> 044 * Event handlers have an {@link EventType}. 045 * {@link EventType} is a list of ALL handler event types. We need to keep 046 * a full list in one place -- and as enums is a good shorthand for an 047 * implemenations -- because event handlers can be passed to executors when 048 * they are to be run asynchronously. The 049 * hbase executor, see ExecutorService, has a switch for passing 050 * event type to executor. 051 * <p> 052 * @see ExecutorService 053 */ 054@InterfaceAudience.Private 055public abstract class EventHandler implements Runnable, Comparable<EventHandler> { 056 private static final Logger LOG = LoggerFactory.getLogger(EventHandler.class); 057 058 // type of event this object represents 059 protected EventType eventType; 060 061 protected Server server; 062 063 // sequence id generator for default FIFO ordering of events 064 protected static final AtomicLong seqids = new AtomicLong(0); 065 066 // sequence id for this event 067 private final long seqid; 068 069 // Time to wait for events to happen, should be kept short 070 protected int waitingTimeForEvents; 071 072 private final Span parent; 073 074 /** 075 * Default base class constructor. 076 */ 077 public EventHandler(Server server, EventType eventType) { 078 this.parent = Tracer.getCurrentSpan(); 079 this.server = server; 080 this.eventType = eventType; 081 seqid = seqids.incrementAndGet(); 082 if (server != null) { 083 this.waitingTimeForEvents = server.getConfiguration(). 084 getInt("hbase.master.event.waiting.time", 1000); 085 } 086 } 087 088 /** 089 * Event handlers should do all the necessary checks in this method (rather than 090 * in the constructor, or in process()) so that the caller, which is mostly executed 091 * in the ipc context can fail fast. Process is executed async from the client ipc, 092 * so this method gives a quick chance to do some basic checks. 093 * Should be called after constructing the EventHandler, and before process(). 094 * @return the instance of this class 095 * @throws Exception when something goes wrong 096 */ 097 public EventHandler prepare() throws Exception { 098 return this; 099 } 100 101 @Override 102 public void run() { 103 try (TraceScope scope = TraceUtil.createTrace(this.getClass().getSimpleName(), parent)) { 104 process(); 105 } catch(Throwable t) { 106 handleException(t); 107 } 108 } 109 110 /** 111 * This method is the main processing loop to be implemented by the various 112 * subclasses. 113 * @throws IOException 114 */ 115 public abstract void process() throws IOException; 116 117 /** 118 * Return the event type 119 * @return The event type. 120 */ 121 public EventType getEventType() { 122 return this.eventType; 123 } 124 125 /** 126 * Get the priority level for this handler instance. This uses natural 127 * ordering so lower numbers are higher priority. 128 * <p> 129 * Lowest priority is Integer.MAX_VALUE. Highest priority is 0. 130 * <p> 131 * Subclasses should override this method to allow prioritizing handlers. 132 * <p> 133 * Handlers with the same priority are handled in FIFO order. 134 * <p> 135 * @return Integer.MAX_VALUE by default, override to set higher priorities 136 */ 137 public int getPriority() { 138 return Integer.MAX_VALUE; 139 } 140 141 /** 142 * @return This events' sequence id. 143 */ 144 public long getSeqid() { 145 return this.seqid; 146 } 147 148 /** 149 * Default prioritized runnable comparator which implements a FIFO ordering. 150 * <p> 151 * Subclasses should not override this. Instead, if they want to implement 152 * priority beyond FIFO, they should override {@link #getPriority()}. 153 */ 154 @Override 155 public int compareTo(EventHandler o) { 156 if (o == null) { 157 return 1; 158 } 159 if(getPriority() != o.getPriority()) { 160 return (getPriority() < o.getPriority()) ? -1 : 1; 161 } 162 return (this.seqid < o.seqid) ? -1 : 1; 163 } 164 165 @Override 166 public String toString() { 167 return "Event #" + getSeqid() + 168 " of type " + eventType + 169 " (" + getInformativeName() + ")"; 170 } 171 172 /** 173 * Event implementations should override thie class to provide an 174 * informative name about what event they are handling. For example, 175 * event-specific information such as which region or server is 176 * being processed should be included if possible. 177 */ 178 public String getInformativeName() { 179 return this.getClass().toString(); 180 } 181 182 /** 183 * Event exception handler, may be overridden 184 * @param t Throwable object 185 */ 186 protected void handleException(Throwable t) { 187 String msg = "Caught throwable while processing event " + eventType; 188 LOG.error(msg, t); 189 if (server != null && (t instanceof Error || t instanceof RuntimeException)) { 190 server.abort(msg, t); 191 } 192 } 193}