This is an automated email from the ASF dual-hosted git repository.

zhangduo pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-3 by this push:
     new c30c493b77c HBASE-29982 Upgrade TestTags to JUnit5 and polish the code 
(#7897)
c30c493b77c is described below

commit c30c493b77c2148bceaff92e66d8ccd0fea0bf73
Author: Duo Zhang <[email protected]>
AuthorDate: Wed Mar 11 19:25:18 2026 +0800

    HBASE-29982 Upgrade TestTags to JUnit5 and polish the code (#7897)
    
    Signed-off-by: Nihal Jain <[email protected]>
    Reviewed-by: Liu Xiao <[email protected]>
    (cherry picked from commit 1606be719c730dd5d9267f3221f88b81d159d3fd)
---
 .../apache/hadoop/hbase/regionserver/TestTags.java | 587 +++++++--------------
 .../hbase/regionserver/TestTagsReverseScan.java    | 158 ++++++
 2 files changed, 360 insertions(+), 385 deletions(-)

diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java
index bf230b844a2..31304c0815f 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java
@@ -19,11 +19,13 @@ package org.apache.hadoop.hbase.regionserver;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.ArrayBackedTag;
 import org.apache.hadoop.hbase.Cell;
@@ -31,7 +33,6 @@ import org.apache.hadoop.hbase.CellScanner;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.ExtendedCell;
 import org.apache.hadoop.hbase.ExtendedCellScanner;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.KeyValue;
@@ -39,12 +40,8 @@ import org.apache.hadoop.hbase.KeyValueUtil;
 import org.apache.hadoop.hbase.PrivateCellUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.Tag;
-import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.client.Append;
 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
-import org.apache.hadoop.hbase.client.CompactionState;
-import org.apache.hadoop.hbase.client.Connection;
-import org.apache.hadoop.hbase.client.ConnectionFactory;
 import org.apache.hadoop.hbase.client.Durability;
 import org.apache.hadoop.hbase.client.Increment;
 import org.apache.hadoop.hbase.client.Mutation;
@@ -61,40 +58,28 @@ import 
org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
 import org.apache.hadoop.hbase.coprocessor.RegionObserver;
 import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
-import org.apache.hadoop.hbase.testclassification.LargeTests;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.RegionServerTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.wal.WALEdit;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
 
 /**
  * Class that test tags
  */
-@Category({ RegionServerTests.class, LargeTests.class })
[email protected](RegionServerTests.TAG)
[email protected](MediumTests.TAG)
 public class TestTags {
 
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE = 
HBaseClassTestRule.forClass(TestTags.class);
-
-  private static final Logger LOG = LoggerFactory.getLogger(TestTags.class);
-
-  static boolean useFilter = false;
-
   private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
 
-  @Rule
-  public final TestName TEST_NAME = new TestName();
-
-  @BeforeClass
+  @BeforeAll
   public static void setUpBeforeClass() throws Exception {
     Configuration conf = TEST_UTIL.getConfiguration();
     conf.setInt("hfile.format.version", 3);
@@ -103,212 +88,99 @@ public class TestTags {
     TEST_UTIL.startMiniCluster(2);
   }
 
-  @AfterClass
+  @AfterAll
   public static void tearDownAfterClass() throws Exception {
     TEST_UTIL.shutdownMiniCluster();
   }
 
-  @After
-  public void tearDown() {
-    useFilter = false;
+  @AfterEach
+  public void tearDown() throws InterruptedException {
+    resetCoprocessorFlags();
   }
 
-  /**
-   * Test that we can do reverse scans when writing tags and using 
DataBlockEncoding. Fails with an
-   * exception for PREFIX, DIFF, and FAST_DIFF prior to HBASE-27580
-   */
-  @Test
-  public void testReverseScanWithDBE() throws IOException {
-    byte[] family = Bytes.toBytes("0");
-
-    Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
-    conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
-
-    try (Connection connection = ConnectionFactory.createConnection(conf)) {
-      for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
-        testReverseScanWithDBE(connection, encoding, family, 
HConstants.DEFAULT_BLOCKSIZE, 10);
-      }
-    }
+  private void resetCoprocessorFlags() throws InterruptedException {
+    TestCoprocessorForTags.checkTagPresence = false;
+    // to avoid data race, here we sleep for a little while before reseting 
tags
+    Thread.sleep(100);
+    TestCoprocessorForTags.tags.clear();
   }
 
-  /**
-   * Test that we can do reverse scans when writing tags and using 
DataBlockEncoding. Fails with an
-   * exception for PREFIX, DIFF, and FAST_DIFF
-   */
   @Test
-  public void testReverseScanWithDBEWhenCurrentBlockUpdates() throws 
IOException {
-    byte[] family = Bytes.toBytes("0");
-
-    Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
-    conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
-
-    try (Connection connection = ConnectionFactory.createConnection(conf)) {
-      for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
-        testReverseScanWithDBE(connection, encoding, family, 1024, 30000);
-      }
-    }
-  }
-
-  private void testReverseScanWithDBE(Connection conn, DataBlockEncoding 
encoding, byte[] family,
-    int blockSize, int maxRows) throws IOException {
-    LOG.info("Running test with DBE={}", encoding);
-    TableName tableName = TableName.valueOf(TEST_NAME.getMethodName() + "-" + 
encoding);
-    TEST_UTIL.createTable(
-      
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder
-        
.newBuilder(family).setDataBlockEncoding(encoding).setBlocksize(blockSize).build()).build(),
-      null);
-
-    Table table = conn.getTable(tableName);
-
-    byte[] val1 = new byte[10];
-    byte[] val2 = new byte[10];
-    Bytes.random(val1);
-    Bytes.random(val2);
-
-    for (int i = 0; i < maxRows; i++) {
-      table.put(new Put(Bytes.toBytes(i)).addColumn(family, Bytes.toBytes(1), 
val1)
-        .addColumn(family, Bytes.toBytes(2), val2).setTTL(600_000));
-    }
-
-    TEST_UTIL.flush(table.getName());
-
-    Scan scan = new Scan();
-    scan.setReversed(true);
-
-    try (ResultScanner scanner = table.getScanner(scan)) {
-      for (int i = maxRows - 1; i >= 0; i--) {
-        Result row = scanner.next();
-        assertEquals(2, row.size());
-
-        Cell cell1 = row.getColumnLatestCell(family, Bytes.toBytes(1));
-        assertTrue(CellUtil.matchingRows(cell1, Bytes.toBytes(i)));
-        assertTrue(CellUtil.matchingValue(cell1, val1));
-
-        Cell cell2 = row.getColumnLatestCell(family, Bytes.toBytes(2));
-        assertTrue(CellUtil.matchingRows(cell2, Bytes.toBytes(i)));
-        assertTrue(CellUtil.matchingValue(cell2, val2));
-      }
-    }
-
-  }
+  public void testTags(TestInfo testInfo) throws Exception {
+    TableName tableName = 
TableName.valueOf(testInfo.getTestMethod().get().getName());
+    byte[] fam = Bytes.toBytes("info");
+    byte[] row = Bytes.toBytes("rowa");
+    // column names
+    byte[] qual = Bytes.toBytes("qual");
+    byte[] row1 = Bytes.toBytes("rowb");
+    byte[] row2 = Bytes.toBytes("rowc");
 
-  @Test
-  public void testTags() throws Exception {
-    Table table = null;
-    try {
-      TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
-      byte[] fam = Bytes.toBytes("info");
-      byte[] row = Bytes.toBytes("rowa");
-      // column names
-      byte[] qual = Bytes.toBytes("qual");
-
-      byte[] row1 = Bytes.toBytes("rowb");
-
-      byte[] row2 = Bytes.toBytes("rowc");
-
-      TableDescriptor tableDescriptor =
-        TableDescriptorBuilder
-          
.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(fam)
-            
.setBlockCacheEnabled(true).setDataBlockEncoding(DataBlockEncoding.NONE).build())
-          .build();
-      Admin admin = TEST_UTIL.getAdmin();
-      admin.createTable(tableDescriptor);
+    TableDescriptor tableDescriptor = 
TableDescriptorBuilder.newBuilder(tableName)
+      
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(fam).setBlockCacheEnabled(true)
+        .setDataBlockEncoding(DataBlockEncoding.NONE).build())
+      .build();
+    try (Table table = TEST_UTIL.createTable(tableDescriptor, null)) {
       byte[] value = Bytes.toBytes("value");
-      table = TEST_UTIL.getConnection().getTable(tableName);
       Put put = new Put(row);
       put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value);
       put.setAttribute("visibility", Bytes.toBytes("myTag"));
       table.put(put);
-      admin.flush(tableName);
-      // We are lacking an API for confirming flush request compaction.
-      // Just sleep for a short time. We won't be able to confirm flush
-      // completion but the test won't hang now or in the future if
-      // default compaction policy causes compaction between flush and
-      // when we go to confirm it.
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
       Put put1 = new Put(row1);
       byte[] value1 = Bytes.toBytes("1000dfsdf");
       put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
       // put1.setAttribute("visibility", Bytes.toBytes("myTag3"));
       table.put(put1);
-      admin.flush(tableName);
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
       Put put2 = new Put(row2);
       byte[] value2 = Bytes.toBytes("1000dfsdf");
       put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
       put2.setAttribute("visibility", Bytes.toBytes("myTag3"));
       table.put(put2);
-      admin.flush(tableName);
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
-      result(fam, row, qual, row2, table, value, value2, row1, value1);
+      assertResult(fam, row, qual, row2, table, value, value2, row1, value1);
 
-      admin.compact(tableName);
-      while (admin.getCompactionState(tableName) != CompactionState.NONE) {
-        Thread.sleep(10);
-      }
-      result(fam, row, qual, row2, table, value, value2, row1, value1);
-    } finally {
-      if (table != null) {
-        table.close();
-      }
+      TEST_UTIL.compact(tableName, false);
+      assertResult(fam, row, qual, row2, table, value, value2, row1, value1);
     }
   }
 
   @Test
-  public void testFlushAndCompactionWithoutTags() throws Exception {
-    Table table = null;
-    try {
-      TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
-      byte[] fam = Bytes.toBytes("info");
-      byte[] row = Bytes.toBytes("rowa");
-      // column names
-      byte[] qual = Bytes.toBytes("qual");
-
-      byte[] row1 = Bytes.toBytes("rowb");
-
-      byte[] row2 = Bytes.toBytes("rowc");
-
-      TableDescriptor tableDescriptor =
-        TableDescriptorBuilder.newBuilder(tableName)
-          .setColumnFamily(
-            
ColumnFamilyDescriptorBuilder.newBuilder(fam).setBlockCacheEnabled(true).build())
-          .build();
-      Admin admin = TEST_UTIL.getAdmin();
-      admin.createTable(tableDescriptor);
-
-      table = TEST_UTIL.getConnection().getTable(tableName);
+  public void testFlushAndCompactionWithoutTags(TestInfo testInfo) throws 
Exception {
+    TableName tableName = 
TableName.valueOf(testInfo.getTestMethod().get().getName());
+    byte[] fam = Bytes.toBytes("info");
+    byte[] row = Bytes.toBytes("rowa");
+    // column names
+    byte[] qual = Bytes.toBytes("qual");
+    byte[] row1 = Bytes.toBytes("rowb");
+    byte[] row2 = Bytes.toBytes("rowc");
+
+    TableDescriptor tableDescriptor = 
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(
+      
ColumnFamilyDescriptorBuilder.newBuilder(fam).setBlockCacheEnabled(true).build()).build();
+    try (Table table = TEST_UTIL.createTable(tableDescriptor, null)) {
       Put put = new Put(row);
       byte[] value = Bytes.toBytes("value");
       put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value);
       table.put(put);
-      admin.flush(tableName);
-      // We are lacking an API for confirming flush request compaction.
-      // Just sleep for a short time. We won't be able to confirm flush
-      // completion but the test won't hang now or in the future if
-      // default compaction policy causes compaction between flush and
-      // when we go to confirm it.
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
       Put put1 = new Put(row1);
       byte[] value1 = Bytes.toBytes("1000dfsdf");
       put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
       table.put(put1);
-      admin.flush(tableName);
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
       Put put2 = new Put(row2);
       byte[] value2 = Bytes.toBytes("1000dfsdf");
       put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
       table.put(put2);
-      admin.flush(tableName);
-      Thread.sleep(1000);
+      TEST_UTIL.flush(tableName);
 
       Scan s = new Scan().withStartRow(row);
-      ResultScanner scanner = table.getScanner(s);
-      try {
+      try (ResultScanner scanner = table.getScanner(s)) {
         Result[] next = scanner.next(3);
         for (Result result : next) {
           ExtendedCellScanner cellScanner = result.cellScanner();
@@ -316,16 +188,11 @@ public class TestTags {
           ExtendedCell current = cellScanner.current();
           assertEquals(0, current.getTagsLength());
         }
-      } finally {
-        if (scanner != null) scanner.close();
-      }
-      admin.compact(tableName);
-      while (admin.getCompactionState(tableName) != CompactionState.NONE) {
-        Thread.sleep(10);
       }
+
+      TEST_UTIL.compact(tableName, false);
       s = new Scan().withStartRow(row);
-      scanner = table.getScanner(s);
-      try {
+      try (ResultScanner scanner = table.getScanner(s)) {
         Result[] next = scanner.next(3);
         for (Result result : next) {
           ExtendedCellScanner cellScanner = result.cellScanner();
@@ -333,141 +200,104 @@ public class TestTags {
           ExtendedCell current = cellScanner.current();
           assertEquals(0, current.getTagsLength());
         }
-      } finally {
-        if (scanner != null) {
-          scanner.close();
-        }
-      }
-    } finally {
-      if (table != null) {
-        table.close();
       }
     }
   }
 
-  @Test
-  public void testFlushAndCompactionwithCombinations() throws Exception {
-    TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
+  @ParameterizedTest(name = "{index}: DataBlockEncoding = {0}")
+  @EnumSource(DataBlockEncoding.class)
+  public void testFlushAndCompactionwithCombinations(DataBlockEncoding 
encoding, TestInfo testInfo)
+    throws Exception {
+    TableName tableName =
+      TableName.valueOf(testInfo.getTestMethod().get().getName() + "-" + 
encoding.name());
     byte[] fam = Bytes.toBytes("info");
     byte[] row = Bytes.toBytes("rowa");
     // column names
     byte[] qual = Bytes.toBytes("qual");
-
     byte[] row1 = Bytes.toBytes("rowb");
-
     byte[] row2 = Bytes.toBytes("rowc");
     byte[] rowd = Bytes.toBytes("rowd");
     byte[] rowe = Bytes.toBytes("rowe");
-    Table table = null;
-    for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
-      TableDescriptor tableDescriptor = 
TableDescriptorBuilder.newBuilder(tableName)
-        
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(fam).setBlockCacheEnabled(true)
-          .setDataBlockEncoding(encoding).build())
-        .build();
-      Admin admin = TEST_UTIL.getAdmin();
-      admin.createTable(tableDescriptor);
-      try {
-        table = TEST_UTIL.getConnection().getTable(tableName);
-        Put put = new Put(row);
-        byte[] value = Bytes.toBytes("value");
-        put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value);
-        int bigTagLen = Short.MAX_VALUE - 5;
-        put.setAttribute("visibility", new byte[bigTagLen]);
-        table.put(put);
-        Put put1 = new Put(row1);
-        byte[] value1 = Bytes.toBytes("1000dfsdf");
-        put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
-        table.put(put1);
-        admin.flush(tableName);
-        // We are lacking an API for confirming flush request compaction.
-        // Just sleep for a short time. We won't be able to confirm flush
-        // completion but the test won't hang now or in the future if
-        // default compaction policy causes compaction between flush and
-        // when we go to confirm it.
-        Thread.sleep(1000);
-
-        put1 = new Put(row2);
-        value1 = Bytes.toBytes("1000dfsdf");
-        put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
-        table.put(put1);
-        admin.flush(tableName);
-        Thread.sleep(1000);
-
-        Put put2 = new Put(rowd);
-        byte[] value2 = Bytes.toBytes("1000dfsdf");
-        put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
-        table.put(put2);
-        put2 = new Put(rowe);
-        value2 = Bytes.toBytes("1000dfsddfdf");
-        put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
-        put.setAttribute("visibility", Bytes.toBytes("ram"));
-        table.put(put2);
-        admin.flush(tableName);
-        Thread.sleep(1000);
-
-        TestCoprocessorForTags.checkTagPresence = true;
-        Scan s = new Scan().withStartRow(row);
-        s.setCaching(1);
-        ResultScanner scanner = table.getScanner(s);
-        try {
-          Result next = null;
-          while ((next = scanner.next()) != null) {
-            CellScanner cellScanner = next.cellScanner();
-            cellScanner.advance();
-            Cell current = cellScanner.current();
-            if (CellUtil.matchingRows(current, row)) {
-              assertEquals(1, TestCoprocessorForTags.tags.size());
-              Tag tag = TestCoprocessorForTags.tags.get(0);
-              assertEquals(bigTagLen, tag.getValueLength());
-            } else {
-              assertEquals(0, TestCoprocessorForTags.tags.size());
-            }
-          }
-        } finally {
-          if (scanner != null) {
-            scanner.close();
+    TableDescriptor tableDescriptor =
+      
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder
+        
.newBuilder(fam).setBlockCacheEnabled(true).setDataBlockEncoding(encoding).build()).build();
+    try (Table table = TEST_UTIL.createTable(tableDescriptor, null)) {
+      Put put = new Put(row);
+      byte[] value = Bytes.toBytes("value");
+      put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value);
+      int bigTagLen = Short.MAX_VALUE - 5;
+      put.setAttribute("visibility", new byte[bigTagLen]);
+      table.put(put);
+      Put put1 = new Put(row1);
+      byte[] value1 = Bytes.toBytes("1000dfsdf");
+      put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
+      table.put(put1);
+      TEST_UTIL.flush(tableName);
+
+      put1 = new Put(row2);
+      value1 = Bytes.toBytes("1000dfsdf");
+      put1.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value1);
+      table.put(put1);
+      TEST_UTIL.flush(tableName);
+
+      Put put2 = new Put(rowd);
+      byte[] value2 = Bytes.toBytes("1000dfsdf");
+      put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
+      table.put(put2);
+      put2 = new Put(rowe);
+      value2 = Bytes.toBytes("1000dfsddfdf");
+      put2.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value2);
+      put.setAttribute("visibility", Bytes.toBytes("ram"));
+      table.put(put2);
+      TEST_UTIL.flush(tableName);
+
+      TestCoprocessorForTags.checkTagPresence = true;
+      Scan s = new Scan().withStartRow(row);
+      s.setCaching(1);
+      try (ResultScanner scanner = table.getScanner(s)) {
+        Result next = null;
+        while ((next = scanner.next()) != null) {
+          CellScanner cellScanner = next.cellScanner();
+          cellScanner.advance();
+          Cell current = cellScanner.current();
+          List<Tag> tags = TestCoprocessorForTags.tags.poll();
+          if (CellUtil.matchingRows(current, row)) {
+            assertEquals(1, tags.size());
+            Tag tag = tags.get(0);
+            assertEquals(bigTagLen, tag.getValueLength());
+          } else {
+            assertEquals(0, tags.size());
           }
-          TestCoprocessorForTags.checkTagPresence = false;
-        }
-        while (admin.getCompactionState(tableName) != CompactionState.NONE) {
-          Thread.sleep(10);
         }
-        TestCoprocessorForTags.checkTagPresence = true;
-        scanner = table.getScanner(s);
-        try {
-          Result next = null;
-          while ((next = scanner.next()) != null) {
-            CellScanner cellScanner = next.cellScanner();
-            cellScanner.advance();
-            Cell current = cellScanner.current();
-            if (CellUtil.matchingRows(current, row)) {
-              assertEquals(1, TestCoprocessorForTags.tags.size());
-              Tag tag = TestCoprocessorForTags.tags.get(0);
-              assertEquals(bigTagLen, tag.getValueLength());
-            } else {
-              assertEquals(0, TestCoprocessorForTags.tags.size());
-            }
-          }
-        } finally {
-          if (scanner != null) {
-            scanner.close();
+      }
+      resetCoprocessorFlags();
+
+      TEST_UTIL.compact(tableName, false);
+
+      TestCoprocessorForTags.checkTagPresence = true;
+
+      try (ResultScanner scanner = table.getScanner(s)) {
+        Result next = null;
+        while ((next = scanner.next()) != null) {
+          CellScanner cellScanner = next.cellScanner();
+          cellScanner.advance();
+          Cell current = cellScanner.current();
+          List<Tag> tags = TestCoprocessorForTags.tags.poll();
+          if (CellUtil.matchingRows(current, row)) {
+            assertEquals(1, tags.size());
+            Tag tag = tags.get(0);
+            assertEquals(bigTagLen, tag.getValueLength());
+          } else {
+            assertEquals(0, tags.size());
           }
-          TestCoprocessorForTags.checkTagPresence = false;
-        }
-      } finally {
-        if (table != null) {
-          table.close();
         }
-        // delete the table
-        admin.disableTable(tableName);
-        admin.deleteTable(tableName);
       }
     }
   }
 
   @Test
-  public void testTagsWithAppendAndIncrement() throws Exception {
-    TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
+  public void testTagsWithAppendAndIncrement(TestInfo testInfo) throws 
Exception {
+    TableName tableName = 
TableName.valueOf(testInfo.getTestMethod().get().getName());
     byte[] f = Bytes.toBytes("f");
     byte[] q = Bytes.toBytes("q");
     byte[] row1 = Bytes.toBytes("r1");
@@ -475,11 +305,8 @@ public class TestTags {
 
     TableDescriptor tableDescriptor = 
TableDescriptorBuilder.newBuilder(tableName)
       .setColumnFamily(ColumnFamilyDescriptorBuilder.of(f)).build();
-    TEST_UTIL.getAdmin().createTable(tableDescriptor);
 
-    Table table = null;
-    try {
-      table = TEST_UTIL.getConnection().getTable(tableName);
+    try (Table table = TEST_UTIL.createTable(tableDescriptor, null)) {
       Put put = new Put(row1);
       byte[] v = Bytes.toBytes(2L);
       put.addColumn(f, q, v);
@@ -489,36 +316,38 @@ public class TestTags {
       increment.addColumn(f, q, 1L);
       table.increment(increment);
       TestCoprocessorForTags.checkTagPresence = true;
-      ResultScanner scanner = table.getScanner(new Scan());
-      Result result = scanner.next();
-      KeyValue kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      List<Tag> tags = TestCoprocessorForTags.tags;
-      assertEquals(3L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
-      assertEquals(1, tags.size());
-      assertEquals("tag1", Bytes.toString(Tag.cloneValue(tags.get(0))));
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
+      try (ResultScanner scanner = table.getScanner(new Scan())) {
+        Result result = scanner.next();
+        Cell kv = result.getColumnLatestCell(f, q);
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(3L,
+          Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
+        assertEquals(1, tags.size());
+        assertEquals("tag1", Bytes.toString(Tag.cloneValue(tags.get(0))));
+      }
+      resetCoprocessorFlags();
 
       increment = new Increment(row1);
       increment.add(new KeyValue(row1, f, q, 1234L, v));
       increment.setAttribute("visibility", Bytes.toBytes("tag2"));
       table.increment(increment);
       TestCoprocessorForTags.checkTagPresence = true;
-      scanner = table.getScanner(new Scan());
-      result = scanner.next();
-      kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      tags = TestCoprocessorForTags.tags;
-      assertEquals(5L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
-      assertEquals(2, tags.size());
-      // We cannot assume the ordering of tags
-      List<String> tagValues = new ArrayList<>();
-      for (Tag tag : tags) {
-        tagValues.add(Bytes.toString(Tag.cloneValue(tag)));
+      try (ResultScanner scanner = table.getScanner(new Scan())) {
+        Result result = scanner.next();
+        Cell kv = result.getColumnLatestCell(f, q);
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(5L,
+          Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
+        assertEquals(2, tags.size());
+        // We cannot assume the ordering of tags
+        List<String> tagValues = new ArrayList<>();
+        for (Tag tag : tags) {
+          tagValues.add(Bytes.toString(Tag.cloneValue(tag)));
+        }
+        assertTrue(tagValues.contains("tag1"));
+        assertTrue(tagValues.contains("tag2"));
       }
-      assertTrue(tagValues.contains("tag1"));
-      assertTrue(tagValues.contains("tag2"));
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
+      resetCoprocessorFlags();
 
       put = new Put(row2);
       v = Bytes.toBytes(2L);
@@ -529,15 +358,16 @@ public class TestTags {
       increment.setAttribute("visibility", Bytes.toBytes("tag2"));
       table.increment(increment);
       TestCoprocessorForTags.checkTagPresence = true;
-      scanner = table.getScanner(new Scan().withStartRow(row2));
-      result = scanner.next();
-      kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      tags = TestCoprocessorForTags.tags;
-      assertEquals(4L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
-      assertEquals(1, tags.size());
-      assertEquals("tag2", Bytes.toString(Tag.cloneValue(tags.get(0))));
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
+      try (ResultScanner scanner = table.getScanner(new 
Scan().withStartRow(row2))) {
+        Result result = scanner.next();
+        Cell kv = result.getColumnLatestCell(f, q);
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(4L,
+          Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), 
kv.getValueLength()));
+        assertEquals(1, tags.size());
+        assertEquals("tag2", Bytes.toString(Tag.cloneValue(tags.get(0))));
+      }
+      resetCoprocessorFlags();
 
       // Test Append
       byte[] row3 = Bytes.toBytes("r3");
@@ -549,34 +379,32 @@ public class TestTags {
       append.addColumn(f, q, Bytes.toBytes("b"));
       table.append(append);
       TestCoprocessorForTags.checkTagPresence = true;
-      scanner = table.getScanner(new Scan().withStartRow(row3));
-      result = scanner.next();
-      kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      tags = TestCoprocessorForTags.tags;
-      assertEquals(1, tags.size());
-      assertEquals("tag1", Bytes.toString(Tag.cloneValue(tags.get(0))));
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
+      try (ResultScanner scanner = table.getScanner(new 
Scan().withStartRow(row3))) {
+        assertNotNull(scanner.next());
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(1, tags.size());
+        assertEquals("tag1", Bytes.toString(Tag.cloneValue(tags.get(0))));
+      }
+      resetCoprocessorFlags();
 
       append = new Append(row3);
       append.add(new KeyValue(row3, f, q, 1234L, v));
       append.setAttribute("visibility", Bytes.toBytes("tag2"));
       table.append(append);
       TestCoprocessorForTags.checkTagPresence = true;
-      scanner = table.getScanner(new Scan().withStartRow(row3));
-      result = scanner.next();
-      kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      tags = TestCoprocessorForTags.tags;
-      assertEquals(2, tags.size());
-      // We cannot assume the ordering of tags
-      tagValues.clear();
-      for (Tag tag : tags) {
-        tagValues.add(Bytes.toString(Tag.cloneValue(tag)));
+      try (ResultScanner scanner = table.getScanner(new 
Scan().withStartRow(row3))) {
+        assertNotNull(scanner.next());
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(2, tags.size());
+        // We cannot assume the ordering of tags
+        List<String> tagValues = new ArrayList<>();
+        for (Tag tag : tags) {
+          tagValues.add(Bytes.toString(Tag.cloneValue(tag)));
+        }
+        assertTrue(tagValues.contains("tag1"));
+        assertTrue(tagValues.contains("tag2"));
       }
-      assertTrue(tagValues.contains("tag1"));
-      assertTrue(tagValues.contains("tag2"));
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
+      resetCoprocessorFlags();
 
       byte[] row4 = Bytes.toBytes("r4");
       put = new Put(row4);
@@ -587,31 +415,23 @@ public class TestTags {
       append.setAttribute("visibility", Bytes.toBytes("tag2"));
       table.append(append);
       TestCoprocessorForTags.checkTagPresence = true;
-      scanner = table.getScanner(new Scan().withStartRow(row4));
-      result = scanner.next();
-      kv = KeyValueUtil.ensureKeyValue((ExtendedCell) 
result.getColumnLatestCell(f, q));
-      tags = TestCoprocessorForTags.tags;
-      assertEquals(1, tags.size());
-      assertEquals("tag2", Bytes.toString(Tag.cloneValue(tags.get(0))));
-    } finally {
-      TestCoprocessorForTags.checkTagPresence = false;
-      TestCoprocessorForTags.tags = null;
-      if (table != null) {
-        table.close();
+      try (ResultScanner scanner = table.getScanner(new 
Scan().withStartRow(row4))) {
+        assertNotNull(scanner.next());
+        List<Tag> tags = TestCoprocessorForTags.tags.poll();
+        assertEquals(1, tags.size());
+        assertEquals("tag2", Bytes.toString(Tag.cloneValue(tags.get(0))));
       }
     }
   }
 
-  private void result(byte[] fam, byte[] row, byte[] qual, byte[] row2, Table 
table, byte[] value,
-    byte[] value2, byte[] row1, byte[] value1) throws IOException {
+  private void assertResult(byte[] fam, byte[] row, byte[] qual, byte[] row2, 
Table table,
+    byte[] value, byte[] value2, byte[] row1, byte[] value1) throws 
IOException {
     Scan s = new Scan().withStartRow(row);
     // If filters are used this attribute can be specifically check for in
     // filterKV method and
     // kvs can be filtered out if the tags of interest is not found in that kv
     s.setAttribute("visibility", Bytes.toBytes("myTag"));
-    ResultScanner scanner = null;
-    try {
-      scanner = table.getScanner(s);
+    try (ResultScanner scanner = table.getScanner(s)) {
       Result next = scanner.next();
 
       assertTrue(Bytes.equals(next.getRow(), row));
@@ -626,16 +446,13 @@ public class TestTags {
       assertTrue(next2 != null);
       assertTrue(Bytes.equals(next2.getRow(), row2));
       assertTrue(Bytes.equals(next2.getValue(fam, qual), value2));
-
-    } finally {
-      if (scanner != null) scanner.close();
     }
   }
 
   public static class TestCoprocessorForTags implements RegionCoprocessor, 
RegionObserver {
 
     public static volatile boolean checkTagPresence = false;
-    public static List<Tag> tags = null;
+    public static final ConcurrentLinkedQueue<List<Tag>> tags = new 
ConcurrentLinkedQueue<>();
 
     @Override
     public Optional<RegionObserver> getRegionObserver() {
@@ -701,7 +518,7 @@ public class TestTags {
           ExtendedCellScanner cellScanner = result.cellScanner();
           if (cellScanner.advance()) {
             ExtendedCell cell = cellScanner.current();
-            tags = PrivateCellUtil.getTags(cell);
+            tags.add(PrivateCellUtil.getTags(cell));
           }
         }
       }
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTagsReverseScan.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTagsReverseScan.java
new file mode 100644
index 00000000000..eedba5db7d7
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTagsReverseScan.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.regionserver;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.ConnectionFactory;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
+import org.apache.hadoop.hbase.testclassification.LargeTests;
+import org.apache.hadoop.hbase.testclassification.RegionServerTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.TestTemplate;
+import org.junit.jupiter.params.provider.Arguments;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Tag(RegionServerTests.TAG)
+@Tag(LargeTests.TAG)
+@HBaseParameterizedTestTemplate(name = "{index}: DataBlockEncoding = {0}")
+public class TestTagsReverseScan {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestTagsReverseScan.class);
+
+  private final static HBaseTestingUtil UTIL = new HBaseTestingUtil();
+
+  private DataBlockEncoding encoding;
+
+  public TestTagsReverseScan(DataBlockEncoding encoding) {
+    this.encoding = encoding;
+  }
+
+  public static Stream<Arguments> parameters() {
+    return Arrays.stream(DataBlockEncoding.values()).map(Arguments::of);
+  }
+
+  @BeforeAll
+  public static void setUpBeforeClass() throws Exception {
+    UTIL.startMiniCluster(2);
+  }
+
+  @AfterAll
+  public static void tearDownAfterClass() throws Exception {
+    UTIL.shutdownMiniCluster();
+  }
+
+  /**
+   * Test that we can do reverse scans when writing tags and using 
DataBlockEncoding. Fails with an
+   * exception for PREFIX, DIFF, and FAST_DIFF prior to HBASE-27580
+   */
+  @TestTemplate
+  public void testReverseScanWithDBE(TestInfo testInfo) throws IOException {
+    byte[] family = Bytes.toBytes("0");
+
+    Configuration conf = new Configuration(UTIL.getConfiguration());
+    conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
+
+    try (Connection connection = ConnectionFactory.createConnection(conf)) {
+      testReverseScanWithDBE(testInfo, connection, family, 
HConstants.DEFAULT_BLOCKSIZE, 10);
+    }
+  }
+
+  /**
+   * Test that we can do reverse scans when writing tags and using 
DataBlockEncoding. Fails with an
+   * exception for PREFIX, DIFF, and FAST_DIFF
+   */
+  @TestTemplate
+  public void testReverseScanWithDBEWhenCurrentBlockUpdates(TestInfo testInfo) 
throws IOException {
+    byte[] family = Bytes.toBytes("0");
+
+    Configuration conf = new Configuration(UTIL.getConfiguration());
+    conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
+
+    try (Connection connection = ConnectionFactory.createConnection(conf)) {
+      testReverseScanWithDBE(testInfo, connection, family, 1024, 30000);
+    }
+  }
+
+  private void testReverseScanWithDBE(TestInfo testInfo, Connection conn, 
byte[] family,
+    int blockSize, int maxRows) throws IOException {
+    LOG.info("Running test with DBE={}", encoding);
+    TableName tableName =
+      TableName.valueOf(testInfo.getTestMethod().get().getName() + "-" + 
encoding);
+    UTIL.createTable(
+      
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder
+        
.newBuilder(family).setDataBlockEncoding(encoding).setBlocksize(blockSize).build()).build(),
+      null);
+
+    Table table = conn.getTable(tableName);
+
+    byte[] val1 = new byte[10];
+    byte[] val2 = new byte[10];
+    Bytes.random(val1);
+    Bytes.random(val2);
+
+    for (int i = 0; i < maxRows; i++) {
+      table.put(new Put(Bytes.toBytes(i)).addColumn(family, Bytes.toBytes(1), 
val1)
+        .addColumn(family, Bytes.toBytes(2), val2).setTTL(600_000));
+    }
+
+    UTIL.flush(table.getName());
+
+    Scan scan = new Scan();
+    scan.setReversed(true);
+
+    try (ResultScanner scanner = table.getScanner(scan)) {
+      for (int i = maxRows - 1; i >= 0; i--) {
+        Result row = scanner.next();
+        assertEquals(2, row.size());
+
+        Cell cell1 = row.getColumnLatestCell(family, Bytes.toBytes(1));
+        assertTrue(CellUtil.matchingRows(cell1, Bytes.toBytes(i)));
+        assertTrue(CellUtil.matchingValue(cell1, val1));
+
+        Cell cell2 = row.getColumnLatestCell(family, Bytes.toBytes(2));
+        assertTrue(CellUtil.matchingRows(cell2, Bytes.toBytes(i)));
+        assertTrue(CellUtil.matchingValue(cell2, val2));
+      }
+    }
+  }
+}


Reply via email to