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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 */
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.util.Collection;
22 import java.util.Iterator;
23
24 import org.apache.hadoop.hbase.classification.InterfaceAudience;
25 import org.apache.hadoop.hbase.HRegionInfo;
26 import org.apache.hadoop.hbase.util.Bytes;
27
28 /**
29 * Utility methods which contain the logic for regions and replicas.
30 */
31 @InterfaceAudience.Private
32 public class RegionReplicaUtil {
33
34 /**
35 * Whether or not the secondary region will wait for observing a flush / region open event
36 * from the primary region via async wal replication before enabling read requests. Since replayed
37 * edits from async wal replication from primary is not persisted in WAL, the memstore of the
38 * secondary region might be non-empty at the time of close or crash. For ensuring seqId's not
39 * "going back in time" in the secondary region replica, this should be enabled. However, in some
40 * cases the above semantics might be ok for some application classes.
41 * See HBASE-11580 for more context.
42 */
43 public static final String REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY
44 = "hbase.region.replica.wait.for.primary.flush";
45 protected static final boolean DEFAULT_REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH = true;
46
47 /**
48 * The default replicaId for the region
49 */
50 static final int DEFAULT_REPLICA_ID = 0;
51
52 /**
53 * Returns the HRegionInfo for the given replicaId. HRegionInfo's correspond to
54 * a range of a table, but more than one "instance" of the same range can be
55 * deployed which are differentiated by the replicaId.
56 * @param replicaId the replicaId to use
57 * @return an HRegionInfo object corresponding to the same range (table, start and
58 * end key), but for the given replicaId.
59 */
60 public static HRegionInfo getRegionInfoForReplica(HRegionInfo regionInfo, int replicaId) {
61 if (regionInfo.getReplicaId() == replicaId) {
62 return regionInfo;
63 }
64 HRegionInfo replicaInfo;
65 if (regionInfo.isMetaRegion()) {
66 replicaInfo = new HRegionInfo(regionInfo.getRegionId(), regionInfo.getTable(), replicaId);
67 } else {
68 replicaInfo = new HRegionInfo(regionInfo.getTable(), regionInfo.getStartKey(),
69 regionInfo.getEndKey(), regionInfo.isSplit(), regionInfo.getRegionId(), replicaId);
70 }
71 replicaInfo.setOffline(regionInfo.isOffline());
72 return replicaInfo;
73 }
74
75 /**
76 * Returns the HRegionInfo for the default replicaId (0). HRegionInfo's correspond to
77 * a range of a table, but more than one "instance" of the same range can be
78 * deployed which are differentiated by the replicaId.
79 * @return an HRegionInfo object corresponding to the same range (table, start and
80 * end key), but for the default replicaId.
81 */
82 public static HRegionInfo getRegionInfoForDefaultReplica(HRegionInfo regionInfo) {
83 return getRegionInfoForReplica(regionInfo, DEFAULT_REPLICA_ID);
84 }
85
86 /** @return true if this replicaId corresponds to default replica for the region */
87 public static boolean isDefaultReplica(int replicaId) {
88 return DEFAULT_REPLICA_ID == replicaId;
89 }
90
91 /** @return true if this region is a default replica for the region */
92 public static boolean isDefaultReplica(HRegionInfo hri) {
93 return hri.getReplicaId() == DEFAULT_REPLICA_ID;
94 }
95
96 /**
97 * Removes the non-default replicas from the passed regions collection
98 * @param regions
99 */
100 public static void removeNonDefaultRegions(Collection<HRegionInfo> regions) {
101 Iterator<HRegionInfo> iterator = regions.iterator();
102 while (iterator.hasNext()) {
103 HRegionInfo hri = iterator.next();
104 if (!RegionReplicaUtil.isDefaultReplica(hri)) {
105 iterator.remove();
106 }
107 }
108 }
109
110 public static boolean isReplicasForSameRegion(HRegionInfo regionInfoA, HRegionInfo regionInfoB) {
111 return compareRegionInfosWithoutReplicaId(regionInfoA, regionInfoB) == 0;
112 }
113
114 private static int compareRegionInfosWithoutReplicaId(HRegionInfo regionInfoA,
115 HRegionInfo regionInfoB) {
116 int result = regionInfoA.getTable().compareTo(regionInfoB.getTable());
117 if (result != 0) {
118 return result;
119 }
120
121 // Compare start keys.
122 result = Bytes.compareTo(regionInfoA.getStartKey(), regionInfoB.getStartKey());
123 if (result != 0) {
124 return result;
125 }
126
127 // Compare end keys.
128 result = Bytes.compareTo(regionInfoA.getEndKey(), regionInfoB.getEndKey());
129
130 if (result != 0) {
131 if (regionInfoA.getStartKey().length != 0
132 && regionInfoA.getEndKey().length == 0) {
133 return 1; // this is last region
134 }
135 if (regionInfoB.getStartKey().length != 0
136 && regionInfoB.getEndKey().length == 0) {
137 return -1; // o is the last region
138 }
139 return result;
140 }
141
142 // regionId is usually milli timestamp -- this defines older stamps
143 // to be "smaller" than newer stamps in sort order.
144 if (regionInfoA.getRegionId() > regionInfoB.getRegionId()) {
145 return 1;
146 } else if (regionInfoA.getRegionId() < regionInfoB.getRegionId()) {
147 return -1;
148 }
149 return 0;
150 }
151 }