1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
66
67
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
83 TEST_UTIL.createTable(TABLENAME, FAMILIES);
84
85 HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
86 TEST_UTIL.waitUntilNoRegionsInTransition();
87
88
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
111 assertTrue(admin.isTableAvailable(TABLENAME));
112
113
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
121 Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
122 assertTrue(fs.exists(tableDir));
123
124
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
149 admin.disableTable(TABLENAME);
150 admin.deleteColumn(TABLENAME, Bytes.toBytes("cf2"));
151
152
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
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
190 assertTrue(admin.isTableAvailable(TABLENAME));
191
192
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
204 Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), TABLENAME);
205 assertTrue(fs.exists(tableDir));
206
207
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
235 if (admin.isTableEnabled(TABLENAME)) {
236 admin.disableTable(TABLENAME);
237 }
238 admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
239
240
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
263 admin.deleteColumn(TABLENAME, Bytes.toBytes(cfToDelete));
264 Assert.fail("Delete a non-exist column family should fail");
265 } catch (InvalidFamilyOperationException e) {
266
267 }
268 }
269 }