This is an automated email from the ASF dual-hosted git repository. sagarmiglani pushed a commit to branch SLING-13284-1.x in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
commit 268c5dddee737f1a72ad59fa8e6444bcf66e040b Author: Sagar Miglani <[email protected]> AuthorDate: Fri Jul 31 17:00:13 2026 +0530 SLING-13284 - Do not abort alias/vanity cache init on out-of-order query results The ordering check in PagedQueryIterator compared live property values (read from the repository) against the sort order delivered by an async Lucene index. Since async indexes are eventually consistent, their sort order can lag behind the current repository state after a property write. The previous behavior treated this lag as a fatal error and aborted the entire alias/vanity cache build, leaving alias resolution non-functional until a manual reindex + restart. Demote the two throws to log.warn and continue processing. The row contains a valid alias/vanity value that should be cached regardless of sort position. This also addresses the vanity-path variant (SLING-13248). --- .../impl/mapping/PagedQueryIterator.java | 24 +++++++------ .../impl/mapping/PagedQueryIteratorTest.java | 42 +++++++++++++++++----- 2 files changed, 47 insertions(+), 19 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..8a1239b0 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 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..7af9b43d 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,55 @@ 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); + while (it.hasNext()) { + it.next(); + } + } + + @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. + String[] indexOrder = new String[] {"ayacucho", "ayacucho-bamboo", "ayacucho-fleeces"}; + Collection<Resource> resources = toResourceList(indexOrder); + when(resourceResolver.findResources(eq("staleIndex"), eq("JCR-SQL2"))).thenReturn(resources.iterator()); + + // Simulate: index thinks order is ayacucho < ayacucho-bamboo < ayacucho-fleeces + // but the live values on the second node changed from "ayacucho-bamboo" to "aaa" + // (the index hasn't caught up). We model this by having the values already in the + // "wrong" order from the iterator's perspective: row 2 < row 1. + String[] staleOrder = new String[] {"ayacucho-fleeces", "ayacucho-bamboo", "ayacucho"}; + Collection<Resource> staleResources = toResourceList(staleOrder); + when(resourceResolver.findResources(eq("staleIndex"), eq("JCR-SQL2"))).thenReturn(staleResources.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
