View Javadoc

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 used to send messages between master and regionservers.  Messages are
31   * sent as payload on the regionserver-to-master heartbeats.  Region assignment
32   * does not use this mechanism.  It goes via zookeeper.
33   *
34   * <p>Most of the time the messages are simple but some messages are accompanied
35   * by the region affected.  HMsg may also carry an optional message.
36   * 
37   * <p>TODO: Clean out all messages that go from master to regionserver; by
38   * design, these are to go via zk from here on out.
39   */
40  public class HMsg implements Writable {
41    public static final HMsg [] STOP_REGIONSERVER_ARRAY =
42      new HMsg [] {new HMsg(Type.STOP_REGIONSERVER)};
43    public static final HMsg [] EMPTY_HMSG_ARRAY = new HMsg[0];
44  
45    public static enum Type {
46      /** Master tells region server to stop.
47       */
48      STOP_REGIONSERVER,
49  
50      /**
51       * Region server split the region associated with this message.
52       */
53      REGION_SPLIT,
54  
55      /**
56       * When RegionServer receives this message, it goes into a sleep that only
57       * an exit will cure.  This message is sent by unit tests simulating
58       * pathological states.
59       */
60      TESTING_BLOCK_REGIONSERVER,
61    }
62  
63    private Type type = null;
64    private HRegionInfo info = null;
65    private byte[] message = null;
66    private HRegionInfo daughterA = null;
67    private HRegionInfo daughterB = null;
68  
69    /** Default constructor. Used during deserialization */
70    public HMsg() {
71      this(null);
72    }
73  
74    /**
75     * Construct a message with the specified message and empty HRegionInfo
76     * @param type Message type
77     */
78    public HMsg(final HMsg.Type type) {
79      this(type, new HRegionInfo(), null);
80    }
81  
82    /**
83     * Construct a message with the specified message and HRegionInfo
84     * @param type Message type
85     * @param hri Region to which message <code>type</code> applies
86     */
87    public HMsg(final HMsg.Type type, final HRegionInfo hri) {
88      this(type, hri, null);
89    }
90  
91    /**
92     * Construct a message with the specified message and HRegionInfo
93     *
94     * @param type Message type
95     * @param hri Region to which message <code>type</code> applies.  Cannot be
96     * null.  If no info associated, used other Constructor.
97     * @param msg Optional message (Stringified exception, etc.)
98     */
99    public HMsg(final HMsg.Type type, final HRegionInfo hri, final byte[] msg) {
100     this(type, hri, null, null, msg);
101   }
102 
103   /**
104    * Construct a message with the specified message and HRegionInfo
105    *
106    * @param type Message type
107    * @param hri Region to which message <code>type</code> applies.  Cannot be
108    * null.  If no info associated, used other Constructor.
109    * @param daughterA
110    * @param daughterB
111    * @param msg Optional message (Stringified exception, etc.)
112    */
113   public HMsg(final HMsg.Type type, final HRegionInfo hri,
114       final HRegionInfo daughterA, final HRegionInfo daughterB, final byte[] msg) {
115     this.type = type;
116     if (hri == null) {
117       throw new NullPointerException("Region cannot be null");
118     }
119     this.info = hri;
120     this.message = msg;
121     this.daughterA = daughterA;
122     this.daughterB = daughterB;
123   }
124 
125   /**
126    * @return Region info or null if none associated with this message type.
127    */
128   public HRegionInfo getRegionInfo() {
129     return this.info;
130   }
131 
132   /** @return the type of message */
133   public Type getType() {
134     return this.type;
135   }
136 
137   /**
138    * @param other Message type to compare to
139    * @return True if we are of same message type as <code>other</code>
140    */
141   public boolean isType(final HMsg.Type other) {
142     return this.type.equals(other);
143   }
144 
145   /** @return the message type */
146   public byte[] getMessage() {
147     return this.message;
148   }
149 
150   /**
151    * @return First daughter if Type is MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS else
152    * null
153    */
154   public HRegionInfo getDaughterA() {
155     return this.daughterA;
156   }
157 
158   /**
159    * @return Second daughter if Type is MSG_REPORT_SPLIT_INCLUDES_DAUGHTERS else
160    * null
161    */
162   public HRegionInfo getDaughterB() {
163     return this.daughterB;
164   }
165 
166   /**
167    * @see java.lang.Object#toString()
168    */
169   @Override
170   public String toString() {
171     StringBuilder sb = new StringBuilder();
172     sb.append(this.type.toString());
173     // If null or empty region, don't bother printing it out.
174     if (this.info != null && this.info.getRegionName().length > 0) {
175       sb.append(": ");
176       sb.append(this.info.getRegionNameAsString());
177     }
178     if (this.message != null && this.message.length > 0) {
179       sb.append(": " + Bytes.toString(this.message));
180     }
181     return sb.toString();
182   }
183 
184   /**
185    * @see java.lang.Object#equals(java.lang.Object)
186    */
187   @Override
188   public boolean equals(Object obj) {
189     if (this == obj) {
190       return true;
191     }
192     if (obj == null) {
193       return false;
194     }
195     if (getClass() != obj.getClass()) {
196       return false;
197     }
198     HMsg that = (HMsg)obj;
199     return this.type.equals(that.type) &&
200       (this.info != null)? this.info.equals(that.info):
201         that.info == null;
202   }
203 
204   /**
205    * @see java.lang.Object#hashCode()
206    */
207   @Override
208   public int hashCode() {
209     int result = this.type.hashCode();
210     if (this.info != null) {
211       result ^= this.info.hashCode();
212     }
213     return result;
214   }
215 
216   // ////////////////////////////////////////////////////////////////////////////
217   // Writable
218   //////////////////////////////////////////////////////////////////////////////
219 
220   /**
221    * @see org.apache.hadoop.io.Writable#write(java.io.DataOutput)
222    */
223   public void write(DataOutput out) throws IOException {
224      out.writeInt(this.type.ordinal());
225      this.info.write(out);
226      if (this.message == null || this.message.length == 0) {
227        out.writeBoolean(false);
228      } else {
229        out.writeBoolean(true);
230        Bytes.writeByteArray(out, this.message);
231      }
232      if (this.type.equals(Type.REGION_SPLIT)) {
233        this.daughterA.write(out);
234        this.daughterB.write(out);
235      }
236    }
237 
238   /**
239    * @see org.apache.hadoop.io.Writable#readFields(java.io.DataInput)
240    */
241   public void readFields(DataInput in) throws IOException {
242      int ordinal = in.readInt();
243      this.type = HMsg.Type.values()[ordinal];
244      this.info.readFields(in);
245      boolean hasMessage = in.readBoolean();
246      if (hasMessage) {
247        this.message = Bytes.readByteArray(in);
248      }
249      if (this.type.equals(Type.REGION_SPLIT)) {
250        this.daughterA = new HRegionInfo();
251        this.daughterB = new HRegionInfo();
252        this.daughterA.readFields(in);
253        this.daughterB.readFields(in);
254      }
255    }
256 }