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