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