HBASE-26688 Threads shared EMPTY_RESULT may lead to unexpected client job down. ...
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / client / MutableRegionInfo.java
blob0aa301c4c8cd95d1472ffbf26e5bae8cecf802f5
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.client;
19 import java.util.Arrays;
20 import org.apache.hadoop.hbase.CellComparator;
21 import org.apache.hadoop.hbase.CellComparatorImpl;
22 import org.apache.hadoop.hbase.HConstants;
23 import org.apache.hadoop.hbase.TableName;
24 import org.apache.hadoop.hbase.util.Bytes;
25 import org.apache.yetus.audience.InterfaceAudience;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 /**
30 * An implementation of RegionInfo that adds mutable methods so can build a RegionInfo instance.
31 * Package private. Use {@link RegionInfoBuilder} creating instances of {@link RegionInfo}s.
33 @InterfaceAudience.Private
34 class MutableRegionInfo implements RegionInfo {
35 private static final Logger LOG = LoggerFactory.getLogger(MutableRegionInfo.class);
36 private static final int MAX_REPLICA_ID = 0xFFFF;
38 /**
39 * The new format for a region name contains its encodedName at the end.
40 * The encoded name also serves as the directory name for the region
41 * in the filesystem.
43 * New region name format:
44 * <tablename>,,<startkey>,<regionIdTimestamp>.<encodedName>.
45 * where,
46 * <encodedName> is a hex version of the MD5 hash of
47 * <tablename>,<startkey>,<regionIdTimestamp>
49 * The old region name format:
50 * <tablename>,<startkey>,<regionIdTimestamp>
51 * For region names in the old format, the encoded name is a 32-bit
52 * JenkinsHash integer value (in its decimal notation, string form).
53 *<p>
54 * **NOTE**
56 * The first hbase:meta region, and regions created by an older
57 * version of HBase (0.20 or prior) will continue to use the
58 * old region name format.
61 // This flag is in the parent of a split while the parent is still referenced by daughter
62 // regions. We USED to set this flag when we disabled a table but now table state is kept up in
63 // zookeeper as of 0.90.0 HBase. And now in DisableTableProcedure, finally we will create bunch
64 // of UnassignProcedures and at the last of the procedure we will set the region state to
65 // CLOSED, and will not change the offLine flag.
66 private boolean offLine;
67 private boolean split;
68 private final long regionId;
69 private final int replicaId;
70 private final byte[] regionName;
71 private final byte[] startKey;
72 private final byte[] endKey;
73 private final int hashCode;
74 private final String encodedName;
75 private final byte[] encodedNameAsBytes;
76 private final TableName tableName;
78 private static int generateHashCode(final TableName tableName, final byte[] startKey,
79 final byte[] endKey, final long regionId,
80 final int replicaId, boolean offLine, byte[] regionName) {
81 int result = Arrays.hashCode(regionName);
82 result = (int) (result ^ regionId);
83 result ^= Arrays.hashCode(checkStartKey(startKey));
84 result ^= Arrays.hashCode(checkEndKey(endKey));
85 result ^= Boolean.valueOf(offLine).hashCode();
86 result ^= Arrays.hashCode(tableName.getName());
87 result ^= replicaId;
88 return result;
91 private static byte[] checkStartKey(byte[] startKey) {
92 return startKey == null? HConstants.EMPTY_START_ROW: startKey;
95 private static byte[] checkEndKey(byte[] endKey) {
96 return endKey == null? HConstants.EMPTY_END_ROW: endKey;
99 private static TableName checkTableName(TableName tableName) {
100 if (tableName == null) {
101 throw new IllegalArgumentException("TableName cannot be null");
103 return tableName;
106 private static int checkReplicaId(int regionId) {
107 if (regionId > MAX_REPLICA_ID) {
108 throw new IllegalArgumentException("ReplicaId cannot be greater than" + MAX_REPLICA_ID);
110 return regionId;
114 * Package private constructor used constructing MutableRegionInfo for the first meta regions
116 MutableRegionInfo(long regionId, TableName tableName, int replicaId) {
117 this(tableName, HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, false, regionId,
118 replicaId, false);
121 MutableRegionInfo(final TableName tableName, final byte[] startKey, final byte[] endKey,
122 final boolean split, final long regionId, final int replicaId, boolean offLine) {
123 this.tableName = checkTableName(tableName);
124 this.startKey = checkStartKey(startKey);
125 this.endKey = checkEndKey(endKey);
126 this.split = split;
127 this.regionId = regionId;
128 this.replicaId = checkReplicaId(replicaId);
129 this.offLine = offLine;
130 this.regionName = RegionInfo.createRegionName(this.tableName, this.startKey, this.regionId,
131 this.replicaId, !this.tableName.equals(TableName.META_TABLE_NAME));
132 this.encodedName = RegionInfo.encodeRegionName(this.regionName);
133 this.hashCode = generateHashCode(this.tableName, this.startKey, this.endKey, this.regionId,
134 this.replicaId, this.offLine, this.regionName);
135 this.encodedNameAsBytes = Bytes.toBytes(this.encodedName);
139 * @return Return a short, printable name for this region (usually encoded name) for us logging.
141 @Override
142 public String getShortNameToLog() {
143 return RegionInfo.prettyPrint(this.getEncodedName());
146 /** @return the regionId */
147 @Override
148 public long getRegionId(){
149 return regionId;
154 * @return the regionName as an array of bytes.
155 * @see #getRegionNameAsString()
157 @Override
158 public byte[] getRegionName() {
159 return regionName;
163 * @return Region name as a String for use in logging, etc.
165 @Override
166 public String getRegionNameAsString() {
167 return RegionInfo.getRegionNameAsString(this, this.regionName);
170 /** @return the encoded region name */
171 @Override
172 public String getEncodedName() {
173 return this.encodedName;
176 @Override
177 public byte[] getEncodedNameAsBytes() {
178 return this.encodedNameAsBytes;
181 /** @return the startKey */
182 @Override
183 public byte[] getStartKey() {
184 return startKey;
187 /** @return the endKey */
188 @Override
189 public byte[] getEndKey() {
190 return endKey;
194 * Get current table name of the region
195 * @return TableName
197 @Override
198 public TableName getTable() {
199 return this.tableName;
203 * Returns true if the given inclusive range of rows is fully contained
204 * by this region. For example, if the region is foo,a,g and this is
205 * passed ["b","c"] or ["a","c"] it will return true, but if this is passed
206 * ["b","z"] it will return false.
207 * @throws IllegalArgumentException if the range passed is invalid (ie. end &lt; start)
209 @Override
210 public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) {
211 CellComparator cellComparator = CellComparatorImpl.getCellComparator(tableName);
212 if (cellComparator.compareRows(rangeStartKey, rangeEndKey) > 0) {
213 throw new IllegalArgumentException(
214 "Invalid range: " + Bytes.toStringBinary(rangeStartKey) +
215 " > " + Bytes.toStringBinary(rangeEndKey));
218 boolean firstKeyInRange = cellComparator.compareRows(rangeStartKey, startKey) >= 0;
219 boolean lastKeyInRange =
220 cellComparator.compareRows(rangeEndKey, endKey) < 0 ||
221 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY);
222 return firstKeyInRange && lastKeyInRange;
226 * Return true if the given row falls in this region.
228 @Override
229 public boolean containsRow(byte[] row) {
230 CellComparator cellComparator = CellComparatorImpl.getCellComparator(tableName);
231 return cellComparator.compareRows(row, startKey) >= 0 &&
232 (cellComparator.compareRows(row, endKey) < 0 ||
233 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY));
236 /** @return true if this region is a meta region */
237 @Override
238 public boolean isMetaRegion() {
239 return tableName.equals(TableName.META_TABLE_NAME);
243 * @return True if has been split and has daughters.
245 @Override
246 public boolean isSplit() {
247 return this.split;
251 * @param split set split status
252 * @return MutableRegionInfo
254 public MutableRegionInfo setSplit(boolean split) {
255 this.split = split;
256 return this;
260 * @return True if this region is offline.
261 * @deprecated since 3.0.0 and will be removed in 4.0.0
262 * @see <a href="https://issues.apache.org/jira/browse/HBASE-25210">HBASE-25210</a>
264 @Override
265 @Deprecated
266 public boolean isOffline() {
267 return this.offLine;
271 * The parent of a region split is offline while split daughters hold
272 * references to the parent. Offlined regions are closed.
273 * @param offLine Set online/offline status.
274 * @return MutableRegionInfo
276 public MutableRegionInfo setOffline(boolean offLine) {
277 this.offLine = offLine;
278 return this;
282 * @return True if this is a split parent region.
283 * @deprecated since 3.0.0 and will be removed in 4.0.0, Use {@link #isSplit()} instead.
284 * @see <a href="https://issues.apache.org/jira/browse/HBASE-25210">HBASE-25210</a>
286 @Override
287 @Deprecated
288 public boolean isSplitParent() {
289 if (!isSplit()) {
290 return false;
292 if (!isOffline()) {
293 LOG.warn("Region is split but NOT offline: " + getRegionNameAsString());
295 return true;
299 * Returns the region replica id
300 * @return returns region replica id
302 @Override
303 public int getReplicaId() {
304 return replicaId;
308 * @see Object#toString()
310 @Override
311 public String toString() {
312 return "{ENCODED => " + getEncodedName() + ", " +
313 HConstants.NAME + " => '" + Bytes.toStringBinary(this.regionName)
314 + "', STARTKEY => '" +
315 Bytes.toStringBinary(this.startKey) + "', ENDKEY => '" +
316 Bytes.toStringBinary(this.endKey) + "'" +
317 (isOffline()? ", OFFLINE => true": "") +
318 (isSplit()? ", SPLIT => true": "") +
319 ((replicaId > 0)? ", REPLICA_ID => " + replicaId : "") + "}";
323 * @see Object#equals(Object)
325 @Override
326 public boolean equals(Object o) {
327 if (this == o) {
328 return true;
330 if (o == null) {
331 return false;
333 if (!(o instanceof RegionInfo)) {
334 return false;
336 return compareTo((RegionInfo)o) == 0;
340 * @see Object#hashCode()
342 @Override
343 public int hashCode() {
344 return this.hashCode;