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

abhay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 92890a1  RANGER-3107: Optimize memory requirements for storing 
Tag/Policy/Zone trie - Trade-off processing time for memory
92890a1 is described below

commit 92890a199d2957e0849cab4b099847dc90958bba
Author: Abhay Kulkarni <[email protected]>
AuthorDate: Tue Dec 8 10:40:24 2020 -0800

    RANGER-3107: Optimize memory requirements for storing Tag/Policy/Zone trie 
- Trade-off processing time for memory
---
 .../plugin/contextenricher/RangerTagEnricher.java  |  95 +++++++++++--------
 .../validation/RangerSecurityZoneValidator.java    | 105 ++++++++++++---------
 .../model/validation/RangerServiceDefHelper.java   |  73 ++++++++++++++
 .../ranger/plugin/policyengine/PolicyEngine.java   |  93 +++++++++---------
 .../policyengine/RangerPolicyRepository.java       |  96 ++++++++++---------
 .../plugin/policyengine/RangerResourceTrie.java    |  45 +++++++--
 .../plugin/contextenricher/TestTagEnricher.java    |   1 +
 .../policyengine/TestPolicyEngineComparison.java   |   4 +
 8 files changed, 324 insertions(+), 188 deletions(-)

diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
index d1afd6f..f31b2c5 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
@@ -85,6 +85,8 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
        private final BlockingQueue<DownloadTrigger> tagDownloadQueue = new 
LinkedBlockingQueue<>();
        private Timer                              tagDownloadTimer;
 
+       private RangerServiceDefHelper             serviceDefHelper;
+
        @Override
        public void init() {
                if (LOG.isDebugEnabled()) {
@@ -99,6 +101,8 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
 
                disableTrieLookupPrefilter = 
getBooleanOption(TAG_DISABLE_TRIE_PREFILTER_OPTION, false);
 
+               serviceDefHelper = new RangerServiceDefHelper(serviceDef, 
false);
+
                if (StringUtils.isNotBlank(tagRetrieverClassName)) {
 
                        try {
@@ -366,7 +370,6 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
                        enrichedServiceTags = null;
                } else {
 
-                       RangerServiceDefHelper serviceDefHelper = new 
RangerServiceDefHelper(serviceDef, false);
                        ResourceHierarchies    hierarchies      = new 
ResourceHierarchies();
 
                        List<RangerServiceResourceMatcher> resourceMatchers = 
new ArrayList<>();
@@ -408,7 +411,6 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
 
                boolean isInError = false;
 
-               RangerServiceDefHelper serviceDefHelper = new 
RangerServiceDefHelper(serviceDef, false);
                ResourceHierarchies    hierarchies      = new 
ResourceHierarchies();
 
                List<RangerServiceResourceMatcher>                            
resourceMatchers    = new ArrayList<>();
@@ -506,8 +508,11 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
 
                        for (RangerServiceResourceMatcher matcher : 
oldMatchers) {
 
-                               for (String resourceDefName : 
serviceResource.getResourceElements().keySet()) {
+                               for (RangerServiceDef.RangerResourceDef 
resourceDef : serviceDef.getResources()) {
+                                       String resourceDefName = 
resourceDef.getName();
+
                                        
RangerResourceTrie<RangerServiceResourceMatcher> trie = 
resourceTries.get(resourceDefName);
+
                                        if (trie != null) {
                                                
trie.delete(serviceResource.getResourceElements().get(resourceDefName), 
matcher);
                                        } else {
@@ -673,16 +678,13 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
                if (resource == null || resource.getKeys() == null || 
resource.getKeys().isEmpty() || serviceResourceTrie == null) {
                        ret = enrichedServiceTags.getServiceResourceMatchers();
                } else {
-                       Set<RangerServiceResourceMatcher> evaluators = null;
-
                        RangerPerfTracer perf = null;
 
                        if 
(RangerPerfTracer.isPerfTraceEnabled(PERF_TRIE_OP_LOG)) {
                                perf = 
RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, 
"RangerTagEnricher.getEvaluators(resource=" + resource.getAsString() + ")");
                        }
 
-                       Set<String>                             resourceKeys = 
resource.getKeys();
-                       List<Set<RangerServiceResourceMatcher>> 
serviceResourceMatchersList = null;
+                       List<String>                            resourceKeys = 
serviceDefHelper.getOrderedResourceNames(resource.getKeys());
                        Set<RangerServiceResourceMatcher>       smallestList = 
null;
 
                        if (CollectionUtils.isNotEmpty(resourceKeys)) {
@@ -694,47 +696,58 @@ public class RangerTagEnricher extends 
RangerAbstractContextEnricher {
                                                continue;
                                        }
 
-                                       Set<RangerServiceResourceMatcher> 
serviceResourceMatchers = 
trie.getEvaluatorsForResource(resource.getValue(resourceName));
-
-                                       if 
(CollectionUtils.isEmpty(serviceResourceMatchers)) { // no tags for this 
resource, bail out
-                                               serviceResourceMatchersList = 
null;
-                                               smallestList = null;
-                                               break;
-                                       }
-
-                                       if (smallestList == null) {
-                                               smallestList = 
serviceResourceMatchers;
-                                       } else {
-                                               if (serviceResourceMatchersList 
== null) {
-                                                       
serviceResourceMatchersList = new ArrayList<>();
-                                                       
serviceResourceMatchersList.add(smallestList);
+                                       Set<RangerServiceResourceMatcher> 
serviceResourceMatchersForResource = 
trie.getEvaluatorsForResource(resource.getValue(resourceName));
+                                       Set<RangerServiceResourceMatcher> 
inheritedResourceMatchers = trie.getInheritedEvaluators();
+
+                                       if (smallestList != null) {
+                                               if 
(CollectionUtils.isEmpty(inheritedResourceMatchers) && 
CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                                                       smallestList = null;
+                                               } else if 
(CollectionUtils.isEmpty(inheritedResourceMatchers)) {
+                                                       
smallestList.retainAll(serviceResourceMatchersForResource);
+                                               } else if 
(CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                                                       
smallestList.retainAll(inheritedResourceMatchers);
+                                               } else {
+                                                       
Set<RangerServiceResourceMatcher> smaller, bigger;
+                                                       if 
(serviceResourceMatchersForResource.size() < inheritedResourceMatchers.size()) {
+                                                               smaller = 
serviceResourceMatchersForResource;
+                                                               bigger = 
inheritedResourceMatchers;
+                                                       } else {
+                                                               smaller = 
inheritedResourceMatchers;
+                                                               bigger = 
serviceResourceMatchersForResource;
+                                                       }
+                                                       
Set<RangerServiceResourceMatcher> tmp = new HashSet<>();
+                                                       if (smallestList.size() 
< smaller.size()) {
+                                                               
smallestList.stream().filter(smaller::contains).forEach(tmp::add);
+                                                               
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                                                       } else {
+                                                               
smaller.stream().filter(smallestList::contains).forEach(tmp::add);
+                                                               if 
(smallestList.size() < bigger.size()) {
+                                                                       
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                                                               } else {
+                                                                       
bigger.stream().filter(smallestList::contains).forEach(tmp::add);
+                                                               }
+                                                       }
+                                                       smallestList = tmp;
                                                }
-                                               
serviceResourceMatchersList.add(serviceResourceMatchers);
-
-                                               if (smallestList.size() > 
serviceResourceMatchers.size()) {
-                                                       smallestList = 
serviceResourceMatchers;
+                                       } else {
+                                               if 
(CollectionUtils.isEmpty(inheritedResourceMatchers) || 
CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                                                       
Set<RangerServiceResourceMatcher> tmp = 
CollectionUtils.isEmpty(inheritedResourceMatchers) ? 
serviceResourceMatchersForResource : inheritedResourceMatchers;
+                                                       smallestList = 
resourceKeys.size() == 1 || CollectionUtils.isEmpty(tmp) ? tmp : new 
HashSet<>(tmp);
+                                               } else {
+                                                       smallestList = new 
HashSet<>(serviceResourceMatchersForResource);
+                                                       
smallestList.addAll(inheritedResourceMatchers);
                                                }
                                        }
-                               }
-                               if (serviceResourceMatchersList != null) {
-                                       evaluators = new 
HashSet<>(smallestList);
-                                       for (Set<RangerServiceResourceMatcher> 
serviceResourceMatchers : serviceResourceMatchersList) {
-                                               if (serviceResourceMatchers != 
smallestList) {
-                                                       // remove other 
serviceResourceMatchers from ret that are not in serviceResourceMatchers
-                                                       
evaluators.retainAll(serviceResourceMatchers);
-                                                       if 
(CollectionUtils.isEmpty(evaluators)) { // if no policy exists, bail out and 
return empty list
-                                                               evaluators = 
null;
-                                                               break;
-                                                       }
-                                               }
+
+                                       if 
(CollectionUtils.isEmpty(smallestList)) {// no tags for this resource, bail out
+                                               smallestList = null;
+                                               break;
                                        }
-                               } else {
-                                       evaluators = smallestList;
                                }
                        }
 
-                       if (evaluators != null) {
-                               ret = new ArrayList<>(evaluators);
+                       if (smallestList != null) {
+                               ret = new ArrayList<>(smallestList);
                        }
 
                        RangerPerfTracer.logAlways(perf);
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
index 2db2f22..0c2dcee 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
@@ -247,17 +247,17 @@ public class RangerSecurityZoneValidator extends 
RangerValidator {
         }
 
         if (securityZone.getServices() != null) {
-                       for (Map.Entry<String, RangerSecurityZoneService> 
serviceResouceMapEntry : securityZone.getServices()
+                       for (Map.Entry<String, RangerSecurityZoneService> 
serviceResourceMapEntry : securityZone.getServices()
                                        .entrySet()) {
-                               if 
(serviceResouceMapEntry.getValue().getResources() != null) {
-                                       for (Map<String, List<String>> resource 
: serviceResouceMapEntry.getValue().getResources()) {
+                               if 
(serviceResourceMapEntry.getValue().getResources() != null) {
+                                       for (Map<String, List<String>> resource 
: serviceResourceMapEntry.getValue().getResources()) {
                                                if (resource != null) {
                                                        for (Map.Entry<String, 
List<String>> entry : resource.entrySet()) {
                                                                if 
(CollectionUtils.isEmpty(entry.getValue())) {
                                                                        
ValidationErrorCode error = 
ValidationErrorCode.SECURITY_ZONE_VALIDATION_ERR_MISSING_RESOURCES;
                                                                        
failures.add(new ValidationFailureDetailsBuilder().field("security zone 
resources")
                                                                                
        .subField("resources").isMissing()
-                                                                               
        .becauseOf(error.getMessage(serviceResouceMapEntry.getKey()))
+                                                                               
        .becauseOf(error.getMessage(serviceResourceMapEntry.getKey()))
                                                                                
        .errorCode(error.getErrorCode()).build());
                                                                        ret = 
false;
                                                                }
@@ -406,70 +406,81 @@ public class RangerSecurityZoneValidator extends 
RangerValidator {
         //       check each evaluator to see if the resource-match actually 
happens. If yes then add the zone-evaluator to matching evaluators.
         //       flag error if there are more than one matching evaluators 
with different zone-ids.
         //
+
+        RangerServiceDefHelper serviceDefHelper = new 
RangerServiceDefHelper(serviceDef, true);
+
         for (RangerSecurityZone zone : zones) {
             List<HashMap<String, List<String>>> resources = 
zone.getServices().get(serviceName).getResources();
 
             for (Map<String, List<String>> resource : resources) {
 
-                List<Set<RangerZoneResourceMatcher>> zoneMatchersList = null;
                 Set<RangerZoneResourceMatcher>       smallestList     = null;
 
-                for (Map.Entry<String, List<String>> entry : 
resource.entrySet()) {
-                    String       resourceDefName = entry.getKey();
-                    List<String> resourceValues  = entry.getValue();
+                List<String> resourceKeys = 
serviceDefHelper.getOrderedResourceNames(resource.keySet());
 
-                    RangerResourceTrie<RangerZoneResourceMatcher> trie         
= trieMap.get(resourceDefName);
-                    Set<RangerZoneResourceMatcher>               matchedZones 
= trie.getEvaluatorsForResource(resourceValues);
+                for (String resourceDefName : resourceKeys) {
+                    List<String> resourceValues = 
resource.get(resourceDefName);
 
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("ResourceDefName:[" + resourceDefName +"], 
values:[" + resourceValues +"], matched-zones:[" + matchedZones +"]");
-                    }
-                    if (CollectionUtils.isEmpty(matchedZones)) { // no 
policies for this resource, bail out
-                        zoneMatchersList = null;
-                        smallestList     = null;
-                        break;
-                    }
+                    RangerResourceTrie<RangerZoneResourceMatcher> trie = 
trieMap.get(resourceDefName);
 
-                    if (smallestList == null) {
-                        smallestList = matchedZones;
-                    } else {
-                        if (zoneMatchersList == null) {
-                            zoneMatchersList = new ArrayList<>();
-                            zoneMatchersList.add(smallestList);
-                        }
-                        zoneMatchersList.add(matchedZones);
+                    Set<RangerZoneResourceMatcher> zoneMatchersForResource = 
trie.getEvaluatorsForResource(resourceValues);
+                    Set<RangerZoneResourceMatcher> inheritedZoneMatchers = 
trie.getInheritedEvaluators();
 
-                        if (smallestList.size() > matchedZones.size()) {
-                            smallestList = matchedZones;
-                        }
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("ResourceDefName:[" + resourceDefName + "], 
values:[" + resourceValues + "], matched-zones:[" + zoneMatchersForResource + 
"], inherited-zones:[" + inheritedZoneMatchers + "]");
                     }
-                }
-                if (smallestList == null) {
-                    continue;
-                }
-                final Set<RangerZoneResourceMatcher> intersection;
-
-                if (zoneMatchersList != null) {
-                    intersection = new HashSet<>(smallestList);
-                    for (Set<RangerZoneResourceMatcher> zoneMatchers : 
zoneMatchersList) {
-                        if (zoneMatchers != smallestList) {
-                            // remove zones from intersection that are not in 
zoneMatchers
-                            intersection.retainAll(zoneMatchers);
-                            if (CollectionUtils.isEmpty(intersection)) { // if 
no zoneMatcher exists, bail out and return empty list
-                                break;
+
+                    if (smallestList != null) {
+                        if (CollectionUtils.isEmpty(inheritedZoneMatchers) && 
CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                            smallestList = null;
+                        } else if 
(CollectionUtils.isEmpty(inheritedZoneMatchers)) {
+                            smallestList.retainAll(zoneMatchersForResource);
+                        } else if 
(CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                            smallestList.retainAll(inheritedZoneMatchers);
+                        } else {
+                            Set<RangerZoneResourceMatcher> smaller, bigger;
+                            if (zoneMatchersForResource.size() < 
inheritedZoneMatchers.size()) {
+                                smaller = zoneMatchersForResource;
+                                bigger = inheritedZoneMatchers;
+                            } else {
+                                smaller = inheritedZoneMatchers;
+                                bigger = zoneMatchersForResource;
+                            }
+                            Set<RangerZoneResourceMatcher> tmp = new 
HashSet<>();
+                            if (smallestList.size() < smaller.size()) {
+                                
smallestList.stream().filter(smaller::contains).forEach(tmp::add);
+                                
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                            } else {
+                                
smaller.stream().filter(smallestList::contains).forEach(tmp::add);
+                                if (smallestList.size() < bigger.size()) {
+                                    
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                                } else {
+                                    
bigger.stream().filter(smallestList::contains).forEach(tmp::add);
+                                }
                             }
+                            smallestList = tmp;
+                        }
+                    } else {
+                        if (CollectionUtils.isEmpty(inheritedZoneMatchers) || 
CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                            Set<RangerZoneResourceMatcher> tmp = 
CollectionUtils.isEmpty(inheritedZoneMatchers) ? zoneMatchersForResource : 
inheritedZoneMatchers;
+                            smallestList = resourceKeys.size() == 1 || 
CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
+                        } else {
+                            smallestList = new 
HashSet<>(zoneMatchersForResource);
+                            smallestList.addAll(inheritedZoneMatchers);
                         }
                     }
-                } else {
-                    intersection = smallestList;
                 }
+
                 if (LOG.isDebugEnabled()) {
-                    LOG.debug("Resource:[" + resource +"], matched-zones:[" + 
intersection +"]");
+                    LOG.debug("Resource:[" + resource +"], matched-zones:[" + 
smallestList +"]");
                 }
-                if (intersection.size() <= 1) {
+
+                if (CollectionUtils.isEmpty(smallestList) || 
smallestList.size() == 1) {
                     continue;
                 }
 
+                final Set<RangerZoneResourceMatcher> intersection = 
smallestList;
+
                 RangerAccessResourceImpl accessResource = new 
RangerAccessResourceImpl();
 
                 accessResource.setServiceDef(serviceDef);
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java
index bbcf82f..33ec2d8 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java
@@ -289,6 +289,24 @@ public class RangerServiceDefHelper {
                return _delegate.isResourceGraphValid();
        }
 
+       public List<String> getOrderedResourceNames(Collection<String> 
resourceNames) {
+               final List<String> ret;
+               if (resourceNames != null) {
+                       ret = new ArrayList<>();
+                       for (String orderedName : 
_delegate.getAllOrderedResourceNames()) {
+                               for (String resourceName : resourceNames) {
+                                       if (StringUtils.equals(orderedName, 
resourceName) && !ret.contains(resourceName)) {
+                                               ret.add(resourceName);
+                                               break;
+                                       }
+                               }
+                       }
+               } else {
+                       ret = Collections.EMPTY_LIST;
+               }
+               return ret;
+       }
+
        /**
         * Not designed for public access.  Package level only for testability.
         */
@@ -299,6 +317,7 @@ public class RangerServiceDefHelper {
                final String _serviceName;
                final boolean _checkForCycles;
                final boolean _valid;
+               final List<String> _orderedResourceNames;
                final static Set<List<RangerResourceDef>> 
EMPTY_RESOURCE_HIERARCHY = Collections.unmodifiableSet(new 
HashSet<List<RangerResourceDef>>());
 
 
@@ -327,6 +346,13 @@ public class RangerServiceDefHelper {
                                        _hierarchies.put(policyType, 
EMPTY_RESOURCE_HIERARCHY);
                                }
                        }
+
+                       if (isValid) {
+                               _orderedResourceNames = 
buildSortedResourceNames();
+                       } else {
+                               _orderedResourceNames = new ArrayList<>();
+                       }
+
                        _valid = isValid;
                        if (LOG.isDebugEnabled()) {
                                String message = String.format("Found [%d] 
resource hierarchies for service [%s] update-date[%s]: %s", 
_hierarchies.size(), _serviceName,
@@ -537,6 +563,53 @@ public class RangerServiceDefHelper {
                        }
                        return map;
                }
+
+               List<String> getAllOrderedResourceNames() {
+                       return this._orderedResourceNames;
+               }
+
+               private static class ResourceNameLevel implements 
Comparable<ResourceNameLevel> {
+                       private String resourceName;
+                       private int    level;
+
+                       ResourceNameLevel(String resourceName, int level) {
+                               this.resourceName = resourceName;
+                               this.level        = level;
+                       }
+
+                       @Override
+                       public int compareTo(ResourceNameLevel other) {
+                               return Integer.compare(this.level, other.level);
+                       }
+               }
+
+               private List<String> buildSortedResourceNames() {
+                       final List<String> ret = new ArrayList<>();
+
+                       boolean isValid = true;
+                       List<ResourceNameLevel> resourceNameLevels = new 
ArrayList<>();
+                       for (RangerResourceDef resourceDef : 
_serviceDef.getResources()) {
+                               String name = resourceDef.getName();
+                               Integer level = resourceDef.getLevel();
+                               if (name != null && level != null) {
+                                       ResourceNameLevel resourceNameLevel = 
new ResourceNameLevel(name, level);
+                                       
resourceNameLevels.add(resourceNameLevel);
+                               } else {
+                                       LOG.error("Incorrect 
resourceDef:[name=" + name + "]");
+                                       isValid = false;
+                                       break;
+                               }
+                       }
+
+                       if (isValid) {
+                               Collections.sort(resourceNameLevels);
+
+                               for (ResourceNameLevel resourceNameLevel : 
resourceNameLevels) {
+                                       ret.add(resourceNameLevel.resourceName);
+                               }
+                       }
+                       return ret;
+               }
        }
 
        /**
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
index 2742312..1909ad4 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
@@ -37,6 +37,7 @@ import 
org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicyDelta;
 import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
 import org.apache.ranger.plugin.model.validation.RangerZoneResourceMatcher;
 import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
 import 
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
@@ -437,66 +438,70 @@ public class PolicyEngine {
         Set<String> ret = null;
 
         if (MapUtils.isNotEmpty(this.resourceZoneTrie)) {
-            List<Set<RangerZoneResourceMatcher>> zoneMatchersList = null;
             Set<RangerZoneResourceMatcher>       smallestList     = null;
+            RangerServiceDefHelper               serviceDefHelper = 
policyRepository.getOptions().getServiceDefHelper();
 
-            for (Map.Entry<String, ?> entry : resource.entrySet()) {
-                String                                        resourceDefName 
= entry.getKey();
-                Object                                        resourceValues  
= entry.getValue();
-                RangerResourceTrie<RangerZoneResourceMatcher> trie            
= resourceZoneTrie.get(resourceDefName);
+            List<String> resourceKeys = resource == null ? new ArrayList<>() : 
serviceDefHelper.getOrderedResourceNames(resource.keySet());
+
+            for (String resourceDefName : resourceKeys) {
+                RangerResourceTrie<RangerZoneResourceMatcher> trie = 
resourceZoneTrie.get(resourceDefName);
 
                 if (trie == null) {
                     continue;
                 }
 
-                Set<RangerZoneResourceMatcher> matchedZones = 
trie.getEvaluatorsForResource(resourceValues);
-
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug("ResourceDefName:[" + resourceDefName + "], 
values:[" + resourceValues + "], matched-zones:[" + matchedZones + "]");
-                }
+                Object resourceValues = resource.get(resourceDefName);
 
-                if (CollectionUtils.isEmpty(matchedZones)) { // no policies 
for this resource, bail out
-                    zoneMatchersList = null;
-                    smallestList     = null;
+                Set<RangerZoneResourceMatcher> zoneMatchersForResource = 
trie.getEvaluatorsForResource(resourceValues);
+                Set<RangerZoneResourceMatcher> inheritedZoneMatchers = 
trie.getInheritedEvaluators();
 
-                    break;
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("ResourceDefName:[" + resourceDefName + "], 
values:[" + resourceValues + "], matched-zones:[" + zoneMatchersForResource + 
"], inherited-zones:[" + inheritedZoneMatchers + "]");
                 }
 
-                if (smallestList == null) {
-                    smallestList = matchedZones;
-                } else {
-                    if (zoneMatchersList == null) {
-                        zoneMatchersList = new ArrayList<>();
-
-                        zoneMatchersList.add(smallestList);
-                    }
-
-                    zoneMatchersList.add(matchedZones);
-
-                    if (smallestList.size() > matchedZones.size()) {
-                        smallestList = matchedZones;
-                    }
-                }
-            }
-            if (smallestList != null) {
-                final Set<RangerZoneResourceMatcher> intersection;
-
-                if (zoneMatchersList != null) {
-                    intersection = new HashSet<>(smallestList);
-
-                    for (Set<RangerZoneResourceMatcher> zoneMatchers : 
zoneMatchersList) {
-                        if (zoneMatchers != smallestList) {
-                            // remove zones from intersection that are not in 
zoneMatchers
-                            intersection.retainAll(zoneMatchers);
-
-                            if (CollectionUtils.isEmpty(intersection)) { // if 
no zoneMatcher exists, bail out and return empty list
-                                break;
+                if (smallestList != null) {
+                    if (CollectionUtils.isEmpty(inheritedZoneMatchers) && 
CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                        smallestList = null;
+                    } else if (CollectionUtils.isEmpty(inheritedZoneMatchers)) 
{
+                        smallestList.retainAll(zoneMatchersForResource);
+                    } else if 
(CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                        smallestList.retainAll(inheritedZoneMatchers);
+                    } else {
+                        Set<RangerZoneResourceMatcher> smaller, bigger;
+                        if (zoneMatchersForResource.size() < 
inheritedZoneMatchers.size()) {
+                            smaller = zoneMatchersForResource;
+                            bigger = inheritedZoneMatchers;
+                        } else {
+                            smaller = inheritedZoneMatchers;
+                            bigger = zoneMatchersForResource;
+                        }
+                        Set<RangerZoneResourceMatcher> tmp = new HashSet<>();
+                        if (smallestList.size() < smaller.size()) {
+                            
smallestList.stream().filter(smaller::contains).forEach(tmp::add);
+                            
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                        } else {
+                            
smaller.stream().filter(smallestList::contains).forEach(tmp::add);
+                            if (smallestList.size() < bigger.size()) {
+                                
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                            } else {
+                                
bigger.stream().filter(smallestList::contains).forEach(tmp::add);
                             }
                         }
+                        smallestList = tmp;
                     }
                 } else {
-                    intersection = smallestList;
+                    if (CollectionUtils.isEmpty(inheritedZoneMatchers) || 
CollectionUtils.isEmpty(zoneMatchersForResource)) {
+                        Set<RangerZoneResourceMatcher> tmp = 
CollectionUtils.isEmpty(inheritedZoneMatchers) ? zoneMatchersForResource : 
inheritedZoneMatchers;
+                        smallestList = resourceKeys.size() == 1 || 
CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
+                    } else {
+                        smallestList = new HashSet<>(zoneMatchersForResource);
+                        smallestList.addAll(inheritedZoneMatchers);
+                    }
                 }
+            }
+
+            if (CollectionUtils.isNotEmpty(smallestList)) {
+                final Set<RangerZoneResourceMatcher> intersection = 
smallestList;
 
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Resource:[" + resource + "], matched-zones:[" + 
intersection + "]");
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
index ffbd908..2655103 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
@@ -790,64 +790,71 @@ public class RangerPolicyRepository {
             perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, 
"RangerPolicyRepository.getLikelyMatchEvaluators(resource=" + 
resource.getAsString() + ")");
         }
 
-        Set<String>                 resourceKeys = resource == null ? null : 
resource.getKeys();
+        List<String>                     resourceKeys = resource == null ? 
null : 
options.getServiceDefHelper().getOrderedResourceNames(resource.getKeys());
+        Set<RangerPolicyEvaluator>       smallestList = null;
 
-        if(CollectionUtils.isNotEmpty(resourceKeys)) {
-            Set<RangerPolicyEvaluator>       evaluators = null;
-            List<Set<RangerPolicyEvaluator>> resourceEvaluatorsSet = null;
-            Set<RangerPolicyEvaluator>       smallestSet = null;
+        if (CollectionUtils.isNotEmpty(resourceKeys)) {
 
             for (String resourceName : resourceKeys) {
-                RangerResourceTrie trie = resourceTrie.get(resourceName);
+                RangerResourceTrie<RangerPolicyEvaluator> trie = 
resourceTrie.get(resourceName);
 
                 if (trie == null) { // if no trie exists for this resource 
level, ignore and continue to next level
                     continue;
                 }
 
-                Set<RangerPolicyEvaluator> resourceEvaluators = 
trie.getEvaluatorsForResource(resource.getValue(resourceName));
+                Set<RangerPolicyEvaluator> serviceResourceMatchersForResource 
= trie.getEvaluatorsForResource(resource.getValue(resourceName));
+                Set<RangerPolicyEvaluator> inheritedResourceMatchers = 
trie.getInheritedEvaluators();
 
-                if (CollectionUtils.isEmpty(resourceEvaluators)) { // no 
policies for this resource, bail out
-                    resourceEvaluatorsSet = null;
-                    smallestSet = null;
-                    break;
-                }
-
-                if (smallestSet == null) {
-                    smallestSet = resourceEvaluators;
-                } else {
-                    if (resourceEvaluatorsSet == null) {
-                        resourceEvaluatorsSet = new ArrayList<>();
-                        resourceEvaluatorsSet.add(smallestSet);
+                if (smallestList != null) {
+                    if (CollectionUtils.isEmpty(inheritedResourceMatchers) && 
CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                        smallestList = null;
+                    } else if 
(CollectionUtils.isEmpty(inheritedResourceMatchers)) {
+                        
smallestList.retainAll(serviceResourceMatchersForResource);
+                    } else if 
(CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                        smallestList.retainAll(inheritedResourceMatchers);
+                    } else {
+                        Set<RangerPolicyEvaluator> smaller, bigger;
+                        if (serviceResourceMatchersForResource.size() < 
inheritedResourceMatchers.size()) {
+                            smaller = serviceResourceMatchersForResource;
+                            bigger = inheritedResourceMatchers;
+                        } else {
+                            smaller = inheritedResourceMatchers;
+                            bigger = serviceResourceMatchersForResource;
+                        }
+                        Set<RangerPolicyEvaluator> tmp = new HashSet<>();
+                        if (smallestList.size() < smaller.size()) {
+                            
smallestList.stream().filter(smaller::contains).forEach(tmp::add);
+                            
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                        } else {
+                            
smaller.stream().filter(smallestList::contains).forEach(tmp::add);
+                            if (smallestList.size() < bigger.size()) {
+                                
smallestList.stream().filter(bigger::contains).forEach(tmp::add);
+                            } else {
+                                
bigger.stream().filter(smallestList::contains).forEach(tmp::add);
+                            }
+                        }
+                        smallestList = tmp;
                     }
-                    resourceEvaluatorsSet.add(resourceEvaluators);
-
-                    if (smallestSet.size() > resourceEvaluators.size()) {
-                        smallestSet = resourceEvaluators;
+                } else {
+                    if (CollectionUtils.isEmpty(inheritedResourceMatchers) || 
CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
+                        Set<RangerPolicyEvaluator> tmp = 
CollectionUtils.isEmpty(inheritedResourceMatchers) ? 
serviceResourceMatchersForResource : inheritedResourceMatchers;
+                        smallestList = resourceKeys.size() == 1 || 
CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
+                    } else {
+                        smallestList = new 
HashSet<>(serviceResourceMatchersForResource);
+                        smallestList.addAll(inheritedResourceMatchers);
                     }
                 }
-            }
-
-            if (resourceEvaluatorsSet != null) {
-                evaluators = new HashSet<>(smallestSet);
-                for (Set<RangerPolicyEvaluator> resourceEvaluators : 
resourceEvaluatorsSet) {
-                    if (resourceEvaluators != smallestSet) {
-                        // remove policies from ret that are not in 
resourceEvaluators
-                        evaluators.retainAll(resourceEvaluators);
 
-                        if (CollectionUtils.isEmpty(evaluators)) { // if no 
policy exists, bail out and return empty list
-                            evaluators = null;
-                            break;
-                        }
-                    }
+                if (CollectionUtils.isEmpty(smallestList)) {// no tags for 
this resource, bail out
+                    smallestList = null;
+                    break;
                 }
-            } else {
-                evaluators = smallestSet;
             }
+        }
 
-            if (evaluators != null) {
-                ret = new ArrayList<>(evaluators);
-                ret.sort(RangerPolicyEvaluator.EVAL_ORDER_COMPARATOR);
-            }
+        if (smallestList != null) {
+            ret = new ArrayList<>(smallestList);
+            ret.sort(RangerPolicyEvaluator.EVAL_ORDER_COMPARATOR);
         }
 
         RangerPerfTracer.logAlways(perf);
@@ -1320,10 +1327,7 @@ public class RangerPolicyRepository {
 
     private void removeEvaluatorFromTrie(RangerPolicyEvaluator oldEvaluator, 
RangerResourceTrie<RangerPolicyEvaluator> trie, String resourceDefName) {
         if (oldEvaluator != null) {
-            RangerPolicy.RangerPolicyResource resource = 
oldEvaluator.getPolicyResource().get(resourceDefName);
-            if (resource != null) {
-                trie.delete(resource, oldEvaluator);
-            }
+            trie.delete(oldEvaluator.getPolicyResource().get(resourceDefName), 
oldEvaluator);
         }
     }
 
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
index 4428503..b41da47 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
@@ -57,6 +57,7 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
     private final String wildcardChars;
     private final TrieNode<T> root;
     private final boolean isOptimizedForRetrieval;
+    private       Set<T>  inheritedEvaluators;
 
     public RangerResourceTrie(RangerServiceDef.RangerResourceDef resourceDef, 
List<T> evaluators) {
         this(resourceDef, evaluators, true, null);
@@ -73,6 +74,7 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
         this.optIgnoreCase = other.optIgnoreCase;
         this.optWildcard = other.optWildcard;
         this.wildcardChars = other.wildcardChars;
+        this.inheritedEvaluators = other.inheritedEvaluators != null ? new 
HashSet<>(other.inheritedEvaluators) : null;
         this.isOptimizedForRetrieval = false;
         this.root = copyTrieSubtree(other.root, null);
 
@@ -159,6 +161,10 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
         }
     }
 
+    public Set<T> getInheritedEvaluators() {
+        return inheritedEvaluators;
+    }
+
     public Set<T> getEvaluatorsForResource(Object resource) {
         if (resource instanceof String) {
             return getEvaluatorsForResource((String) resource);
@@ -186,11 +192,11 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
 
         if (resource == null) {
             if (evaluator.isAncestorOf(resourceDef)) {
-                root.addWildcardEvaluator(evaluator);
+                addInheritedEvaluator(evaluator);
             }
         } else {
             if (resource.getIsExcludes()) {
-                root.addWildcardEvaluator(evaluator);
+                addInheritedEvaluator(evaluator);
             } else {
                 if (CollectionUtils.isNotEmpty(resource.getValues())) {
                     for (String value : resource.getValues()) {
@@ -216,11 +222,13 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
             perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_INIT_LOG, 
"RangerResourceTrie.delete(name=" + resource + ")");
         }
 
-        boolean isRemoved = false;
-        if (resource.getIsExcludes()) {
-            isRemoved = root.removeWildcardEvaluator(evaluator);
-        }
-        if (!isRemoved) {
+        if (resource == null) {
+            if (evaluator.isAncestorOf(resourceDef)) {
+                removeInheritedEvaluator(evaluator);
+            }
+        } else if (resource.getIsExcludes()) {
+            removeInheritedEvaluator(evaluator);
+        } else {
             for (String value : resource.getValues()) {
                 TrieNode<T> node = getNodeForResource(value);
                 if (node != null) {
@@ -247,6 +255,23 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
         return root;
     }
 
+    private void addInheritedEvaluator(T evaluator) {
+        if (inheritedEvaluators == null) {
+            inheritedEvaluators = new HashSet<>();
+        }
+
+        inheritedEvaluators.add(evaluator);
+    }
+
+    private void removeInheritedEvaluator(T evaluator) {
+        if (CollectionUtils.isNotEmpty(inheritedEvaluators) && 
inheritedEvaluators.contains(evaluator)) {
+            inheritedEvaluators.remove(evaluator);
+            if (CollectionUtils.isEmpty(inheritedEvaluators)) {
+                inheritedEvaluators = null;
+            }
+        }
+    }
+
     private TrieNode<T> copyTrieSubtree(final TrieNode<T> source, final 
TrieNode<T> parent) {
         if (TRACE_LOG.isTraceEnabled()) {
             StringBuilder sb = new StringBuilder();
@@ -339,14 +364,14 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
 
             if (policyResource == null) {
                 if (evaluator.isAncestorOf(resourceDef)) {
-                    ret.addWildcardEvaluator(evaluator);
+                    addInheritedEvaluator(evaluator);
                 }
 
                 continue;
             }
 
             if (policyResource.getIsExcludes()) {
-                ret.addWildcardEvaluator(evaluator);
+                addInheritedEvaluator(evaluator);
             } else {
                 RangerResourceMatcher resourceMatcher = 
evaluator.getResourceMatcher(resourceName);
 
@@ -810,7 +835,7 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
                 }
 
                 for (Map.Entry<Character, TrieNode<U>> entry : 
children.entrySet()) {
-                    TrieNode child = entry.getValue();
+                    TrieNode<U> child = entry.getValue();
 
                     child.populateTrieData(trieData);
                 }
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/contextenricher/TestTagEnricher.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/contextenricher/TestTagEnricher.java
index 83b39ed..799787c 100644
--- 
a/agents-common/src/test/java/org/apache/ranger/plugin/contextenricher/TestTagEnricher.java
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/contextenricher/TestTagEnricher.java
@@ -96,6 +96,7 @@ public class TestTagEnricher {
 
         tagEnricher.setServiceName(testCase.serviceName);
         tagEnricher.setServiceDef(testCase.serviceDef);
+        tagEnricher.init();
         tagEnricher.setServiceTags(serviceTags);
 
         List<String> expectedTags = new ArrayList<>();
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngineComparison.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngineComparison.java
index e204983..6f644cc 100644
--- 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngineComparison.java
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngineComparison.java
@@ -138,11 +138,15 @@ public class TestPolicyEngineComparison {
                     myTagEnricher.setAppId("test-compare-my-tags");
                     
myTagEnricher.setServiceDef(myServicePolicies.getServiceDef());
                     
myTagEnricher.setServiceName(myServiceTags.getServiceName());
+                    myTagEnricher.init();
+
                     myTagEnricher.setServiceTags(myServiceTags);
 
                     otherTagEnricher.setAppId("test-compare-other-tags");
                     
otherTagEnricher.setServiceDef(myServicePolicies.getServiceDef());
                     
otherTagEnricher.setServiceName(otherServiceTags.getServiceName());
+                    otherTagEnricher.init();
+
                     otherTagEnricher.setServiceTags(otherServiceTags);
 
                     isTagsEqual = TestPolicyEngine.compare(myTagEnricher, 
otherTagEnricher) && TestPolicyEngine.compare(otherTagEnricher, myTagEnricher);

Reply via email to