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