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.handler;
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 TestTableDeleteFamilyHandler {
57  
58    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
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      HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
85      while(TEST_UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager()
86          .getRegionStates().getRegionsInTransition().size() > 0) {
87        Thread.sleep(100);
88      }
89      // Create multiple regions in all the three column families
90      while(TEST_UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager()
91          .getRegionStates().getRegionsInTransition().size() > 0) {
92        Thread.sleep(100);
93      }
94      // Load the table with data for all families
95      TEST_UTIL.loadTable(t, FAMILIES);
96  
97      TEST_UTIL.flush();
98  
99      t.close();
100 
101     TEST_UTIL.ensureSomeRegionServersAvailable(2);
102   }
103 
104   @After
105   public void cleanup() throws Exception {
106     TEST_UTIL.deleteTable(TABLENAME);
107   }
108 
109   @Test
110   public void deleteColumnFamilyWithMultipleRegions() throws Exception {
111     Admin admin = TEST_UTIL.getHBaseAdmin();
112     HTableDescriptor beforehtd = admin.getTableDescriptor(TABLENAME);
113 
114     FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
115 
116     // 1 - Check if table exists in descriptor
117     assertTrue(admin.isTableAvailable(TABLENAME));
118 
119     // 2 - Check if all three families exist in descriptor
120     assertEquals(3, beforehtd.getColumnFamilies().length);
121     HColumnDescriptor[] families = beforehtd.getColumnFamilies();
122     for (int i = 0; i < families.length; i++) {
123       assertTrue(families[i].getNameAsString().equals("cf" + (i + 1)));
124     }
125 
126     // 3 - Check if table exists in FS
127     Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
128     assertTrue(fs.exists(tableDir));
129 
130     // 4 - Check if all the 3 column families exist in FS
131     FileStatus[] fileStatus = fs.listStatus(tableDir);
132     for (int i = 0; i < fileStatus.length; i++) {
133       if (fileStatus[i].isDirectory() == true) {
134         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
135           @Override
136           public boolean accept(Path p) {
137             if (p.getName().contains(HConstants.RECOVERED_EDITS_DIR)) {
138               return false;
139             }
140             return true;
141           }
142         });
143         int k = 1;
144         for (int j = 0; j < cf.length; j++) {
145           if (cf[j].isDirectory() == true
146               && cf[j].getPath().getName().startsWith(".") == false) {
147             assertEquals(cf[j].getPath().getName(), "cf" + k);
148             k++;
149           }
150         }
151       }
152     }
153 
154     // TEST - Disable and delete the column family
155     admin.disableTable(TABLENAME);
156     admin.deleteColumn(TABLENAME, Bytes.toBytes("cf2"));
157 
158     // 5 - Check if only 2 column families exist in the descriptor
159     HTableDescriptor afterhtd = admin.getTableDescriptor(TABLENAME);
160     assertEquals(2, afterhtd.getColumnFamilies().length);
161     HColumnDescriptor[] newFamilies = afterhtd.getColumnFamilies();
162     assertTrue(newFamilies[0].getNameAsString().equals("cf1"));
163     assertTrue(newFamilies[1].getNameAsString().equals("cf3"));
164 
165     // 6 - Check if the second column family is gone from the FS
166     fileStatus = fs.listStatus(tableDir);
167     for (int i = 0; i < fileStatus.length; i++) {
168       if (fileStatus[i].isDirectory() == true) {
169         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
170           @Override
171           public boolean accept(Path p) {
172             if (WALSplitter.isSequenceIdFile(p)) {
173               return false;
174             }
175             return true;
176           }
177         });
178         for (int j = 0; j < cf.length; j++) {
179           if (cf[j].isDirectory() == true) {
180             assertFalse(cf[j].getPath().getName().equals("cf2"));
181           }
182         }
183       }
184     }
185   }
186 
187   @Test
188   public void deleteColumnFamilyTwice() throws Exception {
189 
190     Admin admin = TEST_UTIL.getHBaseAdmin();
191     HTableDescriptor beforehtd = admin.getTableDescriptor(TABLENAME);
192     String cfToDelete = "cf1";
193 
194     FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
195 
196     // 1 - Check if table exists in descriptor
197     assertTrue(admin.isTableAvailable(TABLENAME));
198 
199     // 2 - Check if all the target column family exist in descriptor
200     HColumnDescriptor[] families = beforehtd.getColumnFamilies();
201     Boolean foundCF = false;
202     int i;
203     for (i = 0; i < families.length; i++) {
204       if (families[i].getNameAsString().equals(cfToDelete)) {
205         foundCF = true;
206         break;
207       }
208     }
209     assertTrue(foundCF);
210 
211     // 3 - Check if table exists in FS
212     Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
213     assertTrue(fs.exists(tableDir));
214 
215     // 4 - Check if all the target column family exist in FS
216     FileStatus[] fileStatus = fs.listStatus(tableDir);
217     foundCF = false;
218     for (i = 0; i < fileStatus.length; i++) {
219       if (fileStatus[i].isDirectory() == true) {
220         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
221           @Override
222           public boolean accept(Path p) {
223             if (p.getName().contains(HConstants.RECOVERED_EDITS_DIR)) {
224               return false;
225             }
226             return true;
227           }
228         });
229         for (int j = 0; j < cf.length; j++) {
230           if (cf[j].isDirectory() == true && cf[j].getPath().getName().equals(cfToDelete)) {
231             foundCF = true;
232             break;
233           }
234         }
235       }
236       if (foundCF) {
237         break;
238       }
239     }
240     assertTrue(foundCF);
241 
242     // TEST - Disable and delete the column family
243     if (admin.isTableEnabled(TABLENAME)) {
244       admin.disableTable(TABLENAME);
245     }
246     admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
247 
248     // 5 - Check if the target column family is gone from the FS
249     fileStatus = fs.listStatus(tableDir);
250     for (i = 0; i < fileStatus.length; i++) {
251       if (fileStatus[i].isDirectory() == true) {
252         FileStatus[] cf = fs.listStatus(fileStatus[i].getPath(), new PathFilter() {
253           @Override
254           public boolean accept(Path p) {
255             if (WALSplitter.isSequenceIdFile(p)) {
256               return false;
257             }
258             return true;
259           }
260         });
261         for (int j = 0; j < cf.length; j++) {
262           if (cf[j].isDirectory() == true) {
263             assertFalse(cf[j].getPath().getName().equals(cfToDelete));
264           }
265         }
266       }
267     }
268 
269     try {
270       // Test: delete again
271       admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
272       Assert.fail("Delete a non-exist column family should fail");
273     } catch (InvalidFamilyOperationException e) {
274       // Expected.
275     }
276   }
277 
278 }