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 com.google.common.collect.Sets;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.hbase.HBaseCluster;
25  import org.apache.hadoop.hbase.HBaseTestingUtility;
26  import org.apache.hadoop.hbase.HConstants;
27  import org.apache.hadoop.hbase.HRegionInfo;
28  import org.apache.hadoop.hbase.MiniHBaseCluster;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.Waiter;
31  import org.apache.hadoop.hbase.client.HBaseAdmin;
32  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
33  import org.apache.hadoop.hbase.master.HMaster;
34  import org.apache.hadoop.hbase.master.ServerManager;
35  import org.apache.hadoop.hbase.regionserver.HRegionServer;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.apache.hadoop.hbase.util.Bytes;
38  import org.junit.AfterClass;
39  import org.junit.Assert;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  
44  
45  import static org.junit.Assert.assertEquals;
46  import static org.junit.Assert.assertFalse;
47  
48  
49  //This tests that GroupBasedBalancer will use data in zk
50  //to do balancing during master startup
51  //This does not test retain assignment
52  @Category(MediumTests.class)
53  public class TestRSGroupsOfflineMode {
54    private static final org.apache.commons.logging.Log LOG =
55        LogFactory.getLog(TestRSGroupsOfflineMode.class);
56    private static HMaster master;
57    private static HBaseAdmin hbaseAdmin;
58    private static HBaseTestingUtility TEST_UTIL;
59    private static HBaseCluster cluster;
60    private static RSGroupAdminEndpoint RSGroupAdminEndpoint;
61    public final static long WAIT_TIMEOUT = 60000*5;
62  
63    @BeforeClass
64    public static void setUp() throws Exception {
65      TEST_UTIL = new HBaseTestingUtility();
66      TEST_UTIL.getConfiguration().set(
67          HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
68          RSGroupBasedLoadBalancer.class.getName());
69      TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
70          RSGroupAdminEndpoint.class.getName());
71      TEST_UTIL.getConfiguration().set(
72          ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
73          "1");
74      TEST_UTIL.startMiniCluster(2, 3);
75      cluster = TEST_UTIL.getHBaseCluster();
76      master = ((MiniHBaseCluster)cluster).getMaster();
77      master.balanceSwitch(false);
78      hbaseAdmin = TEST_UTIL.getHBaseAdmin();
79      //wait till the balancer is in online mode
80      TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
81        @Override
82        public boolean evaluate() throws Exception {
83          return master.isInitialized() &&
84              ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline() &&
85              master.getServerManager().getOnlineServersList().size() >= 3;
86        }
87      });
88      RSGroupAdminEndpoint =
89          master.getMasterCoprocessorHost().findCoprocessors(RSGroupAdminEndpoint.class).get(0);
90    }
91  
92    @AfterClass
93    public static void tearDown() throws Exception {
94      TEST_UTIL.shutdownMiniCluster();
95    }
96  
97    @Test
98    public void testOffline() throws Exception, InterruptedException {
99      //table should be after group table name
100     //so it gets assigned later
101     final TableName failoverTable = TableName.valueOf("testOffline");
102     TEST_UTIL.createTable(failoverTable, Bytes.toBytes("f"));
103 
104     RSGroupAdmin groupAdmin = RSGroupAdmin.newClient(TEST_UTIL.getConnection());
105 
106     final HRegionServer killRS = ((MiniHBaseCluster)cluster).getRegionServer(0);
107     final HRegionServer groupRS = ((MiniHBaseCluster)cluster).getRegionServer(1);
108     final HRegionServer failoverRS = ((MiniHBaseCluster)cluster).getRegionServer(2);
109 
110     String newGroup =  "my_group";
111     groupAdmin.addRSGroup(newGroup);
112     if(master.getAssignmentManager().getRegionStates().getRegionAssignments()
113         .containsValue(failoverRS.getServerName())) {
114       for(HRegionInfo regionInfo: hbaseAdmin.getOnlineRegions(failoverRS.getServerName())) {
115         hbaseAdmin.move(regionInfo.getEncodedNameAsBytes(),
116             Bytes.toBytes(failoverRS.getServerName().getServerName()));
117       }
118       LOG.info("Waiting for region unassignments on failover RS...");
119       TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
120         @Override
121         public boolean evaluate() throws Exception {
122           return master.getServerManager().getLoad(failoverRS.getServerName())
123               .getRegionsLoad().size() > 0;
124         }
125       });
126     }
127 
128     //move server to group and make sure all tables are assigned
129     groupAdmin.moveServers(Sets.newHashSet(groupRS.getServerName().getHostPort()), newGroup);
130     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
131       @Override
132       public boolean evaluate() throws Exception {
133         return groupRS.getNumberOfOnlineRegions() < 1 &&
134             master.getAssignmentManager().getRegionStates().getRegionsInTransition().size() < 1;
135       }
136     });
137     //move table to group and wait
138     groupAdmin.moveTables(Sets.newHashSet(RSGroupInfoManager.RSGROUP_TABLE_NAME), newGroup);
139     LOG.info("Waiting for move table...");
140     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
141       @Override
142       public boolean evaluate() throws Exception {
143         return groupRS.getNumberOfOnlineRegions() == 1;
144       }
145     });
146 
147     groupRS.stop("die");
148     //race condition here
149     TEST_UTIL.getHBaseCluster().getMaster().stopMaster();
150     LOG.info("Waiting for offline mode...");
151     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
152       @Override
153       public boolean evaluate() throws Exception {
154         return TEST_UTIL.getHBaseCluster().getMaster() != null &&
155             TEST_UTIL.getHBaseCluster().getMaster().isActiveMaster() &&
156             TEST_UTIL.getHBaseCluster().getMaster().isInitialized() &&
157             TEST_UTIL.getHBaseCluster().getMaster().getServerManager().getOnlineServers().size()
158                 <= 3;
159       }
160     });
161 
162 
163     RSGroupInfoManager groupMgr = RSGroupAdminEndpoint.getGroupInfoManager();
164     //make sure balancer is in offline mode, since this is what we're testing
165     assertFalse(groupMgr.isOnline());
166     //verify the group affiliation that's loaded from ZK instead of tables
167     assertEquals(newGroup,
168         groupMgr.getRSGroupOfTable(RSGroupInfoManager.RSGROUP_TABLE_NAME));
169     assertEquals(RSGroupInfo.DEFAULT_GROUP, groupMgr.getRSGroupOfTable(failoverTable));
170 
171     //kill final regionserver to see the failover happens for all tables
172     //except GROUP table since it's group does not have any online RS
173     killRS.stop("die");
174     master = TEST_UTIL.getHBaseCluster().getMaster();
175     LOG.info("Waiting for new table assignment...");
176     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
177       @Override
178       public boolean evaluate() throws Exception {
179         return failoverRS.getOnlineRegions(failoverTable).size() >= 1;
180       }
181     });
182     Assert.assertEquals(0, failoverRS.getOnlineRegions(RSGroupInfoManager.RSGROUP_TABLE_NAME).size());
183 
184     //need this for minicluster to shutdown cleanly
185     master.stopMaster();
186   }
187 }