001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master.assignment; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import java.util.concurrent.Executors; 024import java.util.concurrent.Future; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HBaseTestingUtility; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.client.RegionInfo; 029import org.apache.hadoop.hbase.client.RegionInfoBuilder; 030import org.apache.hadoop.hbase.master.RegionState.State; 031import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 032import org.apache.hadoop.hbase.procedure2.util.StringUtils; 033import org.apache.hadoop.hbase.testclassification.LargeTests; 034import org.apache.hadoop.hbase.testclassification.MasterTests; 035import org.junit.ClassRule; 036import org.junit.Test; 037import org.junit.experimental.categories.Category; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041@Category({ MasterTests.class, LargeTests.class }) 042public class TestAssignmentManager extends TestAssignmentManagerBase { 043 044 @ClassRule 045 public static final HBaseClassTestRule CLASS_RULE = 046 HBaseClassTestRule.forClass(TestAssignmentManager.class); 047 048 private static final Logger LOG = LoggerFactory.getLogger(TestAssignmentManager.class); 049 050 @Test 051 public void testAssignWithGoodExec() throws Exception { 052 // collect AM metrics before test 053 collectAssignmentManagerMetrics(); 054 055 testAssign(new GoodRsExecutor()); 056 057 assertEquals(assignSubmittedCount + NREGIONS, 058 assignProcMetrics.getSubmittedCounter().getCount()); 059 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 060 } 061 062 @Test 063 public void testAssignAndCrashBeforeResponse() throws Exception { 064 TableName tableName = TableName.valueOf("testAssignAndCrashBeforeResponse"); 065 RegionInfo hri = createRegionInfo(tableName, 1); 066 rsDispatcher.setMockRsExecutor(new HangThenRSCrashExecutor()); 067 TransitRegionStateProcedure proc = createAssignProcedure(hri); 068 waitOnFuture(submitProcedure(proc)); 069 } 070 071 @Test 072 public void testUnassignAndCrashBeforeResponse() throws Exception { 073 TableName tableName = TableName.valueOf("testAssignAndCrashBeforeResponse"); 074 RegionInfo hri = createRegionInfo(tableName, 1); 075 rsDispatcher.setMockRsExecutor(new HangOnCloseThenRSCrashExecutor()); 076 for (int i = 0; i < HangOnCloseThenRSCrashExecutor.TYPES_OF_FAILURE; i++) { 077 TransitRegionStateProcedure assign = createAssignProcedure(hri); 078 waitOnFuture(submitProcedure(assign)); 079 TransitRegionStateProcedure unassign = createUnassignProcedure(hri); 080 waitOnFuture(submitProcedure(unassign)); 081 } 082 } 083 084 @Test 085 public void testAssignSocketTimeout() throws Exception { 086 TableName tableName = TableName.valueOf(this.name.getMethodName()); 087 RegionInfo hri = createRegionInfo(tableName, 1); 088 089 // collect AM metrics before test 090 collectAssignmentManagerMetrics(); 091 092 rsDispatcher.setMockRsExecutor(new SocketTimeoutRsExecutor(20)); 093 waitOnFuture(submitProcedure(createAssignProcedure(hri))); 094 095 // we crashed a rs, so it is possible that there are other regions on the rs which will also be 096 // reassigned, so here we just assert greater than, not the exact number. 097 assertTrue(assignProcMetrics.getSubmittedCounter().getCount() > assignSubmittedCount); 098 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 099 } 100 101 @Test 102 public void testAssignQueueFullOnce() throws Exception { 103 TableName tableName = TableName.valueOf(this.name.getMethodName()); 104 RegionInfo hri = createRegionInfo(tableName, 1); 105 106 // collect AM metrics before test 107 collectAssignmentManagerMetrics(); 108 109 rsDispatcher.setMockRsExecutor(new CallQueueTooBigOnceRsExecutor()); 110 waitOnFuture(submitProcedure(createAssignProcedure(hri))); 111 112 assertEquals(assignSubmittedCount + 1, assignProcMetrics.getSubmittedCounter().getCount()); 113 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 114 } 115 116 @Test 117 public void testTimeoutThenQueueFull() throws Exception { 118 TableName tableName = TableName.valueOf(this.name.getMethodName()); 119 RegionInfo hri = createRegionInfo(tableName, 1); 120 121 // collect AM metrics before test 122 collectAssignmentManagerMetrics(); 123 124 rsDispatcher.setMockRsExecutor(new TimeoutThenCallQueueTooBigRsExecutor(10)); 125 waitOnFuture(submitProcedure(createAssignProcedure(hri))); 126 rsDispatcher.setMockRsExecutor(new TimeoutThenCallQueueTooBigRsExecutor(15)); 127 waitOnFuture(submitProcedure(createUnassignProcedure(hri))); 128 129 assertEquals(assignSubmittedCount + 1, assignProcMetrics.getSubmittedCounter().getCount()); 130 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 131 assertEquals(unassignSubmittedCount + 1, unassignProcMetrics.getSubmittedCounter().getCount()); 132 assertEquals(unassignFailedCount, unassignProcMetrics.getFailedCounter().getCount()); 133 } 134 135 private void testAssign(final MockRSExecutor executor) throws Exception { 136 testAssign(executor, NREGIONS); 137 } 138 139 private void testAssign(MockRSExecutor executor, int nRegions) throws Exception { 140 rsDispatcher.setMockRsExecutor(executor); 141 142 TransitRegionStateProcedure[] assignments = new TransitRegionStateProcedure[nRegions]; 143 144 long st = System.currentTimeMillis(); 145 bulkSubmit(assignments); 146 147 for (int i = 0; i < assignments.length; ++i) { 148 ProcedureTestingUtility.waitProcedure(master.getMasterProcedureExecutor(), assignments[i]); 149 assertTrue(assignments[i].toString(), assignments[i].isSuccess()); 150 } 151 long et = System.currentTimeMillis(); 152 float sec = ((et - st) / 1000.0f); 153 LOG.info(String.format("[T] Assigning %dprocs in %s (%.2fproc/sec)", assignments.length, 154 StringUtils.humanTimeDiff(et - st), assignments.length / sec)); 155 } 156 157 @Test 158 public void testAssignAnAssignedRegion() throws Exception { 159 final TableName tableName = TableName.valueOf("testAssignAnAssignedRegion"); 160 final RegionInfo hri = createRegionInfo(tableName, 1); 161 162 // collect AM metrics before test 163 collectAssignmentManagerMetrics(); 164 165 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 166 167 Future<byte[]> futureA = submitProcedure(createAssignProcedure(hri)); 168 169 // wait first assign 170 waitOnFuture(futureA); 171 am.getRegionStates().isRegionInState(hri, State.OPEN); 172 // Second should be a noop. We should recognize region is already OPEN internally 173 // and skip out doing nothing. 174 // wait second assign 175 Future<byte[]> futureB = submitProcedure(createAssignProcedure(hri)); 176 waitOnFuture(futureB); 177 am.getRegionStates().isRegionInState(hri, State.OPEN); 178 // TODO: What else can we do to ensure just a noop. 179 180 // TODO: Though second assign is noop, it's considered success, can noop be handled in a 181 // better way? 182 assertEquals(assignSubmittedCount + 2, assignProcMetrics.getSubmittedCounter().getCount()); 183 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 184 } 185 186 @Test 187 public void testUnassignAnUnassignedRegion() throws Exception { 188 final TableName tableName = TableName.valueOf("testUnassignAnUnassignedRegion"); 189 final RegionInfo hri = createRegionInfo(tableName, 1); 190 191 // collect AM metrics before test 192 collectAssignmentManagerMetrics(); 193 194 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 195 196 // assign the region first 197 waitOnFuture(submitProcedure(createAssignProcedure(hri))); 198 199 final Future<byte[]> futureA = submitProcedure(createUnassignProcedure(hri)); 200 201 // Wait first unassign. 202 waitOnFuture(futureA); 203 am.getRegionStates().isRegionInState(hri, State.CLOSED); 204 // Second should be a noop. We should recognize region is already CLOSED internally 205 // and skip out doing nothing. 206 final Future<byte[]> futureB = submitProcedure(createUnassignProcedure(hri)); 207 waitOnFuture(futureB); 208 // Ensure we are still CLOSED. 209 am.getRegionStates().isRegionInState(hri, State.CLOSED); 210 // TODO: What else can we do to ensure just a noop. 211 212 assertEquals(assignSubmittedCount + 1, assignProcMetrics.getSubmittedCounter().getCount()); 213 assertEquals(assignFailedCount, assignProcMetrics.getFailedCounter().getCount()); 214 // TODO: Though second unassign is noop, it's considered success, can noop be handled in a 215 // better way? 216 assertEquals(unassignSubmittedCount + 2, unassignProcMetrics.getSubmittedCounter().getCount()); 217 assertEquals(unassignFailedCount, unassignProcMetrics.getFailedCounter().getCount()); 218 } 219 220 /** 221 * It is possible that when AM send assign meta request to a RS successfully, but RS can not send 222 * back any response, which cause master startup hangs forever 223 */ 224 @Test 225 public void testAssignMetaAndCrashBeforeResponse() throws Exception { 226 tearDown(); 227 // See setUp(), start HBase until set up meta 228 util = new HBaseTestingUtility(); 229 this.executor = Executors.newSingleThreadScheduledExecutor(); 230 setupConfiguration(util.getConfiguration()); 231 master = new MockMasterServices(util.getConfiguration(), this.regionsToRegionServers); 232 rsDispatcher = new MockRSProcedureDispatcher(master); 233 master.start(NSERVERS, rsDispatcher); 234 am = master.getAssignmentManager(); 235 236 // Assign meta 237 rsDispatcher.setMockRsExecutor(new HangThenRSRestartExecutor()); 238 am.assign(RegionInfoBuilder.FIRST_META_REGIONINFO); 239 assertEquals(true, am.isMetaAssigned()); 240 241 // set it back as default, see setUpMeta() 242 am.wakeMetaLoadedEvent(); 243 } 244 245 private void assertCloseThenOpen() { 246 assertEquals(closeSubmittedCount + 1, closeProcMetrics.getSubmittedCounter().getCount()); 247 assertEquals(closeFailedCount, closeProcMetrics.getFailedCounter().getCount()); 248 assertEquals(openSubmittedCount + 1, openProcMetrics.getSubmittedCounter().getCount()); 249 assertEquals(openFailedCount, openProcMetrics.getFailedCounter().getCount()); 250 } 251 252 @Test 253 public void testMove() throws Exception { 254 TableName tableName = TableName.valueOf("testMove"); 255 RegionInfo hri = createRegionInfo(tableName, 1); 256 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 257 am.assign(hri); 258 259 // collect AM metrics before test 260 collectAssignmentManagerMetrics(); 261 262 am.move(hri); 263 264 assertEquals(moveSubmittedCount + 1, moveProcMetrics.getSubmittedCounter().getCount()); 265 assertEquals(moveFailedCount, moveProcMetrics.getFailedCounter().getCount()); 266 assertCloseThenOpen(); 267 } 268 269 @Test 270 public void testReopen() throws Exception { 271 TableName tableName = TableName.valueOf("testReopen"); 272 RegionInfo hri = createRegionInfo(tableName, 1); 273 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 274 am.assign(hri); 275 276 // collect AM metrics before test 277 collectAssignmentManagerMetrics(); 278 279 TransitRegionStateProcedure proc = 280 TransitRegionStateProcedure.reopen(master.getMasterProcedureExecutor().getEnvironment(), hri); 281 am.getRegionStates().getRegionStateNode(hri).setProcedure(proc); 282 waitOnFuture(submitProcedure(proc)); 283 284 assertEquals(reopenSubmittedCount + 1, reopenProcMetrics.getSubmittedCounter().getCount()); 285 assertEquals(reopenFailedCount, reopenProcMetrics.getFailedCounter().getCount()); 286 assertCloseThenOpen(); 287 } 288}