Author: mbautin Date: Thu Feb 2 19:40:34 2012 New Revision: 1239786 URL: http://svn.apache.org/viewvc?rev=1239786&view=rev Log: [jira][HBASE-5199] Delete out of TTL store files before compaction selection
Summary: Currently, HBase deletes the out of TTL store files after compaction. We can change the sequence to delete the out of TTL store files before selecting store files for compactions. In this way, HBase can keep deleting the old invalid store files without compaction, and also prevent from unnecessary compactions since the out of TTL store files will be deleted before the compaction selection. Test Plan: TestStore Reviewers: Kannan, khemani, aaiyer, Karthik Reviewed By: Karthik CC: Kannan, tedyu, Karthik, khemani, Liyin, JIRA Differential Revision: https://reviews.facebook.net/D1311 Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/Store.java hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/CompactSelection.java hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStore.java Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/Store.java URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/Store.java?rev=1239786&r1=1239785&r2=1239786&view=diff ============================================================================== --- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/Store.java (original) +++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/Store.java Thu Feb 2 19:40:34 2012 @@ -1112,6 +1112,18 @@ public class Store extends SchemaConfigu boolean forcemajor = this.forceMajor && filesCompacting.isEmpty(); if (!forcemajor) { + // Delete the expired store files before the compaction selection. + if (conf.getBoolean("hbase.store.delete.expired.storefile", false) + && (ttl != Long.MAX_VALUE)) { + CompactSelection expiredSelection = compactSelection + .selectExpiredStoreFilesToCompact(System.currentTimeMillis() + - this.ttl); + + // If there is any expired store files, delete them by compaction. + if (expiredSelection != null) { + return expiredSelection; + } + } // do not compact old files above a configurable threshold // save all references. we MUST compact them int pos = 0; @@ -1454,7 +1466,7 @@ public class Store extends SchemaConfigu /** * @return the number of files in this store */ - public int getNumberOfstorefiles() { + public int getNumberOfStoreFiles() { return this.storefiles.size(); } Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java?rev=1239786&r1=1239785&r2=1239786&view=diff ============================================================================== --- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java (original) +++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java Thu Feb 2 19:40:34 2012 @@ -256,7 +256,7 @@ public class StoreFile { /** * @return Path or null if this StoreFile was made with a Stream. */ - Path getPath() { + public Path getPath() { return this.path; } Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/CompactSelection.java URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/CompactSelection.java?rev=1239786&r1=1239785&r2=1239786&view=diff ============================================================================== --- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/CompactSelection.java (original) +++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/CompactSelection.java Thu Feb 2 19:40:34 2012 @@ -19,7 +19,6 @@ */ package org.apache.hadoop.hbase.regionserver.compactions; -import java.util.AbstractList; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; @@ -73,6 +72,43 @@ public class CompactSelection { } /** + * Select the expired store files to compact + * + * @param maxExpiredTimeStamp + * The store file will be marked as expired if its max time stamp is + * less than this maxExpiredTimeStamp. + * @return A CompactSelection contains the expired store files as + * filesToCompact + */ + public CompactSelection selectExpiredStoreFilesToCompact( + long maxExpiredTimeStamp) { + if (filesToCompact == null || filesToCompact.size() == 0) + return null; + ArrayList<StoreFile> expiredStoreFiles = null; + boolean hasExpiredStoreFiles = false; + CompactSelection expiredSFSelection = null; + + for (StoreFile storeFile : this.filesToCompact) { + if (storeFile.getReader().getMaxTimestamp() < maxExpiredTimeStamp) { + LOG.info("Deleting the expired store file by compaction: " + + storeFile.getPath() + " whose maxTimeStamp is " + + storeFile.getReader().getMaxTimestamp() + + " while the max expired timestamp is " + maxExpiredTimeStamp); + if (!hasExpiredStoreFiles) { + expiredStoreFiles = new ArrayList<StoreFile>(); + hasExpiredStoreFiles = true; + } + expiredStoreFiles.add(storeFile); + } + } + + if (hasExpiredStoreFiles) { + expiredSFSelection = new CompactSelection(conf, expiredStoreFiles); + } + return expiredSFSelection; + } + + /** * If the current hour falls in the off peak times and there are no * outstanding off peak compactions, the current compaction is * promoted to an off peak compaction. Currently only one off peak Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStore.java URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStore.java?rev=1239786&r1=1239785&r2=1239786&view=diff ============================================================================== --- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStore.java (original) +++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStore.java Thu Feb 2 19:40:34 2012 @@ -50,18 +50,16 @@ import org.apache.hadoop.hbase.HConstant import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; -import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; -import org.apache.hadoop.hbase.client.HTable; -import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.monitoring.MonitoredTask; +import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest; import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.security.UnixUserGroupInformation; import org.apache.hadoop.util.Progressable; +import org.mockito.Mockito; import com.google.common.base.Joiner; -import org.mockito.Mockito; /** * Test class for the Store @@ -138,14 +136,57 @@ public class TestStore extends TestCase store = new Store(basedir, region, hcd, fs, conf); } + public void testDeleteExpiredStoreFiles() throws Exception { + Configuration conf = HBaseConfiguration.create(); + // Enable the expired store file deletion + conf.setBoolean("hbase.store.delete.expired.storefile", true); + init(getName(), conf); + + this.store.ttl = 1000; + int storeFileNum = 4; + long sleepTime = this.store.ttl / storeFileNum; + long timeStamp; + + // There are 4 store files and the max time stamp difference among these + // store files will be (this.store.ttl / storeFileNum) + for (int i = 1; i <= storeFileNum; i++) { + LOG.info("Adding some data for the store file #" + i); + timeStamp = System.currentTimeMillis(); + this.store.add(new KeyValue(row, family, qf1, timeStamp, (byte[]) null)); + this.store.add(new KeyValue(row, family, qf2, timeStamp, (byte[]) null)); + this.store.add(new KeyValue(row, family, qf3, timeStamp, (byte[]) null)); + flush(i); + Thread.sleep(sleepTime); + } + + // Verify the total number of store files + assertEquals(storeFileNum, this.store.getStorefiles().size()); + + // Each compaction request will find one expired store file and delete it + // by the compaction. + for (int i = 1; i <= storeFileNum; i++) { + // verify the expired store file. + CompactionRequest cr = this.store.requestCompaction(); + assertEquals(1, cr.getFiles().size()); + assertTrue(cr.getFiles().get(0).getReader().getMaxTimestamp() < + (System.currentTimeMillis() - store.ttl)); + // Verify that the expired the store has been deleted. + this.store.compact(cr); + assertEquals(storeFileNum - i, this.store.getStorefiles().size()); + + // Let the next store file expired. + Thread.sleep(sleepTime); + } + } + public void testLowestModificationTime() throws Exception { Configuration conf = HBaseConfiguration.create(); FileSystem fs = FileSystem.get(conf); // Initialize region init(getName(), conf); - int stroeFileNum = 4; - for (int i = 1; i <= stroeFileNum; i++) { + int storeFileNum = 4; + for (int i = 1; i <= storeFileNum; i++) { LOG.info("Adding some data for the store file #"+i); this.store.add(new KeyValue(row, family, qf1, i, (byte[])null)); this.store.add(new KeyValue(row, family, qf2, i, (byte[])null));
