View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.*;
29  import org.apache.hadoop.hbase.client.*;
30  import org.apache.hadoop.hbase.testclassification.MasterTests;
31  import org.apache.hadoop.hbase.testclassification.MediumTests;
32  import org.apache.hadoop.hbase.util.Bytes;
33  import org.apache.hadoop.hbase.util.PairOfSameType;
34  import org.apache.hadoop.hbase.util.Threads;
35  import static org.junit.Assert.assertFalse;
36  import static org.junit.Assert.assertTrue;
37  import org.junit.AfterClass;
38  import org.junit.BeforeClass;
39  import org.junit.Rule;
40  import org.junit.Test;
41  import org.junit.experimental.categories.Category;
42  
43  import org.junit.rules.TestName;
44  import org.junit.rules.TestRule;
45  
46  import static org.junit.Assert.assertNotNull;
47  
48  @Category({MasterTests.class, MediumTests.class})
49  public class TestCatalogJanitorInMemoryStates {
50    private static final Log LOG = LogFactory.getLog(TestCatalogJanitorInMemoryStates.class);
51    @Rule public final TestRule timeout = CategoryBasedTimeout.builder().
52       withTimeout(this.getClass()).withLookingForStuckThread(true).build();
53    @Rule public final TestName name = new TestName();
54    protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
55    private static byte [] ROW = Bytes.toBytes("testRow");
56    private static byte [] FAMILY = Bytes.toBytes("testFamily");
57    private static byte [] QUALIFIER = Bytes.toBytes("testQualifier");
58    private static byte [] VALUE = Bytes.toBytes("testValue");
59  
60    /**
61     * @throws java.lang.Exception
62     */
63    @BeforeClass
64    public static void setUpBeforeClass() throws Exception {
65      Configuration conf = TEST_UTIL.getConfiguration();
66      TEST_UTIL.startMiniCluster(1);
67    }
68  
69    /**
70     * @throws java.lang.Exception
71     */
72    @AfterClass
73    public static void tearDownAfterClass() throws Exception {
74      TEST_UTIL.shutdownMiniCluster();
75    }
76  
77    /**
78     * Test clearing a split parent from memory.
79     */
80    @Test(timeout = 180000)
81    public void testInMemoryParentCleanup() throws IOException, InterruptedException {
82      final AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager();
83      final ServerManager sm = TEST_UTIL.getHBaseCluster().getMaster().getServerManager();
84      final CatalogJanitor janitor = TEST_UTIL.getHBaseCluster().getMaster().catalogJanitorChore;
85  
86      Admin admin = TEST_UTIL.getHBaseAdmin();
87      admin.enableCatalogJanitor(false);
88  
89      final TableName tableName = TableName.valueOf(name.getMethodName());
90      Table t = TEST_UTIL.createTable(tableName, FAMILY);
91      int rowCount = TEST_UTIL.loadTable(t, FAMILY, false);
92  
93      RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName);
94      List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations();
95  
96      // We need to create a valid split with daughter regions
97      HRegionLocation parent = allRegionLocations.get(0);
98      List<HRegionLocation> daughters = splitRegion(parent.getRegionInfo());
99      LOG.info("Parent region: " + parent);
100     LOG.info("Daughter regions: " + daughters);
101     assertNotNull("Should have found daughter regions for " + parent, daughters);
102 
103     assertTrue("Parent region should exist in RegionStates",
104         am.getRegionStates().isRegionInRegionStates(parent.getRegionInfo()));
105     assertTrue("Parent region should exist in ServerManager",
106         sm.isRegionInServerManagerStates(parent.getRegionInfo()));
107 
108     // clean the parent
109     Result r = MetaMockingUtil.getMetaTableRowResult(parent.getRegionInfo(), null,
110         daughters.get(0).getRegionInfo(), daughters.get(1).getRegionInfo());
111     // We need to wait a little before and after we remove the parent
112     Thread.sleep(5000);
113     janitor.cleanParent(parent.getRegionInfo(), r);
114     Thread.sleep(5000);
115     assertFalse("Parent region should have been removed from RegionStates",
116         am.getRegionStates().isRegionInRegionStates(parent.getRegionInfo()));
117     assertFalse("Parent region should have been removed from ServerManager",
118         sm.isRegionInServerManagerStates(parent.getRegionInfo()));
119 
120   }
121 
122   /**
123    * Test that after replica parent region is split, the parent replica region is removed from
124    * AM's serverHoldings and
125    */
126   @Test(timeout = 180000)
127   public void testInMemoryForReplicaParentCleanup() throws Exception {
128     final AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager();
129     final CatalogJanitor janitor = TEST_UTIL.getHBaseCluster().getMaster().catalogJanitorChore;
130 
131     final TableName tableName = TableName.valueOf("testInMemoryForReplicaParentCleanup");
132     HTableDescriptor hdt = TEST_UTIL.createTableDescriptor(tableName.getNameAsString());
133     hdt.setRegionReplication(2);
134     TEST_UTIL.createTable(hdt, new byte[][] { FAMILY }, TEST_UTIL.getConfiguration());
135 
136     RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName);
137     List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations();
138 
139     // There are two regions, one for primary, one for the replica.
140     assertTrue(allRegionLocations.size() == 2);
141 
142     final HRegionLocation primaryParentRegion
143       = RegionReplicaUtil.isDefaultReplica(
144       allRegionLocations.get(0).getRegionInfo().getReplicaId()) ? allRegionLocations.get(0)
145         : allRegionLocations.get(1);
146     final HRegionLocation replicaParentRegion
147       = RegionReplicaUtil.isDefaultReplica(
148       allRegionLocations.get(0).getRegionInfo().getReplicaId()) ? allRegionLocations.get(1)
149       : allRegionLocations.get(0);
150 
151     assertNotNull("Should have found daughter regions for " + primaryParentRegion,
152       splitRegion(primaryParentRegion.getRegionInfo(), Bytes.toBytes("a")));
153 
154     TEST_UTIL.waitFor(60 * 1000, new Waiter.Predicate<Exception>() {
155       @Override
156       public boolean evaluate() throws Exception {
157         return !am.getRegionStates().existsInServerHoldings(primaryParentRegion.getServerName(),
158           primaryParentRegion.getRegionInfo()) &&
159           !am.getRegionStates().existsInServerHoldings(replicaParentRegion.getServerName(),
160             replicaParentRegion.getRegionInfo());
161       }
162     });
163   }
164 
165   /*
166  * Splits a region
167  * @param t Region to split.
168  * @return List of region locations
169  * @throws IOException, InterruptedException
170  */
171   private List<HRegionLocation> splitRegion(final HRegionInfo r)
172       throws IOException, InterruptedException {
173     List<HRegionLocation> locations = new ArrayList<>();
174     // Split this table in two.
175     Admin admin = TEST_UTIL.getHBaseAdmin();
176     Connection connection = TEST_UTIL.getConnection();
177     admin.splitRegion(r.getEncodedNameAsBytes());
178     admin.close();
179     PairOfSameType<HRegionInfo> regions = waitOnDaughters(r);
180     if (regions != null) {
181       try (RegionLocator rl = connection.getRegionLocator(r.getTable())) {
182         locations.add(rl.getRegionLocation(regions.getFirst().getEncodedNameAsBytes()));
183         locations.add(rl.getRegionLocation(regions.getSecond().getEncodedNameAsBytes()));
184       }
185       return locations;
186     }
187     return locations;
188   }
189 
190   /*
191 * Splits a region
192 * @param t Region to split.
193 * @return List of region locations
194 * @throws IOException, InterruptedException
195 */
196   private List<HRegionLocation> splitRegion(final HRegionInfo r, final byte[] splitPoint)
197       throws IOException, InterruptedException {
198     List<HRegionLocation> locations = new ArrayList<>();
199     // Split this table in two.
200     Admin admin = TEST_UTIL.getHBaseAdmin();
201     Connection connection = TEST_UTIL.getConnection();
202     admin.splitRegion(r.getEncodedNameAsBytes(), splitPoint);
203     admin.close();
204     PairOfSameType<HRegionInfo> regions = waitOnDaughters(r);
205     if (regions != null) {
206       try (RegionLocator rl = connection.getRegionLocator(r.getTable())) {
207         locations.add(rl.getRegionLocation(regions.getFirst().getEncodedNameAsBytes()));
208         locations.add(rl.getRegionLocation(regions.getSecond().getEncodedNameAsBytes()));
209       }
210       return locations;
211     }
212     return locations;
213   }
214 
215   /*
216    * Wait on region split. May return because we waited long enough on the split
217    * and it didn't happen.  Caller should check.
218    * @param r
219    * @return Daughter regions; caller needs to check table actually split.
220    */
221   private PairOfSameType<HRegionInfo> waitOnDaughters(final HRegionInfo r)
222       throws IOException {
223     long start = System.currentTimeMillis();
224     PairOfSameType<HRegionInfo> pair = null;
225     try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
226          Table metaTable = conn.getTable(TableName.META_TABLE_NAME)) {
227       Result result = null;
228       HRegionInfo region = null;
229       while ((System.currentTimeMillis() - start) < 60000) {
230         result = metaTable.get(new Get(r.getRegionName()));
231         if (result == null) {
232           break;
233         }
234         region = MetaTableAccessor.getHRegionInfo(result);
235         if (region.isSplitParent()) {
236           LOG.debug(region.toString() + " IS a parent!");
237           pair = MetaTableAccessor.getDaughterRegions(result);
238           break;
239         }
240         Threads.sleep(100);
241       }
242 
243       if (pair.getFirst() == null || pair.getSecond() == null) {
244         throw new IOException("Failed to get daughters, for parent region: " + r);
245       }
246       return pair;
247     }
248   }
249 }