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