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.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNull; 022import static org.junit.Assert.assertTrue; 023 024import java.util.Map; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HColumnDescriptor; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.KeepDeletedCells; 029import org.apache.hadoop.hbase.exceptions.DeserializationException; 030import org.apache.hadoop.hbase.exceptions.HBaseException; 031import org.apache.hadoop.hbase.io.compress.Compression; 032import org.apache.hadoop.hbase.io.compress.Compression.Algorithm; 033import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 034import org.apache.hadoop.hbase.io.encoding.IndexBlockEncoding; 035import org.apache.hadoop.hbase.regionserver.BloomType; 036import org.apache.hadoop.hbase.testclassification.MiscTests; 037import org.apache.hadoop.hbase.testclassification.SmallTests; 038import org.apache.hadoop.hbase.util.BuilderStyleTest; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.apache.hadoop.hbase.util.PrettyPrinter; 041import org.junit.Assert; 042import org.junit.ClassRule; 043import org.junit.Rule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.junit.rules.ExpectedException; 047 048@Category({ MiscTests.class, SmallTests.class }) 049public class TestColumnFamilyDescriptorBuilder { 050 @ClassRule 051 public static final HBaseClassTestRule CLASS_RULE = 052 HBaseClassTestRule.forClass(TestColumnFamilyDescriptorBuilder.class); 053 054 @Rule 055 public ExpectedException expectedEx = ExpectedException.none(); 056 057 @Test 058 public void testBuilder() throws DeserializationException { 059 ColumnFamilyDescriptorBuilder builder = 060 ColumnFamilyDescriptorBuilder.newBuilder(HConstants.CATALOG_FAMILY).setInMemory(true) 061 .setScope(HConstants.REPLICATION_SCOPE_LOCAL).setBloomFilterType(BloomType.NONE); 062 final int v = 123; 063 builder.setBlocksize(v); 064 builder.setTimeToLive(v); 065 builder.setBlockCacheEnabled(!HColumnDescriptor.DEFAULT_BLOCKCACHE); 066 builder.setValue(Bytes.toBytes("a"), Bytes.toBytes("b")); 067 builder.setMaxVersions(v); 068 assertEquals(v, builder.build().getMaxVersions()); 069 builder.setMinVersions(v); 070 assertEquals(v, builder.build().getMinVersions()); 071 builder.setKeepDeletedCells(KeepDeletedCells.TRUE); 072 builder.setInMemory(!HColumnDescriptor.DEFAULT_IN_MEMORY); 073 boolean inmemory = builder.build().isInMemory(); 074 builder.setScope(v); 075 builder.setDataBlockEncoding(DataBlockEncoding.FAST_DIFF); 076 builder.setBloomFilterType(BloomType.ROW); 077 builder.setCompressionType(Algorithm.SNAPPY); 078 builder.setMobEnabled(true); 079 builder.setMobThreshold(1000L); 080 builder.setDFSReplication((short) v); 081 082 ColumnFamilyDescriptor hcd = builder.build(); 083 byte[] bytes = ColumnFamilyDescriptorBuilder.toByteArray(hcd); 084 ColumnFamilyDescriptor deserializedHcd = ColumnFamilyDescriptorBuilder.parseFrom(bytes); 085 assertTrue(hcd.equals(deserializedHcd)); 086 assertEquals(v, hcd.getBlocksize()); 087 assertEquals(v, hcd.getTimeToLive()); 088 assertTrue( 089 Bytes.equals(hcd.getValue(Bytes.toBytes("a")), deserializedHcd.getValue(Bytes.toBytes("a")))); 090 assertEquals(hcd.getMaxVersions(), deserializedHcd.getMaxVersions()); 091 assertEquals(hcd.getMinVersions(), deserializedHcd.getMinVersions()); 092 assertEquals(hcd.getKeepDeletedCells(), deserializedHcd.getKeepDeletedCells()); 093 assertEquals(inmemory, deserializedHcd.isInMemory()); 094 assertEquals(hcd.getScope(), deserializedHcd.getScope()); 095 assertTrue(deserializedHcd.getCompressionType().equals(Compression.Algorithm.SNAPPY)); 096 assertTrue(deserializedHcd.getDataBlockEncoding().equals(DataBlockEncoding.FAST_DIFF)); 097 assertTrue(deserializedHcd.getBloomFilterType().equals(BloomType.ROW)); 098 assertEquals(hcd.isMobEnabled(), deserializedHcd.isMobEnabled()); 099 assertEquals(hcd.getMobThreshold(), deserializedHcd.getMobThreshold()); 100 assertEquals(v, deserializedHcd.getDFSReplication()); 101 } 102 103 /** 104 * Tests HColumnDescriptor with empty familyName 105 */ 106 @Test 107 public void testHColumnDescriptorShouldThrowIAEWhenFamilyNameEmpty() throws Exception { 108 expectedEx.expect(IllegalArgumentException.class); 109 expectedEx.expectMessage("Column Family name can not be empty"); 110 ColumnFamilyDescriptorBuilder.of(""); 111 } 112 113 /** 114 * Test that we add and remove strings from configuration properly. 115 */ 116 @Test 117 public void testAddGetRemoveConfiguration() { 118 ColumnFamilyDescriptorBuilder builder = 119 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("foo")); 120 String key = "Some"; 121 String value = "value"; 122 builder.setConfiguration(key, value); 123 assertEquals(value, builder.build().getConfigurationValue(key)); 124 builder.removeConfiguration(key); 125 assertEquals(null, builder.build().getConfigurationValue(key)); 126 } 127 128 @Test 129 public void testMobValuesInHColumnDescriptorShouldReadable() { 130 boolean isMob = true; 131 long threshold = 1000; 132 String policy = "weekly"; 133 // We unify the format of all values saved in the descriptor. 134 // Each value is stored as bytes of string. 135 String isMobString = PrettyPrinter.format(String.valueOf(isMob), 136 HColumnDescriptor.getUnit(HColumnDescriptor.IS_MOB)); 137 String thresholdString = PrettyPrinter.format(String.valueOf(threshold), 138 HColumnDescriptor.getUnit(HColumnDescriptor.MOB_THRESHOLD)); 139 String policyString = PrettyPrinter.format(Bytes.toStringBinary(Bytes.toBytes(policy)), 140 HColumnDescriptor.getUnit(HColumnDescriptor.MOB_COMPACT_PARTITION_POLICY)); 141 assertEquals(String.valueOf(isMob), isMobString); 142 assertEquals(String.valueOf(threshold), thresholdString); 143 assertEquals(String.valueOf(policy), policyString); 144 } 145 146 @Test 147 public void testClassMethodsAreBuilderStyle() { 148 /* 149 * HColumnDescriptor should have a builder style setup where setXXX/addXXX methods can be 150 * chainable together: . For example: HColumnDescriptor hcd = new HColumnDescriptor() 151 * .setFoo(foo) .setBar(bar) .setBuz(buz) This test ensures that all methods starting with "set" 152 * returns the declaring object 153 */ 154 155 BuilderStyleTest.assertClassesAreBuilderStyle(ColumnFamilyDescriptorBuilder.class); 156 } 157 158 @Test 159 public void testSetTimeToLive() throws HBaseException { 160 String ttl; 161 ColumnFamilyDescriptorBuilder builder = 162 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("foo")); 163 164 ttl = "50000"; 165 builder.setTimeToLive(ttl); 166 Assert.assertEquals(50000, builder.build().getTimeToLive()); 167 168 ttl = "50000 seconds"; 169 builder.setTimeToLive(ttl); 170 Assert.assertEquals(50000, builder.build().getTimeToLive()); 171 172 ttl = ""; 173 builder.setTimeToLive(ttl); 174 Assert.assertEquals(0, builder.build().getTimeToLive()); 175 176 ttl = "FOREVER"; 177 builder.setTimeToLive(ttl); 178 Assert.assertEquals(HConstants.FOREVER, builder.build().getTimeToLive()); 179 180 ttl = "1 HOUR 10 minutes 1 second"; 181 builder.setTimeToLive(ttl); 182 Assert.assertEquals(4201, builder.build().getTimeToLive()); 183 184 ttl = "500 Days 23 HOURS"; 185 builder.setTimeToLive(ttl); 186 Assert.assertEquals(43282800, builder.build().getTimeToLive()); 187 188 ttl = "43282800 SECONDS (500 Days 23 hours)"; 189 builder.setTimeToLive(ttl); 190 Assert.assertEquals(43282800, builder.build().getTimeToLive()); 191 } 192 193 @Test 194 public void testSetBlocksize() throws HBaseException { 195 String blocksize; 196 ColumnFamilyDescriptorBuilder builder = 197 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("foo")); 198 199 blocksize = "131072"; 200 builder.setBlocksize(blocksize); 201 assertEquals(131072, builder.build().getBlocksize()); 202 203 blocksize = "100KB"; 204 builder.setBlocksize(blocksize); 205 assertEquals(102400, builder.build().getBlocksize()); 206 207 blocksize = "1MB"; 208 builder.setBlocksize(blocksize); 209 assertEquals(1048576, builder.build().getBlocksize()); 210 211 // ignore case 212 blocksize = "64kb 512B"; 213 builder.setBlocksize(blocksize); 214 assertEquals(66048, builder.build().getBlocksize()); 215 216 blocksize = "66048 B (64KB 512B)"; 217 builder.setBlocksize(blocksize); 218 assertEquals(66048, builder.build().getBlocksize()); 219 } 220 221 /** 222 * Test for verifying the ColumnFamilyDescriptorBuilder's default values so that backward 223 * compatibility with hbase-1.x can be mantained (see HBASE-24981). 224 */ 225 @Test 226 public void testDefaultBuilder() { 227 final Map<String, String> defaultValueMap = ColumnFamilyDescriptorBuilder.getDefaultValues(); 228 assertEquals(defaultValueMap.size(), 12); 229 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.BLOOMFILTER), 230 BloomType.ROW.toString()); 231 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.REPLICATION_SCOPE), "0"); 232 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.MAX_VERSIONS), "1"); 233 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.MIN_VERSIONS), "0"); 234 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.COMPRESSION), 235 Compression.Algorithm.NONE.toString()); 236 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.TTL), 237 Integer.toString(Integer.MAX_VALUE)); 238 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.BLOCKSIZE), 239 Integer.toString(64 * 1024)); 240 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.IN_MEMORY), 241 Boolean.toString(false)); 242 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.BLOCKCACHE), 243 Boolean.toString(true)); 244 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.KEEP_DELETED_CELLS), 245 KeepDeletedCells.FALSE.toString()); 246 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING), 247 DataBlockEncoding.NONE.toString()); 248 assertEquals(defaultValueMap.get(ColumnFamilyDescriptorBuilder.INDEX_BLOCK_ENCODING), 249 IndexBlockEncoding.NONE.toString()); 250 } 251 252 @Test 253 public void testSetEmptyValue() { 254 ColumnFamilyDescriptorBuilder builder = 255 ColumnFamilyDescriptorBuilder.newBuilder(HConstants.CATALOG_FAMILY); 256 String testConf = "TestConfiguration"; 257 String testValue = "TestValue"; 258 // test set value 259 builder.setValue(testValue, "2"); 260 assertEquals("2", Bytes.toString(builder.build().getValue(Bytes.toBytes(testValue)))); 261 builder.setValue(testValue, ""); 262 assertNull(builder.build().getValue(Bytes.toBytes(testValue))); 263 264 // test set configuration 265 builder.setConfiguration(testConf, "1"); 266 assertEquals("1", builder.build().getConfigurationValue(testConf)); 267 builder.setConfiguration(testConf, ""); 268 assertNull(builder.build().getConfigurationValue(testConf)); 269 } 270}