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

reschke pushed a commit to branch 1.x
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git


The following commit(s) were added to refs/heads/1.x by this push:
     new 69f83c6d SLING-13284 - Do not abort alias/vanity cache init on 
out-of-order qu… (#225) (#231)
69f83c6d is described below

commit 69f83c6dbbdaba0fdef66c3f19c448d621274b07
Author: Julian Reschke <[email protected]>
AuthorDate: Tue Aug 18 07:57:07 2026 +0200

    SLING-13284 - Do not abort alias/vanity cache init on out-of-order qu… 
(#225) (#231)
    
    * SLING-13284 - Do not abort alias/vanity cache init on out-of-order query 
results
    
    Demote the ordering checks in PagedQueryIterator from fatal throws to
    log.warn. The checks compared live property values against an async
    index sort order, which can lag after a property write.
    
    * SLING-13284 - Remove unused QueryImplementationException
    
    Co-authored-by: Sagar Miglani 
<[email protected]>
---
 .../impl/mapping/PagedQueryIterator.java           | 33 ++++++------
 .../impl/mapping/PagedQueryIteratorTest.java       | 58 ++++++++++++++++++----
 2 files changed, 63 insertions(+), 28 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIterator.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIterator.java
index 40356f06..2081daa9 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIterator.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIterator.java
@@ -90,18 +90,22 @@ public class PagedQueryIterator implements 
Iterator<Resource> {
         if (values.length > 0) {
             String value = values[0];
             if (value.compareTo(lastKey) < 0) {
-                String message = String.format(
-                        "unexpected query result in page %d, property name 
'%s', got '%s', despite querying for > '%s'",
-                        (page - 1), propertyName, value, lastKey);
-                log.error(message);
-                throw new QueryImplementationException(message);
+                log.warn(
+                        "unexpected query result in page {}, property name 
'{}', got '{}', despite querying for > '{}'"
+                                + " (the async index may not yet reflect the 
current property value)",
+                        (page - 1),
+                        propertyName,
+                        value,
+                        lastKey);
             }
             if (lastValue != null && value.compareTo(lastValue) < 0) {
-                String message = String.format(
-                        "unexpected query result in page %d, property name 
'%s', got '%s', last value was '%s'",
-                        (page - 1), propertyName, value, lastValue);
-                log.error(message);
-                throw new QueryImplementationException(message);
+                log.warn(
+                        "unexpected query result in page {}, property name 
'{}', got '{}', last value was '{}'"
+                                + " (the async index may not yet reflect the 
current property value)",
+                        (page - 1),
+                        propertyName,
+                        value,
+                        lastValue);
             }
 
             // keep information about large key counts
@@ -178,13 +182,4 @@ public class PagedQueryIterator implements 
Iterator<Resource> {
             return "";
         }
     }
-
-    /**
-     * Thrown when the underlying repository misbehaves with respect to 
sorting on multivalued properties.
-     */
-    public static class QueryImplementationException extends RuntimeException {
-        public QueryImplementationException(String message) {
-            super(message);
-        }
-    }
 }
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIteratorTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIteratorTest.java
index 61e1cc5e..24ac0777 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIteratorTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/PagedQueryIteratorTest.java
@@ -86,31 +86,71 @@ public class PagedQueryIteratorTest extends 
AbstractMappingMapEntriesTest {
         assertEquals("", it.getWarning());
     }
 
-    @Test(expected = PagedQueryIterator.QueryImplementationException.class)
+    @Test
     public void testSimpleWrongOrder() {
+        // SLING-13284: out-of-order results (from a stale async index) should 
not abort iteration
         String[] expected = new String[] {"a", "b", "d", "c"};
         Collection<Resource> expectedResources = toResourceList(expected);
         when(resourceResolver.findResources(eq("testSimpleWrongOrder"), 
eq("JCR-SQL2")))
                 .thenReturn(expectedResources.iterator());
-        // incorrect sort order within a query page
-        Iterator<Resource> it =
+        PagedQueryIterator it =
                 new PagedQueryIterator("alias", PROPNAME, resourceResolver, 
"testSimpleWrongOrder", 2000);
-        while (it.hasNext()) {
-            it.next();
-        }
+        checkResult(it, expected);
     }
 
-    @Test(expected = PagedQueryIterator.QueryImplementationException.class)
+    @Test
     public void testSimpleWrongResultAfterKey() {
+        // SLING-13284: out-of-order results across page boundaries should not 
abort iteration
         String[] expected = new String[] {"x", "x", "a", "a"};
         Collection<Resource> expectedResources = toResourceList(expected);
         when(resourceResolver.findResources("testSimpleWrongOrder", 
"JCR-SQL2"))
                 .thenReturn(expectedResources.iterator());
-        // incorrect return value based on previous key
-        Iterator<Resource> it = new PagedQueryIterator("alias", PROPNAME, 
resourceResolver, "testSimpleWrongOrder", 1);
+        PagedQueryIterator it = new PagedQueryIterator("alias", PROPNAME, 
resourceResolver, "testSimpleWrongOrder", 1);
+        int count = 0;
+        while (it.hasNext()) {
+            it.next();
+            count++;
+        }
+        assertEquals(3, count);
+    }
+
+    @Test
+    public void testWrongResultBelowPageBoundary() {
+        // SLING-13284: a result on a new page has a value below the page 
boundary key.
+        // Page 1: ["b", "c"] with pageSize=1 — "c" triggers page break 
(lastKey="c").
+        // Page 2: returns "a" which is < lastKey "c" — must not abort.
+        Collection<Resource> page1 = toResourceList("b", "c");
+        Collection<Resource> page2 = toResourceList("a");
+        when(resourceResolver.findResources("boundary ''", 
"JCR-SQL2")).thenReturn(page1.iterator());
+        when(resourceResolver.findResources("boundary 'c'", 
"JCR-SQL2")).thenReturn(page2.iterator());
+
+        PagedQueryIterator it = new PagedQueryIterator("alias", PROPNAME, 
resourceResolver, "boundary '%s'", 1);
+        int count = 0;
+        while (it.hasNext()) {
+            it.next();
+            count++;
+        }
+        assertEquals(2, count);
+    }
+
+    @Test
+    public void testStaleAsyncIndexDoesNotAbortIteration() {
+        // SLING-13284: Reproduces the scenario where an async index delivers 
rows in an order
+        // that no longer matches the live property values (e.g. sling:alias 
was rewritten
+        // between the last index cycle and a restart). All rows must still be 
processed.
+        // The descending order simulates what happens when the index sorts by 
a stale
+        // first([sling:alias]) value that no longer matches the current 
values[0].
+        String[] staleOrder = new String[] {"ayacucho-fleeces", 
"ayacucho-bamboo", "ayacucho"};
+        Collection<Resource> resources = toResourceList(staleOrder);
+        when(resourceResolver.findResources("staleIndex", 
"JCR-SQL2")).thenReturn(resources.iterator());
+
+        PagedQueryIterator it = new PagedQueryIterator("alias", PROPNAME, 
resourceResolver, "staleIndex", 2000);
+        int count = 0;
         while (it.hasNext()) {
             it.next();
+            count++;
         }
+        assertEquals("all rows must be processed even when order doesn't 
match", 3, count);
     }
 
     @Test

Reply via email to