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.HConstants;
35  import org.apache.hadoop.hbase.HRegionInfo;
36  import org.apache.hadoop.hbase.HTableDescriptor;
37  import org.apache.hadoop.hbase.MediumTests;
38  import org.apache.hadoop.hbase.MiniHBaseCluster;
39  import org.apache.hadoop.hbase.TableName;
40  import org.apache.hadoop.hbase.catalog.MetaEditor;
41  import org.apache.hadoop.hbase.client.Delete;
42  import org.apache.hadoop.hbase.client.HBaseAdmin;
43  import org.apache.hadoop.hbase.client.Mutation;
44  import org.apache.hadoop.hbase.client.Put;
45  import org.apache.hadoop.hbase.regionserver.HRegion;
46  import org.apache.hadoop.hbase.regionserver.HRegionServer;
47  import org.apache.hadoop.hbase.regionserver.RegionMergeTransaction;
48  import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
49  import org.apache.hadoop.hbase.util.Bytes;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  
53  /**
54   * Tests invocation of the {@link org.apache.hadoop.hbase.coprocessor.RegionServerObserver}
55   * interface hooks at all appropriate times during normal HMaster operations.
56   */
57  @Category(MediumTests.class)
58  public class TestRegionServerObserver {
59    private static final Log LOG = LogFactory.getLog(TestRegionServerObserver.class);
60  
61    /**
62     * Test verifies the hooks in regions merge.
63     * @throws Exception
64     */
65    @Test
66    public void testCoprocessorHooksInRegionsMerge() throws Exception {
67      final int NUM_MASTERS = 1;
68      final int NUM_RS = 1;
69      final String TABLENAME = "testRegionServerObserver";
70      final String TABLENAME2 = "testRegionServerObserver_2";
71      final byte[] FAM = Bytes.toBytes("fam");
72  
73      // Create config to use for this cluster
74      Configuration conf = HBaseConfiguration.create();
75      conf.setClass("hbase.coprocessor.regionserver.classes", CPRegionServerObserver.class,
76        RegionServerObserver.class);
77  
78      // Start the cluster
79      HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf);
80      TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
81      HBaseAdmin admin = new HBaseAdmin(conf);
82      try {
83        MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
84        HRegionServer regionServer = cluster.getRegionServer(0);
85        RegionServerCoprocessorHost cpHost = regionServer.getCoprocessorHost();
86        Coprocessor coprocessor = cpHost.findCoprocessor(CPRegionServerObserver.class.getName());
87        CPRegionServerObserver regionServerObserver = (CPRegionServerObserver) coprocessor;
88        HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(TABLENAME));
89        desc.addFamily(new HColumnDescriptor(FAM));
90        admin.createTable(desc, new byte[][] { Bytes.toBytes("row") });
91        desc = new HTableDescriptor(TableName.valueOf(TABLENAME2));
92        desc.addFamily(new HColumnDescriptor(FAM));
93        admin.createTable(desc, new byte[][] { Bytes.toBytes("row") });
94        assertFalse(regionServerObserver.wasRegionMergeCalled());
95        List<HRegion> regions = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME));
96        admin.mergeRegions(regions.get(0).getRegionInfo().getEncodedNameAsBytes(), regions.get(1)
97            .getRegionInfo().getEncodedNameAsBytes(), true);
98        int regionsCount = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME)).size();
99        while (regionsCount != 1) {
100         regionsCount = regionServer.getOnlineRegions(TableName.valueOf(TABLENAME)).size();
101         Thread.sleep(1000);
102       }
103       assertTrue(regionServerObserver.wasRegionMergeCalled());
104       assertTrue(regionServerObserver.wasPreMergeCommit());
105       assertTrue(regionServerObserver.wasPostMergeCommit());
106       assertEquals(regionsCount, 1);
107       assertEquals(regionServer.getOnlineRegions(TableName.valueOf(TABLENAME2)).size(), 1);
108     } finally {
109       if (admin != null) admin.close();
110       TEST_UTIL.shutdownMiniCluster();
111     }
112   }
113 
114   public static class CPRegionServerObserver extends BaseRegionServerObserver {
115     private RegionMergeTransaction rmt = null;
116     private HRegion mergedRegion = null;
117 
118     private boolean bypass = false;
119     private boolean preMergeCalled;
120     private boolean preMergeBeforePONRCalled;
121     private boolean preMergeAfterPONRCalled;
122     private boolean preRollBackMergeCalled;
123     private boolean postRollBackMergeCalled;
124     private boolean postMergeCalled;
125 
126     public void enableBypass(boolean bypass) {
127       this.bypass = bypass;
128     }
129 
130     public void resetStates() {
131       preMergeCalled = false;
132       preMergeBeforePONRCalled = false;
133       preMergeAfterPONRCalled = false;
134       preRollBackMergeCalled = false;
135       postRollBackMergeCalled = false;
136       postMergeCalled = false;
137     }
138 
139     @Override
140     public void preMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx, HRegion regionA,
141         HRegion regionB) throws IOException {
142       preMergeCalled = true;
143     }
144 
145     @Override
146     public void preMergeCommit(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
147         HRegion regionA, HRegion regionB, List<Mutation> metaEntries) throws IOException {
148       preMergeBeforePONRCalled = true;
149       RegionServerCoprocessorEnvironment environment = ctx.getEnvironment();
150       HRegionServer rs = (HRegionServer) environment.getRegionServerServices();
151       List<HRegion> onlineRegions =
152           rs.getOnlineRegions(TableName.valueOf("testRegionServerObserver_2"));
153       rmt = new RegionMergeTransaction(onlineRegions.get(0), onlineRegions.get(1), true);
154       if (!rmt.prepare(rs)) {
155         LOG.error("Prepare for the region merge of table "
156             + onlineRegions.get(0).getTableDesc().getNameAsString()
157             + " failed. So returning null. ");
158         ctx.bypass();
159         return;
160       }
161       mergedRegion = rmt.stepsBeforePONR(rs, rs, false);
162       rmt.prepareMutationsForMerge(mergedRegion.getRegionInfo(), regionA.getRegionInfo(),
163         regionB.getRegionInfo(), rs.getServerName(), metaEntries);
164       MetaEditor.mutateMetaTable(rs.getCatalogTracker(), metaEntries);
165     }
166 
167     @Override
168     public void postMergeCommit(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
169         HRegion regionA, HRegion regionB, HRegion mr) throws IOException {
170       preMergeAfterPONRCalled = true;
171       RegionServerCoprocessorEnvironment environment = ctx.getEnvironment();
172       HRegionServer rs = (HRegionServer) environment.getRegionServerServices();
173       rmt.stepsAfterPONR(rs, rs, this.mergedRegion);
174     }
175 
176     @Override
177     public void preRollBackMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
178         HRegion regionA, HRegion regionB) throws IOException {
179       preRollBackMergeCalled = true;
180     }
181 
182     @Override
183     public void postRollBackMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx,
184         HRegion regionA, HRegion regionB) throws IOException {
185       postRollBackMergeCalled = true;
186     }
187 
188     @Override
189     public void postMerge(ObserverContext<RegionServerCoprocessorEnvironment> c, HRegion regionA,
190         HRegion regionB, HRegion mergedRegion) throws IOException {
191       postMergeCalled = true;
192     }
193 
194     public boolean wasPreMergeCalled() {
195       return this.preMergeCalled;
196     }
197 
198     public boolean wasPostMergeCalled() {
199       return this.postMergeCalled;
200     }
201 
202     public boolean wasPreMergeCommit() {
203       return this.preMergeBeforePONRCalled;
204     }
205 
206     public boolean wasPostMergeCommit() {
207       return this.preMergeAfterPONRCalled;
208     }
209 
210     public boolean wasPreRollBackMerge() {
211       return this.preRollBackMergeCalled;
212     }
213 
214     public boolean wasPostRollBackMerge() {
215       return this.postRollBackMergeCalled;
216     }
217 
218     public boolean wasRegionMergeCalled() {
219       return this.preMergeCalled && this.postMergeCalled;
220     }
221 
222   }
223 
224 }