17
17
*/
18
18
package org .apache .hadoop .hbase .master .balancer ;
19
19
20
+ import org .apache .hadoop .conf .Configuration ;
21
+ import org .apache .hadoop .hbase .client .RegionInfo ;
22
+ import org .apache .hadoop .hbase .client .RegionReplicaUtil ;
20
23
import org .apache .hadoop .hbase .master .RegionPlan ;
21
24
import org .slf4j .Logger ;
22
25
import org .slf4j .LoggerFactory ;
28
31
*/
29
32
public class DistributeReplicasConditional extends RegionPlanConditional {
30
33
34
+ /**
35
+ * Local mini cluster tests can only one on one server/rack by design. If enabled, this will
36
+ * pretend that localhost RegionServer threads are actually running on separate hosts/racks. This
37
+ * should only be used in unit tests.
38
+ */
39
+ public static boolean TEST_MODE_ENABLED = false ;
40
+
31
41
private static final Logger LOG = LoggerFactory .getLogger (DistributeReplicasConditional .class );
32
42
33
43
private final BalancerClusterState cluster ;
34
44
35
- public DistributeReplicasConditional (BalancerClusterState cluster ) {
36
- super (cluster );
45
+ public DistributeReplicasConditional (Configuration conf , BalancerClusterState cluster ) {
46
+ super (conf , cluster );
37
47
this .cluster = cluster ;
38
48
}
39
49
@@ -63,15 +73,17 @@ boolean isViolating(RegionPlan regionPlan) {
63
73
}
64
74
65
75
if (
66
- checkViolation (destinationServerIndex , cluster .serversPerHost , cluster .serverIndexToHostIndex ,
67
- cluster .regionsPerServer , primaryRegionIndex , cluster .regionIndexToPrimaryIndex , "host" )
76
+ checkViolation (cluster .regions , regionPlan .getRegionInfo (), destinationServerIndex ,
77
+ cluster .serversPerHost , cluster .serverIndexToHostIndex , cluster .regionsPerServer ,
78
+ primaryRegionIndex , "host" )
68
79
) {
69
80
return true ;
70
81
}
71
82
72
83
if (
73
- checkViolation (destinationServerIndex , cluster .serversPerRack , cluster .serverIndexToRackIndex ,
74
- cluster .regionsPerServer , primaryRegionIndex , cluster .regionIndexToPrimaryIndex , "rack" )
84
+ checkViolation (cluster .regions , regionPlan .getRegionInfo (), destinationServerIndex ,
85
+ cluster .serversPerRack , cluster .serverIndexToRackIndex , cluster .regionsPerServer ,
86
+ primaryRegionIndex , "rack" )
75
87
) {
76
88
return true ;
77
89
}
@@ -89,23 +101,61 @@ boolean isViolating(RegionPlan regionPlan) {
89
101
* @param locationType Type of location being checked ("Host" or "Rack").
90
102
* @return True if a violation is found, false otherwise.
91
103
*/
92
- static boolean checkViolation (int destinationServerIndex , int [][] serversPerLocation ,
93
- int [] serverToLocationIndex , int [][] regionsPerServer , int primaryRegionIndex ,
94
- int [] regionIndexToPrimaryIndex , String locationType ) {
95
- if (serversPerLocation == null || serversPerLocation .length <= 1 ) {
96
- LOG .debug ("{} violation check skipped: serversPerLocation is null or has <= 1 location" ,
97
- locationType );
104
+ static boolean checkViolation (RegionInfo [] regions , RegionInfo regionToBeMoved ,
105
+ int destinationServerIndex , int [][] serversPerLocation , int [] serverToLocationIndex ,
106
+ int [][] regionsPerServer , int primaryRegionIndex , String locationType ) {
107
+
108
+ if (TEST_MODE_ENABLED ) {
109
+ // Take the flat serversPerLocation, like {0: [0, 1, 2, 3, 4]}
110
+ // and pretend it is multi-location, like {0: [1], 1: [2] ...}
111
+ int numServers = serversPerLocation [0 ].length ;
112
+ // Create a new serversPerLocation array where each server gets its own "location"
113
+ int [][] simulatedServersPerLocation = new int [numServers ][];
114
+ for (int i = 0 ; i < numServers ; i ++) {
115
+ simulatedServersPerLocation [i ] = new int [] { serversPerLocation [0 ][i ] };
116
+ }
117
+ // Adjust serverToLocationIndex to map each server to its simulated location
118
+ int [] simulatedServerToLocationIndex = new int [numServers ];
119
+ for (int i = 0 ; i < numServers ; i ++) {
120
+ simulatedServerToLocationIndex [serversPerLocation [0 ][i ]] = i ;
121
+ }
122
+ LOG .trace ("Test mode enabled: Simulated {} locations for servers." , numServers );
123
+ // Use the simulated arrays for test mode
124
+ serversPerLocation = simulatedServersPerLocation ;
125
+ serverToLocationIndex = simulatedServerToLocationIndex ;
126
+ }
127
+
128
+ if (serversPerLocation == null ) {
129
+ LOG .trace ("{} violation check skipped: serversPerLocation is null" , locationType );
98
130
return false ;
99
131
}
100
132
133
+ if (serversPerLocation .length == 1 ) {
134
+ LOG .warn (
135
+ "{} violation inevitable: serversPerLocation has only 1 entry. You probably should not be using read replicas." ,
136
+ locationType );
137
+ return true ;
138
+ }
139
+
101
140
int destinationLocationIndex = serverToLocationIndex [destinationServerIndex ];
102
- LOG .debug ("Checking {} violations for destination server index {} at location index {}" ,
141
+ LOG .trace ("Checking {} violations for destination server index {} at location index {}" ,
103
142
locationType , destinationServerIndex , destinationLocationIndex );
104
143
144
+ // For every RegionServer on host/rack
105
145
for (int serverIndex : serversPerLocation [destinationLocationIndex ]) {
146
+ // For every Region on RegionServer
106
147
for (int hostedRegion : regionsPerServer [serverIndex ]) {
107
- if (regionIndexToPrimaryIndex [hostedRegion ] == primaryRegionIndex ) {
108
- LOG .debug ("{} violation detected: region {} on {} {}" , locationType , primaryRegionIndex ,
148
+ RegionInfo targetRegion = regions [hostedRegion ];
149
+ if (targetRegion .getEncodedName ().equals (regionToBeMoved .getEncodedName ())) {
150
+ // The balancer state will already show this region as having moved.
151
+ // A region's replicas will also have unique encoded names.
152
+ // So we should skip this check if the encoded name is the same.
153
+ continue ;
154
+ }
155
+ boolean isReplicaForSameRegion =
156
+ RegionReplicaUtil .isReplicasForSameRegion (targetRegion , regionToBeMoved );
157
+ if (isReplicaForSameRegion ) {
158
+ LOG .trace ("{} violation detected: region {} on {} {}" , locationType , primaryRegionIndex ,
109
159
locationType , destinationLocationIndex );
110
160
return true ;
111
161
}
0 commit comments