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.master.snapshot.SnapshotManager;
43  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
44  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
45  import org.apache.hadoop.hbase.testclassification.MediumTests;
46  import org.apache.hadoop.hbase.util.Bytes;
47  import org.junit.After;
48  import org.junit.AfterClass;
49  import org.junit.Assert;
50  import org.junit.Before;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  import org.mockito.Mockito;
55  import org.mockito.invocation.InvocationOnMock;
56  import org.mockito.stubbing.Answer;
57  
58  import javax.management.MBeanServer;
59  import javax.management.ObjectName;
60  import java.io.IOException;
61  import java.lang.management.ManagementFactory;
62  import java.util.Iterator;
63  import java.util.List;
64  import java.util.concurrent.atomic.AtomicReference;
65  
66  import static org.junit.Assert.assertEquals;
67  import static org.junit.Assert.assertNotNull;
68  import static org.junit.Assert.assertTrue;
69  import static org.junit.Assert.fail;
70  
71  @Category({MediumTests.class})
72  public class TestRSGroups extends TestRSGroupsBase {
73    protected static final Log LOG = LogFactory.getLog(TestRSGroups.class);
74    private static HMaster master;
75    private static boolean init = false;
76    private static RSGroupAdminEndpoint RSGroupAdminEndpoint;
77  
78  
79    @BeforeClass
80    public static void setUp() throws Exception {
81      TEST_UTIL = new HBaseTestingUtility();
82      conf = TEST_UTIL.getConfiguration();
83      conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, RSGroupBasedLoadBalancer.class.getName());
84      conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, RSGroupAdminEndpoint.class.getName());
85      conf.setBoolean(HConstants.ZOOKEEPER_USEMULTI, true);
86      final int numSlaves = conf.getInt(NUM_SLAVES_BASE_KEY, DEFAULT_NUM_SLAVES_BASE);
87      TEST_UTIL.startMiniCluster(numSlaves);
88      conf.set(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, Integer.toString(numSlaves));
89      TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
90  
91      admin = TEST_UTIL.getHBaseAdmin();
92      cluster = TEST_UTIL.getHBaseCluster();
93      master = ((MiniHBaseCluster)cluster).getMaster();
94  
95      //wait for balancer to come online
96      final long waitTimeout = conf.getLong(WAIT_TIMEOUT_KEY, DEFAULT_WAIT_TIMEOUT);
97      TEST_UTIL.waitFor(waitTimeout, new Waiter.Predicate<Exception>() {
98        @Override
99        public boolean evaluate() throws Exception {
100         return master.isInitialized() &&
101             ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline();
102       }
103     });
104     admin.setBalancerRunning(false,true);
105     rsGroupAdmin = new VerifyingRSGroupAdminClient(rsGroupAdmin.newClient(TEST_UTIL.getConnection()),
106         conf);
107     RSGroupAdminEndpoint =
108         master.getMasterCoprocessorHost().findCoprocessors(RSGroupAdminEndpoint.class).get(0);
109   }
110 
111   @AfterClass
112   public static void tearDown() throws Exception {
113     TEST_UTIL.shutdownMiniCluster();
114   }
115 
116   @Before
117   public void beforeMethod() throws Exception {
118     if(!init) {
119       init = true;
120       afterMethod();
121     }
122 
123   }
124 
125   @After
126   public void afterMethod() throws Exception {
127     deleteTableIfNecessary();
128     deleteNamespaceIfNecessary();
129     deleteGroups();
130 
131     final int numSlaves = conf.getInt(NUM_SLAVES_BASE_KEY, DEFAULT_NUM_SLAVES_BASE);
132     int missing = numSlaves - getNumServers();
133     LOG.info("Restoring servers: "+missing);
134     for(int i=0; i<missing; i++) {
135       ((MiniHBaseCluster)cluster).startRegionServer();
136     }
137 
138     rsGroupAdmin.addRSGroup("master");
139     ServerName masterServerName =
140         ((MiniHBaseCluster)cluster).getMaster().getServerName();
141 
142     try {
143       rsGroupAdmin.moveServers(
144           Sets.newHashSet(masterServerName.getHostPort()),
145           "master");
146     } catch (Exception ex) {
147       // ignore
148     }
149     final long waitTimeout = conf.getLong(WAIT_TIMEOUT_KEY, DEFAULT_WAIT_TIMEOUT);
150     TEST_UTIL.waitFor(waitTimeout, 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             == numSlaves;
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     final long waitTimeout = conf.getLong(WAIT_TIMEOUT_KEY, DEFAULT_WAIT_TIMEOUT);
186     TEST_UTIL.waitFor(waitTimeout, new Waiter.Predicate<Exception>() {
187       @Override
188       public boolean evaluate() throws Exception {
189         return getTableRegionMap().get(desc.getTableName()) != null;
190       }
191     });
192     ServerName targetServer =
193         ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
194     AdminProtos.AdminService.BlockingInterface rs = admin.getConnection().getAdmin(targetServer);
195     //verify it was assigned to the right group
196     Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
197   }
198 
199   @Test
200   public void testDefaultNamespaceCreateAndAssign() throws Exception {
201     LOG.info("testDefaultNamespaceCreateAndAssign");
202     final byte[] tableName = Bytes.toBytes(tablePrefix + "_testCreateAndAssign");
203     admin.modifyNamespace(NamespaceDescriptor.create("default")
204         .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, "default").build());
205     final HTableDescriptor desc = new HTableDescriptor(tableName);
206     desc.addFamily(new HColumnDescriptor("f"));
207     admin.createTable(desc);
208     //wait for created table to be assigned
209     final long waitTimeout = conf.getLong(WAIT_TIMEOUT_KEY, DEFAULT_WAIT_TIMEOUT);
210     TEST_UTIL.waitFor(waitTimeout, new Waiter.Predicate<Exception>() {
211       @Override
212       public boolean evaluate() throws Exception {
213         return getTableRegionMap().get(desc.getTableName()) != null;
214       }
215     });
216   }
217 
218   @Test
219   public void testNamespaceConstraint() throws Exception {
220     String nsName = tablePrefix+"_foo";
221     String groupName = tablePrefix+"_foo";
222     LOG.info("testNamespaceConstraint");
223     rsGroupAdmin.addRSGroup(groupName);
224     admin.createNamespace(NamespaceDescriptor.create(nsName)
225         .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, groupName)
226         .build());
227     //test removing a referenced group
228     try {
229       rsGroupAdmin.removeRSGroup(groupName);
230       fail("Expected a constraint exception");
231     } catch (IOException ex) {
232     }
233     //test modify group
234     //changing with the same name is fine
235     admin.modifyNamespace(
236         NamespaceDescriptor.create(nsName)
237           .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, groupName)
238           .build());
239     String anotherGroup = tablePrefix+"_anotherGroup";
240     rsGroupAdmin.addRSGroup(anotherGroup);
241     //test add non-existent group
242     admin.deleteNamespace(nsName);
243     rsGroupAdmin.removeRSGroup(groupName);
244     try {
245       admin.createNamespace(NamespaceDescriptor.create(nsName)
246           .addConfiguration(RSGroupInfo.NAMESPACEDESC_PROP_GROUP, "foo")
247           .build());
248       fail("Expected a constraint exception");
249     } catch (IOException ex) {
250     }
251   }
252 
253   @Test
254   public void testGroupInfoMultiAccessing() throws Exception {
255     RSGroupInfoManager manager = RSGroupAdminEndpoint.getGroupInfoManager();
256     final RSGroupInfo defaultGroup = manager.getRSGroup("default");
257     // getRSGroup updates default group's server list
258     // this process must not affect other threads iterating the list
259     Iterator<HostAndPort> it = defaultGroup.getServers().iterator();
260     manager.getRSGroup("default");
261     it.next();
262   }
263 
264   @Test
265   public void testMisplacedRegions() throws Exception {
266     final TableName tableName = TableName.valueOf(tablePrefix+"_testMisplacedRegions");
267     LOG.info("testMisplacedRegions");
268 
269     final RSGroupInfo RSGroupInfo = addGroup(rsGroupAdmin, "testMisplacedRegions", 1);
270 
271     TEST_UTIL.createMultiRegionTable(tableName, new byte[]{'f'}, 15);
272     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
273 
274     RSGroupAdminEndpoint.getGroupInfoManager()
275         .moveTables(Sets.newHashSet(tableName), RSGroupInfo.getName());
276 
277     assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName()));
278 
279     TEST_UTIL.waitFor(60000, new Predicate<Exception>() {
280       @Override
281       public boolean evaluate() throws Exception {
282         ServerName serverName =
283             ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1);
284         return admin.getConnection().getAdmin()
285             .getOnlineRegions(serverName).size() == 15;
286       }
287     });
288   }
289 
290   @Test
291   public void testCloneSnapshot() throws Exception {
292     byte[] FAMILY = Bytes.toBytes("test");
293     final TableName tableName = TableName.valueOf(tablePrefix + "_testCloneSnapshot");
294     String snapshotName = tableName.getNameAsString() + "_snap";
295     TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
296 
297     // create base table
298     TEST_UTIL.createTable(tableName, FAMILY);
299 
300     // create snapshot
301     admin.snapshot(snapshotName, tableName);
302 
303     // clone
304     admin.cloneSnapshot(snapshotName, clonedTableName);
305   }
306 
307 }