001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import java.io.IOException;
021import java.util.Random;
022import org.apache.hadoop.fs.FileSystem;
023import org.apache.hadoop.fs.Path;
024import org.apache.hadoop.hbase.HBaseClassTestRule;
025import org.apache.hadoop.hbase.HBaseTestingUtil;
026import org.apache.hadoop.hbase.TableName;
027import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
028import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
029import org.apache.hadoop.hbase.client.Put;
030import org.apache.hadoop.hbase.client.Result;
031import org.apache.hadoop.hbase.client.ResultScanner;
032import org.apache.hadoop.hbase.client.Scan;
033import org.apache.hadoop.hbase.client.Table;
034import org.apache.hadoop.hbase.client.TableDescriptor;
035import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
036import org.apache.hadoop.hbase.mob.MobConstants;
037import org.apache.hadoop.hbase.mob.MobUtils;
038import org.apache.hadoop.hbase.testclassification.MediumTests;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.apache.hadoop.hbase.util.CommonFSUtils;
041import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
042import org.apache.hadoop.hbase.util.HFileArchiveUtil;
043import org.junit.AfterClass;
044import org.junit.Assert;
045import org.junit.BeforeClass;
046import org.junit.ClassRule;
047import org.junit.Rule;
048import org.junit.Test;
049import org.junit.experimental.categories.Category;
050import org.junit.rules.TestName;
051
052@Category(MediumTests.class)
053public class TestDeleteMobTable {
054
055  @ClassRule
056  public static final HBaseClassTestRule CLASS_RULE =
057      HBaseClassTestRule.forClass(TestDeleteMobTable.class);
058
059  private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
060  private final static byte[] FAMILY = Bytes.toBytes("family");
061  private final static byte[] QF = Bytes.toBytes("qualifier");
062  private static Random random = new Random();
063
064  @Rule
065  public TestName name = new TestName();
066
067  @BeforeClass
068  public static void setUpBeforeClass() throws Exception {
069    TEST_UTIL.startMiniCluster(1);
070  }
071
072  @AfterClass
073  public static void tearDownAfterClass() throws Exception {
074    TEST_UTIL.shutdownMiniCluster();
075  }
076
077  /**
078   * Generate the mob value.
079   *
080   * @param size
081   *          the size of the value
082   * @return the mob value generated
083   */
084  private static byte[] generateMobValue(int size) {
085    byte[] mobVal = new byte[size];
086    random.nextBytes(mobVal);
087    return mobVal;
088  }
089
090  private TableDescriptor createTableDescriptor(TableName tableName, boolean hasMob) {
091    ColumnFamilyDescriptorBuilder builder = ColumnFamilyDescriptorBuilder.newBuilder(FAMILY);
092    if (hasMob) {
093      builder.setMobEnabled(true);
094      builder.setMobThreshold(0);
095    }
096    return TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(builder.build()).build();
097  }
098
099  private Table createTableWithOneFile(TableDescriptor tableDescriptor) throws IOException {
100    Table table = TEST_UTIL.createTable(tableDescriptor, null);
101    try {
102      // insert data
103      byte[] value = generateMobValue(10);
104      byte[] row = Bytes.toBytes("row");
105      Put put = new Put(row);
106      put.addColumn(FAMILY, QF, EnvironmentEdgeManager.currentTime(), value);
107      table.put(put);
108
109      // create an hfile
110      TEST_UTIL.getAdmin().flush(tableDescriptor.getTableName());
111    } catch (IOException e) {
112      table.close();
113      throw e;
114    }
115    return table;
116  }
117
118  @Test
119  public void testDeleteMobTable() throws Exception {
120    final TableName tableName = TableName.valueOf(name.getMethodName());
121    TableDescriptor tableDescriptor = createTableDescriptor(tableName, true);
122    ColumnFamilyDescriptor familyDescriptor = tableDescriptor.getColumnFamily(FAMILY);
123
124    String fileName = null;
125    Table table = createTableWithOneFile(tableDescriptor);
126    try {
127      // the mob file exists
128      Assert.assertEquals(1, countMobFiles(tableName, familyDescriptor.getNameAsString()));
129      Assert.assertEquals(0, countArchiveMobFiles(tableName, familyDescriptor.getNameAsString()));
130      fileName = assertHasOneMobRow(table, tableName, familyDescriptor.getNameAsString());
131      Assert.assertFalse(mobArchiveExist(tableName, familyDescriptor.getNameAsString(), fileName));
132      Assert.assertTrue(mobTableDirExist(tableName));
133    } finally {
134      table.close();
135      TEST_UTIL.deleteTable(tableName);
136    }
137
138    Assert.assertFalse(TEST_UTIL.getAdmin().tableExists(tableName));
139    Assert.assertEquals(0, countMobFiles(tableName, familyDescriptor.getNameAsString()));
140    Assert.assertEquals(1, countArchiveMobFiles(tableName, familyDescriptor.getNameAsString()));
141    Assert.assertTrue(mobArchiveExist(tableName, familyDescriptor.getNameAsString(), fileName));
142    Assert.assertFalse(mobTableDirExist(tableName));
143  }
144
145  @Test
146  public void testDeleteNonMobTable() throws Exception {
147    final TableName tableName = TableName.valueOf(name.getMethodName());
148    TableDescriptor htd = createTableDescriptor(tableName, false);
149    ColumnFamilyDescriptor hcd = htd.getColumnFamily(FAMILY);
150
151    Table table = createTableWithOneFile(htd);
152    try {
153      // the mob file doesn't exist
154      Assert.assertEquals(0, countMobFiles(tableName, hcd.getNameAsString()));
155      Assert.assertEquals(0, countArchiveMobFiles(tableName, hcd.getNameAsString()));
156      Assert.assertFalse(mobTableDirExist(tableName));
157    } finally {
158      table.close();
159      TEST_UTIL.deleteTable(tableName);
160    }
161
162    Assert.assertFalse(TEST_UTIL.getAdmin().tableExists(tableName));
163    Assert.assertEquals(0, countMobFiles(tableName, hcd.getNameAsString()));
164    Assert.assertEquals(0, countArchiveMobFiles(tableName, hcd.getNameAsString()));
165    Assert.assertFalse(mobTableDirExist(tableName));
166  }
167
168  @Test
169  public void testMobFamilyDelete() throws Exception {
170    final TableName tableName = TableName.valueOf(name.getMethodName());
171    TableDescriptor tableDescriptor = createTableDescriptor(tableName, true);
172    ColumnFamilyDescriptor familyDescriptor = tableDescriptor.getColumnFamily(FAMILY);
173    tableDescriptor = TableDescriptorBuilder.newBuilder(tableDescriptor)
174      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("family2"))).build();
175
176    Table table = createTableWithOneFile(tableDescriptor);
177    try {
178      // the mob file exists
179      Assert.assertEquals(1, countMobFiles(tableName, familyDescriptor.getNameAsString()));
180      Assert.assertEquals(0, countArchiveMobFiles(tableName, familyDescriptor.getNameAsString()));
181      String fileName = assertHasOneMobRow(table, tableName, familyDescriptor.getNameAsString());
182      Assert.assertFalse(mobArchiveExist(tableName, familyDescriptor.getNameAsString(), fileName));
183      Assert.assertTrue(mobTableDirExist(tableName));
184
185      TEST_UTIL.getAdmin().deleteColumnFamily(tableName, FAMILY);
186
187      Assert.assertEquals(0, countMobFiles(tableName, familyDescriptor.getNameAsString()));
188      Assert.assertEquals(1, countArchiveMobFiles(tableName, familyDescriptor.getNameAsString()));
189      Assert.assertTrue(mobArchiveExist(tableName, familyDescriptor.getNameAsString(), fileName));
190      Assert.assertFalse(mobColumnFamilyDirExist(tableName, familyDescriptor.getNameAsString()));
191    } finally {
192      table.close();
193      TEST_UTIL.deleteTable(tableName);
194    }
195  }
196
197  private int countMobFiles(TableName tn, String familyName) throws IOException {
198    FileSystem fs = TEST_UTIL.getTestFileSystem();
199    Path mobFileDir = MobUtils.getMobFamilyPath(TEST_UTIL.getConfiguration(), tn, familyName);
200    if (fs.exists(mobFileDir)) {
201      return fs.listStatus(mobFileDir).length;
202    }
203    return 0;
204  }
205
206  private int countArchiveMobFiles(TableName tn, String familyName)
207      throws IOException {
208    FileSystem fs = TEST_UTIL.getTestFileSystem();
209    Path storePath = HFileArchiveUtil.getStoreArchivePath(TEST_UTIL.getConfiguration(), tn,
210        MobUtils.getMobRegionInfo(tn).getEncodedName(), familyName);
211    if (fs.exists(storePath)) {
212      return fs.listStatus(storePath).length;
213    }
214    return 0;
215  }
216
217  private boolean mobTableDirExist(TableName tn) throws IOException {
218    FileSystem fs = TEST_UTIL.getTestFileSystem();
219    Path tableDir =
220      CommonFSUtils.getTableDir(MobUtils.getMobHome(TEST_UTIL.getConfiguration()), tn);
221    return fs.exists(tableDir);
222  }
223
224  private boolean mobColumnFamilyDirExist(TableName tn, String familyName) throws IOException {
225    FileSystem fs = TEST_UTIL.getTestFileSystem();
226    Path mobFamilyDir = MobUtils.getMobFamilyPath(TEST_UTIL.getConfiguration(), tn, familyName);
227    return fs.exists(mobFamilyDir);
228  }
229
230  private boolean mobArchiveExist(TableName tn, String familyName, String fileName)
231      throws IOException {
232    FileSystem fs = TEST_UTIL.getTestFileSystem();
233    Path storePath = HFileArchiveUtil.getStoreArchivePath(TEST_UTIL.getConfiguration(), tn,
234        MobUtils.getMobRegionInfo(tn).getEncodedName(), familyName);
235    return fs.exists(new Path(storePath, fileName));
236  }
237
238  private String assertHasOneMobRow(Table table, TableName tn, String familyName)
239      throws IOException {
240    Scan scan = new Scan();
241    scan.setAttribute(MobConstants.MOB_SCAN_RAW, Bytes.toBytes(Boolean.TRUE));
242    ResultScanner rs = table.getScanner(scan);
243    Result r = rs.next();
244    Assert.assertNotNull(r);
245    String fileName = MobUtils.getMobFileName(r.getColumnLatestCell(FAMILY, QF));
246    Path filePath = new Path(
247        MobUtils.getMobFamilyPath(TEST_UTIL.getConfiguration(), tn, familyName), fileName);
248    FileSystem fs = TEST_UTIL.getTestFileSystem();
249    Assert.assertTrue(fs.exists(filePath));
250    r = rs.next();
251    Assert.assertNull(r);
252    return fileName;
253  }
254}