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<Runnable> {
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(Runnable o) {
156    EventHandler eh = (EventHandler)o;
157    if(getPriority() != eh.getPriority()) {
158      return (getPriority() < eh.getPriority()) ? -1 : 1;
159    }
160    return (this.seqid < eh.seqid) ? -1 : 1;
161  }
162
163  @Override
164  public String toString() {
165    return "Event #" + getSeqid() +
166      " of type " + eventType +
167      " (" + getInformativeName() + ")";
168  }
169
170  /**
171   * Event implementations should override thie class to provide an
172   * informative name about what event they are handling. For example,
173   * event-specific information such as which region or server is
174   * being processed should be included if possible.
175   */
176  public String getInformativeName() {
177    return this.getClass().toString();
178  }
179
180  /**
181   * Event exception handler, may be overridden
182   * @param t Throwable object
183   */
184  protected void handleException(Throwable t) {
185    String msg = "Caught throwable while processing event " + eventType;
186    LOG.error(msg, t);
187    if (server != null && (t instanceof Error || t instanceof RuntimeException)) {
188      server.abort(msg, t);
189    }
190  }
191}