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;
21
22 import java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25
26 import org.apache.hadoop.hbase.util.Bytes;
27 import org.apache.hadoop.io.Writable;
28
29 /**
30 * HMsg is for communicating instructions between the HMaster and the
31 * HRegionServers.
32 *
33 * Most of the time the messages are simple but some messages are accompanied
34 * by the region affected. HMsg may also carry optional message.
35 */
36 public class HMsg implements Writable {
37 public static final HMsg REGIONSERVER_QUIESCE =
38 new HMsg(Type.MSG_REGIONSERVER_QUIESCE);
39 public static final HMsg REGIONSERVER_STOP =
40 new HMsg(Type.MSG_REGIONSERVER_STOP);
41 public static final HMsg [] EMPTY_HMSG_ARRAY = new HMsg[0];
42
43 /**
44 * Message types sent between master and regionservers
45 */
46 public static enum Type {
47 /** null message */
48 MSG_NONE,
49
50 // Message types sent from master to region server
51 /** Start serving the specified region */
52 MSG_REGION_OPEN,
53
54 /** Stop serving the specified region */
55 MSG_REGION_CLOSE,
56
57 /** Split the specified region */
58 MSG_REGION_SPLIT,
59
60 /** Compact the specified region */
61 MSG_REGION_COMPACT,
62
63 /** Master tells region server to stop */
64 MSG_REGIONSERVER_STOP,
65
66 /** Stop serving the specified region and don't report back that it's
67 * closed
68 */
69 MSG_REGION_CLOSE_WITHOUT_REPORT,
70
71 /** Stop serving user regions */
72 MSG_REGIONSERVER_QUIESCE,
73
74 // Message types sent from the region server to the master
75 /** region server is now serving the specified region */
76 MSG_REPORT_OPEN,
77
78 /** region server is no longer serving the specified region */
79 MSG_REPORT_CLOSE,
80
81 /** region server is processing open request */
82 MSG_REPORT_PROCESS_OPEN,
83
84 /**
85 * Region server split the region associated with this message.
86 *
87 * Note that this message is immediately followed by two MSG_REPORT_OPEN
88 * messages, one for each of the new regions resulting from the split
89 * @deprecated See MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS
90 */
91 MSG_REPORT_SPLIT,
92
93 /**
94 * Region server is shutting down
95 *
96 * Note that this message is followed by MSG_REPORT_CLOSE messages for each
97 * region the region server was serving, unless it was told to quiesce.
98 */
99 MSG_REPORT_EXITING,
100
101 /** Region server has closed all user regions but is still serving meta
102 * regions
103 */
104 MSG_REPORT_QUIESCED,
105
106 /**
107 * Flush
108 */
109 MSG_REGION_FLUSH,
110
111 /**
112 * Run Major Compaction
113 */
114 MSG_REGION_MAJOR_COMPACT,
115
116 /**
117 * Region server split the region associated with this message.
118 *
119 * Its like MSG_REPORT_SPLIT only it carries the daughters in the message
120 * rather than send them individually in MSG_REPORT_OPEN messages.
121 */
122 MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS,
123
124 /**
125 * When RegionServer receives this message, it goes into a sleep that only
126 * an exit will cure. This message is sent by unit tests simulating
127 * pathological states.
128 */
129 TESTING_MSG_BLOCK_RS,
130 }
131
132 private Type type = null;
133 private HRegionInfo info = null;
134 private byte[] message = null;
135 private HRegionInfo daughterA = null;
136 private HRegionInfo daughterB = null;
137
138 /** Default constructor. Used during deserialization */
139 public HMsg() {
140 this(Type.MSG_NONE);
141 }
142
143 /**
144 * Construct a message with the specified message and empty HRegionInfo
145 * @param type Message type
146 */
147 public HMsg(final HMsg.Type type) {
148 this(type, new HRegionInfo(), null);
149 }
150
151 /**
152 * Construct a message with the specified message and HRegionInfo
153 * @param type Message type
154 * @param hri Region to which message <code>type</code> applies
155 */
156 public HMsg(final HMsg.Type type, final HRegionInfo hri) {
157 this(type, hri, null);
158 }
159
160 /**
161 * Construct a message with the specified message and HRegionInfo
162 *
163 * @param type Message type
164 * @param hri Region to which message <code>type</code> applies. Cannot be
165 * null. If no info associated, used other Constructor.
166 * @param msg Optional message (Stringified exception, etc.)
167 */
168 public HMsg(final HMsg.Type type, final HRegionInfo hri, final byte[] msg) {
169 this(type, hri, null, null, msg);
170 }
171
172 /**
173 * Construct a message with the specified message and HRegionInfo
174 *
175 * @param type Message type
176 * @param hri Region to which message <code>type</code> applies. Cannot be
177 * null. If no info associated, used other Constructor.
178 * @param daughterA
179 * @param daughterB
180 * @param msg Optional message (Stringified exception, etc.)
181 */
182 public HMsg(final HMsg.Type type, final HRegionInfo hri,
183 final HRegionInfo daughterA, final HRegionInfo daughterB, final byte[] msg) {
184 if (type == null) {
185 throw new NullPointerException("Message type cannot be null");
186 }
187 this.type = type;
188 if (hri == null) {
189 throw new NullPointerException("Region cannot be null");
190 }
191 this.info = hri;
192 this.message = msg;
193 this.daughterA = daughterA;
194 this.daughterB = daughterB;
195 }
196
197 /**
198 * @return Region info or null if none associated with this message type.
199 */
200 public HRegionInfo getRegionInfo() {
201 return this.info;
202 }
203
204 /** @return the type of message */
205 public Type getType() {
206 return this.type;
207 }
208
209 /**
210 * @param other Message type to compare to
211 * @return True if we are of same message type as <code>other</code>
212 */
213 public boolean isType(final HMsg.Type other) {
214 return this.type.equals(other);
215 }
216
217 /** @return the message type */
218 public byte[] getMessage() {
219 return this.message;
220 }
221
222 /**
223 * @return First daughter if Type is MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS else
224 * null
225 */
226 public HRegionInfo getDaughterA() {
227 return this.daughterA;
228 }
229
230 /**
231 * @return Second daughter if Type is MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS else
232 * null
233 */
234 public HRegionInfo getDaughterB() {
235 return this.daughterB;
236 }
237
238 /**
239 * @see java.lang.Object#toString()
240 */
241 @Override
242 public String toString() {
243 StringBuilder sb = new StringBuilder();
244 sb.append(this.type.toString());
245 // If null or empty region, don't bother printing it out.
246 if (this.info != null && this.info.getRegionName().length > 0) {
247 sb.append(": ");
248 sb.append(this.info.getRegionNameAsString());
249 }
250 if (this.message != null && this.message.length > 0) {
251 sb.append(": " + Bytes.toString(this.message));
252 }
253 return sb.toString();
254 }
255
256 /**
257 * @see java.lang.Object#equals(java.lang.Object)
258 */
259 @Override
260 public boolean equals(Object obj) {
261 if (this == obj) {
262 return true;
263 }
264 if (obj == null) {
265 return false;
266 }
267 if (getClass() != obj.getClass()) {
268 return false;
269 }
270 HMsg that = (HMsg)obj;
271 return this.type.equals(that.type) &&
272 (this.info != null)? this.info.equals(that.info):
273 that.info == null;
274 }
275
276 /**
277 * @see java.lang.Object#hashCode()
278 */
279 @Override
280 public int hashCode() {
281 int result = this.type.hashCode();
282 if (this.info != null) {
283 result ^= this.info.hashCode();
284 }
285 return result;
286 }
287
288 // ////////////////////////////////////////////////////////////////////////////
289 // Writable
290 //////////////////////////////////////////////////////////////////////////////
291
292 /**
293 * @see org.apache.hadoop.io.Writable#write(java.io.DataOutput)
294 */
295 public void write(DataOutput out) throws IOException {
296 out.writeInt(this.type.ordinal());
297 this.info.write(out);
298 if (this.message == null || this.message.length == 0) {
299 out.writeBoolean(false);
300 } else {
301 out.writeBoolean(true);
302 Bytes.writeByteArray(out, this.message);
303 }
304 if (this.type.equals(Type.MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS)) {
305 this.daughterA.write(out);
306 this.daughterB.write(out);
307 }
308 }
309
310 /**
311 * @see org.apache.hadoop.io.Writable#readFields(java.io.DataInput)
312 */
313 public void readFields(DataInput in) throws IOException {
314 int ordinal = in.readInt();
315 this.type = HMsg.Type.values()[ordinal];
316 this.info.readFields(in);
317 boolean hasMessage = in.readBoolean();
318 if (hasMessage) {
319 this.message = Bytes.readByteArray(in);
320 }
321 if (this.type.equals(Type.MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS)) {
322 this.daughterA = new HRegionInfo();
323 this.daughterB = new HRegionInfo();
324 this.daughterA.readFields(in);
325 this.daughterB.readFields(in);
326 }
327 }
328 }