View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master.procedure;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  
26  import java.io.IOException;
27  
28  import org.apache.hadoop.fs.FileStatus;
29  import org.apache.hadoop.fs.FileSystem;
30  import org.apache.hadoop.fs.Path;
31  import org.apache.hadoop.fs.PathFilter;
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.HTableDescriptor;
36  import org.apache.hadoop.hbase.testclassification.LargeTests;
37  import org.apache.hadoop.hbase.client.Admin;
38  import org.apache.hadoop.hbase.client.HTable;
39  import org.apache.hadoop.hbase.InvalidFamilyOperationException;
40  import org.apache.hadoop.hbase.TableName;
41  import org.apache.hadoop.hbase.client.Admin;
42  import org.apache.hadoop.hbase.client.Table;
43  import org.apache.hadoop.hbase.testclassification.LargeTests;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.apache.hadoop.hbase.util.FSUtils;
46  import org.apache.hadoop.hbase.wal.WALSplitter;
47  import org.junit.After;
48  import org.junit.AfterClass;
49  import org.junit.Assert;
50  import org.junit.Before;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  
55  @Category(LargeTests.class)
56  public class TestDeleteColumnFamilyProcedureFromClient {
57    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
58  
59    private static final TableName TABLENAME =
60        TableName.valueOf("column_family_handlers");
61    private static final byte[][] FAMILIES = new byte[][] { Bytes.toBytes("cf1"),
62        Bytes.toBytes("cf2"), Bytes.toBytes("cf3") };
63  
64    /**
65     * Start up a mini cluster and put a small table of empty regions into it.
66     *
67     * @throws Exception
68     */
69    @BeforeClass
70    public static void beforeAllTests() throws Exception {
71      TEST_UTIL.getConfiguration().setBoolean("dfs.support.append", true);
72      TEST_UTIL.startMiniCluster(2);
73    }
74  
75    @AfterClass
76    public static void afterAllTests() throws Exception {
77      TEST_UTIL.shutdownMiniCluster();
78    }
79  
80    @Before
81    public void setup() throws IOException, InterruptedException {
82      // Create a table of three families. This will assign a region.
83      TEST_UTIL.createTable(TABLENAME, FAMILIES);
84  
85      HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
86      TEST_UTIL.waitUntilNoRegionsInTransition();
87  
88      // Load the table with data for all families
89      TEST_UTIL.loadTable(t, FAMILIES);
90  
91      TEST_UTIL.flush();
92  
93      t.close();
94  
95      TEST_UTIL.ensureSomeRegionServersAvailable(2);
96    }
97  
98    @After
99    public void cleanup() throws Exception {
100     TEST_UTIL.deleteTable(TABLENAME);
101   }
102 
103   @Test
104   public void deleteColumnFamilyWithMultipleRegions() throws Exception {
105     Admin admin = TEST_UTIL.getHBaseAdmin();
106     HTableDescriptor beforehtd = admin.getTableDescriptor(TABLENAME);
107 
108     FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
109 
110     // 1 - Check if table exists in descriptor
111     assertTrue(admin.isTableAvailable(TABLENAME));
112 
113     // 2 - Check if all three families exist in descriptor
114     assertEquals(3, beforehtd.getColumnFamilies().length);
115     HColumnDescriptor[] families = beforehtd.getColumnFamilies();
116     for (int i = 0; i < families.length; i++) {
117       assertTrue(families[i].getNameAsString().equals("cf" + (i + 1)));
118     }
119 
120     // 3 - Check if table exists in FS
121     Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
122     assertTrue(fs.exists(tableDir));
123 
124     // 4 - Check if all the 3 column families exist in FS
125     FileStatus[] fileStatus = fs.listStatus(tableDir);
126     for (int i = 0; i < fileStatus.length; i++) {
127       if (fileStatus[i].isDirectory() == true) {
128         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
129           @Override
130           public boolean accept(Path p) {
131             if (p.getName().contains(HConstants.RECOVERED_EDITS_DIR)) {
132               return false;
133             }
134             return true;
135           }
136         });
137         int k = 1;
138         for (int j = 0; j < cf.length; j++) {
139           if (cf[j].isDirectory() == true
140               && cf[j].getPath().getName().startsWith(".") == false) {
141             assertEquals(cf[j].getPath().getName(), "cf" + k);
142             k++;
143           }
144         }
145       }
146     }
147 
148     // TEST - Disable and delete the column family
149     admin.disableTable(TABLENAME);
150     admin.deleteColumn(TABLENAME, Bytes.toBytes("cf2"));
151 
152     // 5 - Check if only 2 column families exist in the descriptor
153     HTableDescriptor afterhtd = admin.getTableDescriptor(TABLENAME);
154     assertEquals(2, afterhtd.getColumnFamilies().length);
155     HColumnDescriptor[] newFamilies = afterhtd.getColumnFamilies();
156     assertTrue(newFamilies[0].getNameAsString().equals("cf1"));
157     assertTrue(newFamilies[1].getNameAsString().equals("cf3"));
158 
159     // 6 - Check if the second column family is gone from the FS
160     fileStatus = fs.listStatus(tableDir);
161     for (int i = 0; i < fileStatus.length; i++) {
162       if (fileStatus[i].isDirectory() == true) {
163         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
164           @Override
165           public boolean accept(Path p) {
166             if (WALSplitter.isSequenceIdFile(p)) {
167               return false;
168             }
169             return true;
170           }
171         });
172         for (int j = 0; j < cf.length; j++) {
173           if (cf[j].isDirectory() == true) {
174             assertFalse(cf[j].getPath().getName().equals("cf2"));
175           }
176         }
177       }
178     }
179   }
180 
181   @Test
182   public void deleteColumnFamilyTwice() throws Exception {
183     Admin admin = TEST_UTIL.getHBaseAdmin();
184     HTableDescriptor beforehtd = admin.getTableDescriptor(TABLENAME);
185     String cfToDelete = "cf1";
186 
187     FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
188 
189     // 1 - Check if table exists in descriptor
190     assertTrue(admin.isTableAvailable(TABLENAME));
191 
192     // 2 - Check if all the target column family exist in descriptor
193     HColumnDescriptor[] families = beforehtd.getColumnFamilies();
194     Boolean foundCF = false;
195     for (int i = 0; i < families.length; i++) {
196       if (families[i].getNameAsString().equals(cfToDelete)) {
197         foundCF = true;
198         break;
199       }
200     }
201     assertTrue(foundCF);
202 
203     // 3 - Check if table exists in FS
204     Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
205     assertTrue(fs.exists(tableDir));
206 
207     // 4 - Check if all the target column family exist in FS
208     FileStatus[] fileStatus = fs.listStatus(tableDir);
209     foundCF = false;
210     for (int i = 0; i < fileStatus.length; i++) {
211       if (fileStatus[i].isDirectory() == true) {
212         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
213           @Override
214           public boolean accept(Path p) {
215             if (p.getName().contains(HConstants.RECOVERED_EDITS_DIR)) {
216               return false;
217             }
218             return true;
219           }
220         });
221         for (int j = 0; j < cf.length; j++) {
222           if (cf[j].isDirectory() == true && cf[j].getPath().getName().equals(cfToDelete)) {
223             foundCF = true;
224             break;
225           }
226         }
227       }
228       if (foundCF) {
229         break;
230       }
231     }
232     assertTrue(foundCF);
233 
234     // TEST - Disable and delete the column family
235     if (admin.isTableEnabled(TABLENAME)) {
236       admin.disableTable(TABLENAME);
237     }
238     admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
239 
240     // 5 - Check if the target column family is gone from the FS
241     fileStatus = fs.listStatus(tableDir);
242     for (int i = 0; i < fileStatus.length; i++) {
243       if (fileStatus[i].isDirectory() == true) {
244         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
245           @Override
246           public boolean accept(Path p) {
247             if (WALSplitter.isSequenceIdFile(p)) {
248               return false;
249             }
250             return true;
251           }
252         });
253         for (int j = 0; j < cf.length; j++) {
254           if (cf[j].isDirectory() == true) {
255             assertFalse(cf[j].getPath().getName().equals(cfToDelete));
256           }
257         }
258       }
259     }
260 
261     try {
262       // Test: delete again
263       admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
264       Assert.fail("Delete a non-exist column family should fail");
265     } catch (InvalidFamilyOperationException e) {
266       // Expected.
267     }
268   }
269 }