View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.coprocessor;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.io.IOException;
25  import java.util.List;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.Coprocessor;
31  import org.apache.hadoop.hbase.HBaseConfiguration;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HTableDescriptor;
35  import org.apache.hadoop.hbase.testclassification.MediumTests;
36  import org.apache.hadoop.hbase.MiniHBaseCluster;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.catalog.MetaEditor;
39  import org.apache.hadoop.hbase.client.HBaseAdmin;
40  import org.apache.hadoop.hbase.client.Mutation;
41  import org.apache.hadoop.hbase.regionserver.HRegion;
42  import org.apache.hadoop.hbase.regionserver.HRegionServer;
43  import org.apache.hadoop.hbase.regionserver.RegionMergeTransaction;
44  import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
45  import org.apache.hadoop.hbase.util.Bytes;
46  import org.junit.Test;
47  import org.junit.experimental.categories.Category;
48  
49  /**
50   * Tests invocation of the {@link org.apache.hadoop.hbase.coprocessor.RegionServerObserver}
51   * interface hooks at all appropriate times during normal HMaster operations.
52   */
53  @Category(MediumTests.class)
54  public class TestRegionServerObserver {
55    private static final Log LOG = LogFactory.getLog(TestRegionServerObserver.class);
56  
57    /**
58     * Test verifies the hooks in regions merge.
59     * @throws Exception
60     */
61    @Test
62    public void testCoprocessorHooksInRegionsMerge() throws Exception {
63      final int NUM_MASTERS = 1;
64      final int NUM_RS = 1;
65      final String TABLENAME = "testRegionServerObserver";
66      final String TABLENAME2 = "testRegionServerObserver_2";
67      final byte[] FAM = Bytes.toBytes("fam");
68  
69      // Create config to use for this cluster
70      Configuration conf = HBaseConfiguration.create();
71      conf.setClass("hbase.coprocessor.regionserver.classes", CPRegionServerObserver.class,
72        RegionServerObserver.class);
73  
74      // Start the cluster
75      HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf);
76      TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
77      HBaseAdmin admin = new HBaseAdmin(conf);
78      try {
79        MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
80        HRegionServer regionServer = cluster.getRegionServer(0);
81        RegionServerCoprocessorHost cpHost = regionServer.getCoprocessorHost();
82        Coprocessor coprocessor = cpHost.findCoprocessor(CPRegionServerObserver.class.getName());
83        CPRegionServerObserver regionServerObserver = (CPRegionServerObserver) coprocessor;
84        HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(TABLENAME));
85        desc.addFamily(new HColumnDescriptor(FAM));
86        admin.createTable(desc, new byte[][] { Bytes.toBytes("row") });
87        desc = new HTableDescriptor(TableName.valueOf(TABLENAME2));
88        desc.addFamily(new HColumnDescriptor(FAM));
89        admin.createTable(desc, new byte[][] { Bytes.toBytes("row") });
90        assertFalse(regionServerObserver.wasRegionMergeCalled());
91        List<HRegion> regions = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME));
92        admin.mergeRegions(regions.get(0).getRegionInfo().getEncodedNameAsBytes(), regions.get(1)
93            .getRegionInfo().getEncodedNameAsBytes(), true);
94        int regionsCount = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME)).size();
95        while (regionsCount != 1) {
96          regionsCount = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME)).size();
97          Thread.sleep(1000);
98        }
99        assertTrue(regionServerObserver.wasRegionMergeCalled());
100       assertTrue(regionServerObserver.wasPreMergeCommit());
101       assertTrue(regionServerObserver.wasPostMergeCommit());
102       assertEquals(regionsCount, 1);
103       assertEquals(regionServer.getOnlineRegions(TableName.valueOf(TABLENAME2)).size(), 1);
104     } finally {
105       if (admin != null) admin.close();
106       TEST_UTIL.shutdownMiniCluster();
107     }
108   }
109 
110   public static class CPRegionServerObserver extends BaseRegionServerObserver {
111     private RegionMergeTransaction rmt = null;
112     private HRegion mergedRegion = null;
113 
114     private boolean bypass = false;
115     private boolean preMergeCalled;
116     private boolean preMergeBeforePONRCalled;
117     private boolean preMergeAfterPONRCalled;
118     private boolean preRollBackMergeCalled;
119     private boolean postRollBackMergeCalled;
120     private boolean postMergeCalled;
121 
122     public void enableBypass(boolean bypass) {
123       this.bypass = bypass;
124     }
125 
126     public void resetStates() {
127       preMergeCalled = false;
128       preMergeBeforePONRCalled = false;
129       preMergeAfterPONRCalled = false;
130       preRollBackMergeCalled = false;
131       postRollBackMergeCalled = false;
132       postMergeCalled = false;
133     }
134 
135     @Override
136     public void preMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx, HRegion regionA,
137         HRegion regionB) throws IOException {
138       preMergeCalled = true;
139     }
140 
141     @Override
142     public void preMergeCommit(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
143         HRegion regionA, HRegion regionB, List<Mutation> metaEntries) throws IOException {
144       preMergeBeforePONRCalled = true;
145       RegionServerCoprocessorEnvironment environment = ctx.getEnvironment();
146       HRegionServer rs = (HRegionServer) environment.getRegionServerServices();
147       List<HRegion> onlineRegions =
148           rs.getOnlineRegions(TableName.valueOf("testRegionServerObserver_2"));
149       rmt = new RegionMergeTransaction(onlineRegions.get(0), onlineRegions.get(1), true);
150       if (!rmt.prepare(rs)) {
151         LOG.error("Prepare for the region merge of table "
152             + onlineRegions.get(0).getTableDesc().getNameAsString()
153             + " failed. So returning null. ");
154         ctx.bypass();
155         return;
156       }
157       mergedRegion = rmt.stepsBeforePONR(rs, rs, false);
158       rmt.prepareMutationsForMerge(mergedRegion.getRegionInfo(), regionA.getRegionInfo(),
159         regionB.getRegionInfo(), rs.getServerName(), metaEntries);
160       MetaEditor.mutateMetaTable(rs.getCatalogTracker(), metaEntries);
161     }
162 
163     @Override
164     public void postMergeCommit(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
165         HRegion regionA, HRegion regionB, HRegion mr) throws IOException {
166       preMergeAfterPONRCalled = true;
167       RegionServerCoprocessorEnvironment environment = ctx.getEnvironment();
168       HRegionServer rs = (HRegionServer) environment.getRegionServerServices();
169       rmt.stepsAfterPONR(rs, rs, this.mergedRegion);
170     }
171 
172     @Override
173     public void preRollBackMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
174         HRegion regionA, HRegion regionB) throws IOException {
175       preRollBackMergeCalled = true;
176     }
177 
178     @Override
179     public void postRollBackMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
180         HRegion regionA, HRegion regionB) throws IOException {
181       postRollBackMergeCalled = true;
182     }
183 
184     @Override
185     public void postMerge(ObserverContext<RegionServerCoprocessorEnvironment> c, HRegion regionA,
186         HRegion regionB, HRegion mergedRegion) throws IOException {
187       postMergeCalled = true;
188     }
189 
190     public boolean wasPreMergeCalled() {
191       return this.preMergeCalled;
192     }
193 
194     public boolean wasPostMergeCalled() {
195       return this.postMergeCalled;
196     }
197 
198     public boolean wasPreMergeCommit() {
199       return this.preMergeBeforePONRCalled;
200     }
201 
202     public boolean wasPostMergeCommit() {
203       return this.preMergeAfterPONRCalled;
204     }
205 
206     public boolean wasPreRollBackMerge() {
207       return this.preRollBackMergeCalled;
208     }
209 
210     public boolean wasPostRollBackMerge() {
211       return this.postRollBackMergeCalled;
212     }
213 
214     public boolean wasRegionMergeCalled() {
215       return this.preMergeCalled && this.postMergeCalled;
216     }
217 
218   }
219 
220 }