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