diff --git src/main/java/org/apache/hadoop/hbase/mapreduce/HFileOutputFormat.java src/main/java/org/apache/hadoop/hbase/mapreduce/HFileOutputFormat.java index 028b220..b390c81 100644 --- src/main/java/org/apache/hadoop/hbase/mapreduce/HFileOutputFormat.java +++ src/main/java/org/apache/hadoop/hbase/mapreduce/HFileOutputFormat.java @@ -32,7 +32,6 @@ import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -50,6 +49,7 @@ import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.AbstractHFileWriter; import org.apache.hadoop.hbase.io.hfile.CacheConfig; import org.apache.hadoop.hbase.io.hfile.Compression; +import org.apache.hadoop.hbase.io.hfile.Compression.Algorithm; import org.apache.hadoop.hbase.io.hfile.HFile; import org.apache.hadoop.hbase.io.hfile.HFileDataBlockEncoder; import org.apache.hadoop.hbase.io.hfile.HFileDataBlockEncoderImpl; @@ -78,11 +78,26 @@ import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; */ public class HFileOutputFormat extends FileOutputFormat { static Log LOG = LogFactory.getLog(HFileOutputFormat.class); - static final String COMPRESSION_CONF_KEY = "hbase.hfileoutputformat.families.compression"; - private static final String BLOOM_TYPE_CONF_KEY = "hbase.hfileoutputformat.families.bloomtype"; - private static final String DATABLOCK_ENCODING_CONF_KEY = - "hbase.mapreduce.hfileoutputformat.datablock.encoding"; - private static final String BLOCK_SIZE_CONF_KEY = "hbase.mapreduce.hfileoutputformat.blocksize"; + + // The following constants are private since these are used by + // HFileOutputFormat to internally transfer data between job setup and + // reducer run using conf. + // These should not be changed by the client. + private static final String COMPRESSION_FAMILIES_CONF_KEY = + "hbase.hfileoutputformat.families.compression"; + private static final String BLOOM_TYPE_FAMILIES_CONF_KEY = + "hbase.hfileoutputformat.families.bloomtype"; + private static final String BLOCK_SIZE_FAMILIES_CONF_KEY = + "hbase.mapreduce.hfileoutputformat.blocksize"; + private static final String DATABLOCK_ENCODING_FAMILIES_CONF_KEY = + "hbase.mapreduce.hfileoutputformat.families.datablock.encoding"; + + // This constant is public since the client can modify this when setting + // up their conf object and thus refer to this symbol. + // It is present for backwards compatibility reasons. Use it only to + // override the auto-detection of datablock encoding. + public static final String DATABLOCK_ENCODING_OVERRIDE_CONF_KEY = + "hbase.mapreduce.hfileoutputformat.datablock.encoding"; public RecordWriter getRecordWriter(final TaskAttemptContext context) throws IOException, InterruptedException { @@ -95,30 +110,27 @@ public class HFileOutputFormat extends FileOutputFormat compressionMap = createFamilyCompressionMap(conf); - final Map bloomTypeMap = createFamilyBloomMap(conf); - final Map blockSizeMap = createFamilyBlockSizeMap(conf); + final Map compressionMap = createFamilyCompressionMap(conf); + final Map bloomTypeMap = createFamilyBloomTypeMap(conf); + final Map blockSizeMap = createFamilyBlockSizeMap(conf); - String dataBlockEncodingStr = conf.get(DATABLOCK_ENCODING_CONF_KEY); - final HFileDataBlockEncoder encoder; + String dataBlockEncodingStr = conf.get(DATABLOCK_ENCODING_OVERRIDE_CONF_KEY); + final Map datablockEncodingMap; + final HFileDataBlockEncoder overriddenEncoder; if (dataBlockEncodingStr == null) { - encoder = NoOpDataBlockEncoder.INSTANCE; + overriddenEncoder = null; + datablockEncodingMap = createFamilyDataBlockEncodingMap(conf); } else { - try { - encoder = new HFileDataBlockEncoderImpl(DataBlockEncoding - .valueOf(dataBlockEncodingStr)); - } catch (IllegalArgumentException ex) { - throw new RuntimeException( - "Invalid data block encoding type configured for the param " - + DATABLOCK_ENCODING_CONF_KEY + " : " - + dataBlockEncodingStr); - } + datablockEncodingMap = null; + overriddenEncoder = getDataBlockEncoderFromString(dataBlockEncodingStr); } return new RecordWriter() { @@ -194,21 +206,20 @@ public class HFileOutputFormat extends FileOutputFormat clazz = null; try { - clazz = (Class) Class.forName("org.apache.hadoop.mapreduce.lib.partition.TotalOrderPartitioner"); + clazz = (Class) + Class.forName("org.apache.hadoop.mapreduce.lib.partition.TotalOrderPartitioner"); } catch (ClassNotFoundException e) { clazz = - (Class) Class.forName("org.apache.hadoop.hbase.mapreduce.hadoopbackport.TotalOrderPartitioner"); + (Class) + Class.forName("org.apache.hadoop.hbase.mapreduce.hadoopbackport.TotalOrderPartitioner"); } return clazz; } /** - * Run inside the task to deserialize column family to compression algorithm - * map from the - * configuration. + * Runs inside the task to deserialize column family to compression algorithm + * map from the configuration. * * Package-private for unit tests only. * - * @return a map from column family to the name of the configured compression - * algorithm + * @param conf to read the serialized values from + * @return a map from column family to the configured compression algorithm */ - static Map createFamilyCompressionMap(Configuration conf) { - return createFamilyConfValueMap(conf, COMPRESSION_CONF_KEY); + static Map createFamilyCompressionMap(Configuration + conf) { + Map stringMap = createFamilyConfValueMap(conf, + COMPRESSION_FAMILIES_CONF_KEY); + Map compressionMap = new TreeMap(Bytes.BYTES_COMPARATOR); + for (Map.Entry e : stringMap.entrySet()) { + Algorithm algorithm = AbstractHFileWriter.compressionByName + (e.getValue()); + compressionMap.put(e.getKey(), algorithm); + } + return compressionMap; } - private static Map createFamilyBloomMap(Configuration conf) { - return createFamilyConfValueMap(conf, BLOOM_TYPE_CONF_KEY); + /** + * Runs inside the task to deserialize column family to bloom filter type + * map from the configuration. + * + * Package-private for unit tests only. + * + * @param conf to read the serialized values from + * @return a map from column family to the configured bloom filter type + */ + static Map createFamilyBloomTypeMap(Configuration conf) { + Map stringMap = createFamilyConfValueMap(conf, + BLOOM_TYPE_FAMILIES_CONF_KEY); + Map bloomTypeMap = new TreeMap(Bytes.BYTES_COMPARATOR); + for (Map.Entry e : stringMap.entrySet()) { + BloomType bloomType = BloomType.valueOf(e.getValue()); + bloomTypeMap.put(e.getKey(), bloomType); + } + return bloomTypeMap; } - private static Map createFamilyBlockSizeMap(Configuration conf) { - return createFamilyConfValueMap(conf, BLOCK_SIZE_CONF_KEY); + /** + * Runs inside the task to deserialize column family to block size + * map from the configuration. + * + * Package-private for unit tests only. + * + * @param conf to read the serialized values from + * @return a map from column family to the configured block size + */ + static Map createFamilyBlockSizeMap(Configuration conf) { + Map stringMap = createFamilyConfValueMap(conf, + BLOCK_SIZE_FAMILIES_CONF_KEY); + Map blockSizeMap = new TreeMap(Bytes.BYTES_COMPARATOR); + for (Map.Entry e : stringMap.entrySet()) { + Integer blockSize = Integer.parseInt(e.getValue()); + blockSizeMap.put(e.getKey(), blockSize); + } + return blockSizeMap; + } + + /** + * Runs inside the task to deserialize column family to data block encoding + * type map from the configuration. + * + * Package-private for unit tests only. + * + * @param conf to read the serialized values from + * @return a map from column family to HFileDataBlockEncoder for the + * configured data block type for the family + */ + static Map createFamilyDataBlockEncodingMap( + Configuration conf) { + Map stringMap = createFamilyConfValueMap(conf, + DATABLOCK_ENCODING_FAMILIES_CONF_KEY); + Map encoderMap = new TreeMap(Bytes.BYTES_COMPARATOR); + for (Map.Entry e : stringMap.entrySet()) { + encoderMap.put(e.getKey(), getDataBlockEncoderFromString + (e.getValue())); + } + return encoderMap; + } + + private static HFileDataBlockEncoder getDataBlockEncoderFromString( + String dataBlockEncodingStr) { + HFileDataBlockEncoder encoder; + try { + encoder = new HFileDataBlockEncoderImpl(DataBlockEncoding + .valueOf(dataBlockEncodingStr)); + } catch (IllegalArgumentException ex) { + throw new RuntimeException( + "Invalid data block encoding type configured for the param " + + DATABLOCK_ENCODING_FAMILIES_CONF_KEY + " : " + + dataBlockEncodingStr); + } + return encoder; } + /** * Run inside the task to deserialize column family to given conf value map. - * - * @param conf - * @param confName + * + * @param conf to read the serialized values from + * @param confName conf key to read from the configuration * @return a map of column family to the given configuration value */ private static Map createFamilyConfValueMap(Configuration conf, String confName) { @@ -458,6 +554,8 @@ public class HFileOutputFormat extends FileOutputFormat families = tableDescriptor.getFamilies(); + int i = 0; + for (HColumnDescriptor familyDescriptor : families) { + if (i++ > 0) { + dataBlockEncodingConfigValue.append('&'); + } + dataBlockEncodingConfigValue.append( + URLEncoder.encode(familyDescriptor.getNameAsString(), "UTF-8")); + dataBlockEncodingConfigValue.append('='); + DataBlockEncoding encoding = familyDescriptor.getDataBlockEncoding(); + if (encoding == null) { + encoding = DataBlockEncoding.NONE; + } + dataBlockEncodingConfigValue.append(URLEncoder.encode(encoding.toString(), + "UTF-8")); + } + conf.set(DATABLOCK_ENCODING_FAMILIES_CONF_KEY, + dataBlockEncodingConfigValue.toString()); } } diff --git src/test/java/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java src/test/java/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java index 2bf0c1b..bec182f 100644 --- src/test/java/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java +++ src/test/java/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java @@ -30,14 +30,11 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Random; import java.util.Set; -import java.util.TreeSet; import java.util.concurrent.Callable; -import java.util.Random; - import junit.framework.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -45,7 +42,14 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hbase.*; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.LargeTests; +import org.apache.hadoop.hbase.PerformanceEvaluation; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; @@ -53,13 +57,16 @@ import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.CacheConfig; import org.apache.hadoop.hbase.io.hfile.Compression; import org.apache.hadoop.hbase.io.hfile.Compression.Algorithm; import org.apache.hadoop.hbase.io.hfile.HFile; import org.apache.hadoop.hbase.io.hfile.HFile.Reader; +import org.apache.hadoop.hbase.io.hfile.HFileDataBlockEncoder; import org.apache.hadoop.hbase.regionserver.Store; import org.apache.hadoop.hbase.regionserver.StoreFile; +import org.apache.hadoop.hbase.regionserver.StoreFile.BloomType; import org.apache.hadoop.hbase.regionserver.TimeRangeTracker; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.FSUtils; @@ -77,8 +84,6 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.mockito.Mockito; -import com.google.common.collect.Lists; - /** * Simple test for {@link KeyValueSortReducer} and {@link HFileOutputFormat}. * Sets up and runs a mapreduce job that writes hfile output. @@ -484,35 +489,40 @@ public class TestHFileOutputFormat { } /** - * Test for - * {@link HFileOutputFormat#createFamilyCompressionMap(Configuration)}. Tests - * that the compression map is correctly deserialized from configuration + * Test for {@link HFileOutputFormat#configureCompression(HTable, + * Configuration)} and {@link HFileOutputFormat#createFamilyCompressionMap + * (Configuration)}. + * Tests that the compression map is correctly serialized into + * and deserialized from configuration * * @throws IOException */ @Test - public void testCreateFamilyCompressionMap() throws IOException { + public void testSerializeDeserializeFamilyCompressionMap() throws IOException { for (int numCfs = 0; numCfs <= 3; numCfs++) { Configuration conf = new Configuration(this.util.getConfiguration()); - Map familyToCompression = getMockColumnFamilies(numCfs); + Map familyToCompression = + getMockColumnFamiliesForCompression(numCfs); HTable table = Mockito.mock(HTable.class); - setupMockColumnFamilies(table, familyToCompression); + setupMockColumnFamiliesForCompression(table, familyToCompression); HFileOutputFormat.configureCompression(table, conf); // read back family specific compression setting from the configuration - Map retrievedFamilyToCompressionMap = HFileOutputFormat.createFamilyCompressionMap(conf); + Map retrievedFamilyToCompressionMap = HFileOutputFormat + .createFamilyCompressionMap(conf); // test that we have a value for all column families that matches with the // used mock values for (Entry entry : familyToCompression.entrySet()) { - assertEquals("Compression configuration incorrect for column family:" + entry.getKey(), entry.getValue() - .getName(), retrievedFamilyToCompressionMap.get(entry.getKey().getBytes())); + assertEquals("Compression configuration incorrect for column family:" + + entry.getKey(), entry.getValue(), + retrievedFamilyToCompressionMap.get(entry.getKey().getBytes())); } } } - private void setupMockColumnFamilies(HTable table, - Map familyToCompression) throws IOException + private void setupMockColumnFamiliesForCompression(HTable table, + Map familyToCompression) throws IOException { HTableDescriptor mockTableDescriptor = new HTableDescriptor(TABLE_NAME); for (Entry entry : familyToCompression.entrySet()) { @@ -525,21 +535,12 @@ public class TestHFileOutputFormat { Mockito.doReturn(mockTableDescriptor).when(table).getTableDescriptor(); } - private void setupMockStartKeys(HTable table) throws IOException { - byte[][] mockKeys = new byte[][] { - HConstants.EMPTY_BYTE_ARRAY, - Bytes.toBytes("aaa"), - Bytes.toBytes("ggg"), - Bytes.toBytes("zzz") - }; - Mockito.doReturn(mockKeys).when(table).getStartKeys(); - } - /** * @return a map from column family names to compression algorithms for * testing column family compression. Column family names have special characters */ - private Map getMockColumnFamilies(int numCfs) { + private Map + getMockColumnFamiliesForCompression (int numCfs) { Map familyToCompression = new HashMap(); // use column family names having special characters if (numCfs-- > 0) { @@ -558,6 +559,242 @@ public class TestHFileOutputFormat { } /** + * Test for {@link HFileOutputFormat#configureBloomType(HTable, + * Configuration)} and {@link HFileOutputFormat#createFamilyBloomTypeMap + * (Configuration)}. + * Tests that the compression map is correctly serialized into + * and deserialized from configuration + * + * @throws IOException + */ + @Test + public void testSerializeDeserializeFamilyBloomTypeMap() throws IOException { + for (int numCfs = 0; numCfs <= 2; numCfs++) { + Configuration conf = new Configuration(this.util.getConfiguration()); + Map familyToBloomType = + getMockColumnFamiliesForBloomType(numCfs); + HTable table = Mockito.mock(HTable.class); + setupMockColumnFamiliesForBloomType(table, + familyToBloomType); + HFileOutputFormat.configureBloomType(table, conf); + + // read back family specific data block encoding settings from the + // configuration + Map retrievedFamilyToBloomTypeMap = + HFileOutputFormat + .createFamilyBloomTypeMap(conf); + + // test that we have a value for all column families that matches with the + // used mock values + for (Entry entry : familyToBloomType.entrySet()) { + assertEquals("BloomType configuration incorrect for column family:" + + entry.getKey(), entry.getValue(), + retrievedFamilyToBloomTypeMap.get(entry.getKey().getBytes())); + } + } + } + + private void setupMockColumnFamiliesForBloomType(HTable table, + Map familyToDataBlockEncoding) throws IOException + { + HTableDescriptor mockTableDescriptor = new HTableDescriptor(TABLE_NAME); + for (Entry entry : familyToDataBlockEncoding.entrySet()) { + mockTableDescriptor.addFamily(new HColumnDescriptor(entry.getKey()) + .setMaxVersions(1) + .setBloomFilterType(entry.getValue()) + .setBlockCacheEnabled(false) + .setTimeToLive(0)); + } + Mockito.doReturn(mockTableDescriptor).when(table).getTableDescriptor(); + } + + /** + * @return a map from column family names to compression algorithms for + * testing column family compression. Column family names have special characters + */ + private Map + getMockColumnFamiliesForBloomType (int numCfs) { + Map familyToBloomType = + new HashMap(); + // use column family names having special characters + if (numCfs-- > 0) { + familyToBloomType.put("Family1!@#!@#&", BloomType.ROW); + } + if (numCfs-- > 0) { + familyToBloomType.put("Family2=asdads&!AASD", + BloomType.ROWCOL); + } + if (numCfs-- > 0) { + familyToBloomType.put("Family3", BloomType.NONE); + } + return familyToBloomType; + } + + /** + * Test for {@link HFileOutputFormat#configureBlockSize(HTable, + * Configuration)} and {@link HFileOutputFormat#createFamilyBlockSizeMap + * (Configuration)}. + * Tests that the compression map is correctly serialized into + * and deserialized from configuration + * + * @throws IOException + */ + @Test + public void testSerializeDeserializeFamilyBlockSizeMap() throws IOException { + for (int numCfs = 0; numCfs <= 3; numCfs++) { + Configuration conf = new Configuration(this.util.getConfiguration()); + Map familyToBlockSize = + getMockColumnFamiliesForBlockSize(numCfs); + HTable table = Mockito.mock(HTable.class); + setupMockColumnFamiliesForBlockSize(table, + familyToBlockSize); + HFileOutputFormat.configureBlockSize(table, conf); + + // read back family specific data block encoding settings from the + // configuration + Map retrievedFamilyToBlockSizeMap = + HFileOutputFormat + .createFamilyBlockSizeMap(conf); + + // test that we have a value for all column families that matches with the + // used mock values + for (Entry entry : familyToBlockSize.entrySet() + ) { + assertEquals("BlockSize configuration incorrect for column family:" + + entry.getKey(), entry.getValue(), + retrievedFamilyToBlockSizeMap.get(entry.getKey().getBytes())); + } + } + } + + private void setupMockColumnFamiliesForBlockSize(HTable table, + Map familyToDataBlockEncoding) throws IOException + { + HTableDescriptor mockTableDescriptor = new HTableDescriptor(TABLE_NAME); + for (Entry entry : familyToDataBlockEncoding.entrySet()) { + mockTableDescriptor.addFamily(new HColumnDescriptor(entry.getKey()) + .setMaxVersions(1) + .setBlocksize(entry.getValue()) + .setBlockCacheEnabled(false) + .setTimeToLive(0)); + } + Mockito.doReturn(mockTableDescriptor).when(table).getTableDescriptor(); + } + + /** + * @return a map from column family names to compression algorithms for + * testing column family compression. Column family names have special characters + */ + private Map + getMockColumnFamiliesForBlockSize (int numCfs) { + Map familyToBlockSize = + new HashMap(); + // use column family names having special characters + if (numCfs-- > 0) { + familyToBlockSize.put("Family1!@#!@#&", 1234); + } + if (numCfs-- > 0) { + familyToBlockSize.put("Family2=asdads&!AASD", + Integer.MAX_VALUE); + } + if (numCfs-- > 0) { + familyToBlockSize.put("Family2=asdads&!AASD", + Integer.MAX_VALUE); + } + if (numCfs-- > 0) { + familyToBlockSize.put("Family3", 0); + } + return familyToBlockSize; + } + + /** + * Test for {@link HFileOutputFormat#configureDataBlockEncoding(HTable, + * Configuration)} and {@link HFileOutputFormat#createFamilyDataBlockEncodingMap + * (Configuration)}. + * Tests that the compression map is correctly serialized into + * and deserialized from configuration + * + * @throws IOException + */ + @Test + public void testSerializeDeserializeFamilyDataBlockEncodingMap() throws IOException { + for (int numCfs = 0; numCfs <= 3; numCfs++) { + Configuration conf = new Configuration(this.util.getConfiguration()); + Map familyToDataBlockEncoding = + getMockColumnFamiliesForDataBlockEncoding(numCfs); + HTable table = Mockito.mock(HTable.class); + setupMockColumnFamiliesForDataBlockEncoding(table, + familyToDataBlockEncoding); + HFileOutputFormat.configureDataBlockEncoding(table, conf); + + // read back family specific data block encoding settings from the + // configuration + Map retrievedFamilyToDataBlockEncodingMap = + HFileOutputFormat + .createFamilyDataBlockEncodingMap(conf); + + // test that we have a value for all column families that matches with the + // used mock values + for (Entry entry : familyToDataBlockEncoding.entrySet()) { + assertEquals("DataBlockEncoding configuration incorrect for column family:" + + entry.getKey(), entry.getValue(), + retrievedFamilyToDataBlockEncodingMap.get(entry.getKey().getBytes + ()).getEncodingOnDisk()); + } + } + } + + private void setupMockColumnFamiliesForDataBlockEncoding(HTable table, + Map familyToDataBlockEncoding) throws IOException + { + HTableDescriptor mockTableDescriptor = new HTableDescriptor(TABLE_NAME); + for (Entry entry : familyToDataBlockEncoding.entrySet()) { + mockTableDescriptor.addFamily(new HColumnDescriptor(entry.getKey()) + .setMaxVersions(1) + .setDataBlockEncoding(entry.getValue()) + .setBlockCacheEnabled(false) + .setTimeToLive(0)); + } + Mockito.doReturn(mockTableDescriptor).when(table).getTableDescriptor(); + } + + /** + * @return a map from column family names to compression algorithms for + * testing column family compression. Column family names have special characters + */ + private Map + getMockColumnFamiliesForDataBlockEncoding (int numCfs) { + Map familyToDataBlockEncoding = + new HashMap(); + // use column family names having special characters + if (numCfs-- > 0) { + familyToDataBlockEncoding.put("Family1!@#!@#&", DataBlockEncoding.DIFF); + } + if (numCfs-- > 0) { + familyToDataBlockEncoding.put("Family2=asdads&!AASD", + DataBlockEncoding.FAST_DIFF); + } + if (numCfs-- > 0) { + familyToDataBlockEncoding.put("Family2=asdads&!AASD", + DataBlockEncoding.PREFIX); + } + if (numCfs-- > 0) { + familyToDataBlockEncoding.put("Family3", DataBlockEncoding.NONE); + } + return familyToDataBlockEncoding; + } + + private void setupMockStartKeys(HTable table) throws IOException { + byte[][] mockKeys = new byte[][] { + HConstants.EMPTY_BYTE_ARRAY, + Bytes.toBytes("aaa"), + Bytes.toBytes("ggg"), + Bytes.toBytes("zzz") + }; + Mockito.doReturn(mockKeys).when(table).getStartKeys(); + } + + /** * Test that {@link HFileOutputFormat} RecordWriter uses compression and * bloom filter settings from the column family descriptor */