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