View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to you under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations
15   * under the License.
16   */
17  package org.apache.hadoop.hbase.procedure;
18  
19  import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY;
20  import static org.junit.Assert.fail;
21  
22  import java.io.IOException;
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.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.ProcedureInfo;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver;
34  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
35  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
36  import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos;
37  import org.apache.hadoop.hbase.security.AccessDeniedException;
38  import org.apache.hadoop.hbase.testclassification.MediumTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.After;
41  import org.junit.BeforeClass;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  /**
46   * Check if CompletedProcedureCleaner cleans up failed nonce procedures.
47   */
48  @Category(MediumTests.class)
49  public class TestFailedProcCleanup {
50    private static final Log LOG = LogFactory.getLog(TestFailedProcCleanup.class);
51  
52    protected static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
53    private static Configuration conf;
54    private static final TableName TABLE = TableName.valueOf("test");
55    private static final byte[] FAMILY = Bytes.toBytesBinary("f");
56    private static final int evictionDelay = 10 * 1000;
57  
58    @BeforeClass
59    public static void setUpBeforeClass() {
60      conf = TEST_UTIL.getConfiguration();
61      conf.setInt("hbase.procedure.cleaner.evict.ttl", evictionDelay);
62    }
63  
64    @After
65    public void tearDown() throws Exception {
66      TEST_UTIL.cleanupTestDir();
67      TEST_UTIL.cleanupDataTestDirOnTestFS();
68      TEST_UTIL.shutdownMiniCluster();
69    }
70  
71    @Test
72    public void testFailCreateTable() throws Exception {
73      conf.set(MASTER_COPROCESSOR_CONF_KEY, CreateFailObserver.class.getName());
74      TEST_UTIL.startMiniCluster(3);
75      try {
76        TEST_UTIL.createTable(TABLE, FAMILY);
77      } catch (AccessDeniedException e) {
78        LOG.debug("Ignoring exception: ", e);
79        Thread.sleep(evictionDelay * 3);
80      }
81      List<ProcedureInfo> procedureInfos =
82          TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor().listProcedures();
83      for (ProcedureInfo procedureInfo : procedureInfos) {
84        if (procedureInfo.getProcName().equals("CreateTableProcedure")
85            && procedureInfo.getProcState() == ProcedureProtos.ProcedureState.ROLLEDBACK) {
86          fail("Found procedure " + procedureInfo + " that hasn't been cleaned up");
87        }
88      }
89    }
90  
91    @Test
92    public void testFailCreateTableHandler() throws Exception {
93      conf.set(MASTER_COPROCESSOR_CONF_KEY, CreateFailObserverHandler.class.getName());
94      TEST_UTIL.startMiniCluster(3);
95      try {
96        TEST_UTIL.createTable(TABLE, FAMILY);
97      } catch (AccessDeniedException e) {
98        LOG.debug("Ignoring exception: ", e);
99        Thread.sleep(evictionDelay * 3);
100     }
101     List<ProcedureInfo> procedureInfos =
102         TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor().listProcedures();
103     for (ProcedureInfo procedureInfo : procedureInfos) {
104       if (procedureInfo.getProcName().equals("CreateTableProcedure")
105           && procedureInfo.getProcState() == ProcedureProtos.ProcedureState.ROLLEDBACK) {
106         fail("Found procedure " + procedureInfo + " that hasn't been cleaned up");
107       }
108     }
109   }
110 
111   public static class CreateFailObserver extends BaseMasterObserver {
112 
113     @Override
114     public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
115         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
116 
117       if (desc.getTableName().equals(TABLE)) {
118         throw new AccessDeniedException("Don't allow creation of table");
119       }
120     }
121   }
122 
123   public static class CreateFailObserverHandler extends BaseMasterObserver {
124 
125     @Override
126     public void preCreateTableHandler(
127         final ObserverContext<MasterCoprocessorEnvironment> ctx,
128         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
129 
130       if (desc.getTableName().equals(TABLE)) {
131         throw new AccessDeniedException("Don't allow creation of table");
132       }
133     }
134   }
135 }