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  package org.apache.hadoop.hbase.mob;
19  
20  import static org.junit.Assert.assertEquals;
21  
22  import java.util.Random;
23  
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.fs.FileStatus;
26  import org.apache.hadoop.fs.Path;
27  import org.apache.hadoop.hbase.HBaseTestingUtility;
28  import org.apache.hadoop.hbase.HColumnDescriptor;
29  import org.apache.hadoop.hbase.HTableDescriptor;
30  import org.apache.hadoop.hbase.testclassification.MediumTests;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.client.Admin;
33  import org.apache.hadoop.hbase.client.HTable;
34  import org.apache.hadoop.hbase.client.Put;
35  import org.apache.hadoop.hbase.mob.ExpiredMobFileCleaner;
36  import org.apache.hadoop.hbase.mob.MobUtils;
37  import org.apache.hadoop.hbase.util.Bytes;
38  import org.apache.hadoop.util.ToolRunner;
39  import org.junit.After;
40  import org.junit.AfterClass;
41  import org.junit.Before;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  @Category(MediumTests.class)
47  public class TestExpiredMobFileCleaner {
48  
49    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
50    private final static TableName tableName = TableName.valueOf("TestExpiredMobFileCleaner");
51    private final static String family = "family";
52    private final static byte[] row1 = Bytes.toBytes("row1");
53    private final static byte[] row2 = Bytes.toBytes("row2");
54    private final static byte[] qf = Bytes.toBytes("qf");
55  
56    private static HTable table;
57    private static Admin admin;
58  
59    @BeforeClass
60    public static void setUpBeforeClass() throws Exception {
61      TEST_UTIL.getConfiguration().setInt("hbase.master.info.port", 0);
62      TEST_UTIL.getConfiguration().setBoolean("hbase.regionserver.info.port.auto", true);
63  
64      TEST_UTIL.getConfiguration().setInt("hfile.format.version", 3);
65    }
66  
67    @AfterClass
68    public static void tearDownAfterClass() throws Exception {
69  
70    }
71  
72    @Before
73    public void setUp() throws Exception {
74      TEST_UTIL.startMiniCluster(1);
75    }
76  
77    @After
78    public void tearDown() throws Exception {
79      admin.disableTable(tableName);
80      admin.deleteTable(tableName);
81      admin.close();
82      TEST_UTIL.shutdownMiniCluster();
83      TEST_UTIL.getTestFileSystem().delete(TEST_UTIL.getDataTestDir(), true);
84    }
85  
86    private void init() throws Exception {
87      HTableDescriptor desc = new HTableDescriptor(tableName);
88      HColumnDescriptor hcd = new HColumnDescriptor(family);
89      hcd.setMobEnabled(true);
90      hcd.setMobThreshold(3L);
91      hcd.setMaxVersions(4);
92      desc.addFamily(hcd);
93  
94      admin = TEST_UTIL.getHBaseAdmin();
95      admin.createTable(desc);
96      table = new HTable(TEST_UTIL.getConfiguration(), tableName);
97      table.setAutoFlush(false, false);
98    }
99  
100   private void modifyColumnExpiryDays(int expireDays) throws Exception {
101     HColumnDescriptor hcd = new HColumnDescriptor(family);
102     hcd.setMobEnabled(true);
103     hcd.setMobThreshold(3L);
104     // change ttl as expire days to make some row expired
105     int timeToLive = expireDays * secondsOfDay();
106     hcd.setTimeToLive(timeToLive);
107 
108     admin.modifyColumn(tableName, hcd);
109   }
110 
111   private void putKVAndFlush(HTable table, byte[] row, byte[] value, long ts)
112       throws Exception {
113 
114     Put put = new Put(row, ts);
115     put.add(Bytes.toBytes(family), qf, value);
116     table.put(put);
117 
118     table.flushCommits();
119     admin.flush(tableName);
120   }
121 
122   /**
123    * Creates a 3 day old hfile and an 1 day old hfile then sets expiry to 2 days.
124    * Verifies that the 3 day old hfile is removed but the 1 day one is still present
125    * after the expiry based cleaner is run.
126    */
127   @Test
128   public void testCleaner() throws Exception {
129     init();
130 
131     Path mobDirPath = getMobFamilyPath(TEST_UTIL.getConfiguration(), tableName, family);
132 
133     byte[] dummyData = makeDummyData(600);
134     long ts = System.currentTimeMillis() - 3 * secondsOfDay() * 1000; // 3 days before
135     putKVAndFlush(table, row1, dummyData, ts);
136     FileStatus[] firstFiles = TEST_UTIL.getTestFileSystem().listStatus(mobDirPath);
137     //the first mob file
138     assertEquals("Before cleanup without delay 1", 1, firstFiles.length);
139     String firstFile = firstFiles[0].getPath().getName();
140 
141     ts = System.currentTimeMillis() - 1 * secondsOfDay() * 1000; // 1 day before
142     putKVAndFlush(table, row2, dummyData, ts);
143     FileStatus[] secondFiles = TEST_UTIL.getTestFileSystem().listStatus(mobDirPath);
144     //now there are 2 mob files
145     assertEquals("Before cleanup without delay 2", 2, secondFiles.length);
146     String f1 = secondFiles[0].getPath().getName();
147     String f2 = secondFiles[1].getPath().getName();
148     String secondFile = f1.equals(firstFile) ? f2 : f1;
149 
150     modifyColumnExpiryDays(2); // ttl = 2, make the first row expired
151 
152     //run the cleaner
153     String[] args = new String[2];
154     args[0] = tableName.getNameAsString();
155     args[1] = family;
156     ToolRunner.run(TEST_UTIL.getConfiguration(), new ExpiredMobFileCleaner(), args);
157 
158     FileStatus[] filesAfterClean = TEST_UTIL.getTestFileSystem().listStatus(mobDirPath);
159     String lastFile = filesAfterClean[0].getPath().getName();
160     //the first mob fie is removed
161     assertEquals("After cleanup without delay 1", 1, filesAfterClean.length);
162     assertEquals("After cleanup without delay 2", secondFile, lastFile);
163   }
164 
165   private Path getMobFamilyPath(Configuration conf, TableName tableName, String familyName) {
166     Path p = new Path(MobUtils.getMobRegionPath(conf, tableName), familyName);
167     return p;
168   }
169 
170   private int secondsOfDay() {
171     return 24 * 3600;
172   }
173 
174   private byte[] makeDummyData(int size) {
175     byte [] dummyData = new byte[size];
176     new Random().nextBytes(dummyData);
177     return dummyData;
178   }
179 }