You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ka...@apache.org on 2019/12/12 19:47:51 UTC

[phoenix] branch 4.14-HBase-1.3 updated: PHOENIX-5615 Index read repair should delete all the cells of an invalid unverified row

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

kadir pushed a commit to branch 4.14-HBase-1.3
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/4.14-HBase-1.3 by this push:
     new 4a5b748  PHOENIX-5615 Index read repair should delete all the cells of an invalid unverified row
4a5b748 is described below

commit 4a5b7483e1cabfec2b8a5dd089199925096b3847
Author: Kadir <ko...@salesforce.com>
AuthorDate: Thu Dec 12 05:00:13 2019 -0800

    PHOENIX-5615 Index read repair should delete all the cells of an invalid unverified row
---
 .../phoenix/end2end/index/GlobalIndexCheckerIT.java    | 18 +++++++++++++++---
 .../org/apache/phoenix/index/GlobalIndexChecker.java   | 13 ++++++++++++-
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java
index 248a520..c09cad7 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java
@@ -37,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.phoenix.end2end.BaseUniqueNamesOwnClusterIT;
 import org.apache.phoenix.end2end.IndexToolIT;
 import org.apache.phoenix.hbase.index.IndexRegionObserver;
+import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.QueryUtil;
 import org.apache.phoenix.util.ReadOnlyProps;
@@ -66,6 +67,7 @@ public class GlobalIndexCheckerIT extends BaseUniqueNamesOwnClusterIT {
     @BeforeClass
     public static void doSetup() throws Exception {
         Map<String, String> props = Maps.newHashMapWithExpectedSize(1);
+        props.put(QueryServices.GLOBAL_INDEX_ROW_AGE_THRESHOLD_TO_DELETE_MS_ATTRIB, Long.toString(0));
         setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator()));
     }
 
@@ -318,18 +320,28 @@ public class GlobalIndexCheckerIT extends BaseUniqueNamesOwnClusterIT {
             // update phase) and check that this does not impact the correctness (one overwrite)
             IndexRegionObserver.setFailDataTableUpdatesForTesting(true);
             IndexRegionObserver.setFailPostIndexUpdatesForTesting(true);
-            conn.createStatement().execute("upsert into " + dataTableName + " (id, val2) values ('a', 'abcc')");
+            conn.createStatement().execute("upsert into " + dataTableName + " (id, val2, val3) values ('a', 'abcc', 'abccc')");
             commitWithException(conn);
             IndexRegionObserver.setFailDataTableUpdatesForTesting(false);
             IndexRegionObserver.setFailPostIndexUpdatesForTesting(false);
-            String selectSql =  "SELECT val2, val3 from " + dataTableName + " WHERE val1  = 'ab'";
+            // Read only one column and verify that this is sufficient for the read repair to fix
+            // all the columns of the unverified index row that was generated due to doing only one phase write above
+            String selectSql =  "SELECT val2 from " + dataTableName + " WHERE val1  = 'ab'";
             // Verify that we will read from the first index table
             assertExplainPlan(conn, selectSql, dataTableName, indexTableName + "1");
             // Verify that one phase write has no effect
             ResultSet rs = conn.createStatement().executeQuery(selectSql);
             assertTrue(rs.next());
             assertEquals("abc", rs.getString(1));
-            assertEquals("abcd", rs.getString(2));
+            assertFalse(rs.next());
+            // Now read the other column and verify that it is also fixed
+            selectSql =  "SELECT val3 from " + dataTableName + " WHERE val1  = 'ab'";
+            // Verify that we will read from the first index table
+            assertExplainPlan(conn, selectSql, dataTableName, indexTableName + "1");
+            // Verify that one phase write has no effect
+            rs = conn.createStatement().executeQuery(selectSql);
+            assertTrue(rs.next());
+            assertEquals("abcd", rs.getString(1));
             assertFalse(rs.next());
             selectSql =  "SELECT val2, val3 from " + dataTableName + " WHERE val2  = 'abcc'";
             // Verify that we will read from the second index table
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java b/phoenix-core/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
index 170da53..acd4804 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
@@ -114,10 +114,12 @@ public class GlobalIndexChecker extends BaseRegionObserver {
      * and used to verify individual rows and rebuild them if they are not valid
      */
     private class GlobalIndexScanner implements RegionScanner {
-        RegionScanner scanner;
+        private RegionScanner scanner;
+        private RegionScanner deleteRowScanner;
         private long ageThreshold;
         private Scan scan;
         private Scan indexScan;
+        private Scan deleteRowScan;
         private Scan singleRowIndexScan;
         private Scan buildIndexScan = null;
         private Table dataHTable = null;
@@ -246,6 +248,14 @@ public class GlobalIndexChecker extends BaseRegionObserver {
             if ((EnvironmentEdgeManager.currentTimeMillis() - ts) > ageThreshold) {
                 Delete del = new Delete(indexRowKey, ts);
                 if (specific) {
+                    // Get all the cells of this row
+                    deleteRowScan.setStartRow(indexRowKey);
+                    deleteRowScan.setStopRow(indexRowKey);
+                    deleteRowScan.setTimeRange(0, ts + 1);
+                    deleteRowScanner = region.getScanner(deleteRowScan);
+                    row.clear();
+                    deleteRowScanner.next(row);
+                    deleteRowScanner.close();
                     // We are deleting a specific version of a row so the flowing loop is for that
                     for (Cell cell : row) {
                         del.addColumn(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell), cell.getTimestamp());
@@ -261,6 +271,7 @@ public class GlobalIndexChecker extends BaseRegionObserver {
             if (buildIndexScan == null) {
                 buildIndexScan = new Scan();
                 indexScan = new Scan(scan);
+                deleteRowScan = new Scan();
                 singleRowIndexScan = new Scan(scan);
                 byte[] dataTableName = scan.getAttribute(PHYSICAL_DATA_TABLE_NAME);
                 byte[] indexTableName = region.getRegionInfo().getTable().getName();