This is an automated email from the ASF dual-hosted git repository.
tkhurana pushed a commit to branch 5.2
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/5.2 by this push:
new 271c2a5cf9 PHOENIX-7666 Index query failure with SkipScanFilter (#2223)
271c2a5cf9 is described below
commit 271c2a5cf9b106afc0a528b9a447d955c161c5ba
Author: tkhurana <[email protected]>
AuthorDate: Fri Jul 18 16:36:54 2025 -0700
PHOENIX-7666 Index query failure with SkipScanFilter (#2223)
---
.../apache/phoenix/index/GlobalIndexChecker.java | 16 ++---
.../end2end/index/GlobalIndexCheckerIT.java | 69 ++++++++++++++++++++++
2 files changed, 78 insertions(+), 7 deletions(-)
diff --git
a/phoenix-core-server/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
b/phoenix-core-server/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
index 906aef4a69..8e82f17036 100644
---
a/phoenix-core-server/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
+++
b/phoenix-core-server/src/main/java/org/apache/phoenix/index/GlobalIndexChecker.java
@@ -457,15 +457,17 @@ public class GlobalIndexChecker extends
BaseScannerRegionObserver implements Reg
Bytes.compareTo(row.get(0).getRowArray(), row.get(0).getRowOffset(),
row.get(0).getRowLength(), indexRowKey, 0, indexRowKey.length) != 0
) {
- // This means the index row has been deleted before opening the new
scanner. We got a
- // different row
- // If this row is "verified" (or empty) then we are good to go.
+ // We got a different index row. This means either the unverified
index row has
+ // been deleted by the single row rebuild as part of the read repair
process,
+ // or the filters on the scan object skip the rebuilt index row.
+ // If this new row is "verified" (or empty) then we are good to go.
if (verifyRowAndRemoveEmptyColumn(row)) {
return;
}
// The row is "unverified". Rewind the scanner and let the row be
scanned again
// so that it can be repaired
scanner.close();
+ indexScan.withStartRow(CellUtil.cloneRow(row.get(0)), true);
scanner = ((DelegateRegionScanner)
delegate).getNewRegionScanner(indexScan);
hasMore = true;
row.clear();
@@ -619,8 +621,8 @@ public class GlobalIndexChecker extends
BaseScannerRegionObserver implements Reg
metricsSource.updateIndexRepairTime(indexName,
EnvironmentEdgeManager.currentTimeMillis() - repairStart);
if (shouldLog()) {
- LOG.info("Index row repair on region {} took {} ms.",
- env.getRegionInfo().getRegionNameAsString(), repairTime);
+ LOG.info("Index row repair on region {} row ts {} took {} ms.",
+ env.getRegionInfo().getRegionNameAsString(), ts, repairTime);
}
} catch (IOException e) {
repairTime = EnvironmentEdgeManager.currentTimeMillis() -
repairStart;
@@ -628,8 +630,8 @@ public class GlobalIndexChecker extends
BaseScannerRegionObserver implements Reg
metricsSource.updateIndexRepairFailureTime(indexName,
EnvironmentEdgeManager.currentTimeMillis() - repairStart);
if (shouldLog()) {
- LOG.warn("Index row repair failure on region {} took {} ms.",
- env.getRegionInfo().getRegionNameAsString(), repairTime);
+ LOG.warn("Index row repair failure on region {} row ts {} took {}
ms.",
+ env.getRegionInfo().getRegionNameAsString(), ts, repairTime);
}
throw e;
}
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 27146e9b81..c13e9c4091 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
@@ -1290,6 +1290,75 @@ public class GlobalIndexCheckerIT extends BaseTest {
}
}
+ @Test
+ public void testUnverifiedIndexRowWithSkipScanFilter2() throws Exception {
+ if (async) {
+ // ignoring running this test with async = true
+ return;
+ }
+
+ try (Connection conn = DriverManager.getConnection(getUrl())) {
+ String dataTableName = generateUniqueName();
+ String indexName = generateUniqueName();
+ conn.createStatement()
+ .execute("create table " + dataTableName
+ + " (id varchar(10) not null primary key, val1 varchar(10), val2
varchar(10), "
+ + "val3 varchar(10))" + tableDDLOptions);
+ conn.createStatement().execute("CREATE INDEX " + indexName + " on " +
dataTableName
+ + " (val1, val2) include (val3)" + this.indexDDLOptions);
+ IndexRegionObserver.setFailPostIndexUpdatesForTesting(true);
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('a', 'val1',
'val2a', 'val3')");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('b', 'val1',
'val2a', 'val31')");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('c', 'val1',
'val2c', 'val3')");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('d', 'val1',
'val2d', 'val3')");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('e', 'val1',
'val2e', null)");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('f', 'val1',
'val2f', null)");
+ conn.createStatement()
+ .execute("upsert into " + dataTableName + " " + "values ('g', 'val1',
'val2g', null)");
+ conn.commit();
+ // Fail phase 3
+ IndexRegionObserver.setFailPostIndexUpdatesForTesting(false);
+ String selectSql = "SELECT id from " + dataTableName
+ + " WHERE val1 = 'val1' AND val2 IN ('val2a', 'val2d') AND val3 =
'val3'";
+ List<String> expectedIDs = Lists.newArrayList("a", "d");
+ List<String> actualIDs = Lists.newArrayList();
+ try (ResultSet rs = conn.createStatement().executeQuery(selectSql)) {
+ PhoenixResultSet prs = rs.unwrap(PhoenixResultSet.class);
+ String actualExplainPlan =
QueryUtil.getExplainPlan(prs.getUnderlyingIterator());
+ assertTrue(actualExplainPlan.contains(indexName));
+ while (rs.next()) {
+ actualIDs.add(rs.getString("id"));
+ }
+ assertEquals(expectedIDs, actualIDs);
+ } catch (AssertionError e) {
+ TestUtil.dumpTable(conn, TableName.valueOf(indexName));
+ throw e;
+ }
+ selectSql = "SELECT id from " + dataTableName
+ + " WHERE val1 = 'val1' AND val2 IN ('val2e', 'val2g') AND val3 is
null";
+ expectedIDs = Lists.newArrayList("e", "g");
+ actualIDs = Lists.newArrayList();
+ try (ResultSet rs = conn.createStatement().executeQuery(selectSql)) {
+ PhoenixResultSet prs = rs.unwrap(PhoenixResultSet.class);
+ String actualExplainPlan =
QueryUtil.getExplainPlan(prs.getUnderlyingIterator());
+ assertTrue(actualExplainPlan.contains(indexName));
+ while (rs.next()) {
+ actualIDs.add(rs.getString("id"));
+ }
+ assertEquals(expectedIDs, actualIDs);
+ } catch (AssertionError e) {
+ TestUtil.dumpTable(conn, TableName.valueOf(indexName));
+ throw e;
+ }
+ }
+ }
+
@Test
public void testUnverifiedIndexRowWithFirstKeyOnlyFilter() throws Exception {
if (async) {