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