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

nfsantos pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 1ceb9b13e2 OAK-11510 - Performance improvements to IndexDefinition 
class (#2108)
1ceb9b13e2 is described below

commit 1ceb9b13e2ec9c73afca6498630836df37d55e2e
Author: Nuno Santos <[email protected]>
AuthorDate: Fri Feb 28 13:42:50 2025 +0100

    OAK-11510 - Performance improvements to IndexDefinition class (#2108)
---
 .../oak/plugins/index/search/IndexDefinition.java  | 125 +++++++++++----------
 1 file changed, 63 insertions(+), 62 deletions(-)

diff --git 
a/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
 
b/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
index 55d02bd832..9ca458b323 100644
--- 
a/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
+++ 
b/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
@@ -19,7 +19,6 @@
 package org.apache.jackrabbit.oak.plugins.index.search;
 
 import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.guava.common.collect.ImmutableSet;
 import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.IllegalRepositoryStateException;
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -28,6 +27,7 @@ import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.commons.collections.IterableUtils;
+import org.apache.jackrabbit.oak.commons.collections.SetUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.search.util.ConfigUtil;
@@ -53,7 +53,6 @@ import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.NodeTypeIterator;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -61,6 +60,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.UUID;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
@@ -292,7 +292,6 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
     private final boolean suggestAnalyzed;
 
     private final SecureFacetConfiguration secureFacets;
-    private final long randomSeed;
 
     private final int numberOfTopFacets;
 
@@ -422,7 +421,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         this(root, getIndexDefinitionState(defn), 
determineIndexFormatVersion(defn), determineUniqueId(defn), indexPath);
     }
 
-    protected IndexDefinition(NodeState root, NodeState defn, 
IndexFormatVersion version, String uid, String indexPath) {
+    protected IndexDefinition(NodeState root, NodeState defn, 
IndexFormatVersion version, @Nullable String uid, String indexPath) {
         try {
             this.root = root;
             this.version = requireNonNull(version);
@@ -487,6 +486,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
             this.queryPaths = getOptionalValues(defn, 
IndexConstants.QUERY_PATHS, Type.STRINGS, String.class);
             this.suggestAnalyzed = evaluateSuggestAnalyzed(defn, false);
 
+            long randomSeed;
             {
                 PropertyState randomPS = defn.getProperty(PROP_RANDOM_SEED);
                 if (randomPS != null && randomPS.getType() == Type.LONG) {
@@ -679,7 +679,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
     }
 
     public String getTikaMappedMimeType(String type) {
-        return customTikaMimeTypeMappings.getOrDefault(type, type);
+        return type == null ? null : 
customTikaMimeTypeMappings.getOrDefault(type, type);
     }
 
     public String getIndexName() {
@@ -690,7 +690,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         return indexTags;
     }
 
-    public String getIndexSelectionPolicy() {
+    public @Nullable String getIndexSelectionPolicy() {
         return indexSelectionPolicy;
     }
 
@@ -827,7 +827,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
                 }
                 includes.add(new Aggregate.NodeInclude(this, primaryType, 
path, relativeNode));
             }
-            aggregateMap.put(nodeType, new Aggregate(nodeType, includes, 
recursionLimit));
+            aggregateMap.put(nodeType, new Aggregate(nodeType, 
List.copyOf(includes), recursionLimit));
         }
 
         return Map.copyOf(aggregateMap);
@@ -858,14 +858,11 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
     public IndexingRule getApplicableIndexingRule(String primaryNodeType) {
         //This method would be invoked for every node. So be as
         //conservative as possible in object creation
-        List<IndexingRule> rules = null;
-        List<IndexingRule> r = indexRules.get(primaryNodeType);
-        if (r != null) {
-            rules = new ArrayList<>(r);
-        }
-
+        List<IndexingRule> rules = indexRules.get(primaryNodeType);
         if (rules != null) {
-            for (IndexingRule rule : rules) {
+            // Used traversal with index to avoid creating iterator object.
+            for (int i = 0; i < rules.size(); i++) {
+                IndexingRule rule = rules.get(i);
                 if (rule.appliesTo(primaryNodeType)) {
                     return rule;
                 }
@@ -887,31 +884,34 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
     public IndexingRule getApplicableIndexingRule(NodeState state) {
         //This method would be invoked for every node. So be as
         //conservative as possible in object creation
-        List<IndexingRule> rules = null;
-        List<IndexingRule> r = indexRules.get(getPrimaryTypeName(state));
-        if (r != null) {
-            rules = new ArrayList<>(r);
+        List<IndexingRule> rules = indexRules.get(getPrimaryTypeName(state));
+        IndexingRule rule = getApplicableIndexingRule(state, rules);
+        if (rule != null) {
+            return rule;
         }
 
         for (String name : getMixinTypeNames(state)) {
-            r = indexRules.get(name);
-            if (r != null) {
-                if (rules == null) {
-                    rules = new ArrayList<>();
-                }
-                rules.addAll(r);
+            rules = indexRules.get(name);
+            rule = getApplicableIndexingRule(state, rules);
+            if (rule != null) {
+                return rule;
             }
         }
+        // no applicable rule
+        return null;
+    }
 
+    private IndexingRule getApplicableIndexingRule(NodeState state, @Nullable 
List<IndexingRule> rules) {
         if (rules != null) {
-            for (IndexingRule rule : rules) {
+            // Used traversal with index to avoid creating iterator object.
+            for (int i = 0; i < rules.size(); i++) {
+                IndexingRule rule = rules.get(i);
                 if (rule.appliesTo(state)) {
                     return rule;
                 }
             }
-        }
 
-        // no applicable rule
+        }
         return null;
     }
 
@@ -966,7 +966,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
 
     private boolean evaluateSuggestionEnabled() {
         for (IndexingRule indexingRule : definedRules) {
-            for (PropertyDefinition propertyDefinition : 
indexingRule.propConfigs.values()) {
+            for (PropertyDefinition propertyDefinition : 
indexingRule.propDefinitions) {
                 if (propertyDefinition.useInSuggest) {
                     return true;
                 }
@@ -994,7 +994,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
 
     private boolean evaluateSpellcheckEnabled() {
         for (IndexingRule indexingRule : definedRules) {
-            for (PropertyDefinition propertyDefinition : 
indexingRule.propConfigs.values()) {
+            for (PropertyDefinition propertyDefinition : 
indexingRule.propDefinitions) {
                 if (propertyDefinition.useInSpellcheck) {
                     return true;
                 }
@@ -1045,7 +1045,8 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         /**
          * Case-insensitive map of lower cased propertyName to propertyConfigs
          */
-        private final Map<String, PropertyDefinition> propConfigs;
+        private final TreeMap<String, PropertyDefinition> propConfigs;
+        private final List<PropertyDefinition> propDefinitions;
         /**
          * List of {@code NamePattern}s configured for this rule
          */
@@ -1086,6 +1087,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
             List<Aggregate.Include> propIncludes = new ArrayList<>();
             this.propConfigs = collectPropConfigs(config, namePatterns, 
propIncludes, nonExistentProperties,
                     existentProperties, nodeScopeAnalyzedProps, 
functionRestrictions, syncProps, similarityProperties);
+            this.propDefinitions = List.copyOf(propConfigs.values());
             this.propAggregate = new Aggregate(nodeTypeName, propIncludes);
             this.aggregate = combine(propAggregate, nodeTypeName);
 
@@ -1115,6 +1117,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
             this.nodeTypeName = nodeTypeName;
             this.baseNodeType = original.getNodeTypeName();
             this.propConfigs = original.propConfigs;
+            this.propDefinitions = original.propDefinitions;
             this.namePatterns = original.namePatterns;
             this.boost = original.boost;
             this.inherited = original.inherited;
@@ -1172,7 +1175,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
          * @see IndexDefinition#isPureNodeTypeIndex()
          */
         public Iterable<PropertyDefinition> getProperties() {
-            return propConfigs.values();
+            return propDefinitions;
         }
 
         public List<PropertyDefinition> getNullCheckEnabledProperties() {
@@ -1263,10 +1266,10 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
          */
         @Nullable
         public PropertyDefinition getConfig(String propertyName) {
-            PropertyDefinition config = 
propConfigs.get(propertyName.toLowerCase(Locale.ENGLISH));
+            PropertyDefinition config = propConfigs.get(propertyName);
             if (config != null) {
                 return config;
-            } else if (namePatterns.size() > 0) {
+            } else if (!namePatterns.isEmpty()) {
                 // check patterns
                 for (NamePattern np : namePatterns) {
                     if (np.matches(propertyName)) {
@@ -1302,16 +1305,16 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
             return JcrConstants.NT_BASE.equals(baseNodeType);
         }
 
-        private Map<String, PropertyDefinition> collectPropConfigs(NodeState 
config,
-                                                                   
List<NamePattern> patterns,
-                                                                   
List<Aggregate.Include> propAggregate,
-                                                                   
List<PropertyDefinition> nonExistentProperties,
-                                                                   
List<PropertyDefinition> existentProperties,
-                                                                   
List<PropertyDefinition> nodeScopeAnalyzedProps,
-                                                                   
List<PropertyDefinition> functionRestrictions,
-                                                                   
List<PropertyDefinition> syncProps,
-                                                                   
List<PropertyDefinition> similarityProperties) {
-            Map<String, PropertyDefinition> propDefns = new HashMap<>();
+        private TreeMap<String, PropertyDefinition> 
collectPropConfigs(NodeState config,
+                                                                       
List<NamePattern> patterns,
+                                                                       
List<Aggregate.Include> propAggregate,
+                                                                       
List<PropertyDefinition> nonExistentProperties,
+                                                                       
List<PropertyDefinition> existentProperties,
+                                                                       
List<PropertyDefinition> nodeScopeAnalyzedProps,
+                                                                       
List<PropertyDefinition> functionRestrictions,
+                                                                       
List<PropertyDefinition> syncProps,
+                                                                       
List<PropertyDefinition> similarityProperties) {
+            TreeMap<String, PropertyDefinition> propDefns = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
             NodeState propNode = 
config.getChildNode(FulltextIndexConstants.PROP_NODE);
 
             if (propNode.exists() && !hasOrderableChildren(propNode)) {
@@ -1326,8 +1329,8 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
                 PropertyDefinition pdpt = createNodeTypeDefinition(this, 
JcrConstants.JCR_PRIMARYTYPE, sync);
                 PropertyDefinition pdmixin = createNodeTypeDefinition(this, 
JcrConstants.JCR_MIXINTYPES, sync);
 
-                propDefns.put(pdpt.name.toLowerCase(Locale.ENGLISH), pdpt);
-                propDefns.put(pdmixin.name.toLowerCase(Locale.ENGLISH), 
pdmixin);
+                propDefns.put(pdpt.name, pdpt);
+                propDefns.put(pdmixin.name, pdmixin);
 
                 if (sync) {
                     syncProps.add(pdpt);
@@ -1339,7 +1342,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
                             "definitions", indexPath, 
FulltextIndexConstants.PROP_INDEX_NODE_TYPE);
                 }
 
-                return Map.copyOf(propDefns);
+                return propDefns;
             }
 
             //Include all immediate child nodes to 'properties' node by default
@@ -1364,7 +1367,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
                     if (pd.isRegexp) {
                         patterns.add(new NamePattern(pd.name, pd));
                     } else {
-                        propDefns.put(pd.name.toLowerCase(Locale.ENGLISH), pd);
+                        propDefns.put(pd.name, pd);
                     }
 
                     if (pd.relative) {
@@ -1395,27 +1398,27 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
                 }
             }
             ensureNodeTypeIndexingIsConsistent(propDefns, syncProps);
-            return Map.copyOf(propDefns);
+            return propDefns;
         }
 
         /**
          * If jcr:primaryType is indexed but jcr:mixinTypes is not indexed
          * then ensure that jcr:mixinTypes is also indexed
          */
-        private void ensureNodeTypeIndexingIsConsistent(Map<String, 
PropertyDefinition> propDefns,
+        private void ensureNodeTypeIndexingIsConsistent(TreeMap<String, 
PropertyDefinition> propDefns,
                                                         
List<PropertyDefinition> syncProps) {
-            PropertyDefinition pd_pr = 
propDefns.get(JcrConstants.JCR_PRIMARYTYPE.toLowerCase(Locale.ENGLISH));
-            PropertyDefinition pd_mixin = 
propDefns.get(JcrConstants.JCR_MIXINTYPES.toLowerCase(Locale.ENGLISH));
+            PropertyDefinition pd_pr = 
propDefns.get(JcrConstants.JCR_PRIMARYTYPE);
+            PropertyDefinition pd_mixin = 
propDefns.get(JcrConstants.JCR_MIXINTYPES);
 
             if (pd_pr != null && pd_pr.propertyIndex && pd_mixin == null) {
                 pd_mixin = createNodeTypeDefinition(this, 
JcrConstants.JCR_MIXINTYPES, pd_pr.sync);
                 syncProps.add(pd_mixin);
-                
propDefns.put(JcrConstants.JCR_MIXINTYPES.toLowerCase(Locale.ENGLISH), 
pd_mixin);
+                propDefns.put(JcrConstants.JCR_MIXINTYPES, pd_mixin);
             }
         }
 
         private boolean hasAnyFullTextEnabledProperty() {
-            for (PropertyDefinition pd : propConfigs.values()) {
+            for (PropertyDefinition pd : propDefinitions) {
                 if (pd.fulltextEnabled()) {
                     return true;
                 }
@@ -1430,7 +1433,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         }
 
         private boolean hasAnyPropertyIndexConfigured() {
-            for (PropertyDefinition pd : propConfigs.values()) {
+            for (PropertyDefinition pd : propDefinitions) {
                 if (pd.propertyIndex) {
                     return true;
                 }
@@ -1447,7 +1450,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         private boolean anyNodeScopeIndexedProperty() {
             //Check if there is any nodeScope indexed property as
             //for such case a node would always be indexed
-            for (PropertyDefinition pd : propConfigs.values()) {
+            for (PropertyDefinition pd : propDefinitions) {
                 if (pd.nodeScopeIndex) {
                     return true;
                 }
@@ -1494,7 +1497,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
             }
 
             //iterate over property definitions
-            for (PropertyDefinition pd : propConfigs.values()) {
+            for (PropertyDefinition pd : propDefinitions) {
                 if 
(FulltextIndexConstants.PROPDEF_PROP_NODE_NAME.equals(pd.name)) {
                     return true;
                 }
@@ -1739,7 +1742,7 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
 
     private static Set<String> getMultiProperty(NodeState definition, String 
propName) {
         PropertyState pse = definition.getProperty(propName);
-        return pse != null ? ImmutableSet.copyOf(pse.getValue(Type.STRINGS)) : 
Set.of();
+        return pse != null ? 
Set.copyOf(SetUtils.toSet(pse.getValue(Type.STRINGS))) : Set.of();
     }
 
     private static Set<String> toLowerCase(Set<String> values) {
@@ -1956,16 +1959,14 @@ public class IndexDefinition implements 
Aggregate.AggregateMapper {
         Map<String, String> map = new HashMap<>();
         for (ChildNodeEntry child : node.getChildNodeEntries()) {
             for (ChildNodeEntry subChild : 
child.getNodeState().getChildNodeEntries()) {
-                StringBuilder typeBuilder = new StringBuilder(child.getName())
-                        .append('/')
-                        .append(subChild.getName());
                 PropertyState property = 
subChild.getNodeState().getProperty(TIKA_MAPPED_TYPE);
                 if (property != null) {
-                    map.put(typeBuilder.toString(), 
property.getValue(Type.STRING));
+                    String subChildPath = child.getName() + "/" + 
subChild.getName();
+                    map.put(subChildPath, property.getValue(Type.STRING));
                 }
             }
         }
-        return Collections.unmodifiableMap(map);
+        return Map.copyOf(map);
     }
 
     private PropertyDefinition createNodeTypeDefinition(IndexingRule rule, 
String name, boolean sync) {

Reply via email to