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