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 2882f522 SLING-12879: alias bg init add wiring to handler and test 
class (#191)
2882f522 is described below

commit 2882f522c80c778dc7fe188ee3cc05a4bf293af4
Author: Julian Reschke <[email protected]>
AuthorDate: Mon Aug 18 15:32:20 2025 +0200

    SLING-12879: alias bg init add wiring to handler and test class (#191)
---
 .../impl/CommonResourceResolverFactoryImpl.java    |   6 +
 .../impl/mapping/AliasHandler.java                 | 143 ++++++++++++---------
 .../impl/mapping/MapConfigurationProvider.java     |   4 +-
 .../impl/mapping/VanityPathHandler.java            |   2 +-
 .../impl/mapping/AliasMapEntriesTest.java          |  45 +++++--
 5 files changed, 126 insertions(+), 74 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
index 935fe244..3428e8c6 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
@@ -397,6 +397,12 @@ public class CommonResourceResolverFactoryImpl implements 
MapConfigurationProvid
         return 
this.activator.getVanityPathConfigurer().isVanityPathCacheInitInBackground();
     }
 
+    @Override
+    public boolean isAliasCacheInitInBackground() {
+        // wiring to config will be added later
+        return false;
+    }
+
     /**
      * get's the ServiceTracker of the ResourceAccessSecurity service
      */
diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/AliasHandler.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/AliasHandler.java
index 6b0e8d53..de9b3676 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/AliasHandler.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/AliasHandler.java
@@ -30,6 +30,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
@@ -88,6 +89,8 @@ class AliasHandler {
     final AtomicLong detectedConflictingAliases;
     final AtomicLong detectedInvalidAliases;
 
+    private final AtomicBoolean aliasesProcessed = new AtomicBoolean(false);
+
     public AliasHandler(
             @NotNull MapConfigurationProvider factory,
             @NotNull ReentrantLock initializing,
@@ -103,6 +106,10 @@ class AliasHandler {
         this.detectedInvalidAliases = new AtomicLong(0);
     }
 
+    public boolean isReady() {
+        return this.aliasesProcessed.get();
+    }
+
     public void dispose() {
         this.factory = null;
     }
@@ -126,10 +133,17 @@ class AliasHandler {
                 return;
             }
 
-            // optimization made in SLING-2521
+            aliasesProcessed.set(false);
+
             if (this.factory.isOptimizeAliasResolutionEnabled()) {
                 AliasInitializer ai = new AliasInitializer();
-                ai.run();
+                if (this.factory.isAliasCacheInitInBackground()) {
+                    this.log.debug("starting alias initialization in the 
background");
+                    Thread aiinit = new Thread(ai, "AliasInitializer");
+                    aiinit.start();
+                } else {
+                    ai.run();
+                }
             }
 
             doUpdateConfiguration.run();
@@ -151,30 +165,34 @@ class AliasHandler {
         }
 
         private void execute() {
-            try {
+            try (ResourceResolver resolver =
+                    
factory.getServiceResourceResolver(factory.getServiceUserAuthenticationInfo(SERVICE_USER)))
 {
                 List<String> conflictingAliases = new ArrayList<>();
                 List<String> invalidAliases = new ArrayList<>();
+                StringBuilder diagnostics = new StringBuilder();
 
-                aliasMapsMap = loadAliases(conflictingAliases, invalidAliases);
+                long initStart = System.nanoTime();
+                log.debug("alias initialization - start");
 
-                // warn if there are more than a few defunct aliases
-                if (conflictingAliases.size() >= MAX_REPORT_DEFUNCT_ALIASES) {
-                    log.warn(
-                            "There are {} conflicting aliases; excerpt: {}",
-                            conflictingAliases.size(),
-                            conflictingAliases);
-                } else if (!conflictingAliases.isEmpty()) {
-                    log.warn("There are {} conflicting aliases: {}", 
conflictingAliases.size(), conflictingAliases);
-                }
+                aliasMapsMap = loadAliases(resolver, conflictingAliases, 
invalidAliases, diagnostics);
 
-                if (invalidAliases.size() >= MAX_REPORT_DEFUNCT_ALIASES) {
-                    log.warn("There are {} invalid aliases; excerpt: {}", 
invalidAliases.size(), invalidAliases);
-                } else if (!invalidAliases.isEmpty()) {
-                    log.warn("There are {} invalid aliases: {}", 
invalidAliases.size(), invalidAliases);
-                }
-            } catch (Exception e) {
+                aliasesProcessed.set(true);
+
+                long processElapsed = System.nanoTime() - initStart;
+                long resourcePerSecond = (aliasResourcesOnStartup.get()
+                        * TimeUnit.SECONDS.toNanos(1)
+                        / (processElapsed == 0 ? 1 : processElapsed));
+                log.info(
+                        "alias initialization - completed, processed {} 
resources with sling:alias properties in {}ms (~{} resource/s){}",
+                        aliasResourcesOnStartup.get(),
+                        TimeUnit.NANOSECONDS.toMillis(processElapsed),
+                        resourcePerSecond,
+                        diagnostics);
+
+            } catch (Exception ex) {
+                log.error("Alias init failed", ex);
                 aliasMapsMap = UNITIALIZED_MAP;
-                logDisableAliasOptimization(e);
+                logDisableAliasOptimization(ex);
             }
         }
 
@@ -184,61 +202,60 @@ class AliasHandler {
          */
         @NotNull
         private Map<String, Map<String, Collection<String>>> loadAliases(
-                @Nullable List<String> conflictingAliases, @Nullable 
List<String> invalidAliases) {
+                @NotNull ResourceResolver resolver,
+                @Nullable List<String> conflictingAliases,
+                @Nullable List<String> invalidAliases,
+                @NotNull StringBuilder diagnostics) {
 
             Map<String, Map<String, Collection<String>>> map = new 
ConcurrentHashMap<>();
 
-            try (ResourceResolver resolver =
-                    
factory.getServiceResourceResolver(factory.getServiceUserAuthenticationInfo(SERVICE_USER)))
 {
-                String baseQueryString = generateAliasQuery();
-
-                Iterator<Resource> it;
-                try {
-                    String queryStringWithSort =
-                            baseQueryString + " AND FIRST([sling:alias]) >= 
'%s' ORDER BY FIRST([sling:alias])";
-                    it = new PagedQueryIterator("alias", "sling:alias", 
resolver, queryStringWithSort, 2000);
-                } catch (QuerySyntaxException ex) {
-                    log.debug("sort with first() not supported, falling back 
to base query", ex);
-                    it = queryUnpaged(baseQueryString, resolver);
-                } catch (UnsupportedOperationException ex) {
-                    log.debug("query failed as unsupported, retrying without 
paging/sorting", ex);
-                    it = queryUnpaged(baseQueryString, resolver);
-                }
+            String baseQueryString = generateAliasQuery();
 
-                log.debug("alias initialization - start");
-                long count = 0;
-                long processStart = System.nanoTime();
-                while (it.hasNext()) {
-                    count += 1;
-                    loadAlias(it.next(), map, conflictingAliases, 
invalidAliases);
-                }
-                long processElapsed = System.nanoTime() - processStart;
-                long resourcePerSecond =
-                        (count * TimeUnit.SECONDS.toNanos(1) / (processElapsed 
== 0 ? 1 : processElapsed));
+            Iterator<Resource> it;
+            try {
+                String queryStringWithSort =
+                        baseQueryString + " AND FIRST([sling:alias]) >= '%s' 
ORDER BY FIRST([sling:alias])";
+                it = new PagedQueryIterator("alias", "sling:alias", resolver, 
queryStringWithSort, 2000);
+            } catch (QuerySyntaxException ex) {
+                log.debug("sort with first() not supported, falling back to 
base query", ex);
+                it = queryUnpaged(baseQueryString, resolver);
+            } catch (UnsupportedOperationException ex) {
+                log.debug("query failed as unsupported, retrying without 
paging/sorting", ex);
+                it = queryUnpaged(baseQueryString, resolver);
+            }
 
-                String diagnostics = "";
-                if (it instanceof PagedQueryIterator) {
-                    PagedQueryIterator pit = (PagedQueryIterator) it;
+            long count = 0;
+            while (it.hasNext()) {
+                count += 1;
+                loadAlias(it.next(), map, conflictingAliases, invalidAliases);
+            }
 
-                    if (!pit.getWarning().isEmpty()) {
-                        log.warn(pit.getWarning());
-                    }
+            if (it instanceof PagedQueryIterator) {
+                PagedQueryIterator pit = (PagedQueryIterator) it;
 
-                    diagnostics = pit.getStatistics();
+                if (!pit.getWarning().isEmpty()) {
+                    log.warn(pit.getWarning());
                 }
 
-                log.info(
-                        "alias initialization - completed, processed {} 
resources with sling:alias properties in {}ms (~{} resource/s){}",
-                        count,
-                        TimeUnit.NANOSECONDS.toMillis(processElapsed),
-                        resourcePerSecond,
-                        diagnostics);
+                diagnostics.append(pit.getStatistics());
+            }
 
-                aliasResourcesOnStartup.set(count);
-            } catch (LoginException ex) {
-                log.error("Alias init failed", ex);
+            // warn if there are more than a few defunct aliases
+            if (conflictingAliases.size() >= MAX_REPORT_DEFUNCT_ALIASES) {
+                log.warn(
+                        "There are {} conflicting aliases; excerpt: {}", 
conflictingAliases.size(), conflictingAliases);
+            } else if (!conflictingAliases.isEmpty()) {
+                log.warn("There are {} conflicting aliases: {}", 
conflictingAliases.size(), conflictingAliases);
             }
 
+            if (invalidAliases.size() >= MAX_REPORT_DEFUNCT_ALIASES) {
+                log.warn("There are {} invalid aliases; excerpt: {}", 
invalidAliases.size(), invalidAliases);
+            } else if (!invalidAliases.isEmpty()) {
+                log.warn("There are {} invalid aliases: {}", 
invalidAliases.size(), invalidAliases);
+            }
+
+            aliasResourcesOnStartup.set(count);
+
             return map;
         }
 
diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapConfigurationProvider.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapConfigurationProvider.java
index b731aed6..aab6e86b 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapConfigurationProvider.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapConfigurationProvider.java
@@ -57,9 +57,11 @@ public interface MapConfigurationProvider extends 
ResourceResolverFactory {
 
     int getVanityBloomFilterMaxBytes();
 
+    boolean hasVanityPathPrecedence();
+
     boolean isOptimizeAliasResolutionEnabled();
 
-    boolean hasVanityPathPrecedence();
+    boolean isAliasCacheInitInBackground();
 
     Map<String, Object> getServiceUserAuthenticationInfo(final String 
subServiceName) throws LoginException;
 
diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
index f91a57db..95f8f6ed 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
@@ -129,7 +129,7 @@ public class VanityPathHandler {
                 VanityPathInitializer vpi = new 
VanityPathInitializer(this.factory);
 
                 if (this.factory.isVanityPathCacheInitInBackground()) {
-                    this.log.debug("bg init starting");
+                    this.log.debug("starting vanity path initialization in the 
background");
                     Thread vpinit = new Thread(vpi, "VanityPathInitializer");
                     vpinit.start();
                 } else {
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AliasMapEntriesTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AliasMapEntriesTest.java
index 4ec7eb39..8ac52f15 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AliasMapEntriesTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AliasMapEntriesTest.java
@@ -18,7 +18,6 @@
  */
 package org.apache.sling.resourceresolver.impl.mapping;
 
-import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -37,7 +36,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.QuerySyntaxException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
@@ -46,6 +44,7 @@ import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.resource.path.Path;
 import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
 import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
+import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
@@ -100,13 +99,17 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
 
     private final boolean isOptimizeAliasResolutionEnabled;
 
-    @Parameterized.Parameters(name = "isOptimizeAliasResolutionEnabled={0}")
+    private final boolean isAliasCacheInitInBackground;
+
+    @Parameterized.Parameters(name = 
"isOptimizeAliasResolutionEnabled={0},isAliasCacheInitInBackground{1}")
     public static Collection<Object[]> data() {
-        return List.of(new Object[][] {{false}, {true}});
+        // (optimized==false && backgroundInit == false) does not need to be 
tested
+        return List.of(new Object[][] {{false, false}, {true, false}, {true, 
true}});
     }
 
-    public AliasMapEntriesTest(boolean isOptimizeAliasResolutionEnabled) {
+    public AliasMapEntriesTest(boolean isOptimizeAliasResolutionEnabled, 
boolean isAliasCacheInitInBackground) {
         this.isOptimizeAliasResolutionEnabled = 
isOptimizeAliasResolutionEnabled;
+        this.isAliasCacheInitInBackground = isAliasCacheInitInBackground;
     }
 
     private AutoCloseable mockCloser;
@@ -124,6 +127,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         when(resourceResolverFactory.getObservationPaths()).thenReturn(new 
Path[] {new Path("/")});
         
when(resourceResolverFactory.getServiceResourceResolver(any(Map.class))).thenReturn(resourceResolver);
         
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(isOptimizeAliasResolutionEnabled);
+        
when(resourceResolverFactory.isAliasCacheInitInBackground()).thenReturn(isAliasCacheInitInBackground);
         
when(resourceResolverFactory.getMapRoot()).thenReturn(MapEntries.DEFAULT_MAP_ROOT);
 
         when(resourceResolver.findResources(anyString(), 
eq("sql"))).thenReturn(Collections.emptyIterator());
@@ -134,6 +138,8 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         mapEntries = new MapEntries(
                 resourceResolverFactory, bundleContext, eventAdmin, 
stringInterpolationProvider, metrics);
 
+        waitForBgInit();
+
         final Field aliasMapField = 
AliasHandler.class.getDeclaredField("aliasMapsMap");
         aliasMapField.setAccessible(true);
         this.aliasMap = (Map<String, Map<String, String>>) 
aliasMapField.get(mapEntries.ah);
@@ -154,6 +160,22 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         mockCloser.close();
     }
 
+    // wait for background thread to complete
+    private void waitForBgInit() {
+        if (this.isOptimizeAliasResolutionEnabled) {
+            long start = System.currentTimeMillis();
+            while (!mapEntries.ah.isReady()) {
+                // give up after five seconds
+                assertFalse("init should be done withing five seconds", 
System.currentTimeMillis() - start > 5000);
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    // ignored
+                }
+            }
+        }
+    }
+
     private static void addResource(MapEntries mapEntries, String path, 
AtomicBoolean bool)
             throws IllegalAccessException, NoSuchMethodException, 
InvocationTargetException {
         Method method = MapEntries.class.getDeclaredMethod("addResource", 
String.class, AtomicBoolean.class);
@@ -242,6 +264,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
 
         prepareMapEntriesForAlias(false, false, false, true, "foo", "bar");
         mapEntries.ah.initializeAliases();
+        waitForBgInit();
         assertTrue(mapEntries.ah.usesCache());
     }
 
@@ -270,6 +293,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         // invalid aliases filtered out
         prepareMapEntriesForAlias(false, false, "", "foo", ".", "bar", "x/y", 
"qux", " ");
         mapEntries.ah.initializeAliases();
+        waitForBgInit();
         Map<String, Collection<String>> aliasMap = 
mapEntries.getAliasMap("/parent");
         assertNotNull(aliasMap);
         assertTrue(aliasMap.containsKey("child"));
@@ -283,6 +307,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         for (String invalidAlias : invalidAliases) {
             prepareMapEntriesForAlias(false, false, invalidAlias);
             mapEntries.ah.initializeAliases();
+            waitForBgInit();
             Map<String, Collection<String>> aliasMap = 
mapEntries.getAliasMap("/parent");
             assertEquals(Collections.emptyMap(), aliasMap);
         }
@@ -369,6 +394,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
                 });
 
         mapEntries.ah.initializeAliases();
+        waitForBgInit();
 
         Map<String, Collection<String>> aliasMap = 
mapEntries.getAliasMap("/parent");
         assertNotNull(aliasMap);
@@ -403,7 +429,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
         Map<String, Collection<String>> parentAliasMap = 
mapEntries.getAliasMap("/parent");
         assertNotNull("alias map should never be null", parentAliasMap);
         assertTrue("should have entry for node 'node'", 
parentAliasMap.containsKey("node"));
-        List nodeAliases = List.of("alias", "contentalias");
+        List<@NotNull String> nodeAliases = List.of("alias", "contentalias");
         assertEquals(
                 "alias map " + parentAliasMap + " should have " + 
nodeAliases.size() + " entries",
                 nodeAliases.size(),
@@ -442,7 +468,7 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
     }
 
     @Test
-    public void test_allowed_locations_query() throws LoginException, 
IOException {
+    public void test_allowed_locations_query() {
         Assume.assumeTrue(
                 "allowed alias locations only processed in 'optimized' mode",
                 resourceResolverFactory.isOptimizeAliasResolutionEnabled());
@@ -458,9 +484,10 @@ public class AliasMapEntriesTest extends 
AbstractMappingMapEntriesTest {
                     return Collections.emptyIterator();
                 });
 
-        new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, 
stringInterpolationProvider, metrics);
+        mapEntries.ah.initializeAliases();
+        waitForBgInit();
 
-        assertTrue("seems no alias query was made", !queryMade.isEmpty());
+        assertFalse("seems no alias query was made", queryMade.isEmpty());
         String match1 = "(isdescendantnode('/a') OR 
isdescendantnode('/''b'''))";
         String match2 = "(isdescendantnode('/''b''') OR 
isdescendantnode('/a'))";
         String actual = queryMade.iterator().next();

Reply via email to