001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.client; 020 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Iterator; 024import java.util.List; 025 026import org.apache.hadoop.hbase.util.Bytes; 027import org.apache.yetus.audience.InterfaceAudience; 028 029/** 030 * Utility methods which contain the logic for regions and replicas. 031 */ 032@InterfaceAudience.Private 033public class RegionReplicaUtil { 034 035 /** 036 * Whether or not the secondary region will wait for observing a flush / region open event 037 * from the primary region via async wal replication before enabling read requests. Since replayed 038 * edits from async wal replication from primary is not persisted in WAL, the memstore of the 039 * secondary region might be non-empty at the time of close or crash. For ensuring seqId's not 040 * "going back in time" in the secondary region replica, this should be enabled. However, in some 041 * cases the above semantics might be ok for some application classes. 042 * See HBASE-11580 for more context. 043 */ 044 public static final String REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY 045 = "hbase.region.replica.wait.for.primary.flush"; 046 protected static final boolean DEFAULT_REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH = true; 047 048 /** 049 * The default replicaId for the region 050 */ 051 static final int DEFAULT_REPLICA_ID = 0; 052 053 /** 054 * Returns the RegionInfo for the given replicaId. 055 * RegionInfo's correspond to a range of a table, but more than one 056 * "instance" of the same range can be deployed which are differentiated by 057 * the replicaId. 058 * @param regionInfo 059 * @param replicaId the replicaId to use 060 * @return an RegionInfo object corresponding to the same range (table, start and 061 * end key), but for the given replicaId. 062 */ 063 public static RegionInfo getRegionInfoForReplica(RegionInfo regionInfo, int replicaId) { 064 if (regionInfo.getReplicaId() == replicaId) { 065 return regionInfo; 066 } 067 return RegionInfoBuilder.newBuilder(regionInfo).setReplicaId(replicaId).build(); 068 } 069 070 /** 071 * Returns the RegionInfo for the default replicaId (0). RegionInfo's correspond to 072 * a range of a table, but more than one "instance" of the same range can be 073 * deployed which are differentiated by the replicaId. 074 * @return an RegionInfo object corresponding to the same range (table, start and 075 * end key), but for the default replicaId. 076 */ 077 public static RegionInfo getRegionInfoForDefaultReplica(RegionInfo regionInfo) { 078 return getRegionInfoForReplica(regionInfo, DEFAULT_REPLICA_ID); 079 } 080 081 /** @return true if this replicaId corresponds to default replica for the region */ 082 public static boolean isDefaultReplica(int replicaId) { 083 return DEFAULT_REPLICA_ID == replicaId; 084 } 085 086 /** @return true if this region is a default replica for the region */ 087 public static boolean isDefaultReplica(RegionInfo hri) { 088 return hri.getReplicaId() == DEFAULT_REPLICA_ID; 089 } 090 091 /** 092 * Removes the non-default replicas from the passed regions collection 093 * @param regions 094 */ 095 public static void removeNonDefaultRegions(Collection<RegionInfo> regions) { 096 Iterator<RegionInfo> iterator = regions.iterator(); 097 while (iterator.hasNext()) { 098 RegionInfo hri = iterator.next(); 099 if (!RegionReplicaUtil.isDefaultReplica(hri)) { 100 iterator.remove(); 101 } 102 } 103 } 104 105 public static boolean isReplicasForSameRegion(RegionInfo regionInfoA, RegionInfo regionInfoB) { 106 return compareRegionInfosWithoutReplicaId(regionInfoA, regionInfoB) == 0; 107 } 108 109 private static int compareRegionInfosWithoutReplicaId(RegionInfo regionInfoA, 110 RegionInfo regionInfoB) { 111 int result = regionInfoA.getTable().compareTo(regionInfoB.getTable()); 112 if (result != 0) { 113 return result; 114 } 115 116 // Compare start keys. 117 result = Bytes.compareTo(regionInfoA.getStartKey(), regionInfoB.getStartKey()); 118 if (result != 0) { 119 return result; 120 } 121 122 // Compare end keys. 123 result = Bytes.compareTo(regionInfoA.getEndKey(), regionInfoB.getEndKey()); 124 125 if (result != 0) { 126 if (regionInfoA.getStartKey().length != 0 127 && regionInfoA.getEndKey().length == 0) { 128 return 1; // this is last region 129 } 130 if (regionInfoB.getStartKey().length != 0 131 && regionInfoB.getEndKey().length == 0) { 132 return -1; // o is the last region 133 } 134 return result; 135 } 136 137 // regionId is usually milli timestamp -- this defines older stamps 138 // to be "smaller" than newer stamps in sort order. 139 if (regionInfoA.getRegionId() > regionInfoB.getRegionId()) { 140 return 1; 141 } else if (regionInfoA.getRegionId() < regionInfoB.getRegionId()) { 142 return -1; 143 } 144 return 0; 145 } 146 147 /** 148 * Create any replicas for the regions (the default replicas that was already created is passed to 149 * the method) 150 * @param tableDescriptor descriptor to use 151 * @param regions existing regions 152 * @param oldReplicaCount existing replica count 153 * @param newReplicaCount updated replica count due to modify table 154 * @return the combined list of default and non-default replicas 155 */ 156 public static List<RegionInfo> addReplicas(final TableDescriptor tableDescriptor, 157 final List<RegionInfo> regions, int oldReplicaCount, int newReplicaCount) { 158 if ((newReplicaCount - 1) <= 0) { 159 return regions; 160 } 161 List<RegionInfo> hRegionInfos = new ArrayList<>((newReplicaCount) * regions.size()); 162 for (RegionInfo ri : regions) { 163 if (RegionReplicaUtil.isDefaultReplica(ri) && 164 (!ri.isOffline() || (!ri.isSplit() && !ri.isSplitParent()))) { 165 // region level replica index starts from 0. So if oldReplicaCount was 2 then the max replicaId for 166 // the existing regions would be 1 167 for (int j = oldReplicaCount; j < newReplicaCount; j++) { 168 hRegionInfos.add(RegionReplicaUtil.getRegionInfoForReplica(ri, j)); 169 } 170 } 171 } 172 hRegionInfos.addAll(regions); 173 return hRegionInfos; 174 } 175}