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