001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.apache.hadoop.hbase.HConstants.RPC_CODEC_CONF_KEY; 021import static org.apache.hadoop.hbase.ipc.RpcClient.DEFAULT_CODEC_CLASS; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertNotEquals; 024import static org.junit.jupiter.api.Assertions.assertNotNull; 025import static org.junit.jupiter.api.Assertions.assertTrue; 026import static org.junit.jupiter.api.Assertions.fail; 027 028import java.io.IOException; 029import java.util.ArrayList; 030import java.util.Collections; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034import org.apache.hadoop.conf.Configuration; 035import org.apache.hadoop.hbase.Cell; 036import org.apache.hadoop.hbase.CellBuilderType; 037import org.apache.hadoop.hbase.DoNotRetryIOException; 038import org.apache.hadoop.hbase.ExtendedCell; 039import org.apache.hadoop.hbase.ExtendedCellBuilderFactory; 040import org.apache.hadoop.hbase.HBaseTestingUtil; 041import org.apache.hadoop.hbase.HConstants; 042import org.apache.hadoop.hbase.KeyValue; 043import org.apache.hadoop.hbase.PrivateCellUtil; 044import org.apache.hadoop.hbase.TableName; 045import org.apache.hadoop.hbase.Tag; 046import org.apache.hadoop.hbase.TagType; 047import org.apache.hadoop.hbase.codec.KeyValueCodecWithTags; 048import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 049import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint; 050import org.apache.hadoop.hbase.testclassification.ClientTests; 051import org.apache.hadoop.hbase.testclassification.LargeTests; 052import org.apache.hadoop.hbase.util.Bytes; 053import org.junit.jupiter.api.AfterAll; 054import org.junit.jupiter.api.BeforeAll; 055import org.junit.jupiter.api.BeforeEach; 056import org.junit.jupiter.api.Test; 057import org.junit.jupiter.api.TestInfo; 058import org.slf4j.Logger; 059import org.slf4j.LoggerFactory; 060 061/** 062 * Run Increment tests that use the HBase clients; {@link TableBuilder}. Test is parameterized to 063 * run the slow and fast increment code paths. If fast, in the @before, we do a rolling restart of 064 * the single regionserver so that it can pick up the go fast configuration. Doing it this way 065 * should be faster than starting/stopping a cluster per test. Test takes a long time because spin 066 * up a cluster between each run -- ugh. 067 */ 068@org.junit.jupiter.api.Tag(LargeTests.TAG) 069@org.junit.jupiter.api.Tag(ClientTests.TAG) 070public class TestIncrementsFromClientSide { 071 072 final Logger LOG = LoggerFactory.getLogger(getClass()); 073 protected final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 074 private static byte[] ROW = Bytes.toBytes("testRow"); 075 private static byte[] FAMILY = Bytes.toBytes("testFamily"); 076 private static byte[] QUALIFIER = Bytes.toBytes("testQualifier"); 077 // This test depends on there being only one slave running at at a time. See the @Before 078 // method where we do rolling restart. 079 protected static int SLAVES = 1; 080 private String methodName; 081 082 @BeforeEach 083 public void setUp(TestInfo testInfo) { 084 methodName = testInfo.getTestMethod().get().getName(); 085 } 086 087 @BeforeAll 088 public static void beforeClass() throws Exception { 089 Configuration conf = TEST_UTIL.getConfiguration(); 090 conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 091 MultiRowMutationEndpoint.class.getName()); 092 // We need more than one region server in this test 093 TEST_UTIL.startMiniCluster(SLAVES); 094 } 095 096 @AfterAll 097 public static void afterClass() throws Exception { 098 TEST_UTIL.shutdownMiniCluster(); 099 } 100 101 /** 102 * Test increment result when there are duplicate rpc request. 103 */ 104 @Test 105 public void testDuplicateIncrement() throws Exception { 106 TableDescriptorBuilder builder = TEST_UTIL.createModifyableTableDescriptor(methodName); 107 Map<String, String> kvs = new HashMap<>(); 108 kvs.put(SleepAtFirstRpcCall.SLEEP_TIME_CONF_KEY, "2000"); 109 builder.setCoprocessor(CoprocessorDescriptorBuilder 110 .newBuilder(SleepAtFirstRpcCall.class.getName()).setPriority(1).setProperties(kvs).build()); 111 TEST_UTIL.createTable(builder.build(), new byte[][] { ROW }).close(); 112 113 Configuration c = new Configuration(TEST_UTIL.getConfiguration()); 114 c.setInt(HConstants.HBASE_CLIENT_PAUSE, 50); 115 // Client will retry beacuse rpc timeout is small than the sleep time of first rpc call 116 c.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500); 117 118 try (Connection connection = ConnectionFactory.createConnection(c); Table table = connection 119 .getTableBuilder(TableName.valueOf(methodName), null).setOperationTimeout(3 * 1000).build()) { 120 Increment inc = new Increment(ROW); 121 inc.addColumn(HBaseTestingUtil.fam1, QUALIFIER, 1); 122 Result result = table.increment(inc); 123 124 Cell[] cells = result.rawCells(); 125 assertEquals(1, cells.length); 126 assertIncrementKey(cells[0], ROW, HBaseTestingUtil.fam1, QUALIFIER, 1); 127 128 // Verify expected result 129 Result readResult = table.get(new Get(ROW)); 130 cells = readResult.rawCells(); 131 assertEquals(1, cells.length); 132 assertIncrementKey(cells[0], ROW, HBaseTestingUtil.fam1, QUALIFIER, 1); 133 } 134 } 135 136 /** 137 * Test batch increment result when there are duplicate rpc request. 138 */ 139 @Test 140 public void testDuplicateBatchIncrement() throws Exception { 141 TableDescriptorBuilder builder = TEST_UTIL.createModifyableTableDescriptor(methodName); 142 Map<String, String> kvs = new HashMap<>(); 143 kvs.put(SleepAtFirstRpcCall.SLEEP_TIME_CONF_KEY, "2000"); 144 builder.setCoprocessor(CoprocessorDescriptorBuilder 145 .newBuilder(SleepAtFirstRpcCall.class.getName()).setPriority(1).setProperties(kvs).build()); 146 TEST_UTIL.createTable(builder.build(), new byte[][] { ROW }).close(); 147 148 Configuration c = new Configuration(TEST_UTIL.getConfiguration()); 149 c.setInt(HConstants.HBASE_CLIENT_PAUSE, 50); 150 // Client will retry beacuse rpc timeout is small than the sleep time of first rpc call 151 c.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500); 152 153 try (Connection connection = ConnectionFactory.createConnection(c); Table table = connection 154 .getTableBuilder(TableName.valueOf(methodName), null).setOperationTimeout(3 * 1000).build()) { 155 Increment inc = new Increment(ROW); 156 inc.addColumn(HBaseTestingUtil.fam1, QUALIFIER, 1); 157 158 // Batch increment 159 Object[] results = new Object[1]; 160 table.batch(Collections.singletonList(inc), results); 161 162 Cell[] cells = ((Result) results[0]).rawCells(); 163 assertEquals(1, cells.length); 164 assertIncrementKey(cells[0], ROW, HBaseTestingUtil.fam1, QUALIFIER, 1); 165 166 // Verify expected result 167 Result readResult = table.get(new Get(ROW)); 168 cells = readResult.rawCells(); 169 assertEquals(1, cells.length); 170 assertIncrementKey(cells[0], ROW, HBaseTestingUtil.fam1, QUALIFIER, 1); 171 } 172 } 173 174 @Test 175 public void testIncrementWithDeletes() throws Exception { 176 LOG.info("Starting " + methodName); 177 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 178 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 179 final byte[] COLUMN = Bytes.toBytes("column"); 180 181 ht.incrementColumnValue(ROW, FAMILY, COLUMN, 5); 182 TEST_UTIL.flush(TABLENAME); 183 184 Delete del = new Delete(ROW); 185 ht.delete(del); 186 187 ht.incrementColumnValue(ROW, FAMILY, COLUMN, 5); 188 189 Get get = new Get(ROW); 190 Result r = ht.get(get); 191 assertEquals(1, r.size()); 192 assertEquals(5, Bytes.toLong(r.getValue(FAMILY, COLUMN))); 193 } 194 195 @Test 196 public void testIncrementingInvalidValue() throws Exception { 197 LOG.info("Starting " + methodName); 198 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 199 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 200 final byte[] COLUMN = Bytes.toBytes("column"); 201 Put p = new Put(ROW); 202 // write an integer here (not a Long) 203 p.addColumn(FAMILY, COLUMN, Bytes.toBytes(5)); 204 ht.put(p); 205 try { 206 ht.incrementColumnValue(ROW, FAMILY, COLUMN, 5); 207 fail("Should have thrown DoNotRetryIOException"); 208 } catch (DoNotRetryIOException iox) { 209 // success 210 } 211 Increment inc = new Increment(ROW); 212 inc.addColumn(FAMILY, COLUMN, 5); 213 try { 214 ht.increment(inc); 215 fail("Should have thrown DoNotRetryIOException"); 216 } catch (DoNotRetryIOException iox) { 217 // success 218 } 219 } 220 221 @Test 222 public void testBatchIncrementsWithReturnResultFalse() throws Exception { 223 LOG.info("Starting testBatchIncrementsWithReturnResultFalse"); 224 final TableName tableName = TableName.valueOf(methodName); 225 Table table = TEST_UTIL.createTable(tableName, FAMILY); 226 Increment inc1 = new Increment(Bytes.toBytes("row2")); 227 inc1.setReturnResults(false); 228 inc1.addColumn(FAMILY, Bytes.toBytes("f1"), 1); 229 Increment inc2 = new Increment(Bytes.toBytes("row2")); 230 inc2.setReturnResults(false); 231 inc2.addColumn(FAMILY, Bytes.toBytes("f1"), 1); 232 List<Increment> incs = new ArrayList<>(); 233 incs.add(inc1); 234 incs.add(inc2); 235 Object[] results = new Object[2]; 236 table.batch(incs, results); 237 assertTrue(results.length == 2); 238 for (Object r : results) { 239 Result result = (Result) r; 240 assertTrue(result.isEmpty()); 241 } 242 table.close(); 243 } 244 245 @Test 246 public void testIncrementInvalidArguments() throws Exception { 247 LOG.info("Starting " + methodName); 248 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 249 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 250 final byte[] COLUMN = Bytes.toBytes("column"); 251 try { 252 // try null row 253 ht.incrementColumnValue(null, FAMILY, COLUMN, 5); 254 fail("Should have thrown NPE/IOE"); 255 } catch (NullPointerException | IOException error) { 256 // success 257 } 258 try { 259 // try null family 260 ht.incrementColumnValue(ROW, null, COLUMN, 5); 261 fail("Should have thrown NPE/IOE"); 262 } catch (NullPointerException | IOException error) { 263 // success 264 } 265 // try null row 266 try { 267 Increment incNoRow = new Increment((byte[]) null); 268 incNoRow.addColumn(FAMILY, COLUMN, 5); 269 fail("Should have thrown IAE/NPE"); 270 } catch (IllegalArgumentException | NullPointerException error) { 271 // success 272 } 273 // try null family 274 try { 275 Increment incNoFamily = new Increment(ROW); 276 incNoFamily.addColumn(null, COLUMN, 5); 277 fail("Should have thrown IAE"); 278 } catch (IllegalArgumentException iax) { 279 // success 280 } 281 } 282 283 @Test 284 public void testIncrementOutOfOrder() throws Exception { 285 LOG.info("Starting " + methodName); 286 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 287 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 288 289 byte[][] QUALIFIERS = 290 new byte[][] { Bytes.toBytes("B"), Bytes.toBytes("A"), Bytes.toBytes("C") }; 291 292 Increment inc = new Increment(ROW); 293 for (int i = 0; i < QUALIFIERS.length; i++) { 294 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 295 } 296 ht.increment(inc); 297 298 // Verify expected results 299 Get get = new Get(ROW); 300 Result r = ht.get(get); 301 Cell[] kvs = r.rawCells(); 302 assertEquals(3, kvs.length); 303 assertIncrementKey(kvs[0], ROW, FAMILY, QUALIFIERS[1], 1); 304 assertIncrementKey(kvs[1], ROW, FAMILY, QUALIFIERS[0], 1); 305 assertIncrementKey(kvs[2], ROW, FAMILY, QUALIFIERS[2], 1); 306 307 // Now try multiple columns again 308 inc = new Increment(ROW); 309 for (int i = 0; i < QUALIFIERS.length; i++) { 310 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 311 } 312 ht.increment(inc); 313 314 // Verify 315 r = ht.get(get); 316 kvs = r.rawCells(); 317 assertEquals(3, kvs.length); 318 assertIncrementKey(kvs[0], ROW, FAMILY, QUALIFIERS[1], 2); 319 assertIncrementKey(kvs[1], ROW, FAMILY, QUALIFIERS[0], 2); 320 assertIncrementKey(kvs[2], ROW, FAMILY, QUALIFIERS[2], 2); 321 } 322 323 @Test 324 public void testIncrementOnSameColumn() throws Exception { 325 LOG.info("Starting " + methodName); 326 final byte[] TABLENAME = Bytes.toBytes(filterStringSoTableNameSafe(methodName)); 327 Table ht = TEST_UTIL.createTable(TableName.valueOf(TABLENAME), FAMILY); 328 329 byte[][] QUALIFIERS = 330 new byte[][] { Bytes.toBytes("A"), Bytes.toBytes("B"), Bytes.toBytes("C") }; 331 332 Increment inc = new Increment(ROW); 333 for (int i = 0; i < QUALIFIERS.length; i++) { 334 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 335 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 336 } 337 ht.increment(inc); 338 339 // Verify expected results 340 Get get = new Get(ROW); 341 Result r = ht.get(get); 342 Cell[] kvs = r.rawCells(); 343 assertEquals(3, kvs.length); 344 assertIncrementKey(kvs[0], ROW, FAMILY, QUALIFIERS[0], 1); 345 assertIncrementKey(kvs[1], ROW, FAMILY, QUALIFIERS[1], 1); 346 assertIncrementKey(kvs[2], ROW, FAMILY, QUALIFIERS[2], 1); 347 348 // Now try multiple columns again 349 inc = new Increment(ROW); 350 for (int i = 0; i < QUALIFIERS.length; i++) { 351 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 352 inc.addColumn(FAMILY, QUALIFIERS[i], 1); 353 } 354 ht.increment(inc); 355 356 // Verify 357 r = ht.get(get); 358 kvs = r.rawCells(); 359 assertEquals(3, kvs.length); 360 assertIncrementKey(kvs[0], ROW, FAMILY, QUALIFIERS[0], 2); 361 assertIncrementKey(kvs[1], ROW, FAMILY, QUALIFIERS[1], 2); 362 assertIncrementKey(kvs[2], ROW, FAMILY, QUALIFIERS[2], 2); 363 364 ht.close(); 365 } 366 367 @Test 368 public void testIncrementIncrZeroAtFirst() throws Exception { 369 LOG.info("Starting " + methodName); 370 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 371 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 372 373 byte[] col1 = Bytes.toBytes("col1"); 374 byte[] col2 = Bytes.toBytes("col2"); 375 byte[] col3 = Bytes.toBytes("col3"); 376 377 // Now increment zero at first time incr 378 Increment inc = new Increment(ROW); 379 inc.addColumn(FAMILY, col1, 0); 380 ht.increment(inc); 381 382 // Verify expected results 383 Get get = new Get(ROW); 384 Result r = ht.get(get); 385 Cell[] kvs = r.rawCells(); 386 assertEquals(1, kvs.length); 387 assertNotNull(kvs[0]); 388 assertIncrementKey(kvs[0], ROW, FAMILY, col1, 0); 389 390 // Now try multiple columns by different amounts 391 inc = new Increment(ROW); 392 inc.addColumn(FAMILY, col1, 1); 393 inc.addColumn(FAMILY, col2, 0); 394 inc.addColumn(FAMILY, col3, 2); 395 ht.increment(inc); 396 // Verify 397 get = new Get(ROW); 398 r = ht.get(get); 399 kvs = r.rawCells(); 400 assertEquals(3, kvs.length); 401 assertNotNull(kvs[0]); 402 assertNotNull(kvs[1]); 403 assertNotNull(kvs[2]); 404 assertIncrementKey(kvs[0], ROW, FAMILY, col1, 1); 405 assertIncrementKey(kvs[1], ROW, FAMILY, col2, 0); 406 assertIncrementKey(kvs[2], ROW, FAMILY, col3, 2); 407 } 408 409 @Test 410 public void testIncrement() throws Exception { 411 LOG.info("Starting " + methodName); 412 final TableName TABLENAME = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 413 Table ht = TEST_UTIL.createTable(TABLENAME, FAMILY); 414 415 byte[][] ROWS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c"), 416 Bytes.toBytes("d"), Bytes.toBytes("e"), Bytes.toBytes("f"), Bytes.toBytes("g"), 417 Bytes.toBytes("h"), Bytes.toBytes("i") }; 418 byte[][] QUALIFIERS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c"), 419 Bytes.toBytes("d"), Bytes.toBytes("e"), Bytes.toBytes("f"), Bytes.toBytes("g"), 420 Bytes.toBytes("h"), Bytes.toBytes("i") }; 421 422 // Do some simple single-column increments 423 424 // First with old API 425 ht.incrementColumnValue(ROW, FAMILY, QUALIFIERS[0], 1); 426 ht.incrementColumnValue(ROW, FAMILY, QUALIFIERS[1], 2); 427 ht.incrementColumnValue(ROW, FAMILY, QUALIFIERS[2], 3); 428 ht.incrementColumnValue(ROW, FAMILY, QUALIFIERS[3], 4); 429 430 // Now increment things incremented with old and do some new 431 Increment inc = new Increment(ROW); 432 inc.addColumn(FAMILY, QUALIFIERS[1], 1); 433 inc.addColumn(FAMILY, QUALIFIERS[3], 1); 434 inc.addColumn(FAMILY, QUALIFIERS[4], 1); 435 ht.increment(inc); 436 437 // Verify expected results 438 Get get = new Get(ROW); 439 Result r = ht.get(get); 440 Cell[] kvs = r.rawCells(); 441 assertEquals(5, kvs.length); 442 assertIncrementKey(kvs[0], ROW, FAMILY, QUALIFIERS[0], 1); 443 assertIncrementKey(kvs[1], ROW, FAMILY, QUALIFIERS[1], 3); 444 assertIncrementKey(kvs[2], ROW, FAMILY, QUALIFIERS[2], 3); 445 assertIncrementKey(kvs[3], ROW, FAMILY, QUALIFIERS[3], 5); 446 assertIncrementKey(kvs[4], ROW, FAMILY, QUALIFIERS[4], 1); 447 448 // Now try multiple columns by different amounts 449 inc = new Increment(ROWS[0]); 450 for (int i = 0; i < QUALIFIERS.length; i++) { 451 inc.addColumn(FAMILY, QUALIFIERS[i], i + 1); 452 } 453 ht.increment(inc); 454 // Verify 455 get = new Get(ROWS[0]); 456 r = ht.get(get); 457 kvs = r.rawCells(); 458 assertEquals(QUALIFIERS.length, kvs.length); 459 for (int i = 0; i < QUALIFIERS.length; i++) { 460 assertIncrementKey(kvs[i], ROWS[0], FAMILY, QUALIFIERS[i], i + 1); 461 } 462 463 // Re-increment them 464 inc = new Increment(ROWS[0]); 465 for (int i = 0; i < QUALIFIERS.length; i++) { 466 inc.addColumn(FAMILY, QUALIFIERS[i], i + 1); 467 } 468 ht.increment(inc); 469 // Verify 470 r = ht.get(get); 471 kvs = r.rawCells(); 472 assertEquals(QUALIFIERS.length, kvs.length); 473 for (int i = 0; i < QUALIFIERS.length; i++) { 474 assertIncrementKey(kvs[i], ROWS[0], FAMILY, QUALIFIERS[i], 2 * (i + 1)); 475 } 476 477 // Verify that an Increment of an amount of zero, returns current count; i.e. same as for above 478 // test, that is: 2 * (i + 1). 479 inc = new Increment(ROWS[0]); 480 for (int i = 0; i < QUALIFIERS.length; i++) { 481 inc.addColumn(FAMILY, QUALIFIERS[i], 0); 482 } 483 ht.increment(inc); 484 r = ht.get(get); 485 kvs = r.rawCells(); 486 assertEquals(QUALIFIERS.length, kvs.length); 487 for (int i = 0; i < QUALIFIERS.length; i++) { 488 assertIncrementKey(kvs[i], ROWS[0], FAMILY, QUALIFIERS[i], 2 * (i + 1)); 489 } 490 } 491 492 @Test 493 public void testIncrementWithCustomTimestamp() throws IOException { 494 TableName TABLENAME = TableName.valueOf(methodName); 495 Table table = TEST_UTIL.createTable(TABLENAME, FAMILY); 496 long timestamp = 999; 497 Increment increment = new Increment(ROW); 498 increment.add(ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY).setRow(ROW) 499 .setFamily(FAMILY).setQualifier(QUALIFIER).setTimestamp(timestamp) 500 .setType(KeyValue.Type.Put.getCode()).setValue(Bytes.toBytes(100L)).build()); 501 Result r = table.increment(increment); 502 assertEquals(1, r.size()); 503 assertEquals(timestamp, r.rawCells()[0].getTimestamp()); 504 r = table.get(new Get(ROW)); 505 assertEquals(1, r.size()); 506 assertEquals(timestamp, r.rawCells()[0].getTimestamp()); 507 r = table.increment(increment); 508 assertEquals(1, r.size()); 509 assertNotEquals(timestamp, r.rawCells()[0].getTimestamp()); 510 r = table.get(new Get(ROW)); 511 assertEquals(1, r.size()); 512 assertNotEquals(timestamp, r.rawCells()[0].getTimestamp()); 513 } 514 515 /** 516 * Call over to the adjacent class's method of same name. 517 */ 518 static void assertIncrementKey(Cell key, byte[] row, byte[] family, byte[] qualifier, long value) 519 throws Exception { 520 FromClientSideTestBase.assertIncrementKey(key, row, family, qualifier, value); 521 } 522 523 public static String filterStringSoTableNameSafe(final String str) { 524 return str.replaceAll("\\[fast\\=(.*)\\]", ".FAST.is.$1"); 525 } 526 527 /* 528 * Test that we have only 1 ttl tag with increment mutation. 529 */ 530 @Test 531 public void testIncrementWithTtlTags() throws Exception { 532 LOG.info("Starting " + methodName); 533 final TableName tableName = TableName.valueOf(filterStringSoTableNameSafe(methodName)); 534 Table ht = TEST_UTIL.createTable(tableName, FAMILY); 535 final byte[] COLUMN = Bytes.toBytes("column"); 536 537 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 538 // Set RPC_CODEC_CONF_KEY to KeyValueCodecWithTags so that scan will return tags. 539 conf.set(RPC_CODEC_CONF_KEY, KeyValueCodecWithTags.class.getName()); 540 conf.set(DEFAULT_CODEC_CLASS, ""); 541 try (Connection connection = ConnectionFactory.createConnection(conf); 542 Table table = connection.getTable(tableName)) { 543 for (int i = 0; i < 10; i++) { 544 Increment inc = new Increment(ROW); 545 inc.addColumn(FAMILY, COLUMN, 1); 546 long ttl = i + 3600000; 547 inc.setTTL(ttl); 548 ht.increment(inc); 549 550 Scan scan = new Scan().withStartRow(ROW); 551 ResultScanner scanner = table.getScanner(scan); 552 int count = 0; 553 Result result; 554 while ((result = scanner.next()) != null) { 555 ExtendedCell[] cells = result.rawExtendedCells(); 556 for (ExtendedCell cell : cells) { 557 List<Tag> tags = PrivateCellUtil.getTags(cell); 558 // Make sure there is only 1 tag. 559 assertEquals(1, tags.size()); 560 Tag tag = tags.get(0); 561 assertEquals(TagType.TTL_TAG_TYPE, tag.getType()); 562 long ttlTagValue = Bytes.toLong(tag.getValueArray(), tag.getValueOffset()); 563 assertEquals(ttl, ttlTagValue); 564 } 565 count++; 566 } 567 // Make sure there is only 1 result. 568 assertEquals(1, count); 569 } 570 } 571 } 572}