View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.rsgroup;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertTrue;
26  import static org.junit.Assert.fail;
27  
28  import com.google.common.collect.Sets;
29  
30  import java.io.IOException;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.hadoop.hbase.HRegionInfo;
38  import org.apache.hadoop.hbase.ServerName;
39  import org.apache.hadoop.hbase.TableName;
40  import org.apache.hadoop.hbase.Waiter;
41  import org.apache.hadoop.hbase.client.ClusterConnection;
42  import org.apache.hadoop.hbase.master.HMaster;
43  import org.apache.hadoop.hbase.master.RegionState;
44  import org.apache.hadoop.hbase.net.Address;
45  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
46  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
47  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoRequest;
48  import org.apache.hadoop.hbase.testclassification.MediumTests;
49  import org.apache.hadoop.hbase.util.Bytes;
50  import org.junit.After;
51  import org.junit.AfterClass;
52  import org.junit.Assert;
53  import org.junit.Before;
54  import org.junit.BeforeClass;
55  import org.junit.Test;
56  import org.junit.experimental.categories.Category;
57  
58  @Category({MediumTests.class})
59  public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
60    protected static final Log LOG = LogFactory.getLog(TestRSGroupsAdmin2.class);
61  
62    @BeforeClass
63    public static void setUp() throws Exception {
64      setUpTestBeforeClass();
65    }
66  
67    @AfterClass
68    public static void tearDown() throws Exception {
69      tearDownAfterClass();
70    }
71  
72    @Before
73    public void beforeMethod() throws Exception {
74      setUpBeforeMethod();
75    }
76  
77    @After
78    public void afterMethod() throws Exception {
79      tearDownAfterMethod();
80    }
81  
82  
83    @Test
84    public void testRegionMove() throws Exception {
85      LOG.info("testRegionMove");
86  
87      final RSGroupInfo newGroup = addGroup(rsGroupAdmin, getGroupName("testRegionMove"), 1);
88      final TableName tableName = TableName.valueOf(tablePrefix + rand.nextInt());
89      final byte[] familyNameBytes = Bytes.toBytes("f");
90      // All the regions created below will be assigned to the default group.
91      TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 6);
92      TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
93        @Override
94        public boolean evaluate() throws Exception {
95          List<String> regions = getTableRegionMap().get(tableName);
96          if (regions == null)
97            return false;
98          return getTableRegionMap().get(tableName).size() >= 6;
99        }
100     });
101 
102     //get target region to move
103     Map<ServerName,List<String>> assignMap =
104         getTableServerRegionMap().get(tableName);
105     String targetRegion = null;
106     for(ServerName server : assignMap.keySet()) {
107       targetRegion = assignMap.get(server).size() > 0 ? assignMap.get(server).get(0) : null;
108       if(targetRegion != null) {
109         break;
110       }
111     }
112     //get server which is not a member of new group
113     ServerName targetServer = null;
114     for(ServerName server : admin.getClusterStatus().getServers()) {
115       if(!newGroup.containsServer(server.getAddress())) {
116         targetServer = server;
117         break;
118       }
119     }
120     assertNotNull(targetServer);
121 
122     final AdminProtos.AdminService.BlockingInterface targetRS =
123         admin.getConnection().getAdmin(targetServer);
124 
125     //move target server to group
126     rsGroupAdmin.moveServers(Sets.newHashSet(targetServer.getAddress()),
127         newGroup.getName());
128     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
129       @Override
130       public boolean evaluate() throws Exception {
131         return ProtobufUtil.getOnlineRegions(targetRS).size() <= 0;
132       }
133     });
134 
135     // Lets move this region to the new group.
136     TEST_UTIL.getHBaseAdmin().move(Bytes.toBytes(HRegionInfo.encodeRegionName(Bytes.toBytes(targetRegion))),
137         Bytes.toBytes(targetServer.getServerName()));
138     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
139       @Override
140       public boolean evaluate() throws Exception {
141         List<String> regions = getTableRegionMap().get(tableName);
142         Set<RegionState> regionsInTransition = admin.getClusterStatus().getRegionsInTransition();
143         return (regions != null && getTableRegionMap().get(tableName).size() == 6) &&
144            ( regionsInTransition == null || regionsInTransition.size() < 1);
145       }
146     });
147 
148     //verify that targetServer didn't open it
149     for (HRegionInfo region: ProtobufUtil.getOnlineRegions(targetRS)) {
150       if (targetRegion.equals(region.getRegionNameAsString())) {
151         fail("Target server opened region");
152       }
153     }
154   }
155 
156   @Test
157   public void testRegionServerMove() throws IOException,
158       InterruptedException {
159     LOG.info("testRegionServerMove");
160 
161     int initNumGroups = rsGroupAdmin.listRSGroups().size();
162     RSGroupInfo appInfo = addGroup(rsGroupAdmin, getGroupName("testRegionServerMove"), 1);
163     RSGroupInfo adminInfo = addGroup(rsGroupAdmin, getGroupName("testRegionServerMove"), 1);
164     RSGroupInfo dInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
165     Assert.assertEquals(initNumGroups + 2, rsGroupAdmin.listRSGroups().size());
166     assertEquals(1, adminInfo.getServers().size());
167     assertEquals(1, appInfo.getServers().size());
168     assertEquals(getNumServers() - 2, dInfo.getServers().size());
169     rsGroupAdmin.moveServers(appInfo.getServers(),
170         RSGroupInfo.DEFAULT_GROUP);
171     rsGroupAdmin.removeRSGroup(appInfo.getName());
172     rsGroupAdmin.moveServers(adminInfo.getServers(),
173         RSGroupInfo.DEFAULT_GROUP);
174     rsGroupAdmin.removeRSGroup(adminInfo.getName());
175     Assert.assertEquals(rsGroupAdmin.listRSGroups().size(), initNumGroups);
176   }
177 
178   @Test
179   public void testMoveServers() throws Exception {
180     LOG.info("testMoveServers");
181 
182     //create groups and assign servers
183     addGroup(rsGroupAdmin, "bar", 3);
184     rsGroupAdmin.addRSGroup("foo");
185 
186     RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
187     RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
188     assertEquals(3, barGroup.getServers().size());
189     assertEquals(0, fooGroup.getServers().size());
190 
191     //test fail bogus server move
192     try {
193       rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromString("foo:9999")),"foo");
194       fail("Bogus servers shouldn't have been successfully moved.");
195     } catch(IOException ex) {
196       String exp = "Server foo:9999 does not have a group.";
197       String msg = "Expected '"+exp+"' in exception message: ";
198       assertTrue(msg+" "+ex.getMessage(), ex.getMessage().contains(exp));
199     }
200 
201     //test success case
202     LOG.info("moving servers "+barGroup.getServers()+" to group foo");
203     rsGroupAdmin.moveServers(barGroup.getServers(), fooGroup.getName());
204 
205     barGroup = rsGroupAdmin.getRSGroupInfo("bar");
206     fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
207     assertEquals(0,barGroup.getServers().size());
208     assertEquals(3,fooGroup.getServers().size());
209 
210     LOG.info("moving servers "+fooGroup.getServers()+" to group default");
211     rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
212 
213     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
214       @Override
215       public boolean evaluate() throws Exception {
216         return getNumServers() ==
217         rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
218       }
219     });
220 
221     fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
222     assertEquals(0,fooGroup.getServers().size());
223 
224     //test group removal
225     LOG.info("Remove group "+barGroup.getName());
226     rsGroupAdmin.removeRSGroup(barGroup.getName());
227     Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(barGroup.getName()));
228     LOG.info("Remove group "+fooGroup.getName());
229     rsGroupAdmin.removeRSGroup(fooGroup.getName());
230     Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
231   }
232 
233   @Test
234   public void testRemoveServers() throws Exception {
235     final RSGroupInfo newGroup = addGroup(rsGroupAdmin, "testRemoveServers", 3);
236     ServerName targetServer = ServerName.parseServerName(
237         newGroup.getServers().iterator().next().toString());
238     try {
239       rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
240       fail("Online servers shouldn't have been successfully removed.");
241     } catch(IOException ex) {
242       String exp = "Server " + targetServer.getAddress()
243           + " is an online server, not allowed to remove.";
244       String msg = "Expected '" + exp + "' in exception message: ";
245       assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
246     }
247     assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
248 
249     AdminProtos.AdminService.BlockingInterface targetRS =
250         ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
251     try {
252       targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
253           GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
254       //stopping may cause an exception
255       //due to the connection loss
256       targetRS.stopServer(null,
257           AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
258     } catch(Exception e) {
259     }
260 
261     final HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
262     //wait for stopped regionserver to dead server list
263     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
264       @Override
265       public boolean evaluate() throws Exception {
266         return !master.getServerManager().areDeadServersInProgress()
267             && cluster.getClusterStatus().getDeadServerNames().size() > 0;
268       }
269     });
270 
271     try {
272       rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
273       fail("Dead servers shouldn't have been successfully removed.");
274     } catch(IOException ex) {
275       String exp = "Server " + targetServer.getAddress() + " is on the dead servers list,"
276           + " Maybe it will come back again, not allowed to remove.";
277       String msg = "Expected '" + exp + "' in exception message: ";
278       assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
279     }
280     assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
281 
282     ServerName sn = TEST_UTIL.getHBaseClusterInterface().getClusterStatus().getMaster();
283     TEST_UTIL.getHBaseClusterInterface().stopMaster(sn);
284     TEST_UTIL.getHBaseClusterInterface().waitForMasterToStop(sn, 60000);
285     TEST_UTIL.getHBaseClusterInterface().startMaster(sn.getHostname(), 0);
286     TEST_UTIL.getHBaseClusterInterface().waitForActiveAndReadyMaster(60000);
287 
288     assertEquals(3, cluster.getClusterStatus().getServersSize());
289     assertFalse(cluster.getClusterStatus().getServers().contains(targetServer));
290     assertFalse(cluster.getClusterStatus().getDeadServerNames().contains(targetServer));
291     assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
292 
293     rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
294     Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
295     assertFalse(newGroupServers.contains(targetServer.getAddress()));
296     assertEquals(2, newGroupServers.size());
297 
298     assertTrue(observer.preRemoveServersCalled);
299   }
300 
301   @Test
302   public void testMoveServersAndTables() throws Exception {
303     final TableName tableName = TableName.valueOf(tablePrefix + "_testMoveServersAndTables");
304     final RSGroupInfo newGroup = addGroup(rsGroupAdmin, getGroupName("testMoveServersAndTables"), 1);
305 
306     //create table
307     final byte[] familyNameBytes = Bytes.toBytes("f");
308     TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
309     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
310       @Override
311       public boolean evaluate() throws Exception {
312         List<String> regions = getTableRegionMap().get(tableName);
313         if (regions == null)
314           return false;
315         return getTableRegionMap().get(tableName).size() >= 5;
316       }
317     });
318 
319     //get server which is not a member of new group
320     ServerName targetServer = null;
321     for(ServerName server : admin.getClusterStatus().getServers()) {
322       if(!newGroup.containsServer(server.getAddress()) &&
323            !rsGroupAdmin.getRSGroupInfo("master").containsServer(server.getAddress())) {
324         targetServer = server;
325         break;
326       }
327     }
328 
329     LOG.debug("Print group info : " + rsGroupAdmin.listRSGroups());
330     int oldDefaultGroupServerSize =
331             rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
332     int oldDefaultGroupTableSize =
333             rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size();
334 
335     //test fail bogus server move
336     try {
337       rsGroupAdmin.moveServersAndTables(Sets.newHashSet(Address.fromString("foo:9999")),
338               Sets.newHashSet(tableName), newGroup.getName());
339       fail("Bogus servers shouldn't have been successfully moved.");
340     } catch(IOException ex) {
341     }
342 
343     //test fail server move
344     try {
345       rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
346               Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
347       fail("servers shouldn't have been successfully moved.");
348     } catch(IOException ex) {
349     }
350 
351     //verify default group info
352     Assert.assertEquals(oldDefaultGroupServerSize,
353             rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size());
354     Assert.assertEquals(oldDefaultGroupTableSize,
355             rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size());
356 
357     //verify new group info
358     Assert.assertEquals(1,
359             rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers().size());
360     Assert.assertEquals(0,
361             rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
362 
363     //get all region to move targetServer
364     List<String> regionList = getTableRegionMap().get(tableName);
365     for(String region : regionList) {
366       // Lets move this region to the targetServer
367       admin.move(Bytes.toBytes(HRegionInfo.encodeRegionName(Bytes.toBytes(region))),
368               Bytes.toBytes(targetServer.getServerName()));
369     }
370 
371     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
372       @Override
373       public boolean evaluate() throws Exception {
374         List<String> regions = getTableRegionMap().get(tableName);
375         Map<ServerName, List<String>> serverMap = getTableServerRegionMap().get(tableName);
376         Set<RegionState> regionsInTransition = admin.getClusterStatus().getRegionsInTransition();
377         return (regions != null && regions.size() == 5) &&
378           (serverMap != null && serverMap.size() == 1) &&
379           (regionsInTransition == null || regionsInTransition.size() < 1);
380       }
381     });
382 
383     //verify that all region move to targetServer
384     Assert.assertNotNull(getTableServerRegionMap().get(tableName));
385     Assert.assertNotNull(getTableServerRegionMap().get(tableName).get(targetServer));
386     Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
387 
388     //move targetServer and table to newGroup
389     LOG.info("moving server and table to newGroup");
390     rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
391             Sets.newHashSet(tableName), newGroup.getName());
392 
393     //verify group change
394     Assert.assertEquals(newGroup.getName(),
395             rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
396 
397     //verify servers' not exist in old group
398     Set<Address> defaultServers = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers();
399     assertFalse(defaultServers.contains(targetServer.getAddress()));
400 
401     //verify servers' exist in new group
402     Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
403     assertTrue(newGroupServers.contains(targetServer.getAddress()));
404 
405     //verify tables' not exist in old group
406     Set<TableName> defaultTables = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
407     assertFalse(defaultTables.contains(tableName));
408 
409     //verify tables' exist in new group
410     Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables();
411     assertTrue(newGroupTables.contains(tableName));
412 
413     assertTrue(observer.preMoveServersAndTables);
414     assertTrue(observer.postMoveServersAndTables);
415   }
416 
417 }