1 /**
2 * Copyright 2010 The Apache Software Foundation
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 package org.apache.hadoop.hbase.executor;
21
22 import java.io.IOException;
23 import java.util.concurrent.atomic.AtomicLong;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.hbase.Server;
28
29
30 /**
31 * Abstract base class for all HBase event handlers. Subclasses should
32 * implement the {@link #process()} method. Subclasses should also do all
33 * necessary checks up in their constructor if possible -- check table exists,
34 * is disabled, etc. -- so they fail fast rather than later when process is
35 * running. Do it this way because process be invoked directly but event
36 * handlers are also
37 * run in an executor context -- i.e. asynchronously -- and in this case,
38 * exceptions thrown at process time will not be seen by the invoker, not till
39 * we implement a call-back mechanism so the client can pick them up later.
40 * <p>
41 * Event handlers have an {@link EventType}.
42 * {@link EventType} is a list of ALL handler event types. We need to keep
43 * a full list in one place -- and as enums is a good shorthand for an
44 * implemenations -- because event handlers can be passed to executors when
45 * they are to be run asynchronously. The
46 * hbase executor, see {@link ExecutorService}, has a switch for passing
47 * event type to executor.
48 * <p>
49 * Event listeners can be installed and will be called pre- and post- process if
50 * this EventHandler is run in a Thread (its a Runnable so if its {@link #run()}
51 * method gets called). Implement
52 * {@link EventHandlerListener}s, and registering using
53 * {@link #setListener(EventHandlerListener)}.
54 * @see ExecutorService
55 */
56 public abstract class EventHandler implements Runnable, Comparable<Runnable> {
57 private static final Log LOG = LogFactory.getLog(EventHandler.class);
58
59 // type of event this object represents
60 protected EventType eventType;
61
62 protected Server server;
63
64 // sequence id generator for default FIFO ordering of events
65 protected static AtomicLong seqids = new AtomicLong(0);
66
67 // sequence id for this event
68 private final long seqid;
69
70 // Listener to call pre- and post- processing. May be null.
71 private EventHandlerListener listener;
72
73 /**
74 * This interface provides pre- and post-process hooks for events.
75 */
76 public interface EventHandlerListener {
77 /**
78 * Called before any event is processed
79 * @param event The event handler whose process method is about to be called.
80 */
81 public void beforeProcess(EventHandler event);
82 /**
83 * Called after any event is processed
84 * @param event The event handler whose process method is about to be called.
85 */
86 public void afterProcess(EventHandler event);
87 }
88
89 /**
90 * List of all HBase event handler types. Event types are named by a
91 * convention: event type names specify the component from which the event
92 * originated and then where its destined -- e.g. RS2ZK_ prefix means the
93 * event came from a regionserver destined for zookeeper -- and then what
94 * the even is; e.g. REGION_OPENING.
95 *
96 * <p>We give the enums indices so we can add types later and keep them
97 * grouped together rather than have to add them always to the end as we
98 * would have to if we used raw enum ordinals.
99 */
100 public enum EventType {
101 // Messages originating from RS (NOTE: there is NO direct communication from
102 // RS to Master). These are a result of RS updates into ZK.
103 RS_ZK_REGION_CLOSING (1), // RS is in process of closing a region
104 RS_ZK_REGION_CLOSED (2), // RS has finished closing a region
105 RS_ZK_REGION_OPENING (3), // RS is in process of opening a region
106 RS_ZK_REGION_OPENED (4), // RS has finished opening a region
107
108 // Messages originating from Master to RS
109 M_RS_OPEN_REGION (20), // Master asking RS to open a region
110 M_RS_OPEN_ROOT (21), // Master asking RS to open root
111 M_RS_OPEN_META (22), // Master asking RS to open meta
112 M_RS_CLOSE_REGION (23), // Master asking RS to close a region
113 M_RS_CLOSE_ROOT (24), // Master asking RS to close root
114 M_RS_CLOSE_META (25), // Master asking RS to close meta
115
116 // Messages originating from Client to Master
117 C_M_DELETE_TABLE (40), // Client asking Master to delete a table
118 C_M_DISABLE_TABLE (41), // Client asking Master to disable a table
119 C_M_ENABLE_TABLE (42), // Client asking Master to enable a table
120 C_M_MODIFY_TABLE (43), // Client asking Master to modify a table
121 C_M_ADD_FAMILY (44), // Client asking Master to add family to table
122 C_M_DELETE_FAMILY (45), // Client asking Master to delete family of table
123 C_M_MODIFY_FAMILY (46), // Client asking Master to modify family of table
124
125 // Updates from master to ZK. This is done by the master and there is
126 // nothing to process by either Master or RS
127 M_ZK_REGION_OFFLINE (50), // Master adds this region as offline in ZK
128
129 // Master controlled events to be executed on the master
130 M_SERVER_SHUTDOWN (70), // Master is processing shutdown of a RS
131 M_META_SERVER_SHUTDOWN (72); // Master is processing shutdown of RS hosting a meta region (-ROOT- or .META.).
132
133 /**
134 * Constructor
135 */
136 EventType(int value) {}
137 }
138
139 /**
140 * Default base class constructor.
141 */
142 public EventHandler(Server server, EventType eventType) {
143 this.server = server;
144 this.eventType = eventType;
145 seqid = seqids.incrementAndGet();
146 }
147
148 public void run() {
149 try {
150 if (getListener() != null) getListener().beforeProcess(this);
151 process();
152 if (getListener() != null) getListener().afterProcess(this);
153 } catch(Throwable t) {
154 LOG.error("Caught throwable while processing event " + eventType, t);
155 }
156 }
157
158 /**
159 * This method is the main processing loop to be implemented by the various
160 * subclasses.
161 * @throws IOException
162 */
163 public abstract void process() throws IOException;
164
165 /**
166 * Return the event type
167 * @return The event type.
168 */
169 public EventType getEventType() {
170 return this.eventType;
171 }
172
173 /**
174 * Get the priority level for this handler instance. This uses natural
175 * ordering so lower numbers are higher priority.
176 * <p>
177 * Lowest priority is Integer.MAX_VALUE. Highest priority is 0.
178 * <p>
179 * Subclasses should override this method to allow prioritizing handlers.
180 * <p>
181 * Handlers with the same priority are handled in FIFO order.
182 * <p>
183 * @return Integer.MAX_VALUE by default, override to set higher priorities
184 */
185 public int getPriority() {
186 return Integer.MAX_VALUE;
187 }
188
189 /**
190 * @return This events' sequence id.
191 */
192 public long getSeqid() {
193 return this.seqid;
194 }
195
196 /**
197 * Default prioritized runnable comparator which implements a FIFO ordering.
198 * <p>
199 * Subclasses should not override this. Instead, if they want to implement
200 * priority beyond FIFO, they should override {@link #getPriority()}.
201 */
202 @Override
203 public int compareTo(Runnable o) {
204 EventHandler eh = (EventHandler)o;
205 if(getPriority() != eh.getPriority()) {
206 return (getPriority() < eh.getPriority()) ? -1 : 1;
207 }
208 return (this.seqid < eh.seqid) ? -1 : 1;
209 }
210
211 /**
212 * @return Current listener or null if none set.
213 */
214 public synchronized EventHandlerListener getListener() {
215 return listener;
216 }
217
218 /**
219 * @param listener Listener to call pre- and post- {@link #process()}.
220 */
221 public synchronized void setListener(EventHandlerListener listener) {
222 this.listener = listener;
223 }
224 }