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.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertNull; 023import static org.junit.jupiter.api.Assertions.assertThrows; 024import static org.junit.jupiter.api.Assertions.assertTrue; 025import static org.junit.jupiter.api.Assertions.fail; 026 027import java.io.IOException; 028import java.util.regex.Pattern; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.exceptions.DeserializationException; 031import org.apache.hadoop.hbase.exceptions.HBaseException; 032import org.apache.hadoop.hbase.rsgroup.RSGroupInfo; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.hbase.testclassification.SmallTests; 035import org.apache.hadoop.hbase.util.BuilderStyleTest; 036import org.apache.hadoop.hbase.util.Bytes; 037import org.junit.jupiter.api.Tag; 038import org.junit.jupiter.api.Test; 039import org.junit.jupiter.api.TestInfo; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043/** 044 * Test setting values in the descriptor. 045 */ 046@Tag(MiscTests.TAG) 047@Tag(SmallTests.TAG) 048public class TestTableDescriptorBuilder { 049 050 private static final Logger LOG = LoggerFactory.getLogger(TestTableDescriptorBuilder.class); 051 052 public String name; 053 054 @org.junit.jupiter.api.BeforeEach 055 public void setupTestName(TestInfo testInfo) { 056 name = testInfo.getTestMethod().get().getName(); 057 } 058 059 @Test 060 public void testAddCoprocessorTwice() throws IOException { 061 String cpName = "a.b.c.d"; 062 assertThrows(IOException.class, () -> TableDescriptorBuilder 063 .newBuilder(TableName.META_TABLE_NAME).setCoprocessor(cpName).setCoprocessor(cpName).build()); 064 } 065 066 @Test 067 public void testPb() throws DeserializationException, IOException { 068 final int v = 123; 069 TableDescriptor htd = 070 TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME).setMaxFileSize(v) 071 .setDurability(Durability.ASYNC_WAL).setReadOnly(true).setRegionReplication(2).build(); 072 073 byte[] bytes = TableDescriptorBuilder.toByteArray(htd); 074 TableDescriptor deserializedHtd = TableDescriptorBuilder.parseFrom(bytes); 075 assertEquals(htd, deserializedHtd); 076 assertEquals(v, deserializedHtd.getMaxFileSize()); 077 assertTrue(deserializedHtd.isReadOnly()); 078 assertEquals(Durability.ASYNC_WAL, deserializedHtd.getDurability()); 079 assertEquals(2, deserializedHtd.getRegionReplication()); 080 } 081 082 /** 083 * Test cps in the table description. 084 * @throws Exception if setting a coprocessor fails 085 */ 086 @Test 087 public void testGetSetRemoveCP() throws Exception { 088 // simple CP 089 String className = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 090 TableDescriptor desc = 091 TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setCoprocessor(className) // add 092 // and 093 // check 094 // that 095 // it is 096 // present 097 .build(); 098 assertTrue(desc.hasCoprocessor(className)); 099 desc = TableDescriptorBuilder.newBuilder(desc).removeCoprocessor(className) // remove it and 100 // check that it is 101 // gone 102 .build(); 103 assertFalse(desc.hasCoprocessor(className)); 104 } 105 106 /** 107 * Test cps in the table description. 108 * @throws Exception if setting a coprocessor fails 109 */ 110 @Test 111 public void testSetListRemoveCP() throws Exception { 112 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).build(); 113 // Check that any coprocessor is present. 114 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 115 116 // simple CP 117 String className1 = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 118 String className2 = "org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver"; 119 // Add the 1 coprocessor and check if present. 120 desc = TableDescriptorBuilder.newBuilder(desc).setCoprocessor(className1).build(); 121 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 122 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 123 .anyMatch(name -> name.equals(className1))); 124 // Add the 2nd coprocessor and check if present. 125 // remove it and check that it is gone 126 desc = TableDescriptorBuilder.newBuilder(desc) 127 128 .setCoprocessor(className2).build(); 129 assertTrue(desc.getCoprocessorDescriptors().size() == 2); 130 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 131 .anyMatch(name -> name.equals(className2))); 132 // Remove one and check 133 desc = TableDescriptorBuilder.newBuilder(desc) 134 135 .removeCoprocessor(className1).build(); 136 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 137 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 138 .anyMatch(name -> name.equals(className1))); 139 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 140 .anyMatch(name -> name.equals(className2))); 141 // Remove the last and check 142 desc = TableDescriptorBuilder.newBuilder(desc) 143 144 .removeCoprocessor(className2).build(); 145 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 146 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 147 .anyMatch(name -> name.equals(className1))); 148 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 149 .anyMatch(name -> name.equals(className2))); 150 } 151 152 /** 153 * Test removing cps in the table description that does not exist 154 * @throws Exception if removing a coprocessor fails other than IllegalArgumentException 155 */ 156 @Test 157 public void testRemoveNonExistingCoprocessor() throws Exception { 158 String className = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 159 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).build(); 160 assertFalse(desc.hasCoprocessor(className)); 161 assertThrows(IllegalArgumentException.class, 162 () -> TableDescriptorBuilder.newBuilder(desc).removeCoprocessor(className).build()); 163 } 164 165 /** 166 * Test that we add and remove strings from settings properly. 167 */ 168 @Test 169 public void testRemoveString() { 170 byte[] key = Bytes.toBytes("Some"); 171 byte[] value = Bytes.toBytes("value"); 172 TableDescriptor desc = 173 TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setValue(key, value).build(); 174 assertTrue(Bytes.equals(value, desc.getValue(key))); 175 desc = TableDescriptorBuilder.newBuilder(desc).removeValue(key).build(); 176 assertTrue(desc.getValue(key) == null); 177 } 178 179 String[] legalTableNames = { "foo", "with-dash_under.dot", "_under_start_ok", 180 "with-dash.with_underscore", "02-01-2012.my_table_01-02", "xyz._mytable_", "9_9_0.table_02", 181 "dot1.dot2.table", "new.-mytable", "with-dash.with.dot", "legal..t2", "legal..legal.t2", 182 "trailingdots..", "trailing.dots...", "ns:mytable", "ns:_mytable_", "ns:my_table_01-02" }; 183 String[] illegalTableNames = { ".dot_start_illegal", "-dash_start_illegal", "spaces not ok", 184 "-dash-.start_illegal", "new.table with space", "01 .table", "ns:-illegaldash", 185 "new:.illegaldot", "new:illegalcolon1:", "new:illegalcolon1:2" }; 186 187 @Test 188 public void testLegalTableNames() { 189 for (String tn : legalTableNames) { 190 TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)); 191 } 192 } 193 194 @Test 195 public void testIllegalTableNames() { 196 for (String tn : illegalTableNames) { 197 try { 198 TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)); 199 fail("invalid tablename " + tn + " should have failed"); 200 } catch (Exception e) { 201 // expected 202 } 203 } 204 } 205 206 @Test 207 public void testLegalTableNamesRegex() { 208 for (String tn : legalTableNames) { 209 TableName tName = TableName.valueOf(tn); 210 assertTrue(Pattern.matches(TableName.VALID_USER_TABLE_REGEX, tName.getNameAsString()), 211 "Testing: '" + tn + "'"); 212 } 213 } 214 215 @Test 216 public void testIllegalTableNamesRegex() { 217 for (String tn : illegalTableNames) { 218 LOG.info("Testing: '" + tn + "'"); 219 assertFalse(Pattern.matches(TableName.VALID_USER_TABLE_REGEX, tn)); 220 } 221 } 222 223 /** 224 * Test default value handling for maxFileSize 225 */ 226 @Test 227 public void testGetMaxFileSize() { 228 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).build(); 229 assertEquals(-1, desc.getMaxFileSize()); 230 desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setMaxFileSize(1111L).build(); 231 assertEquals(1111L, desc.getMaxFileSize()); 232 } 233 234 @Test 235 public void testSetMaxFileSize() throws HBaseException { 236 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)); 237 238 String maxFileSize = "1073741824"; 239 builder.setMaxFileSize(maxFileSize); 240 assertEquals(1073741824, builder.build().getMaxFileSize()); 241 242 maxFileSize = "1GB"; 243 builder.setMaxFileSize(maxFileSize); 244 assertEquals(1073741824, builder.build().getMaxFileSize()); 245 246 maxFileSize = "10GB 25MB"; 247 builder.setMaxFileSize(maxFileSize); 248 assertEquals(10763632640L, builder.build().getMaxFileSize()); 249 250 // ignore case 251 maxFileSize = "10GB 512mb 512KB 512b"; 252 builder.setMaxFileSize(maxFileSize); 253 assertEquals(11274813952L, builder.build().getMaxFileSize()); 254 255 maxFileSize = "10737942528 B (10GB 512KB)"; 256 builder.setMaxFileSize(maxFileSize); 257 assertEquals(10737942528L, builder.build().getMaxFileSize()); 258 } 259 260 /** 261 * Test default value handling for memStoreFlushSize 262 */ 263 @Test 264 public void testGetMemStoreFlushSize() { 265 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).build(); 266 assertEquals(-1, desc.getMemStoreFlushSize()); 267 desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setMemStoreFlushSize(1111L) 268 .build(); 269 assertEquals(1111L, desc.getMemStoreFlushSize()); 270 } 271 272 @Test 273 public void testSetMemStoreFlushSize() throws HBaseException { 274 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)); 275 276 String memstoreFlushSize = "1073741824"; 277 builder.setMemStoreFlushSize(memstoreFlushSize); 278 assertEquals(1073741824, builder.build().getMemStoreFlushSize()); 279 280 memstoreFlushSize = "1GB"; 281 builder.setMemStoreFlushSize(memstoreFlushSize); 282 assertEquals(1073741824, builder.build().getMemStoreFlushSize()); 283 284 memstoreFlushSize = "10GB 25MB"; 285 builder.setMemStoreFlushSize(memstoreFlushSize); 286 assertEquals(10763632640L, builder.build().getMemStoreFlushSize()); 287 288 // ignore case 289 memstoreFlushSize = "10GB 512mb 512KB 512b"; 290 builder.setMemStoreFlushSize(memstoreFlushSize); 291 assertEquals(11274813952L, builder.build().getMemStoreFlushSize()); 292 293 memstoreFlushSize = "10737942528 B (10GB 512KB)"; 294 builder.setMemStoreFlushSize(memstoreFlushSize); 295 assertEquals(10737942528L, builder.build().getMemStoreFlushSize()); 296 } 297 298 @Test 299 public void testClassMethodsAreBuilderStyle() { 300 BuilderStyleTest.assertClassesAreBuilderStyle(TableDescriptorBuilder.class); 301 } 302 303 @Test 304 public void testModifyFamily() { 305 byte[] familyName = Bytes.toBytes("cf"); 306 ColumnFamilyDescriptor hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 307 .setBlocksize(1000).setDFSReplication((short) 3).build(); 308 TableDescriptor htd = 309 TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setColumnFamily(hcd).build(); 310 311 assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize()); 312 assertEquals(3, htd.getColumnFamily(familyName).getDFSReplication()); 313 hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName).setBlocksize(2000) 314 .setDFSReplication((short) 1).build(); 315 htd = TableDescriptorBuilder.newBuilder(htd).modifyColumnFamily(hcd).build(); 316 assertEquals(2000, htd.getColumnFamily(familyName).getBlocksize()); 317 assertEquals(1, htd.getColumnFamily(familyName).getDFSReplication()); 318 } 319 320 @Test 321 public void testModifyInexistentFamily() { 322 byte[] familyName = Bytes.toBytes("cf"); 323 assertThrows(IllegalArgumentException.class, 324 () -> TableDescriptorBuilder.newBuilder(TableName.valueOf(name)) 325 .modifyColumnFamily(ColumnFamilyDescriptorBuilder.of(familyName)).build()); 326 } 327 328 @Test 329 public void testAddDuplicateFamilies() { 330 byte[] familyName = Bytes.toBytes("cf"); 331 ColumnFamilyDescriptor hcd = 332 ColumnFamilyDescriptorBuilder.newBuilder(familyName).setBlocksize(1000).build(); 333 TableDescriptor htd = 334 TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setColumnFamily(hcd).build(); 335 assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize()); 336 hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName).setBlocksize(2000).build(); 337 // add duplicate column 338 ColumnFamilyDescriptor finalHcd = hcd; 339 assertThrows(IllegalArgumentException.class, 340 () -> TableDescriptorBuilder.newBuilder(htd).setColumnFamily(finalHcd).build()); 341 } 342 343 @Test 344 public void testPriority() { 345 TableDescriptor htd = 346 TableDescriptorBuilder.newBuilder(TableName.valueOf(name)).setPriority(42).build(); 347 assertEquals(42, htd.getPriority()); 348 } 349 350 @Test 351 public void testStringCustomizedValues() throws HBaseException { 352 byte[] familyName = Bytes.toBytes("cf"); 353 ColumnFamilyDescriptor hcd = 354 ColumnFamilyDescriptorBuilder.newBuilder(familyName).setBlocksize(131072).build(); 355 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)) 356 .setColumnFamily(hcd).setDurability(Durability.ASYNC_WAL).build(); 357 358 assertEquals( 359 "'testStringCustomizedValues', " + "{TABLE_ATTRIBUTES => {DURABILITY => 'ASYNC_WAL'}}, " 360 + "{NAME => 'cf', BLOCKSIZE => '131072 B (128KB)'}", 361 htd.toStringCustomizedValues()); 362 363 htd = TableDescriptorBuilder.newBuilder(htd).setMaxFileSize("10737942528") 364 .setMemStoreFlushSize("256MB").setErasureCodingPolicy("RS-6-3-1024k").build(); 365 assertEquals( 366 "'testStringCustomizedValues', " + "{TABLE_ATTRIBUTES => {DURABILITY => 'ASYNC_WAL', " 367 + "ERASURE_CODING_POLICY => 'RS-6-3-1024k', MAX_FILESIZE => '10737942528 B (10GB 512KB)', " 368 + "MEMSTORE_FLUSHSIZE => '268435456 B (256MB)'}}, " 369 + "{NAME => 'cf', BLOCKSIZE => '131072 B (128KB)'}", 370 htd.toStringCustomizedValues()); 371 } 372 373 @Test 374 public void testGetSetRegionServerGroup() { 375 String groupName = name; 376 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)) 377 .setRegionServerGroup(groupName).build(); 378 assertEquals(htd.getValue(RSGroupInfo.TABLE_DESC_PROP_GROUP), groupName); 379 htd = TableDescriptorBuilder.newBuilder(htd).setRegionServerGroup(null).build(); 380 assertNull(htd.getValue(RSGroupInfo.TABLE_DESC_PROP_GROUP)); 381 } 382 383 @Test 384 public void testSetEmptyValue() { 385 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(name)); 386 String testValue = "TestValue"; 387 // test setValue 388 builder.setValue(testValue, "2"); 389 assertEquals("2", builder.build().getValue(testValue)); 390 builder.setValue(testValue, ""); 391 assertNull(builder.build().getValue(Bytes.toBytes(testValue))); 392 393 // test setFlushPolicyClassName 394 builder.setFlushPolicyClassName("class"); 395 assertEquals("class", builder.build().getFlushPolicyClassName()); 396 builder.setFlushPolicyClassName(""); 397 assertNull(builder.build().getFlushPolicyClassName()); 398 } 399}