HBASE-19498 Fix findbugs and error-prone warnings in hbase-client (branch-2)
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / client / RegionInfoBuilder.java
blobe17e307205c055d4ccf18775fd911cebc84e2640
1 /**
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 package org.apache.hadoop.hbase.client;
21 import java.util.Arrays;
23 import org.apache.commons.lang3.ArrayUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.hbase.HConstants;
27 import org.apache.hadoop.hbase.TableName;
28 import org.apache.hadoop.hbase.util.Bytes;
29 import org.apache.yetus.audience.InterfaceAudience;
31 @InterfaceAudience.Private
32 public class RegionInfoBuilder {
33 private static final Log LOG = LogFactory.getLog(RegionInfoBuilder.class);
35 /** A non-capture group so that this can be embedded. */
36 public static final String ENCODED_REGION_NAME_REGEX = "(?:[a-f0-9]+)";
38 private static final int MAX_REPLICA_ID = 0xFFFF;
40 //TODO: Move NO_HASH to HStoreFile which is really the only place it is used.
41 public static final String NO_HASH = null;
43 /**
44 * RegionInfo for first meta region
45 * You cannot use this builder to make an instance of the {@link #FIRST_META_REGIONINFO}.
46 * Just refer to this instance. Also, while the instance is actually a MutableRI, its type is
47 * just RI so the mutable methods are not available (unless you go casting); it appears
48 * as immutable (I tried adding Immutable type but it just makes a mess).
50 // TODO: How come Meta regions still do not have encoded region names? Fix.
51 // hbase:meta,,1.1588230740 should be the hbase:meta first region name.
52 public static final RegionInfo FIRST_META_REGIONINFO =
53 new MutableRegionInfo(1L, TableName.META_TABLE_NAME, RegionInfo.DEFAULT_REPLICA_ID);
55 private final TableName tableName;
56 private byte[] startKey = HConstants.EMPTY_START_ROW;
57 private byte[] endKey = HConstants.EMPTY_END_ROW;
58 private long regionId = System.currentTimeMillis();
59 private int replicaId = RegionInfo.DEFAULT_REPLICA_ID;
60 private boolean offLine = false;
61 private boolean split = false;
62 private byte[] regionName = null;
63 private String encodedName = null;
65 public static RegionInfoBuilder newBuilder(TableName tableName) {
66 return new RegionInfoBuilder(tableName);
69 public static RegionInfoBuilder newBuilder(RegionInfo regionInfo) {
70 return new RegionInfoBuilder(regionInfo);
73 private RegionInfoBuilder(TableName tableName) {
74 this.tableName = tableName;
77 private RegionInfoBuilder(RegionInfo regionInfo) {
78 this.tableName = regionInfo.getTable();
79 this.startKey = regionInfo.getStartKey();
80 this.endKey = regionInfo.getEndKey();
81 this.offLine = regionInfo.isOffline();
82 this.split = regionInfo.isSplit();
83 this.regionId = regionInfo.getRegionId();
84 this.replicaId = regionInfo.getReplicaId();
85 this.regionName = regionInfo.getRegionName();
86 this.encodedName = regionInfo.getEncodedName();
89 public RegionInfoBuilder setStartKey(byte[] startKey) {
90 this.startKey = startKey;
91 return this;
94 public RegionInfoBuilder setEndKey(byte[] endKey) {
95 this.endKey = endKey;
96 return this;
99 public RegionInfoBuilder setRegionId(long regionId) {
100 this.regionId = regionId;
101 return this;
104 public RegionInfoBuilder setReplicaId(int replicaId) {
105 this.replicaId = replicaId;
106 return this;
109 public RegionInfoBuilder setSplit(boolean split) {
110 this.split = split;
111 return this;
114 public RegionInfoBuilder setOffline(boolean offLine) {
115 this.offLine = offLine;
116 return this;
119 public RegionInfo build() {
120 return new MutableRegionInfo(tableName, startKey, endKey, split,
121 regionId, replicaId, offLine, regionName, encodedName);
125 * An implementation of RegionInfo that adds mutable methods so can build a RegionInfo instance.
127 @InterfaceAudience.Private
128 static class MutableRegionInfo implements RegionInfo, Comparable<RegionInfo> {
130 * The new format for a region name contains its encodedName at the end.
131 * The encoded name also serves as the directory name for the region
132 * in the filesystem.
134 * New region name format:
135 * &lt;tablename>,,&lt;startkey>,&lt;regionIdTimestamp>.&lt;encodedName>.
136 * where,
137 * &lt;encodedName> is a hex version of the MD5 hash of
138 * &lt;tablename>,&lt;startkey>,&lt;regionIdTimestamp>
140 * The old region name format:
141 * &lt;tablename>,&lt;startkey>,&lt;regionIdTimestamp>
142 * For region names in the old format, the encoded name is a 32-bit
143 * JenkinsHash integer value (in its decimal notation, string form).
144 *<p>
145 * **NOTE**
147 * The first hbase:meta region, and regions created by an older
148 * version of HBase (0.20 or prior) will continue to use the
149 * old region name format.
152 // This flag is in the parent of a split while the parent is still referenced
153 // by daughter regions. We USED to set this flag when we disabled a table
154 // but now table state is kept up in zookeeper as of 0.90.0 HBase.
155 private boolean offLine = false;
156 private boolean split = false;
157 private final long regionId;
158 private final int replicaId;
159 private final byte[] regionName;
160 private final byte[] startKey;
161 private final byte[] endKey;
162 private final int hashCode;
163 private final String encodedName;
164 private final byte[] encodedNameAsBytes;
165 private final TableName tableName;
167 private static int generateHashCode(final TableName tableName, final byte[] startKey,
168 final byte[] endKey, final long regionId,
169 final int replicaId, boolean offLine, byte[] regionName) {
170 int result = Arrays.hashCode(regionName);
171 result = (int) (result ^ regionId);
172 result ^= Arrays.hashCode(checkStartKey(startKey));
173 result ^= Arrays.hashCode(checkEndKey(endKey));
174 result ^= Boolean.valueOf(offLine).hashCode();
175 result ^= Arrays.hashCode(tableName.getName());
176 result ^= replicaId;
177 return result;
180 private static byte[] checkStartKey(byte[] startKey) {
181 return startKey == null? HConstants.EMPTY_START_ROW: startKey;
184 private static byte[] checkEndKey(byte[] endKey) {
185 return endKey == null? HConstants.EMPTY_END_ROW: endKey;
188 private static TableName checkTableName(TableName tableName) {
189 if (tableName == null) {
190 throw new IllegalArgumentException("TableName cannot be null");
192 return tableName;
195 private static int checkReplicaId(int regionId) {
196 if (regionId > MAX_REPLICA_ID) {
197 throw new IllegalArgumentException("ReplicaId cannot be greater than" + MAX_REPLICA_ID);
199 return regionId;
203 * Private constructor used constructing MutableRegionInfo for the
204 * first meta regions
206 private MutableRegionInfo(long regionId, TableName tableName, int replicaId) {
207 this(tableName,
208 HConstants.EMPTY_START_ROW,
209 HConstants.EMPTY_END_ROW,
210 false,
211 regionId,
212 replicaId,
213 false,
214 RegionInfo.createRegionName(tableName, null, regionId, replicaId, false));
217 MutableRegionInfo(final TableName tableName, final byte[] startKey,
218 final byte[] endKey, final boolean split, final long regionId,
219 final int replicaId, boolean offLine, byte[] regionName) {
220 this(checkTableName(tableName),
221 checkStartKey(startKey),
222 checkEndKey(endKey),
223 split, regionId,
224 checkReplicaId(replicaId),
225 offLine,
226 regionName,
227 RegionInfo.encodeRegionName(regionName));
230 MutableRegionInfo(final TableName tableName, final byte[] startKey,
231 final byte[] endKey, final boolean split, final long regionId,
232 final int replicaId, boolean offLine, byte[] regionName, String encodedName) {
233 this.tableName = checkTableName(tableName);
234 this.startKey = checkStartKey(startKey);
235 this.endKey = checkEndKey(endKey);
236 this.split = split;
237 this.regionId = regionId;
238 this.replicaId = checkReplicaId(replicaId);
239 this.offLine = offLine;
240 if (ArrayUtils.isEmpty(regionName)) {
241 this.regionName = RegionInfo.createRegionName(this.tableName, this.startKey, this.regionId, this.replicaId,
242 !this.tableName.equals(TableName.META_TABLE_NAME));
243 this.encodedName = RegionInfo.encodeRegionName(this.regionName);
244 } else {
245 this.regionName = regionName;
246 this.encodedName = encodedName;
248 this.hashCode = generateHashCode(
249 this.tableName,
250 this.startKey,
251 this.endKey,
252 this.regionId,
253 this.replicaId,
254 this.offLine,
255 this.regionName);
256 this.encodedNameAsBytes = Bytes.toBytes(this.encodedName);
259 * @return Return a short, printable name for this region
260 * (usually encoded name) for us logging.
262 @Override
263 public String getShortNameToLog() {
264 return RegionInfo.prettyPrint(this.getEncodedName());
267 /** @return the regionId */
268 @Override
269 public long getRegionId(){
270 return regionId;
275 * @return the regionName as an array of bytes.
276 * @see #getRegionNameAsString()
278 @Override
279 public byte [] getRegionName(){
280 return regionName;
284 * @return Region name as a String for use in logging, etc.
286 @Override
287 public String getRegionNameAsString() {
288 if (RegionInfo.hasEncodedName(this.regionName)) {
289 // new format region names already have their encoded name.
290 return Bytes.toStringBinary(this.regionName);
293 // old format. regionNameStr doesn't have the region name.
296 return Bytes.toStringBinary(this.regionName) + "." + this.getEncodedName();
299 /** @return the encoded region name */
300 @Override
301 public String getEncodedName() {
302 return this.encodedName;
305 @Override
306 public byte [] getEncodedNameAsBytes() {
307 return this.encodedNameAsBytes;
310 /** @return the startKey */
311 @Override
312 public byte [] getStartKey(){
313 return startKey;
317 /** @return the endKey */
318 @Override
319 public byte [] getEndKey(){
320 return endKey;
324 * Get current table name of the region
325 * @return TableName
327 @Override
328 public TableName getTable() {
329 return this.tableName;
333 * Returns true if the given inclusive range of rows is fully contained
334 * by this region. For example, if the region is foo,a,g and this is
335 * passed ["b","c"] or ["a","c"] it will return true, but if this is passed
336 * ["b","z"] it will return false.
337 * @throws IllegalArgumentException if the range passed is invalid (ie. end &lt; start)
339 @Override
340 public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) {
341 if (Bytes.compareTo(rangeStartKey, rangeEndKey) > 0) {
342 throw new IllegalArgumentException(
343 "Invalid range: " + Bytes.toStringBinary(rangeStartKey) +
344 " > " + Bytes.toStringBinary(rangeEndKey));
347 boolean firstKeyInRange = Bytes.compareTo(rangeStartKey, startKey) >= 0;
348 boolean lastKeyInRange =
349 Bytes.compareTo(rangeEndKey, endKey) < 0 ||
350 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY);
351 return firstKeyInRange && lastKeyInRange;
355 * Return true if the given row falls in this region.
357 @Override
358 public boolean containsRow(byte[] row) {
359 return Bytes.compareTo(row, startKey) >= 0 &&
360 (Bytes.compareTo(row, endKey) < 0 ||
361 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY));
364 /** @return true if this region is a meta region */
365 @Override
366 public boolean isMetaRegion() {
367 return tableName.equals(FIRST_META_REGIONINFO.getTable());
371 * @return True if has been split and has daughters.
373 @Override
374 public boolean isSplit() {
375 return this.split;
379 * @param split set split status
380 * @return MutableRegionInfo
382 public MutableRegionInfo setSplit(boolean split) {
383 this.split = split;
384 return this;
388 * @return True if this region is offline.
390 @Override
391 public boolean isOffline() {
392 return this.offLine;
396 * The parent of a region split is offline while split daughters hold
397 * references to the parent. Offlined regions are closed.
398 * @param offLine Set online/offline status.
399 * @return MutableRegionInfo
401 public MutableRegionInfo setOffline(boolean offLine) {
402 this.offLine = offLine;
403 return this;
407 * @return True if this is a split parent region.
409 @Override
410 public boolean isSplitParent() {
411 if (!isSplit()) return false;
412 if (!isOffline()) {
413 LOG.warn("Region is split but NOT offline: " + getRegionNameAsString());
415 return true;
419 * Returns the region replica id
420 * @return returns region replica id
422 @Override
423 public int getReplicaId() {
424 return replicaId;
428 * @see java.lang.Object#toString()
430 @Override
431 public String toString() {
432 return "{ENCODED => " + getEncodedName() + ", " +
433 HConstants.NAME + " => '" + Bytes.toStringBinary(this.regionName)
434 + "', STARTKEY => '" +
435 Bytes.toStringBinary(this.startKey) + "', ENDKEY => '" +
436 Bytes.toStringBinary(this.endKey) + "'" +
437 (isOffline()? ", OFFLINE => true": "") +
438 (isSplit()? ", SPLIT => true": "") +
439 ((replicaId > 0)? ", REPLICA_ID => " + replicaId : "") + "}";
443 * @param o
444 * @see java.lang.Object#equals(java.lang.Object)
446 @Override
447 public boolean equals(Object o) {
448 if (this == o) {
449 return true;
451 if (o == null) {
452 return false;
454 if (!(o instanceof RegionInfo)) {
455 return false;
457 return this.compareTo((RegionInfo)o) == 0;
461 * @see java.lang.Object#hashCode()
463 @Override
464 public int hashCode() {
465 return this.hashCode;
468 @Override
469 public int compareTo(RegionInfo other) {
470 return RegionInfo.COMPARATOR.compare(this, other);