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.Lists;
23  import com.google.common.collect.Sets;
24  
25  import com.google.common.net.HostAndPort;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HColumnDescriptor;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HTableDescriptor;
32  import org.apache.hadoop.hbase.MiniHBaseCluster;
33  import org.apache.hadoop.hbase.NamespaceDescriptor;
34  import org.apache.hadoop.hbase.ServerName;
35  import org.apache.hadoop.hbase.TableName;
36  import org.apache.hadoop.hbase.Waiter;
37  import org.apache.hadoop.hbase.Waiter.Predicate;
38  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
39  import org.apache.hadoop.hbase.master.HMaster;
40  import org.apache.hadoop.hbase.master.MasterServices;
41  import org.apache.hadoop.hbase.master.ServerManager;
42  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
43  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
44  import org.apache.hadoop.hbase.testclassification.MediumTests;
45  import org.apache.hadoop.hbase.util.Bytes;
46  import org.junit.After;
47  import org.junit.AfterClass;
48  import org.junit.Assert;
49  import org.junit.Before;
50  import org.junit.BeforeClass;
51  import org.junit.Test;
52  import org.junit.experimental.categories.Category;
53  import org.mockito.Mockito;
54  import org.mockito.invocation.InvocationOnMock;
55  import org.mockito.stubbing.Answer;
56  
57  import javax.management.MBeanServer;
58  import javax.management.ObjectName;
59  import java.io.IOException;
60  import java.lang.management.ManagementFactory;
61  import java.util.Iterator;
62  import java.util.List;
63  import java.util.concurrent.atomic.AtomicReference;
64  
65  import static org.junit.Assert.assertEquals;
66  import static org.junit.Assert.assertNotNull;
67  import static org.junit.Assert.assertTrue;
68  import static org.junit.Assert.fail;
69  
70  @Category({MediumTests.class})
71  public class TestRSGroups extends TestRSGroupsBase {
72    protected static final Log LOG = LogFactory.getLog(TestRSGroups.class);
73    private static HMaster master;
74    private static boolean init = false;
75    private static RSGroupAdminEndpoint RSGroupAdminEndpoint;
76  
77  
78    @BeforeClass
79    public static void setUp() throws Exception {
80      TEST_UTIL = new HBaseTestingUtility();
81      TEST_UTIL.getConfiguration().set(
82          HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
83          RSGroupBasedLoadBalancer.class.getName());
84      TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
85          RSGroupAdminEndpoint.class.getName());
86      TEST_UTIL.getConfiguration().setBoolean(
87          HConstants.ZOOKEEPER_USEMULTI,
88          true);
89      TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE);
90      TEST_UTIL.getConfiguration().set(
91          ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
92          ""+NUM_SLAVES_BASE);
93  
94      admin = TEST_UTIL.getHBaseAdmin();
95      cluster = TEST_UTIL.getHBaseCluster();
96      master = ((MiniHBaseCluster)cluster).getMaster();
97  
98      //wait for balancer to come online
99      TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
100       @Override
101       public boolean evaluate() throws Exception {
102         return master.isInitialized() &&
103             ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline();
104       }
105     });
106     admin.setBalancerRunning(false,true);
107     rsGroupAdmin = new VerifyingRSGroupAdminClient(rsGroupAdmin.newClient(TEST_UTIL.getConnection()),
108         TEST_UTIL.getConfiguration());
109     RSGroupAdminEndpoint =
110         master.getMasterCoprocessorHost().findCoprocessors(RSGroupAdminEndpoint.class).get(0);
111   }
112 
113   @AfterClass
114   public static void tearDown() throws Exception {
115     TEST_UTIL.shutdownMiniCluster();
116   }
117 
118   @Before
119   public void beforeMethod() throws Exception {
120     if(!init) {
121       init = true;
122       afterMethod();
123     }
124 
125   }
126 
127   @After
128   public void afterMethod() throws Exception {
129     deleteTableIfNecessary();
130     deleteNamespaceIfNecessary();
131     deleteGroups();
132 
133     int missing = NUM_SLAVES_BASE - getNumServers();
134     LOG.info("Restoring servers: "+missing);
135     for(int i=0; i<missing; i++) {
136       ((MiniHBaseCluster)cluster).startRegionServer();
137     }
138 
139     rsGroupAdmin.addRSGroup("master");
140     ServerName masterServerName =
141         ((MiniHBaseCluster)cluster).getMaster().getServerName();
142 
143     try {
144       rsGroupAdmin.moveServers(
145           Sets.newHashSet(masterServerName.getHostPort()),
146           "master");
147     } catch (Exception ex) {
148       // ignore
149     }
150     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
151       @Override
152       public boolean evaluate() throws Exception {
153         LOG.info("Waiting for cleanup to finish " + rsGroupAdmin.listRSGroups());
154         //Might be greater since moving servers back to default
155         //is after starting a server
156 
157         return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
158             == NUM_SLAVES_BASE;
159       }
160     });
161   }
162 
163   @Test
164   public void testBasicStartUp() throws IOException {
165     RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
166     assertEquals(4, defaultInfo.getServers().size());
167     // Assignment of root and meta regions.
168     int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
169     //3 meta,namespace, group
170     assertEquals(3, count);
171   }
172 
173   @Test
174   public void testNamespaceCreateAndAssign() throws Exception {
175     LOG.info("testNamespaceCreateAndAssign");
176     String nsName = tablePrefix+"_foo";
177     final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
178     RSGroupInfo appInfo = addGroup(rsGroupAdmin, "appInfo", 1);
179     admin.createNamespace(NamespaceDescriptor.create(nsName)
180         .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, "appInfo").build());
181     final HTableDescriptor desc = new HTableDescriptor(tableName);
182     desc.addFamily(new HColumnDescriptor("f"));
183     admin.createTable(desc);
184     //wait for created table to be assigned
185     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
186       @Override
187       public boolean evaluate() throws Exception {
188         return getTableRegionMap().get(desc.getTableName()) != null;
189       }
190     });
191     ServerName targetServer =
192         ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
193     AdminProtos.AdminService.BlockingInterface rs = admin.getConnection().getAdmin(targetServer);
194     //verify it was assigned to the right group
195     Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
196   }
197 
198   @Test
199   public void testDefaultNamespaceCreateAndAssign() throws Exception {
200     LOG.info("testDefaultNamespaceCreateAndAssign");
201     final byte[] tableName = Bytes.toBytes(tablePrefix + "_testCreateAndAssign");
202     admin.modifyNamespace(NamespaceDescriptor.create("default")
203         .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, "default").build());
204     final HTableDescriptor desc = new HTableDescriptor(tableName);
205     desc.addFamily(new HColumnDescriptor("f"));
206     admin.createTable(desc);
207     //wait for created table to be assigned
208     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
209       @Override
210       public boolean evaluate() throws Exception {
211         return getTableRegionMap().get(desc.getTableName()) != null;
212       }
213     });
214   }
215 
216   @Test
217   public void testNamespaceConstraint() throws Exception {
218     String nsName = tablePrefix+"_foo";
219     String groupName = tablePrefix+"_foo";
220     LOG.info("testNamespaceConstraint");
221     rsGroupAdmin.addRSGroup(groupName);
222     admin.createNamespace(NamespaceDescriptor.create(nsName)
223         .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, groupName)
224         .build());
225     //test removing a referenced group
226     try {
227       rsGroupAdmin.removeRSGroup(groupName);
228       fail("Expected a constraint exception");
229     } catch (IOException ex) {
230     }
231     //test modify group
232     //changing with the same name is fine
233     admin.modifyNamespace(
234         NamespaceDescriptor.create(nsName)
235           .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, groupName)
236           .build());
237     String anotherGroup = tablePrefix+"_anotherGroup";
238     rsGroupAdmin.addRSGroup(anotherGroup);
239     //test add non-existent group
240     admin.deleteNamespace(nsName);
241     rsGroupAdmin.removeRSGroup(groupName);
242     try {
243       admin.createNamespace(NamespaceDescriptor.create(nsName)
244           .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, "foo")
245           .build());
246       fail("Expected a constraint exception");
247     } catch (IOException ex) {
248     }
249   }
250 
251   @Test
252   public void testGroupInfoMultiAccessing() throws Exception {
253     RSGroupInfoManager manager = RSGroupAdminEndpoint.getGroupInfoManager();
254     final RSGroupInfo defaultGroup = manager.getRSGroup("default");
255     // getRSGroup updates default group's server list
256     // this process must not affect other threads iterating the list
257     Iterator<HostAndPort> it = defaultGroup.getServers().iterator();
258     manager.getRSGroup("default");
259     it.next();
260   }
261 
262   @Test
263   public void testMisplacedRegions() throws Exception {
264     final TableName tableName = TableName.valueOf(tablePrefix+"_testMisplacedRegions");
265     LOG.info("testMisplacedRegions");
266 
267     final RSGroupInfo RSGroupInfo = addGroup(rsGroupAdmin, "testMisplacedRegions", 1);
268 
269     TEST_UTIL.createMultiRegionTable(tableName, new byte[]{'f'}, 15);
270     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
271 
272     RSGroupAdminEndpoint.getGroupInfoManager()
273         .moveTables(Sets.newHashSet(tableName), RSGroupInfo.getName());
274 
275     assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName()));
276 
277     TEST_UTIL.waitFor(60000, new Predicate<Exception>() {
278       @Override
279       public boolean evaluate() throws Exception {
280         ServerName serverName =
281             ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1);
282         return admin.getConnection().getAdmin()
283             .getOnlineRegions(serverName).size() == 15;
284       }
285     });
286   }
287 }