View Javadoc

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.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.Server;
28  import org.htrace.Span;
29  import org.htrace.Trace;
30  import org.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   public void run() {
125     TraceScope chunk = Trace.startSpan(this.getClass().getSimpleName(), parent);
126     try {
127       if (getListener() != null) getListener().beforeProcess(this);
128       process();
129       if (getListener() != null) getListener().afterProcess(this);
130     } catch(Throwable t) {
131       handleException(t);
132     } finally {
133       chunk.close();
134     }
135   }
136 
137   /**
138    * This method is the main processing loop to be implemented by the various
139    * subclasses.
140    * @throws IOException
141    */
142   public abstract void process() throws IOException;
143 
144   /**
145    * Return the event type
146    * @return The event type.
147    */
148   public EventType getEventType() {
149     return this.eventType;
150   }
151 
152   /**
153    * Get the priority level for this handler instance.  This uses natural
154    * ordering so lower numbers are higher priority.
155    * <p>
156    * Lowest priority is Integer.MAX_VALUE.  Highest priority is 0.
157    * <p>
158    * Subclasses should override this method to allow prioritizing handlers.
159    * <p>
160    * Handlers with the same priority are handled in FIFO order.
161    * <p>
162    * @return Integer.MAX_VALUE by default, override to set higher priorities
163    */
164   public int getPriority() {
165     return Integer.MAX_VALUE;
166   }
167 
168   /**
169    * @return This events' sequence id.
170    */
171   public long getSeqid() {
172     return this.seqid;
173   }
174 
175   /**
176    * Default prioritized runnable comparator which implements a FIFO ordering.
177    * <p>
178    * Subclasses should not override this.  Instead, if they want to implement
179    * priority beyond FIFO, they should override {@link #getPriority()}.
180    */
181   @Override
182   public int compareTo(Runnable o) {
183     EventHandler eh = (EventHandler)o;
184     if(getPriority() != eh.getPriority()) {
185       return (getPriority() < eh.getPriority()) ? -1 : 1;
186     }
187     return (this.seqid < eh.seqid) ? -1 : 1;
188   }
189 
190   /**
191    * @return Current listener or null if none set.
192    */
193   public synchronized EventHandlerListener getListener() {
194     return listener;
195   }
196 
197   /**
198    * @param listener Listener to call pre- and post- {@link #process()}.
199    */
200   public synchronized void setListener(EventHandlerListener listener) {
201     this.listener = listener;
202   }
203 
204   @Override
205   public String toString() {
206     return "Event #" + getSeqid() +
207       " of type " + eventType +
208       " (" + getInformativeName() + ")";
209   }
210 
211   /**
212    * Event implementations should override thie class to provide an
213    * informative name about what event they are handling. For example,
214    * event-specific information such as which region or server is
215    * being processed should be included if possible.
216    */
217   public String getInformativeName() {
218     return this.getClass().toString();
219   }
220 
221   /**
222    * Event exception handler, may be overridden
223    * @param t Throwable object
224    */
225   protected void handleException(Throwable t) {
226     LOG.error("Caught throwable while processing event " + eventType, t);
227   }
228 }