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.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25
26 import org.apache.hadoop.hbase.ServerName;
27 import org.apache.hadoop.hbase.executor.EventHandler.EventType;
28 import org.apache.hadoop.hbase.util.Bytes;
29 import org.apache.hadoop.hbase.util.Writables;
30 import org.apache.hadoop.io.Writable;
31
32 /**
33 * Data serialized into ZooKeeper for region transitions.
34 */
35 public class RegionTransitionData implements Writable {
36 /**
37 * Type of transition event (offline, opening, opened, closing, closed).
38 * Required.
39 */
40 private EventType eventType;
41
42 /** Region being transitioned. Required. */
43 private byte [] regionName;
44
45 /** Server event originated from. Optional. */
46 private ServerName origin;
47
48 /** Time the event was created. Required but automatically set. */
49 private long stamp;
50
51 private byte [] payload;
52
53 /**
54 * Writable constructor. Do not use directly.
55 */
56 public RegionTransitionData() {}
57
58 /**
59 * Construct data for a new region transition event with the specified event
60 * type and region name.
61 *
62 * <p>Used when the server name is not known (the master is setting it). This
63 * happens during cluster startup or during failure scenarios. When
64 * processing a failed regionserver, the master assigns the regions from that
65 * server to other servers though the region was never 'closed'. During
66 * master failover, the new master may have regions stuck in transition
67 * without a destination so may have to set regions offline and generate a new
68 * assignment.
69 *
70 * <p>Since only the master uses this constructor, the type should always be
71 * {@link EventType#M_ZK_REGION_OFFLINE}.
72 *
73 * @param eventType type of event
74 * @param regionName name of region as per <code>HRegionInfo#getRegionName()</code>
75 */
76 public RegionTransitionData(EventType eventType, byte [] regionName) {
77 this(eventType, regionName, null);
78 }
79
80 /**
81 * Construct data for a new region transition event with the specified event
82 * type, region name, and server name.
83 *
84 * <p>Used when the server name is known (a regionserver is setting it).
85 *
86 * <p>Valid types for this constructor are {@link EventType#M_ZK_REGION_CLOSING},
87 * {@link EventType#RS_ZK_REGION_CLOSED}, {@link EventType#RS_ZK_REGION_OPENING},
88 * {@link EventType#RS_ZK_REGION_SPLITTING},
89 * and {@link EventType#RS_ZK_REGION_OPENED}.
90 *
91 * @param eventType type of event
92 * @param regionName name of region as per <code>HRegionInfo#getRegionName()</code>
93 * @param origin Originating {@link ServerName}
94 */
95 public RegionTransitionData(EventType eventType, byte [] regionName,
96 final ServerName origin) {
97 this(eventType, regionName, origin, null);
98 }
99
100 /**
101 * Construct data for a new region transition event with the specified event
102 * type, region name, and server name.
103 *
104 * <p>Used when the server name is known (a regionserver is setting it).
105 *
106 * <p>Valid types for this constructor are {@link EventType#RS_ZK_REGION_SPLIT}
107 * since SPLIT is only type that currently carries a payload.
108 *
109 * @param eventType type of event
110 * @param regionName name of region as per <code>HRegionInfo#getRegionName()</code>
111 * @param serverName Originating {@link ServerName}
112 * @param payload Payload examples include the daughters involved in a
113 * {@link EventType#RS_ZK_REGION_SPLIT}. Can be null
114 */
115 public RegionTransitionData(EventType eventType, byte [] regionName,
116 final ServerName serverName, final byte [] payload) {
117 this.eventType = eventType;
118 this.stamp = System.currentTimeMillis();
119 this.regionName = regionName;
120 this.origin = serverName;
121 this.payload = payload;
122 }
123
124 /**
125 * Gets the type of region transition event.
126 *
127 * <p>One of:
128 * <ul>
129 * <li>{@link EventType#M_ZK_REGION_OFFLINE}
130 * <li>{@link EventType#M_ZK_REGION_CLOSING}
131 * <li>{@link EventType#RS_ZK_REGION_CLOSED}
132 * <li>{@link EventType#RS_ZK_REGION_OPENING}
133 * <li>{@link EventType#RS_ZK_REGION_OPENED}
134 * <li>{@link EventType#RS_ZK_REGION_SPLITTING}
135 * <li>{@link EventType#RS_ZK_REGION_SPLIT}
136 * </ul>
137 * @return type of region transition event
138 */
139 public EventType getEventType() {
140 return eventType;
141 }
142
143 /**
144 * Gets the name of the region being transitioned.
145 *
146 * <p>Region name is required so this never returns null.
147 * @return region name, the result of a call to <code>HRegionInfo#getRegionName()</code>
148 */
149 public byte [] getRegionName() {
150 return regionName;
151 }
152
153 /**
154 * Gets the server the event originated from. If null, this event originated
155 * from the master.
156 *
157 * @return server name of originating regionserver, or null if from master
158 */
159 public ServerName getOrigin() {
160 return origin;
161 }
162
163 /**
164 * Gets the timestamp when this event was created.
165 *
166 * @return stamp event was created
167 */
168 public long getStamp() {
169 return stamp;
170 }
171
172 /**
173 * @return Payload if any.
174 */
175 public byte [] getPayload() {
176 return this.payload;
177 }
178
179 @Override
180 public void readFields(DataInput in) throws IOException {
181 // the event type byte
182 eventType = EventType.values()[in.readShort()];
183 // the timestamp
184 stamp = in.readLong();
185 // the encoded name of the region being transitioned
186 regionName = Bytes.readByteArray(in);
187 // remaining fields are optional so prefixed with boolean
188 // the name of the regionserver sending the data
189 if (in.readBoolean()) {
190 byte [] versionedBytes = Bytes.readByteArray(in);
191 this.origin = ServerName.parseVersionedServerName(versionedBytes);
192 }
193 if (in.readBoolean()) {
194 this.payload = Bytes.readByteArray(in);
195 }
196 }
197
198 @Override
199 public void write(DataOutput out) throws IOException {
200 out.writeShort(eventType.ordinal());
201 out.writeLong(System.currentTimeMillis());
202 Bytes.writeByteArray(out, regionName);
203 // remaining fields are optional so prefixed with boolean
204 out.writeBoolean(this.origin != null);
205 if (this.origin != null) {
206 Bytes.writeByteArray(out, this.origin.getVersionedBytes());
207 }
208 out.writeBoolean(this.payload != null);
209 if (this.payload != null) {
210 Bytes.writeByteArray(out, this.payload);
211 }
212 }
213
214 /**
215 * Get the bytes for this instance. Throws a {@link RuntimeException} if
216 * there is an error deserializing this instance because it represents a code
217 * bug.
218 * @return binary representation of this instance
219 */
220 public byte [] getBytes() {
221 try {
222 return Writables.getBytes(this);
223 } catch(IOException e) {
224 throw new RuntimeException(e);
225 }
226 }
227
228 /**
229 * Get an instance from bytes. Throws a {@link RuntimeException} if
230 * there is an error serializing this instance from bytes because it
231 * represents a code bug.
232 * @param bytes binary representation of this instance
233 * @return instance of this class
234 */
235 public static RegionTransitionData fromBytes(byte [] bytes) {
236 try {
237 RegionTransitionData data = new RegionTransitionData();
238 Writables.getWritable(bytes, data);
239 return data;
240 } catch(IOException e) {
241 throw new RuntimeException(e);
242 }
243 }
244
245 @Override
246 public String toString() {
247 return "region=" + Bytes.toStringBinary(regionName) + ", origin=" + this.origin +
248 ", state=" + eventType;
249 }
250 }