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  
19  package org.apache.hadoop.hbase.master.procedure;
20  
21  import static org.junit.Assert.*;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.NamespaceDescriptor;
29  import org.apache.hadoop.hbase.NamespaceNotFoundException;
30  import org.apache.hadoop.hbase.ProcedureInfo;
31  import org.apache.hadoop.hbase.constraint.ConstraintException;
32  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
33  import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
34  import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.ModifyNamespaceState;
35  import org.apache.hadoop.hbase.testclassification.MediumTests;
36  import org.junit.After;
37  import org.junit.AfterClass;
38  import org.junit.Before;
39  import org.junit.BeforeClass;
40  import org.junit.Test;
41  import org.junit.experimental.categories.Category;
42  
43  @Category(MediumTests.class)
44  public class TestModifyNamespaceProcedure {
45    private static final Log LOG = LogFactory.getLog(TestModifyNamespaceProcedure.class);
46  
47    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
48  
49    private static void setupConf(Configuration conf) {
50      conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
51    }
52  
53    @BeforeClass
54    public static void setupCluster() throws Exception {
55      setupConf(UTIL.getConfiguration());
56      UTIL.startMiniCluster(1);
57    }
58  
59    @AfterClass
60    public static void cleanupTest() throws Exception {
61      try {
62        UTIL.shutdownMiniCluster();
63      } catch (Exception e) {
64        LOG.warn("failure shutting down cluster", e);
65      }
66    }
67  
68    @Before
69    public void setup() throws Exception {
70      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
71    }
72  
73    @After
74    public void tearDown() throws Exception {
75      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
76      for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
77        LOG.info("Tear down, remove table=" + htd.getTableName());
78        UTIL.deleteTable(htd.getTableName());
79      }
80    }
81  
82  
83    @Test(timeout = 60000)
84    public void testModifyNamespace() throws Exception {
85      final NamespaceDescriptor nsd = NamespaceDescriptor.create("testModifyNamespace").build();
86      final String nsKey1 = "hbase.namespace.quota.maxregions";
87      final String nsValue1before = "1111";
88      final String nsValue1after = "9999";
89      final String nsKey2 = "hbase.namespace.quota.maxtables";
90      final String nsValue2 = "10";
91      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
92  
93      nsd.setConfiguration(nsKey1, nsValue1before);
94      createNamespaceForTesting(nsd);
95  
96      // Before modify
97      NamespaceDescriptor currentNsDescriptor =
98          UTIL.getHBaseAdmin().getNamespaceDescriptor(nsd.getName());
99      assertEquals(currentNsDescriptor.getConfigurationValue(nsKey1), nsValue1before);
100     assertNull(currentNsDescriptor.getConfigurationValue(nsKey2));
101 
102     // Update
103     nsd.setConfiguration(nsKey1, nsValue1after);
104     nsd.setConfiguration(nsKey2, nsValue2);
105 
106     long procId1 = procExec.submitProcedure(
107       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
108     // Wait the completion
109     ProcedureTestingUtility.waitProcedure(procExec, procId1);
110     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
111 
112     // Verify the namespace is updated.
113     currentNsDescriptor =
114         UTIL.getHBaseAdmin().getNamespaceDescriptor(nsd.getName());
115     assertEquals(nsd.getConfigurationValue(nsKey1), nsValue1after);
116     assertEquals(currentNsDescriptor.getConfigurationValue(nsKey2), nsValue2);
117   }
118 
119   @Test(timeout=60000)
120   public void testModifyNonExistNamespace() throws Exception {
121     final String namespaceName = "testModifyNonExistNamespace";
122     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
123 
124     try {
125       NamespaceDescriptor nsDescriptor = UTIL.getHBaseAdmin().getNamespaceDescriptor(namespaceName);
126       assertNull(nsDescriptor);
127     } catch (NamespaceNotFoundException nsnfe) {
128       // Expected
129       LOG.debug("The namespace " + namespaceName + " does not exist.  This is expected.");
130     }
131 
132     final NamespaceDescriptor nsd = NamespaceDescriptor.create(namespaceName).build();
133 
134     long procId = procExec.submitProcedure(
135       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
136     // Wait the completion
137     ProcedureTestingUtility.waitProcedure(procExec, procId);
138 
139     // Expect fail with NamespaceNotFoundException
140     ProcedureInfo result = procExec.getResult(procId);
141     assertTrue(result.isFailed());
142     LOG.debug("modify namespace failed with exception: " + result.getExceptionFullMessage());
143     assertTrue(
144       ProcedureTestingUtility.getExceptionCause(result) instanceof NamespaceNotFoundException);
145   }
146 
147   @Test(timeout=60000)
148   public void testModifyNamespaceWithInvalidRegionCount() throws Exception {
149     final NamespaceDescriptor nsd =
150         NamespaceDescriptor.create("testModifyNamespaceWithInvalidRegionCount").build();
151     final String nsKey = "hbase.namespace.quota.maxregions";
152     final String nsValue = "-1";
153     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
154 
155     createNamespaceForTesting(nsd);
156 
157     // Modify
158     nsd.setConfiguration(nsKey, nsValue);
159 
160     long procId = procExec.submitProcedure(
161       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
162     // Wait the completion
163     ProcedureTestingUtility.waitProcedure(procExec, procId);
164     ProcedureInfo result = procExec.getResult(procId);
165     assertTrue(result.isFailed());
166     LOG.debug("Modify namespace failed with exception: " + result.getExceptionFullMessage());
167     assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException);
168   }
169 
170   @Test(timeout=60000)
171   public void testModifyNamespaceWithInvalidTableCount() throws Exception {
172     final NamespaceDescriptor nsd =
173         NamespaceDescriptor.create("testModifyNamespaceWithInvalidTableCount").build();
174     final String nsKey = "hbase.namespace.quota.maxtables";
175     final String nsValue = "-1";
176     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
177 
178     createNamespaceForTesting(nsd);
179 
180     // Modify
181     nsd.setConfiguration(nsKey, nsValue);
182 
183     long procId = procExec.submitProcedure(
184       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
185     // Wait the completion
186     ProcedureTestingUtility.waitProcedure(procExec, procId);
187     ProcedureInfo result = procExec.getResult(procId);
188     assertTrue(result.isFailed());
189     LOG.debug("Modify namespace failed with exception: " + result.getExceptionFullMessage());
190     assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException);
191   }
192 
193   @Test(timeout = 60000)
194   public void testRecoveryAndDoubleExecution() throws Exception {
195     final NamespaceDescriptor nsd =
196         NamespaceDescriptor.create("testRecoveryAndDoubleExecution").build();
197     final String nsKey = "foo";
198     final String nsValue = "bar";
199     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
200 
201     createNamespaceForTesting(nsd);
202     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
203     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
204 
205     // Modify
206     nsd.setConfiguration(nsKey, nsValue);
207 
208     // Start the Modify procedure && kill the executor
209     long procId = procExec.submitProcedure(
210       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
211 
212     // Restart the executor and execute the step twice
213     int numberOfSteps = ModifyNamespaceState.values().length;
214     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
215       procExec,
216       procId,
217       numberOfSteps,
218       ModifyNamespaceState.values());
219 
220     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
221     // Validate
222     NamespaceDescriptor currentNsDescriptor =
223         UTIL.getHBaseAdmin().getNamespaceDescriptor(nsd.getName());
224     assertEquals(currentNsDescriptor.getConfigurationValue(nsKey), nsValue);
225   }
226 
227   @Test(timeout = 60000)
228   public void testRollbackAndDoubleExecution() throws Exception {
229     final NamespaceDescriptor nsd =
230         NamespaceDescriptor.create("testRollbackAndDoubleExecution").build();
231     final String nsKey = "foo";
232     final String nsValue = "bar";
233     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
234 
235     createNamespaceForTesting(nsd);
236     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
237     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
238 
239     // Modify
240     nsd.setConfiguration(nsKey, nsValue);
241 
242     // Start the Modify procedure && kill the executor
243     long procId = procExec.submitProcedure(
244       new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd));
245 
246     // Failing in the middle of proc
247     int numberOfSteps = ModifyNamespaceState.values().length - 2;
248     MasterProcedureTestingUtility.testRollbackAndDoubleExecution(
249       procExec,
250       procId,
251       numberOfSteps,
252       ModifyNamespaceState.values());
253 
254     // Validate
255     NamespaceDescriptor currentNsDescriptor =
256         UTIL.getHBaseAdmin().getNamespaceDescriptor(nsd.getName());
257     assertNull(currentNsDescriptor.getConfigurationValue(nsKey));
258   }
259 
260   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
261     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
262   }
263 
264   private void createNamespaceForTesting(NamespaceDescriptor nsDescriptor) throws Exception {
265     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
266 
267     long procId = procExec.submitProcedure(
268       new CreateNamespaceProcedure(procExec.getEnvironment(), nsDescriptor));
269     // Wait the completion
270     ProcedureTestingUtility.waitProcedure(procExec, procId);
271     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
272   }
273 }