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