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.thrift; 019 020import static org.apache.hadoop.hbase.thrift.Constants.COALESCE_INC_KEY; 021import static org.junit.Assert.assertArrayEquals; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertTrue; 025import static org.junit.Assert.fail; 026 027import java.io.IOException; 028import java.net.InetAddress; 029import java.nio.ByteBuffer; 030import java.util.ArrayList; 031import java.util.Collection; 032import java.util.HashMap; 033import java.util.List; 034import java.util.Map; 035import java.util.concurrent.atomic.AtomicInteger; 036import java.util.stream.Collectors; 037import org.apache.hadoop.conf.Configuration; 038import org.apache.hadoop.hbase.CompatibilityFactory; 039import org.apache.hadoop.hbase.HBaseClassTestRule; 040import org.apache.hadoop.hbase.HBaseTestingUtil; 041import org.apache.hadoop.hbase.HConstants; 042import org.apache.hadoop.hbase.TableName; 043import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 044import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 045import org.apache.hadoop.hbase.client.Put; 046import org.apache.hadoop.hbase.client.RegionInfo; 047import org.apache.hadoop.hbase.client.Table; 048import org.apache.hadoop.hbase.client.TableDescriptor; 049import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 050import org.apache.hadoop.hbase.filter.ParseFilter; 051import org.apache.hadoop.hbase.security.UserProvider; 052import org.apache.hadoop.hbase.test.MetricsAssertHelper; 053import org.apache.hadoop.hbase.testclassification.ClientTests; 054import org.apache.hadoop.hbase.testclassification.LargeTests; 055import org.apache.hadoop.hbase.thrift.ThriftMetrics.ThriftServerType; 056import org.apache.hadoop.hbase.thrift.generated.BatchMutation; 057import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor; 058import org.apache.hadoop.hbase.thrift.generated.Hbase; 059import org.apache.hadoop.hbase.thrift.generated.IOError; 060import org.apache.hadoop.hbase.thrift.generated.Mutation; 061import org.apache.hadoop.hbase.thrift.generated.TAppend; 062import org.apache.hadoop.hbase.thrift.generated.TCell; 063import org.apache.hadoop.hbase.thrift.generated.TIncrement; 064import org.apache.hadoop.hbase.thrift.generated.TRegionInfo; 065import org.apache.hadoop.hbase.thrift.generated.TRowResult; 066import org.apache.hadoop.hbase.thrift.generated.TScan; 067import org.apache.hadoop.hbase.thrift.generated.TThriftServerType; 068import org.apache.hadoop.hbase.util.Bytes; 069import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 070import org.apache.hadoop.hbase.util.TableDescriptorChecker; 071import org.apache.hadoop.hbase.util.Threads; 072import org.apache.thrift.protocol.TBinaryProtocol; 073import org.apache.thrift.protocol.TProtocol; 074import org.apache.thrift.transport.TSocket; 075import org.apache.thrift.transport.TTransport; 076import org.junit.AfterClass; 077import org.junit.BeforeClass; 078import org.junit.ClassRule; 079import org.junit.Rule; 080import org.junit.Test; 081import org.junit.experimental.categories.Category; 082import org.junit.rules.TestName; 083import org.slf4j.Logger; 084import org.slf4j.LoggerFactory; 085 086/** 087 * Unit testing for ThriftServerRunner.HBaseServiceHandler, a part of the 088 * org.apache.hadoop.hbase.thrift package. 089 */ 090@Category({ ClientTests.class, LargeTests.class }) 091public class TestThriftServer { 092 093 @ClassRule 094 public static final HBaseClassTestRule CLASS_RULE = 095 HBaseClassTestRule.forClass(TestThriftServer.class); 096 097 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 098 private static final Logger LOG = LoggerFactory.getLogger(TestThriftServer.class); 099 private static final MetricsAssertHelper metricsHelper = 100 CompatibilityFactory.getInstance(MetricsAssertHelper.class); 101 protected static final int MAXVERSIONS = 3; 102 103 private static ByteBuffer asByteBuffer(String i) { 104 return ByteBuffer.wrap(Bytes.toBytes(i)); 105 } 106 107 private static ByteBuffer asByteBuffer(long l) { 108 return ByteBuffer.wrap(Bytes.toBytes(l)); 109 } 110 111 // Static names for tables, columns, rows, and values 112 private static ByteBuffer tableAname = asByteBuffer("tableA"); 113 private static ByteBuffer tableBname = asByteBuffer("tableB"); 114 private static ByteBuffer columnAname = asByteBuffer("columnA:"); 115 private static ByteBuffer columnAAname = asByteBuffer("columnA:A"); 116 private static ByteBuffer columnBname = asByteBuffer("columnB:"); 117 private static ByteBuffer rowAname = asByteBuffer("rowA"); 118 private static ByteBuffer rowBname = asByteBuffer("rowB"); 119 private static ByteBuffer valueAname = asByteBuffer("valueA"); 120 private static ByteBuffer valueBname = asByteBuffer("valueB"); 121 private static ByteBuffer valueCname = asByteBuffer("valueC"); 122 private static ByteBuffer valueDname = asByteBuffer("valueD"); 123 private static ByteBuffer valueEname = asByteBuffer(100L); 124 125 @Rule 126 public TestName name = new TestName(); 127 128 @BeforeClass 129 public static void beforeClass() throws Exception { 130 UTIL.getConfiguration().setBoolean(COALESCE_INC_KEY, true); 131 UTIL.getConfiguration().setBoolean(TableDescriptorChecker.TABLE_SANITY_CHECKS, false); 132 UTIL.getConfiguration().setInt("hbase.client.retries.number", 3); 133 UTIL.startMiniCluster(); 134 } 135 136 @AfterClass 137 public static void afterClass() throws Exception { 138 UTIL.shutdownMiniCluster(); 139 } 140 141 /** 142 * Runs all of the tests under a single JUnit test method. We consolidate all testing to one 143 * method because HBaseClusterTestCase is prone to OutOfMemoryExceptions when there are three or 144 * more JUnit test methods. 145 */ 146 @Test 147 public void testAll() throws Exception { 148 // Run all tests 149 doTestTableCreateDrop(); 150 doTestThriftMetrics(); 151 doTestTableMutations(); 152 doTestTableTimestampsAndColumns(); 153 doTestTableScanners(); 154 doTestGetTableRegions(); 155 doTestFilterRegistration(); 156 doTestGetRegionInfo(); 157 doTestIncrements(); 158 doTestAppend(); 159 doTestCheckAndPut(); 160 } 161 162 /** 163 * Tests for creating, enabling, disabling, and deleting tables. Also tests that creating a table 164 * with an invalid column name yields an IllegalArgument exception. 165 */ 166 public void doTestTableCreateDrop() throws Exception { 167 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 168 UserProvider.instantiate(UTIL.getConfiguration())); 169 doTestTableCreateDrop(handler); 170 } 171 172 public static void doTestTableCreateDrop(Hbase.Iface handler) throws Exception { 173 createTestTables(handler); 174 dropTestTables(handler); 175 } 176 177 public static final class MySlowHBaseHandler extends ThriftHBaseServiceHandler 178 implements Hbase.Iface { 179 180 protected MySlowHBaseHandler(Configuration c) throws IOException { 181 super(c, UserProvider.instantiate(c)); 182 } 183 184 @Override 185 public List<ByteBuffer> getTableNames() throws IOError { 186 Threads.sleepWithoutInterrupt(3000); 187 return super.getTableNames(); 188 } 189 } 190 191 /** 192 * TODO: These counts are supposed to be zero but sometimes they are not, they are equal to the 193 * passed in maybe. Investigate why. My guess is they are set by the test that runs just previous 194 * to this one. Sometimes they are cleared. Sometimes not. 195 */ 196 private int getCurrentCount(final String name, final int maybe, final ThriftMetrics metrics) { 197 int currentCount = 0; 198 try { 199 metricsHelper.assertCounter(name, maybe, metrics.getSource()); 200 LOG.info("Shouldn't this be null? name=" + name + ", equals=" + maybe); 201 currentCount = maybe; 202 } catch (AssertionError e) { 203 // Ignore 204 } 205 return currentCount; 206 } 207 208 /** 209 * Tests if the metrics for thrift handler work correctly 210 */ 211 public void doTestThriftMetrics() throws Exception { 212 LOG.info("START doTestThriftMetrics"); 213 Configuration conf = UTIL.getConfiguration(); 214 ThriftMetrics metrics = getMetrics(conf); 215 Hbase.Iface handler = getHandlerForMetricsTest(metrics, conf); 216 int currentCountCreateTable = getCurrentCount("createTable_num_ops", 2, metrics); 217 int currentCountDeleteTable = getCurrentCount("deleteTable_num_ops", 2, metrics); 218 int currentCountDisableTable = getCurrentCount("disableTable_num_ops", 2, metrics); 219 createTestTables(handler); 220 dropTestTables(handler); 221 metricsHelper.assertCounter("createTable_num_ops", currentCountCreateTable + 2, 222 metrics.getSource()); 223 metricsHelper.assertCounter("deleteTable_num_ops", currentCountDeleteTable + 2, 224 metrics.getSource()); 225 metricsHelper.assertCounter("disableTable_num_ops", currentCountDisableTable + 2, 226 metrics.getSource()); 227 handler.getTableNames(); // This will have an artificial delay. 228 229 // 3 to 6 seconds (to account for potential slowness), measured in nanoseconds 230 try { 231 metricsHelper.assertGaugeGt("getTableNames_avg_time", 3L * 1000 * 1000 * 1000, 232 metrics.getSource()); 233 metricsHelper.assertGaugeLt("getTableNames_avg_time", 6L * 1000 * 1000 * 1000, 234 metrics.getSource()); 235 } catch (AssertionError e) { 236 LOG.info("Fix me! Why does this happen? A concurrent cluster running?", e); 237 } 238 } 239 240 private static Hbase.Iface getHandlerForMetricsTest(ThriftMetrics metrics, Configuration conf) 241 throws Exception { 242 Hbase.Iface handler = new MySlowHBaseHandler(conf); 243 return HbaseHandlerMetricsProxy.newInstance((ThriftHBaseServiceHandler) handler, metrics, conf); 244 } 245 246 private static ThriftMetrics getMetrics(Configuration conf) throws Exception { 247 return new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.ONE); 248 } 249 250 public static void createTestTables(Hbase.Iface handler) throws Exception { 251 // Create/enable/disable/delete tables, ensure methods act correctly 252 List<java.nio.ByteBuffer> bbs = handler.getTableNames(); 253 assertEquals(bbs.stream().map(b -> Bytes.toString(b.array())).collect(Collectors.joining(",")), 254 0, bbs.size()); 255 handler.createTable(tableAname, getColumnDescriptors()); 256 assertEquals(1, handler.getTableNames().size()); 257 assertEquals(2, handler.getColumnDescriptors(tableAname).size()); 258 assertTrue(handler.isTableEnabled(tableAname)); 259 handler.createTable(tableBname, getColumnDescriptors()); 260 assertEquals(2, handler.getTableNames().size()); 261 } 262 263 public static void checkTableList(Hbase.Iface handler) throws Exception { 264 assertTrue(handler.getTableNames().contains(tableAname)); 265 } 266 267 public static void dropTestTables(Hbase.Iface handler) throws Exception { 268 handler.disableTable(tableBname); 269 assertFalse(handler.isTableEnabled(tableBname)); 270 handler.deleteTable(tableBname); 271 assertEquals(1, handler.getTableNames().size()); 272 handler.disableTable(tableAname); 273 assertFalse(handler.isTableEnabled(tableAname)); 274 /* 275 * TODO Reenable. assertFalse(handler.isTableEnabled(tableAname)); 276 * handler.enableTable(tableAname); assertTrue(handler.isTableEnabled(tableAname)); 277 * handler.disableTable(tableAname); 278 */ 279 handler.deleteTable(tableAname); 280 assertEquals(0, handler.getTableNames().size()); 281 } 282 283 public void doTestIncrements() throws Exception { 284 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 285 UserProvider.instantiate(UTIL.getConfiguration())); 286 createTestTables(handler); 287 doTestIncrements(handler); 288 dropTestTables(handler); 289 } 290 291 public static void doTestIncrements(ThriftHBaseServiceHandler handler) throws Exception { 292 List<Mutation> mutations = new ArrayList<>(1); 293 mutations.add(new Mutation(false, columnAAname, valueEname, true)); 294 mutations.add(new Mutation(false, columnAname, valueEname, true)); 295 handler.mutateRow(tableAname, rowAname, mutations, null); 296 handler.mutateRow(tableAname, rowBname, mutations, null); 297 298 List<TIncrement> increments = new ArrayList<>(3); 299 increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7)); 300 increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7)); 301 increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7)); 302 303 int numIncrements = 60000; 304 for (int i = 0; i < numIncrements; i++) { 305 handler.increment(new TIncrement(tableAname, rowAname, columnAname, 2)); 306 handler.incrementRows(increments); 307 } 308 309 Thread.sleep(1000); 310 long lv = handler.get(tableAname, rowAname, columnAname, null).get(0).value.getLong(); 311 // Wait on all increments being flushed 312 while (handler.coalescer.getQueueSize() != 0) { 313 Threads.sleep(10); 314 } 315 316 assertEquals((100 + (2 * numIncrements)), lv); 317 318 lv = handler.get(tableAname, rowBname, columnAAname, null).get(0).value.getLong(); 319 assertEquals((100 + (3 * 7 * numIncrements)), lv); 320 321 assertTrue(handler.coalescer.getSuccessfulCoalescings() > 0); 322 323 } 324 325 /** 326 * Tests adding a series of Mutations and BatchMutations, including a delete mutation. Also tests 327 * data retrieval, and getting back multiple versions. 328 */ 329 public void doTestTableMutations() throws Exception { 330 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 331 UserProvider.instantiate(UTIL.getConfiguration())); 332 doTestTableMutations(handler); 333 } 334 335 public static void doTestTableMutations(Hbase.Iface handler) throws Exception { 336 // Setup 337 handler.createTable(tableAname, getColumnDescriptors()); 338 339 // Apply a few Mutations to rowA 340 // mutations.add(new Mutation(false, columnAname, valueAname)); 341 // mutations.add(new Mutation(false, columnBname, valueBname)); 342 handler.mutateRow(tableAname, rowAname, getMutations(), null); 343 344 // Assert that the changes were made 345 assertEquals(valueAname, handler.get(tableAname, rowAname, columnAname, null).get(0).value); 346 TRowResult rowResult1 = handler.getRow(tableAname, rowAname, null).get(0); 347 assertEquals(rowAname, rowResult1.row); 348 assertEquals(valueBname, rowResult1.columns.get(columnBname).value); 349 350 // Apply a few BatchMutations for rowA and rowB 351 // rowAmutations.add(new Mutation(true, columnAname, null)); 352 // rowAmutations.add(new Mutation(false, columnBname, valueCname)); 353 // batchMutations.add(new BatchMutation(rowAname, rowAmutations)); 354 // Mutations to rowB 355 // rowBmutations.add(new Mutation(false, columnAname, valueCname)); 356 // rowBmutations.add(new Mutation(false, columnBname, valueDname)); 357 // batchMutations.add(new BatchMutation(rowBname, rowBmutations)); 358 handler.mutateRows(tableAname, getBatchMutations(), null); 359 360 // Assert that changes were made to rowA 361 List<TCell> cells = handler.get(tableAname, rowAname, columnAname, null); 362 assertFalse(cells.size() > 0); 363 assertEquals(valueCname, handler.get(tableAname, rowAname, columnBname, null).get(0).value); 364 List<TCell> versions = handler.getVer(tableAname, rowAname, columnBname, MAXVERSIONS, null); 365 assertEquals(valueCname, versions.get(0).value); 366 assertEquals(valueBname, versions.get(1).value); 367 368 // Assert that changes were made to rowB 369 TRowResult rowResult2 = handler.getRow(tableAname, rowBname, null).get(0); 370 assertEquals(rowBname, rowResult2.row); 371 assertEquals(valueCname, rowResult2.columns.get(columnAname).value); 372 assertEquals(valueDname, rowResult2.columns.get(columnBname).value); 373 374 // Apply some deletes 375 handler.deleteAll(tableAname, rowAname, columnBname, null); 376 handler.deleteAllRow(tableAname, rowBname, null); 377 378 // Assert that the deletes were applied 379 int size = handler.get(tableAname, rowAname, columnBname, null).size(); 380 assertEquals(0, size); 381 size = handler.getRow(tableAname, rowBname, null).size(); 382 assertEquals(0, size); 383 384 // Try null mutation 385 List<Mutation> mutations = new ArrayList<>(1); 386 mutations.add(new Mutation(false, columnAname, null, true)); 387 handler.mutateRow(tableAname, rowAname, mutations, null); 388 TRowResult rowResult3 = handler.getRow(tableAname, rowAname, null).get(0); 389 assertEquals(rowAname, rowResult3.row); 390 assertEquals(0, rowResult3.columns.get(columnAname).value.remaining()); 391 392 // Teardown 393 handler.disableTable(tableAname); 394 handler.deleteTable(tableAname); 395 } 396 397 /** 398 * Similar to testTableMutations(), except Mutations are applied with specific timestamps and data 399 * retrieval uses these timestamps to extract specific versions of data. 400 */ 401 public void doTestTableTimestampsAndColumns() throws Exception { 402 // Setup 403 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 404 UserProvider.instantiate(UTIL.getConfiguration())); 405 handler.createTable(tableAname, getColumnDescriptors()); 406 407 // Apply timestamped Mutations to rowA 408 long time1 = EnvironmentEdgeManager.currentTime(); 409 handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null); 410 411 Thread.sleep(1000); 412 413 // Apply timestamped BatchMutations for rowA and rowB 414 long time2 = EnvironmentEdgeManager.currentTime(); 415 handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null); 416 417 // Apply an overlapping timestamped mutation to rowB 418 handler.mutateRowTs(tableAname, rowBname, getMutations(), time2, null); 419 420 // the getVerTs is [inf, ts) so you need to increment one. 421 time1 += 1; 422 time2 += 2; 423 424 // Assert that the timestamp-related methods retrieve the correct data 425 assertEquals(2, 426 handler.getVerTs(tableAname, rowAname, columnBname, time2, MAXVERSIONS, null).size()); 427 assertEquals(1, 428 handler.getVerTs(tableAname, rowAname, columnBname, time1, MAXVERSIONS, null).size()); 429 430 TRowResult rowResult1 = handler.getRowTs(tableAname, rowAname, time1, null).get(0); 431 TRowResult rowResult2 = handler.getRowTs(tableAname, rowAname, time2, null).get(0); 432 // columnA was completely deleted 433 // assertTrue(Bytes.equals(rowResult1.columns.get(columnAname).value, valueAname)); 434 assertEquals(rowResult1.columns.get(columnBname).value, valueBname); 435 assertEquals(rowResult2.columns.get(columnBname).value, valueCname); 436 437 // ColumnAname has been deleted, and will never be visible even with a getRowTs() 438 assertFalse(rowResult2.columns.containsKey(columnAname)); 439 440 List<ByteBuffer> columns = new ArrayList<>(1); 441 columns.add(columnBname); 442 443 rowResult1 = handler.getRowWithColumns(tableAname, rowAname, columns, null).get(0); 444 assertEquals(rowResult1.columns.get(columnBname).value, valueCname); 445 assertFalse(rowResult1.columns.containsKey(columnAname)); 446 447 rowResult1 = handler.getRowWithColumnsTs(tableAname, rowAname, columns, time1, null).get(0); 448 assertEquals(rowResult1.columns.get(columnBname).value, valueBname); 449 assertFalse(rowResult1.columns.containsKey(columnAname)); 450 451 // Apply some timestamped deletes 452 // this actually deletes _everything_. 453 // nukes everything in columnB: forever. 454 handler.deleteAllTs(tableAname, rowAname, columnBname, time1, null); 455 handler.deleteAllRowTs(tableAname, rowBname, time2, null); 456 457 // Assert that the timestamp-related methods retrieve the correct data 458 int size = handler.getVerTs(tableAname, rowAname, columnBname, time1, MAXVERSIONS, null).size(); 459 assertEquals(0, size); 460 461 size = handler.getVerTs(tableAname, rowAname, columnBname, time2, MAXVERSIONS, null).size(); 462 assertEquals(1, size); 463 464 // should be available.... 465 assertEquals(handler.get(tableAname, rowAname, columnBname, null).get(0).value, valueCname); 466 467 assertEquals(0, handler.getRow(tableAname, rowBname, null).size()); 468 469 // Teardown 470 handler.disableTable(tableAname); 471 handler.deleteTable(tableAname); 472 } 473 474 /** 475 * Tests the four different scanner-opening methods (with and without a stoprow, with and without 476 * a timestamp). 477 */ 478 public void doTestTableScanners() throws Exception { 479 // Setup 480 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 481 UserProvider.instantiate(UTIL.getConfiguration())); 482 handler.createTable(tableAname, getColumnDescriptors()); 483 484 // Apply timestamped Mutations to rowA 485 long time1 = EnvironmentEdgeManager.currentTime(); 486 handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null); 487 488 // Sleep to assure that 'time1' and 'time2' will be different even with a 489 // coarse grained system timer. 490 Thread.sleep(1000); 491 492 // Apply timestamped BatchMutations for rowA and rowB 493 long time2 = EnvironmentEdgeManager.currentTime(); 494 handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null); 495 496 time1 += 1; 497 498 // Test a scanner on all rows and all columns, no timestamp 499 int scanner1 = handler.scannerOpen(tableAname, rowAname, getColumnList(true, true), null); 500 TRowResult rowResult1a = handler.scannerGet(scanner1).get(0); 501 assertEquals(rowResult1a.row, rowAname); 502 // This used to be '1'. I don't know why when we are asking for two columns 503 // and when the mutations above would seem to add two columns to the row. 504 // -- St.Ack 05/12/2009 505 assertEquals(1, rowResult1a.columns.size()); 506 assertEquals(rowResult1a.columns.get(columnBname).value, valueCname); 507 508 TRowResult rowResult1b = handler.scannerGet(scanner1).get(0); 509 assertEquals(rowResult1b.row, rowBname); 510 assertEquals(2, rowResult1b.columns.size()); 511 assertEquals(rowResult1b.columns.get(columnAname).value, valueCname); 512 assertEquals(rowResult1b.columns.get(columnBname).value, valueDname); 513 closeScanner(scanner1, handler); 514 515 // Test a scanner on all rows and all columns, with timestamp 516 int scanner2 = 517 handler.scannerOpenTs(tableAname, rowAname, getColumnList(true, true), time1, null); 518 TRowResult rowResult2a = handler.scannerGet(scanner2).get(0); 519 assertEquals(1, rowResult2a.columns.size()); 520 // column A deleted, does not exist. 521 // assertTrue(Bytes.equals(rowResult2a.columns.get(columnAname).value, valueAname)); 522 assertEquals(rowResult2a.columns.get(columnBname).value, valueBname); 523 closeScanner(scanner2, handler); 524 525 // Test a scanner on the first row and first column only, no timestamp 526 int scanner3 = 527 handler.scannerOpenWithStop(tableAname, rowAname, rowBname, getColumnList(true, false), null); 528 closeScanner(scanner3, handler); 529 530 // Test a scanner on the first row and second column only, with timestamp 531 int scanner4 = handler.scannerOpenWithStopTs(tableAname, rowAname, rowBname, 532 getColumnList(false, true), time1, null); 533 TRowResult rowResult4a = handler.scannerGet(scanner4).get(0); 534 assertEquals(1, rowResult4a.columns.size()); 535 assertEquals(rowResult4a.columns.get(columnBname).value, valueBname); 536 537 // Test scanner using a TScan object once with sortColumns False and once with sortColumns true 538 TScan scanNoSortColumns = new TScan(); 539 scanNoSortColumns.setStartRow(rowAname); 540 scanNoSortColumns.setStopRow(rowBname); 541 542 int scanner5 = handler.scannerOpenWithScan(tableAname, scanNoSortColumns, null); 543 TRowResult rowResult5 = handler.scannerGet(scanner5).get(0); 544 assertEquals(1, rowResult5.columns.size()); 545 assertEquals(rowResult5.columns.get(columnBname).value, valueCname); 546 547 TScan scanSortColumns = new TScan(); 548 scanSortColumns.setStartRow(rowAname); 549 scanSortColumns.setStopRow(rowBname); 550 scanSortColumns = scanSortColumns.setSortColumns(true); 551 552 int scanner6 = handler.scannerOpenWithScan(tableAname, scanSortColumns, null); 553 TRowResult rowResult6 = handler.scannerGet(scanner6).get(0); 554 assertEquals(1, rowResult6.sortedColumns.size()); 555 assertEquals(rowResult6.sortedColumns.get(0).getCell().value, valueCname); 556 557 List<Mutation> rowBmutations = new ArrayList<>(20); 558 for (int i = 0; i < 20; i++) { 559 rowBmutations.add(new Mutation(false, asByteBuffer("columnA:" + i), valueCname, true)); 560 } 561 ByteBuffer rowC = asByteBuffer("rowC"); 562 handler.mutateRow(tableAname, rowC, rowBmutations, null); 563 564 TScan scanSortMultiColumns = new TScan(); 565 scanSortMultiColumns.setStartRow(rowC); 566 scanSortMultiColumns = scanSortMultiColumns.setSortColumns(true); 567 int scanner7 = handler.scannerOpenWithScan(tableAname, scanSortMultiColumns, null); 568 TRowResult rowResult7 = handler.scannerGet(scanner7).get(0); 569 570 ByteBuffer smallerColumn = asByteBuffer("columnA:"); 571 for (int i = 0; i < 20; i++) { 572 ByteBuffer currentColumn = rowResult7.sortedColumns.get(i).columnName; 573 assertTrue(Bytes.compareTo(smallerColumn.array(), currentColumn.array()) < 0); 574 smallerColumn = currentColumn; 575 } 576 577 TScan reversedScan = new TScan(); 578 reversedScan.setReversed(true); 579 reversedScan.setStartRow(rowBname); 580 reversedScan.setStopRow(rowAname); 581 582 int scanner8 = handler.scannerOpenWithScan(tableAname, reversedScan, null); 583 List<TRowResult> results = handler.scannerGet(scanner8); 584 handler.scannerClose(scanner8); 585 assertEquals(1, results.size()); 586 assertEquals(ByteBuffer.wrap(results.get(0).getRow()), rowBname); 587 588 // Teardown 589 handler.disableTable(tableAname); 590 handler.deleteTable(tableAname); 591 } 592 593 /** 594 * For HBASE-2556 Tests for GetTableRegions 595 */ 596 public void doTestGetTableRegions() throws Exception { 597 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 598 UserProvider.instantiate(UTIL.getConfiguration())); 599 doTestGetTableRegions(handler); 600 } 601 602 public static void doTestGetTableRegions(Hbase.Iface handler) throws Exception { 603 assertEquals(0, handler.getTableNames().size()); 604 handler.createTable(tableAname, getColumnDescriptors()); 605 assertEquals(1, handler.getTableNames().size()); 606 List<TRegionInfo> regions = handler.getTableRegions(tableAname); 607 int regionCount = regions.size(); 608 assertEquals("empty table should have only 1 region, " + "but found " + regionCount, 1, 609 regionCount); 610 LOG.info("Region found:" + regions.get(0)); 611 handler.disableTable(tableAname); 612 handler.deleteTable(tableAname); 613 regionCount = handler.getTableRegions(tableAname).size(); 614 assertEquals("non-existing table should have 0 region, " + "but found " + regionCount, 0, 615 regionCount); 616 } 617 618 public void doTestFilterRegistration() throws Exception { 619 Configuration conf = UTIL.getConfiguration(); 620 621 conf.set("hbase.thrift.filters", "MyFilter:filterclass"); 622 623 ThriftServer.registerFilters(conf); 624 625 Map<String, String> registeredFilters = ParseFilter.getAllFilters(); 626 627 assertEquals("filterclass", registeredFilters.get("MyFilter")); 628 } 629 630 public void doTestGetRegionInfo() throws Exception { 631 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 632 UserProvider.instantiate(UTIL.getConfiguration())); 633 doTestGetRegionInfo(handler); 634 } 635 636 public static void doTestGetRegionInfo(Hbase.Iface handler) throws Exception { 637 // Create tableA and add two columns to rowA 638 handler.createTable(tableAname, getColumnDescriptors()); 639 try { 640 handler.mutateRow(tableAname, rowAname, getMutations(), null); 641 byte[] searchRow = RegionInfo.createRegionName(TableName.valueOf(tableAname.array()), 642 rowAname.array(), HConstants.NINES, false); 643 TRegionInfo regionInfo = handler.getRegionInfo(ByteBuffer.wrap(searchRow)); 644 assertTrue( 645 Bytes.toStringBinary(regionInfo.getName()).startsWith(Bytes.toStringBinary(tableAname))); 646 } finally { 647 handler.disableTable(tableAname); 648 handler.deleteTable(tableAname); 649 } 650 } 651 652 /** 653 * Appends the value to a cell and checks that the cell value is updated properly. 654 */ 655 public static void doTestAppend() throws Exception { 656 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 657 UserProvider.instantiate(UTIL.getConfiguration())); 658 handler.createTable(tableAname, getColumnDescriptors()); 659 try { 660 List<Mutation> mutations = new ArrayList<>(1); 661 mutations.add(new Mutation(false, columnAname, valueAname, true)); 662 handler.mutateRow(tableAname, rowAname, mutations, null); 663 664 List<ByteBuffer> columnList = new ArrayList<>(1); 665 columnList.add(columnAname); 666 List<ByteBuffer> valueList = new ArrayList<>(1); 667 valueList.add(valueBname); 668 669 TAppend append = new TAppend(tableAname, rowAname, columnList, valueList); 670 handler.append(append); 671 672 TRowResult rowResult = handler.getRow(tableAname, rowAname, null).get(0); 673 assertEquals(rowAname, rowResult.row); 674 assertArrayEquals(Bytes.add(valueAname.array(), valueBname.array()), 675 rowResult.columns.get(columnAname).value.array()); 676 } finally { 677 handler.disableTable(tableAname); 678 handler.deleteTable(tableAname); 679 } 680 } 681 682 /** 683 * Check that checkAndPut fails if the cell does not exist, then put in the cell, then check that 684 * the checkAndPut succeeds. 685 */ 686 public static void doTestCheckAndPut() throws Exception { 687 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 688 UserProvider.instantiate(UTIL.getConfiguration())); 689 handler.createTable(tableAname, getColumnDescriptors()); 690 try { 691 List<Mutation> mutations = new ArrayList<>(1); 692 mutations.add(new Mutation(false, columnAname, valueAname, true)); 693 Mutation putB = (new Mutation(false, columnBname, valueBname, true)); 694 695 assertFalse(handler.checkAndPut(tableAname, rowAname, columnAname, valueAname, putB, null)); 696 697 handler.mutateRow(tableAname, rowAname, mutations, null); 698 699 assertTrue(handler.checkAndPut(tableAname, rowAname, columnAname, valueAname, putB, null)); 700 701 TRowResult rowResult = handler.getRow(tableAname, rowAname, null).get(0); 702 assertEquals(rowAname, rowResult.row); 703 assertEquals(valueBname, rowResult.columns.get(columnBname).value); 704 } finally { 705 handler.disableTable(tableAname); 706 handler.deleteTable(tableAname); 707 } 708 } 709 710 @Test 711 public void testGetTableNamesWithStatus() throws Exception { 712 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 713 UserProvider.instantiate(UTIL.getConfiguration())); 714 715 createTestTables(handler); 716 717 assertEquals(2, handler.getTableNamesWithIsTableEnabled().size()); 718 assertEquals(2, countTablesByStatus(true, handler)); 719 handler.disableTable(tableBname); 720 assertEquals(1, countTablesByStatus(true, handler)); 721 assertEquals(1, countTablesByStatus(false, handler)); 722 assertEquals(2, handler.getTableNamesWithIsTableEnabled().size()); 723 handler.enableTable(tableBname); 724 assertEquals(2, countTablesByStatus(true, handler)); 725 726 dropTestTables(handler); 727 } 728 729 private static int countTablesByStatus(Boolean isEnabled, Hbase.Iface handler) throws Exception { 730 AtomicInteger counter = new AtomicInteger(0); 731 handler.getTableNamesWithIsTableEnabled().forEach((table, tableStatus) -> { 732 if (tableStatus.equals(isEnabled)) counter.getAndIncrement(); 733 }); 734 return counter.get(); 735 } 736 737 @Test 738 public void testMetricsWithException() throws Exception { 739 String rowkey = "row1"; 740 String family = "f"; 741 String col = "c"; 742 // create a table which will throw exceptions for requests 743 final TableName tableName = TableName.valueOf(name.getMethodName()); 744 try { 745 ColumnFamilyDescriptor columnFamilyDescriptor = 746 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(family)).build(); 747 TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName) 748 .setCoprocessor(ErrorThrowingGetObserver.class.getName()) 749 .setColumnFamily(columnFamilyDescriptor).build(); 750 751 Table table = UTIL.createTable(tableDescriptor, null); 752 long now = EnvironmentEdgeManager.currentTime(); 753 table.put(new Put(Bytes.toBytes(rowkey)).addColumn(Bytes.toBytes(family), Bytes.toBytes(col), 754 now, Bytes.toBytes("val1"))); 755 756 Configuration conf = UTIL.getConfiguration(); 757 ThriftMetrics metrics = getMetrics(conf); 758 ThriftHBaseServiceHandler hbaseHandler = new ThriftHBaseServiceHandler( 759 UTIL.getConfiguration(), UserProvider.instantiate(UTIL.getConfiguration())); 760 Hbase.Iface handler = HbaseHandlerMetricsProxy.newInstance(hbaseHandler, metrics, conf); 761 762 ByteBuffer tTableName = asByteBuffer(tableName.getNameAsString()); 763 764 // check metrics increment with a successful get 765 long preGetCounter = metricsHelper.checkCounterExists("getRow_num_ops", metrics.getSource()) 766 ? metricsHelper.getCounter("getRow_num_ops", metrics.getSource()) 767 : 0; 768 List<TRowResult> tRowResult = handler.getRow(tTableName, asByteBuffer(rowkey), null); 769 assertEquals(1, tRowResult.size()); 770 TRowResult tResult = tRowResult.get(0); 771 772 TCell expectedColumnValue = new TCell(asByteBuffer("val1"), now); 773 774 assertArrayEquals(Bytes.toBytes(rowkey), tResult.getRow()); 775 Collection<TCell> returnedColumnValues = tResult.getColumns().values(); 776 assertEquals(1, returnedColumnValues.size()); 777 assertEquals(expectedColumnValue, returnedColumnValues.iterator().next()); 778 779 metricsHelper.assertCounter("getRow_num_ops", preGetCounter + 1, metrics.getSource()); 780 781 // check metrics increment when the get throws each exception type 782 for (ErrorThrowingGetObserver.ErrorType type : ErrorThrowingGetObserver.ErrorType.values()) { 783 testExceptionType(handler, metrics, tTableName, rowkey, type); 784 } 785 } finally { 786 UTIL.deleteTable(tableName); 787 } 788 } 789 790 private void testExceptionType(Hbase.Iface handler, ThriftMetrics metrics, ByteBuffer tTableName, 791 String rowkey, ErrorThrowingGetObserver.ErrorType errorType) throws Exception { 792 long preGetCounter = metricsHelper.getCounter("getRow_num_ops", metrics.getSource()); 793 String exceptionKey = errorType.getMetricName(); 794 long preExceptionCounter = metricsHelper.checkCounterExists(exceptionKey, metrics.getSource()) 795 ? metricsHelper.getCounter(exceptionKey, metrics.getSource()) 796 : 0; 797 Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>(); 798 attributes.put(asByteBuffer(ErrorThrowingGetObserver.SHOULD_ERROR_ATTRIBUTE), 799 asByteBuffer(errorType.name())); 800 try { 801 List<TRowResult> tRowResult = handler.getRow(tTableName, asByteBuffer(rowkey), attributes); 802 fail("Get with error attribute should have thrown an exception"); 803 } catch (IOError e) { 804 LOG.info("Received exception: ", e); 805 metricsHelper.assertCounter("getRow_num_ops", preGetCounter + 1, metrics.getSource()); 806 metricsHelper.assertCounter(exceptionKey, preExceptionCounter + 1, metrics.getSource()); 807 } 808 } 809 810 /** 811 * @return a List of ColumnDescriptors for use in creating a table. Has one default 812 * ColumnDescriptor and one ColumnDescriptor with fewer versions 813 */ 814 private static List<ColumnDescriptor> getColumnDescriptors() { 815 ArrayList<ColumnDescriptor> cDescriptors = new ArrayList<>(2); 816 817 // A default ColumnDescriptor 818 ColumnDescriptor cDescA = new ColumnDescriptor(); 819 cDescA.name = columnAname; 820 cDescriptors.add(cDescA); 821 822 // A slightly customized ColumnDescriptor (only 2 versions) 823 ColumnDescriptor cDescB = 824 new ColumnDescriptor(columnBname, 2, "NONE", false, "NONE", 0, 0, false, -1); 825 cDescriptors.add(cDescB); 826 827 return cDescriptors; 828 } 829 830 /** 831 * @param includeA whether or not to include columnA 832 * @param includeB whether or not to include columnB 833 * @return a List of column names for use in retrieving a scanner 834 */ 835 private List<ByteBuffer> getColumnList(boolean includeA, boolean includeB) { 836 List<ByteBuffer> columnList = new ArrayList<>(); 837 838 if (includeA) { 839 columnList.add(columnAname); 840 } 841 if (includeB) { 842 columnList.add(columnBname); 843 } 844 845 return columnList; 846 } 847 848 /** Returns a List of Mutations for a row, with columnA having valueA and columnB having valueB */ 849 private static List<Mutation> getMutations() { 850 List<Mutation> mutations = new ArrayList<>(2); 851 mutations.add(new Mutation(false, columnAname, valueAname, true)); 852 mutations.add(new Mutation(false, columnBname, valueBname, true)); 853 return mutations; 854 } 855 856 /** 857 * @return a List of BatchMutations with the following effects: (rowA, columnA): delete (rowA, 858 * columnB): place valueC (rowB, columnA): place valueC (rowB, columnB): place valueD 859 */ 860 private static List<BatchMutation> getBatchMutations() { 861 List<BatchMutation> batchMutations = new ArrayList<>(3); 862 863 // Mutations to rowA. You can't mix delete and put anymore. 864 List<Mutation> rowAmutations = new ArrayList<>(1); 865 rowAmutations.add(new Mutation(true, columnAname, null, true)); 866 batchMutations.add(new BatchMutation(rowAname, rowAmutations)); 867 868 rowAmutations = new ArrayList<>(1); 869 rowAmutations.add(new Mutation(false, columnBname, valueCname, true)); 870 batchMutations.add(new BatchMutation(rowAname, rowAmutations)); 871 872 // Mutations to rowB 873 List<Mutation> rowBmutations = new ArrayList<>(2); 874 rowBmutations.add(new Mutation(false, columnAname, valueCname, true)); 875 rowBmutations.add(new Mutation(false, columnBname, valueDname, true)); 876 batchMutations.add(new BatchMutation(rowBname, rowBmutations)); 877 878 return batchMutations; 879 } 880 881 /** 882 * Asserts that the passed scanner is exhausted, and then closes the scanner. 883 * @param scannerId the scanner to close 884 * @param handler the HBaseServiceHandler interfacing to HBase 885 */ 886 private void closeScanner(int scannerId, ThriftHBaseServiceHandler handler) throws Exception { 887 handler.scannerGet(scannerId); 888 handler.scannerClose(scannerId); 889 } 890 891 @Test 892 public void testGetThriftServerType() throws Exception { 893 ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(UTIL.getConfiguration(), 894 UserProvider.instantiate(UTIL.getConfiguration())); 895 assertEquals(TThriftServerType.ONE, handler.getThriftServerType()); 896 } 897 898 /** 899 * Verify that thrift client calling thrift2 server can get the thrift2 server type correctly. 900 */ 901 @Test 902 public void testGetThriftServerOneType() throws Exception { 903 // start a thrift2 server 904 HBaseThriftTestingUtility THRIFT_TEST_UTIL = new HBaseThriftTestingUtility(); 905 906 LOG.info("Starting HBase Thrift Server Two"); 907 THRIFT_TEST_UTIL.startThriftServer(UTIL.getConfiguration(), ThriftServerType.TWO); 908 try (TTransport transport = 909 new TSocket(InetAddress.getLocalHost().getHostName(), THRIFT_TEST_UTIL.getServerPort())) { 910 TProtocol protocol = new TBinaryProtocol(transport); 911 // This is our thrift client. 912 Hbase.Client client = new Hbase.Client(protocol); 913 // open the transport 914 transport.open(); 915 assertEquals(TThriftServerType.TWO.name(), client.getThriftServerType().name()); 916 } finally { 917 THRIFT_TEST_UTIL.stopThriftServer(); 918 } 919 } 920}