This is an automated email from the ASF dual-hosted git repository. vjasani 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 ee0f4051fb PHOENIX-7299 :- ScanningResultIterator should not time out a query after receiving a valid result (#1872) ee0f4051fb is described below commit ee0f4051fbefdecf8226ff7f3a42e0cad83d1405 Author: Lokesh Khurana <khuranalokes...@gmail.com> AuthorDate: Wed Apr 3 22:04:07 2024 -0700 PHOENIX-7299 :- ScanningResultIterator should not time out a query after receiving a valid result (#1872) --- .../phoenix/iterate/ScanningResultIterator.java | 5 +- .../phoenix/iterate/PhoenixQueryTimeoutIT.java | 55 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java b/phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java index 82081267bf..979bd1f41a 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java @@ -85,6 +85,8 @@ public class ScanningResultIterator implements ResultIterator { private long dummyRowCounter = 0; + private boolean hasFirstValidResult = false; + private final ScanningResultPostDummyResultCaller scanningResultPostDummyResultCaller; private final ScanningResultPostValidResultCaller scanningResultPostValidResultCaller; @@ -205,7 +207,7 @@ public class ScanningResultIterator implements ResultIterator { while (result != null && (result.isEmpty() || isDummy(result))) { dummyRowCounter += 1; long timeOutForScan = maxQueryEndTime - EnvironmentEdgeManager.currentTimeMillis(); - if (timeOutForScan < 0) { + if (!hasFirstValidResult && timeOutForScan < 0) { throw new SQLExceptionInfo.Builder(OPERATION_TIMED_OUT).setMessage( ". Query couldn't be completed in the allotted time : " + context.getStatement().getQueryTimeoutInMillis() + " ms").build().buildException(); @@ -225,6 +227,7 @@ public class ScanningResultIterator implements ResultIterator { close(); // Free up resources early return null; } + hasFirstValidResult = true; // TODO: use ResultTuple.setResult(result)? // Need to create a new one if holding on to it (i.e. OrderedResultIterator) processAfterRetrievingValidResult(); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/iterate/PhoenixQueryTimeoutIT.java b/phoenix-core/src/it/java/org/apache/phoenix/iterate/PhoenixQueryTimeoutIT.java index 43dd06a645..8157135e40 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/iterate/PhoenixQueryTimeoutIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/iterate/PhoenixQueryTimeoutIT.java @@ -48,6 +48,8 @@ import org.apache.phoenix.end2end.ParallelStatsDisabledIT; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.util.EnvironmentEdgeManager; +import org.apache.phoenix.util.ManualEnvironmentEdge; import org.apache.phoenix.util.ReadOnlyProps; import org.junit.Before; import org.junit.BeforeClass; @@ -202,6 +204,59 @@ public class PhoenixQueryTimeoutIT extends ParallelStatsDisabledIT { } } + @Test + public void testScanningResultIteratorShouldNotQueryTimeoutForPagingAfterReceivingAValidRow() throws Exception { + //Arrange + PreparedStatement ps = loadDataAndPreparePagedQuery(10,1); + + ManualEnvironmentEdge injectEdge; + injectEdge = new ManualEnvironmentEdge(); + injectEdge.setValue(EnvironmentEdgeManager.currentTimeMillis()); + EnvironmentEdgeManager.injectEdge(injectEdge); + // First query we are executing with timeout of 10ms, so it should not timeout as first row will be retrieved + // before 10 ms. + + //Act + Assert + try { + //Do not let BaseResultIterators throw Timeout Exception Let ScanningResultIterator handle it. + BaseResultIterators.setForTestingSetTimeoutToMaxToLetQueryPassHere(true); + ResultSet rs = ps.executeQuery(); + while(rs.next()) { + injectEdge.incrementValue(10); + } + } catch (SQLException e) { + fail("Query should have run smoothly"); + } finally { + BaseResultIterators.setForTestingSetTimeoutToMaxToLetQueryPassHere(false); + } + + PreparedStatement failingPs = loadDataAndPreparePagedQuery(0,0); + //Second query should timeout as queryTimeout is set to 0ms + try { + //Do not let BaseResultIterators throw Timeout Exception Let ScanningResultIterator handle it. + BaseResultIterators.setForTestingSetTimeoutToMaxToLetQueryPassHere(true); + ResultSet rs = failingPs.executeQuery(); + EnvironmentEdgeManager.reset(); + while(rs.next()) {} + fail("Expected query to timeout with a 0 ms timeout"); + } catch (SQLException e) { + //OPERATION_TIMED_OUT Exception expected + Throwable t = e; + // SQLTimeoutException can be wrapped inside outer exceptions like PhoenixIOException + while (t != null && !(t instanceof SQLTimeoutException)) { + t = t.getCause(); + } + if (t == null) { + fail("Expected query to fail with SQLTimeoutException"); + } + assertEquals(OPERATION_TIMED_OUT.getErrorCode(), + ((SQLTimeoutException)t).getErrorCode()); + } finally { + BaseResultIterators.setForTestingSetTimeoutToMaxToLetQueryPassHere(false); + } + + } + @Test public void testScanningResultIteratorQueryTimeoutForPagingWithNormalLowTimeout() throws Exception { //Arrange