1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.balancer;
20
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.SortedMap;
30 import java.util.TreeMap;
31
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.HRegionInfo;
35 import org.apache.hadoop.hbase.testclassification.SmallTests;
36 import org.apache.hadoop.hbase.ServerName;
37 import org.apache.hadoop.hbase.master.RackManager;
38 import org.apache.hadoop.hbase.util.Bytes;
39 import org.apache.hadoop.hbase.util.Triple;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 import org.junit.Ignore;
43 import org.junit.experimental.categories.Category;
44 import org.mockito.Mockito;
45
46 @Category(SmallTests.class)
47 public class TestFavoredNodeAssignmentHelper {
48
49 private static List<ServerName> servers = new ArrayList<ServerName>();
50 private static Map<String, List<ServerName>> rackToServers = new HashMap<String,
51 List<ServerName>>();
52 private static RackManager rackManager = Mockito.mock(RackManager.class);
53
54 @BeforeClass
55 public static void setupBeforeClass() throws Exception {
56
57
58 for (int i = 0; i < 40; i++) {
59 ServerName server = ServerName.valueOf("foo" + i + ":1234", -1);
60 if (i < 10) {
61 Mockito.when(rackManager.getRack(server)).thenReturn("rack1");
62 if (rackToServers.get("rack1") == null) {
63 List<ServerName> servers = new ArrayList<ServerName>();
64 rackToServers.put("rack1", servers);
65 }
66 rackToServers.get("rack1").add(server);
67 }
68 if (i >= 10 && i < 20) {
69 Mockito.when(rackManager.getRack(server)).thenReturn("rack2");
70 if (rackToServers.get("rack2") == null) {
71 List<ServerName> servers = new ArrayList<ServerName>();
72 rackToServers.put("rack2", servers);
73 }
74 rackToServers.get("rack2").add(server);
75 }
76 if (i >= 20 && i < 30) {
77 Mockito.when(rackManager.getRack(server)).thenReturn("rack3");
78 if (rackToServers.get("rack3") == null) {
79 List<ServerName> servers = new ArrayList<ServerName>();
80 rackToServers.put("rack3", servers);
81 }
82 rackToServers.get("rack3").add(server);
83 }
84 servers.add(server);
85 }
86 }
87
88
89
90
91 private static List<ServerName> getServersFromRack(Map<String, Integer> rackToServerCount) {
92 List<ServerName> chosenServers = new ArrayList<ServerName>();
93 for (Map.Entry<String, Integer> entry : rackToServerCount.entrySet()) {
94 List<ServerName> servers = rackToServers.get(entry.getKey());
95 for (int i = 0; i < entry.getValue(); i++) {
96 chosenServers.add(servers.get(i));
97 }
98 }
99 return chosenServers;
100 }
101
102 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
103 public void testSmallCluster() {
104
105
106 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
107 rackToServerCount.put("rack1", 2);
108 List<ServerName> servers = getServersFromRack(rackToServerCount);
109 FavoredNodeAssignmentHelper helper = new FavoredNodeAssignmentHelper(servers,
110 new Configuration());
111 assertFalse(helper.canPlaceFavoredNodes());
112 }
113
114 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
115 public void testPlacePrimaryRSAsRoundRobin() {
116
117
118 primaryRSPlacement(6, null, 10, 10, 10);
119
120 primaryRSPlacement(600, null, 10, 10, 10);
121 }
122
123 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
124 public void testRoundRobinAssignmentsWithUnevenSizedRacks() {
125
126
127 primaryRSPlacement(6, null, 10, 10, 10);
128 primaryRSPlacement(600, null, 10, 10, 5);
129 primaryRSPlacement(600, null, 10, 5, 10);
130 primaryRSPlacement(600, null, 5, 10, 10);
131 primaryRSPlacement(500, null, 10, 10, 5);
132 primaryRSPlacement(500, null, 10, 5, 10);
133 primaryRSPlacement(500, null, 5, 10, 10);
134 primaryRSPlacement(500, null, 9, 7, 8);
135 primaryRSPlacement(500, null, 8, 7, 9);
136 primaryRSPlacement(500, null, 7, 9, 8);
137 primaryRSPlacement(459, null, 7, 9, 8);
138 }
139
140 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
141 public void testSecondaryAndTertiaryPlacementWithSingleRack() {
142
143
144 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
145 rackToServerCount.put("rack1", 10);
146
147 Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
148 primaryRSMapAndHelper = secondaryAndTertiaryRSPlacementHelper(60000, rackToServerCount);
149 FavoredNodeAssignmentHelper helper = primaryRSMapAndHelper.getSecond();
150 Map<HRegionInfo, ServerName> primaryRSMap = primaryRSMapAndHelper.getFirst();
151 List<HRegionInfo> regions = primaryRSMapAndHelper.getThird();
152 Map<HRegionInfo, ServerName[]> secondaryAndTertiaryMap =
153 helper.placeSecondaryAndTertiaryRS(primaryRSMap);
154
155
156 for (HRegionInfo region : regions) {
157 ServerName[] secondaryAndTertiaryServers = secondaryAndTertiaryMap.get(region);
158 assertTrue(!secondaryAndTertiaryServers[0].equals(primaryRSMap.get(region)));
159 assertTrue(!secondaryAndTertiaryServers[1].equals(primaryRSMap.get(region)));
160 assertTrue(!secondaryAndTertiaryServers[0].equals(secondaryAndTertiaryServers[1]));
161 }
162 }
163
164 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
165 public void testSecondaryAndTertiaryPlacementWithSingleServer() {
166
167
168 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
169 rackToServerCount.put("rack1", 1);
170 Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
171 primaryRSMapAndHelper = secondaryAndTertiaryRSPlacementHelper(1, rackToServerCount);
172 FavoredNodeAssignmentHelper helper = primaryRSMapAndHelper.getSecond();
173 Map<HRegionInfo, ServerName> primaryRSMap = primaryRSMapAndHelper.getFirst();
174 List<HRegionInfo> regions = primaryRSMapAndHelper.getThird();
175
176 Map<HRegionInfo, ServerName[]> secondaryAndTertiaryMap =
177 helper.placeSecondaryAndTertiaryRS(primaryRSMap);
178
179 assertTrue(secondaryAndTertiaryMap.get(regions.get(0)) == null);
180 }
181
182 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
183 public void testSecondaryAndTertiaryPlacementWithMultipleRacks() {
184
185
186 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
187 rackToServerCount.put("rack1", 10);
188 rackToServerCount.put("rack2", 10);
189
190 Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
191 primaryRSMapAndHelper = secondaryAndTertiaryRSPlacementHelper(60000, rackToServerCount);
192 FavoredNodeAssignmentHelper helper = primaryRSMapAndHelper.getSecond();
193 Map<HRegionInfo, ServerName> primaryRSMap = primaryRSMapAndHelper.getFirst();
194
195 assertTrue(primaryRSMap.size() == 60000);
196 Map<HRegionInfo, ServerName[]> secondaryAndTertiaryMap =
197 helper.placeSecondaryAndTertiaryRS(primaryRSMap);
198 assertTrue(secondaryAndTertiaryMap.size() == 60000);
199
200
201 for (Map.Entry<HRegionInfo, ServerName[]> entry : secondaryAndTertiaryMap.entrySet()) {
202 ServerName[] allServersForRegion = entry.getValue();
203 String primaryRSRack = rackManager.getRack(primaryRSMap.get(entry.getKey()));
204 String secondaryRSRack = rackManager.getRack(allServersForRegion[0]);
205 String tertiaryRSRack = rackManager.getRack(allServersForRegion[1]);
206 assertTrue(!primaryRSRack.equals(secondaryRSRack));
207 assertTrue(secondaryRSRack.equals(tertiaryRSRack));
208 }
209 }
210
211 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
212 public void testSecondaryAndTertiaryPlacementWithLessThanTwoServersInRacks() {
213
214
215 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
216 rackToServerCount.put("rack1", 1);
217 rackToServerCount.put("rack2", 1);
218 Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
219 primaryRSMapAndHelper = secondaryAndTertiaryRSPlacementHelper(6, rackToServerCount);
220 FavoredNodeAssignmentHelper helper = primaryRSMapAndHelper.getSecond();
221 Map<HRegionInfo, ServerName> primaryRSMap = primaryRSMapAndHelper.getFirst();
222 List<HRegionInfo> regions = primaryRSMapAndHelper.getThird();
223 assertTrue(primaryRSMap.size() == 6);
224 Map<HRegionInfo, ServerName[]> secondaryAndTertiaryMap =
225 helper.placeSecondaryAndTertiaryRS(primaryRSMap);
226 for (HRegionInfo region : regions) {
227
228 assertTrue(secondaryAndTertiaryMap.get(region) == null);
229 }
230 }
231
232 @Ignore("Disabled for now until FavoredNodes gets finished as a feature") @Test
233 public void testSecondaryAndTertiaryPlacementWithMoreThanOneServerInPrimaryRack() {
234
235
236
237
238
239 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
240 rackToServerCount.put("rack1", 2);
241 rackToServerCount.put("rack2", 1);
242 Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
243 primaryRSMapAndHelper = secondaryAndTertiaryRSPlacementHelper(6, rackToServerCount);
244 FavoredNodeAssignmentHelper helper = primaryRSMapAndHelper.getSecond();
245 Map<HRegionInfo, ServerName> primaryRSMap = primaryRSMapAndHelper.getFirst();
246 List<HRegionInfo> regions = primaryRSMapAndHelper.getThird();
247 assertTrue(primaryRSMap.size() == 6);
248 Map<HRegionInfo, ServerName[]> secondaryAndTertiaryMap =
249 helper.placeSecondaryAndTertiaryRS(primaryRSMap);
250 for (HRegionInfo region : regions) {
251 ServerName s = primaryRSMap.get(region);
252 ServerName secondaryRS = secondaryAndTertiaryMap.get(region)[0];
253 ServerName tertiaryRS = secondaryAndTertiaryMap.get(region)[1];
254 if (rackManager.getRack(s).equals("rack1")) {
255 assertTrue(rackManager.getRack(secondaryRS).equals("rack2") &&
256 rackManager.getRack(tertiaryRS).equals("rack1"));
257 }
258 if (rackManager.getRack(s).equals("rack2")) {
259 assertTrue(rackManager.getRack(secondaryRS).equals("rack1") &&
260 rackManager.getRack(tertiaryRS).equals("rack1"));
261 }
262 }
263 }
264
265 private Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
266 secondaryAndTertiaryRSPlacementHelper(
267 int regionCount, Map<String, Integer> rackToServerCount) {
268 Map<HRegionInfo, ServerName> primaryRSMap = new HashMap<HRegionInfo, ServerName>();
269 List<ServerName> servers = getServersFromRack(rackToServerCount);
270 FavoredNodeAssignmentHelper helper = new FavoredNodeAssignmentHelper(servers, rackManager);
271 Map<ServerName, List<HRegionInfo>> assignmentMap =
272 new HashMap<ServerName, List<HRegionInfo>>();
273 helper.initialize();
274
275 List<HRegionInfo> regions = new ArrayList<HRegionInfo>(regionCount);
276 for (int i = 0; i < regionCount; i++) {
277 HRegionInfo region = new HRegionInfo(TableName.valueOf("foobar"),
278 Bytes.toBytes(i), Bytes.toBytes(i + 1));
279 regions.add(region);
280 }
281
282 helper.placePrimaryRSAsRoundRobin(assignmentMap, primaryRSMap, regions);
283 return new Triple<Map<HRegionInfo, ServerName>, FavoredNodeAssignmentHelper, List<HRegionInfo>>
284 (primaryRSMap, helper, regions);
285 }
286
287 private void primaryRSPlacement(int regionCount, Map<HRegionInfo, ServerName> primaryRSMap,
288 int firstRackSize, int secondRackSize, int thirdRackSize) {
289 Map<String,Integer> rackToServerCount = new HashMap<String,Integer>();
290 rackToServerCount.put("rack1", firstRackSize);
291 rackToServerCount.put("rack2", secondRackSize);
292 rackToServerCount.put("rack3", thirdRackSize);
293 List<ServerName> servers = getServersFromRack(rackToServerCount);
294 FavoredNodeAssignmentHelper helper = new FavoredNodeAssignmentHelper(servers,
295 rackManager);
296 helper.initialize();
297
298 assertTrue(helper.canPlaceFavoredNodes());
299
300 Map<ServerName, List<HRegionInfo>> assignmentMap =
301 new HashMap<ServerName, List<HRegionInfo>>();
302 if (primaryRSMap == null) primaryRSMap = new HashMap<HRegionInfo, ServerName>();
303
304 List<HRegionInfo> regions = new ArrayList<HRegionInfo>(regionCount);
305 for (int i = 0; i < regionCount; i++) {
306 HRegionInfo region = new HRegionInfo(TableName.valueOf("foobar"),
307 Bytes.toBytes(i), Bytes.toBytes(i + 1));
308 regions.add(region);
309 }
310
311 helper.placePrimaryRSAsRoundRobin(assignmentMap, primaryRSMap, regions);
312
313
314 int regionsOnRack1 = 0;
315 int regionsOnRack2 = 0;
316 int regionsOnRack3 = 0;
317 for (HRegionInfo region : regions) {
318 if (rackManager.getRack(primaryRSMap.get(region)).equals("rack1")) {
319 regionsOnRack1++;
320 } else if (rackManager.getRack(primaryRSMap.get(region)).equals("rack2")) {
321 regionsOnRack2++;
322 } else if (rackManager.getRack(primaryRSMap.get(region)).equals("rack3")) {
323 regionsOnRack3++;
324 }
325 }
326
327
328 checkNumRegions(regionCount, firstRackSize, secondRackSize, thirdRackSize, regionsOnRack1,
329 regionsOnRack2, regionsOnRack3, assignmentMap);
330 }
331
332 private void checkNumRegions(int regionCount, int firstRackSize, int secondRackSize,
333 int thirdRackSize, int regionsOnRack1, int regionsOnRack2, int regionsOnRack3,
334 Map<ServerName, List<HRegionInfo>> assignmentMap) {
335
336
337
338
339 SortedMap<Integer, Integer> rackMap = new TreeMap<Integer, Integer>();
340 rackMap.put(firstRackSize, 1);
341 rackMap.put(secondRackSize, 2);
342 rackMap.put(thirdRackSize, 3);
343 SortedMap<Integer, Integer> regionMap = new TreeMap<Integer, Integer>();
344 regionMap.put(regionsOnRack1, 1);
345 regionMap.put(regionsOnRack2, 2);
346 regionMap.put(regionsOnRack3, 3);
347 assertTrue(printProportions(firstRackSize, secondRackSize, thirdRackSize,
348 regionsOnRack1, regionsOnRack2, regionsOnRack3),
349 Objects.equals(rackMap.get(firstRackSize), regionMap.get(regionsOnRack1)));
350 assertTrue(printProportions(firstRackSize, secondRackSize, thirdRackSize,
351 regionsOnRack1, regionsOnRack2, regionsOnRack3),
352 Objects.equals(rackMap.get(secondRackSize), regionMap.get(regionsOnRack2)));
353 assertTrue(printProportions(firstRackSize, secondRackSize, thirdRackSize,
354 regionsOnRack1, regionsOnRack2, regionsOnRack3),
355 Objects.equals(rackMap.get(thirdRackSize), regionMap.get(regionsOnRack3)));
356 }
357
358 private String printProportions(int firstRackSize, int secondRackSize,
359 int thirdRackSize, int regionsOnRack1, int regionsOnRack2, int regionsOnRack3) {
360 return "The rack sizes " + firstRackSize + " " + secondRackSize
361 + " " + thirdRackSize + " " + regionsOnRack1 + " " + regionsOnRack2 +
362 " " + regionsOnRack3;
363 }
364 }