This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch ranger-2.5 in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/ranger-2.5 by this push: new 03925dbc6 RANGER-4852: De-duplicated tags do not work correctly when tag-deltas are enabled 03925dbc6 is described below commit 03925dbc646aa85a6a81f94a39327ce1f7bd414b Author: Abhay Kulkarni <akulka...@cloudera.com> AuthorDate: Fri Jul 12 16:13:39 2024 -0700 RANGER-4852: De-duplicated tags do not work correctly when tag-deltas are enabled (cherry picked from commit 9648f8f8c9e6f178837942ee76a992636e83f772) --- .../contextenricher/RangerAdminTagRetriever.java | 13 --- .../RangerFileBasedTagRetriever.java | 8 +- .../plugin/contextenricher/RangerTagEnricher.java | 7 +- .../plugin/contextenricher/RangerTagRetriever.java | 1 + .../ranger/plugin/model/RangerServiceTags.java | 2 +- .../ranger/plugin/util/RangerCommonConstants.java | 4 +- .../plugin/util/RangerServiceTagsDeltaUtil.java | 124 ++++++++++++--------- .../org/apache/ranger/plugin/util/ServiceTags.java | 57 ++++++++-- .../java/org/apache/ranger/biz/TagDBStore.java | 18 ++- .../ranger/common/RangerServiceTagsCache.java | 4 +- 10 files changed, 148 insertions(+), 90 deletions(-) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java index b2b7d5f71..bae31e6cc 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java @@ -33,12 +33,7 @@ import java.util.Map; public class RangerAdminTagRetriever extends RangerTagRetriever { private static final Logger LOG = LoggerFactory.getLogger(RangerAdminTagRetriever.class); - private static final String OPTION_DEDUP_TAGS = "deDupTags"; - private static final Boolean OPTION_DEDUP_TAGS_DEFAULT = true; - - private RangerAdminClient adminClient; - private boolean deDupTags; @Override public void init(Map<String, String> options) { @@ -50,11 +45,9 @@ public class RangerAdminTagRetriever extends RangerTagRetriever { pluginConfig = new RangerPluginConfig(serviceDef.getName(), serviceName, appId, null, null, null); } - String deDupTagsVal = options != null? options.get(OPTION_DEDUP_TAGS) : null; RangerPluginContext pluginContext = getPluginContext(); RangerAdminClient rangerAdmin = pluginContext.getAdminClient(); - this.deDupTags = StringUtils.isNotBlank(deDupTagsVal) ? Boolean.parseBoolean(deDupTagsVal) : OPTION_DEDUP_TAGS_DEFAULT; this.adminClient = (rangerAdmin != null) ? rangerAdmin : pluginContext.createAdminClient(pluginConfig); } else { LOG.error("FATAL: Cannot find service/serviceDef to use for retrieving tags. Will NOT be able to retrieve tags."); @@ -78,12 +71,6 @@ public class RangerAdminTagRetriever extends RangerTagRetriever { } } - if (serviceTags != null && !serviceTags.getIsDelta() && deDupTags) { - final int countOfDuplicateTags = serviceTags.dedupTags(); - - LOG.info("Number of duplicate tags removed from the received serviceTags:[" + countOfDuplicateTags + "]. Number of tags in the de-duplicated serviceTags :[" + serviceTags.getTags().size() + "]."); - } - return serviceTags; } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java index 2a3643399..1e39d93fa 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java @@ -37,7 +37,6 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever { private URL serviceTagsFileURL; private String serviceTagsFileName; - private boolean deDupTags; int tagFilesCount = 0; int currentTagFileIndex = 0; boolean isInitial = true; @@ -50,15 +49,12 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever { String serviceTagsFileNameProperty = "serviceTagsFileName"; String serviceTagsDefaultFileName = "/testdata/test_servicetags_hive.json"; - String deDupTagsProperty = "deDupTags"; String tagFilesCountProperty = "tagFileCount"; if (StringUtils.isNotBlank(serviceName) && serviceDef != null && StringUtils.isNotBlank(appId)) { // Open specified file from options- it should contain service-tags serviceTagsFileName = options != null? options.get(serviceTagsFileNameProperty) : null; - String deDupTagsVal = options != null? options.get(deDupTagsProperty) : "false"; - deDupTags = Boolean.parseBoolean(deDupTagsVal); serviceTagsFileName = serviceTagsFileName == null ? serviceTagsDefaultFileName : serviceTagsFileName; if (options != null) { @@ -179,7 +175,7 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever { ) { ret = JsonUtils.jsonToObject(reader, ServiceTags.class); - if (deDupTags) { + if (ret.getIsTagsDeduped()) { final int countOfDuplicateTags = ret.dedupTags(); LOG.info("Number of duplicate tags removed from the received serviceTags:[" + countOfDuplicateTags + "]. Number of tags in the de-duplicated serviceTags :[" + ret.getTags().size() + "]."); } @@ -204,7 +200,7 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever { ret = JsonUtils.jsonToObject(reader, ServiceTags.class); currentTagFileIndex++; - if (deDupTags) { + if (ret.getIsTagsDeduped()) { final int countOfDuplicateTags = ret.dedupTags(); LOG.info("Number of duplicate tags removed from the received serviceTags:[" + countOfDuplicateTags + "]. Number of tags in the de-duplicated serviceTags :[" + ret.getTags().size() + "]."); } 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 0208e6892..2fa24eba6 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 @@ -309,13 +309,18 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher { } if (!serviceTags.getIsDelta()) { + if (serviceTags.getIsTagsDeduped()) { + final int countOfDuplicateTags = serviceTags.dedupTags(); + + LOG.info("Number of duplicate tags removed from the received serviceTags:[" + countOfDuplicateTags + "]. Number of tags in the de-duplicated serviceTags :[" + serviceTags.getTags().size() + "]."); + } processServiceTags(serviceTags); } else { if (LOG.isDebugEnabled()) { LOG.debug("Received service-tag deltas:" + serviceTags); } ServiceTags oldServiceTags = enrichedServiceTags != null ? enrichedServiceTags.getServiceTags() : new ServiceTags(); - ServiceTags allServiceTags = rebuildOnlyIndex ? oldServiceTags : RangerServiceTagsDeltaUtil.applyDelta(oldServiceTags, serviceTags); + ServiceTags allServiceTags = rebuildOnlyIndex ? oldServiceTags : RangerServiceTagsDeltaUtil.applyDelta(oldServiceTags, serviceTags, serviceTags.getIsTagsDeduped()); if (serviceTags.getTagsChangeExtent() == ServiceTags.TagsChangeExtent.NONE) { if (LOG.isDebugEnabled()) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java index d7c737525..584959e02 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java @@ -71,4 +71,5 @@ public abstract class RangerTagRetriever { public void setPluginContext(RangerPluginContext pluginContext) { this.pluginContext = pluginContext; } + } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceTags.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceTags.java index 59288f7d5..3a2633974 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceTags.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceTags.java @@ -170,7 +170,7 @@ public class RangerServiceTags implements java.io.Serializable { ret = new ServiceTags(toServiceTagsOp(tags.getOp()), tags.getServiceName(), tags.tagVersion, tags.getTagUpdateTime(), tags.getTagDefinitions(), tags.getTags(), tags.getServiceResources(), tags.getResourceToTagIds(), false, - ServiceTags.TagsChangeExtent.ALL); + ServiceTags.TagsChangeExtent.ALL, false); } return ret; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java index 23689790d..9d6e1f0b5 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java @@ -40,7 +40,7 @@ public class RangerCommonConstants { public static final String RANGER_ADMIN_SUFFIX_IN_PLACE_TAG_UPDATES = ".supports.in.place.tag.updates"; public static final String PLUGIN_CONFIG_SUFFIX_IN_PLACE_TAG_UPDATES = ".supports.in.place.tag.updates"; - public static final String RANGER_ADMIN_SUPPORTS_TAGS_DEDUP = ".supports.tags.dedup"; + public static final String RANGER_SUPPORTS_TAGS_DEDUP = ".supports.tags.dedup"; public static final boolean RANGER_ADMIN_SUFFIX_POLICY_DELTA_DEFAULT = false; public static final boolean PLUGIN_CONFIG_SUFFIX_POLICY_DELTA_DEFAULT = false; @@ -54,7 +54,7 @@ public class RangerCommonConstants { public static final boolean RANGER_ADMIN_SUFFIX_IN_PLACE_TAG_UPDATES_DEFAULT = false; public static final boolean PLUGIN_CONFIG_SUFFIX_IN_PLACE_TAG_UPDATES_DEFAULT = false; - public static final boolean RANGER_ADMIN_SUPPORTS_TAGS_DEDUP_DEFAULT = true; + public static final boolean RANGER_SUPPORTS_TAGS_DEDUP_DEFAULT = true; public static final boolean POLICY_REST_CLIENT_SESSION_COOKIE_ENABLED = true; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerServiceTagsDeltaUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerServiceTagsDeltaUtil.java index f2e68aed9..d5a0915e0 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerServiceTagsDeltaUtil.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerServiceTagsDeltaUtil.java @@ -19,8 +19,10 @@ package org.apache.ranger.plugin.util; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; -import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig; +import org.apache.commons.lang3.tuple.MutablePair; import org.apache.ranger.plugin.model.RangerServiceResource; import org.apache.ranger.plugin.model.RangerTag; import org.apache.ranger.plugin.model.RangerTagDef; @@ -42,16 +44,13 @@ public class RangerServiceTagsDeltaUtil { private static final Logger PERF_TAGS_DELTA_LOG = RangerPerfTracer.getPerfLogger("tags.delta"); - private static boolean SUPPORTS_TAGS_DEDUP_INITIALIZED = false; - private static boolean SUPPORTS_TAGS_DEDUP = false; - /* It should be possible to call applyDelta() multiple times with serviceTags and delta resulting from previous call to applyDelta() The end result should be same if called once or multiple times. */ - static public ServiceTags applyDelta(ServiceTags serviceTags, ServiceTags delta) { + static public ServiceTags applyDelta(ServiceTags serviceTags, ServiceTags delta, boolean supportsTagsDedup) { if (LOG.isDebugEnabled()) { - LOG.debug("==> RangerServiceTagsDeltaUtil.applyDelta()"); + LOG.debug("==> RangerServiceTagsDeltaUtil.applyDelta(): serviceTags:[" + serviceTags + "], delta:[" + delta + "], supportsTagsDedup:[" + supportsTagsDedup + "]"); } ServiceTags ret = serviceTags; @@ -66,6 +65,7 @@ public class RangerServiceTagsDeltaUtil { ret.setServiceName(delta.getServiceName()); ret.setTagVersion(delta.getTagVersion()); + ret.setIsTagsDeduped(delta.getIsTagsDeduped()); int tagDefsAdded = 0, tagDefsUpdated = 0, tagDefsRemoved = 0; int tagsAdded = 0, tagsUpdated = 0, tagsRemoved = 0; @@ -103,25 +103,47 @@ public class RangerServiceTagsDeltaUtil { RangerTag deltaTag = entry.getValue(); if (StringUtils.isEmpty(deltaTag.getType())) { // tag has been removed - RangerTag removedTag = tags.remove(deltaTagId); - - if (removedTag != null) { - tagsRemoved++; + if (supportsTagsDedup) { + boolean found = false; + + for (Iterator<Map.Entry<RangerTag, MutablePair<Long, Long>>> iterator = ret.cachedTags.entrySet().iterator(); iterator.hasNext(); ) { + MutablePair<Long, Long> value = iterator.next().getValue(); + if (value.left.equals(deltaTagId)) { + if (--value.right == 0) { + // This may never be true when this tag is duplicated + // as the mapping between de-duplicated tags is not maintained - only the reference count is stored + // So, the tag with the smallest tag-id (among duplicate tags) will never be removed + if (tags.remove(deltaTagId) != null) { + tagsRemoved++; + } + iterator.remove(); + } + found = true; + break; + } + } - if (isSupportsTagsDedup()) { - ret.cachedTags.remove(removedTag); + if (!found) { + if (tags.remove(deltaTagId) != null) { + tagsRemoved++; + } + } + } else { + if (tags.remove(deltaTagId) != null) { + tagsRemoved++; } } } else { - if (isSupportsTagsDedup()) { - Long cachedTagId = ret.cachedTags.get(deltaTag); + if (supportsTagsDedup) { + MutablePair<Long, Long> cachedTag = ret.cachedTags.get(deltaTag); - if (cachedTagId == null) { - ret.cachedTags.put(deltaTag, deltaTagId); + if (cachedTag == null) { + ret.cachedTags.put(deltaTag, new MutablePair<>(deltaTagId, 1L)); tags.put(deltaTagId, deltaTag); + tagsAdded++; } else { - replacedTagIds.put(deltaTagId, cachedTagId); - deltaTagIter.remove(); + cachedTag.right++; + replacedTagIds.put(deltaTagId, cachedTag.left); } } else { RangerTag existing = tags.put(deltaTagId, deltaTag); @@ -147,43 +169,29 @@ public class RangerServiceTagsDeltaUtil { if (existingResource != null) { if (StringUtils.isNotEmpty(resource.getResourceSignature())) { if (!StringUtils.equals(resource.getResourceSignature(), existingResource.getResourceSignature())) { // ServiceResource changed; replace existing instance - existingResource.setResourceSignature(null); - - boolean isAddedResource = resourcesToAdd.remove(existingResource.getId()) == existingResource; - - // if a resource with this ID was already removed, don't replace the entry in resourcesToRemove - if (!isAddedResource && !resourcesToRemove.containsKey(existingResource.getId())) { - resourcesToRemove.put(existingResource.getId(), existingResource); - } - + /* If the signature changed, we need to remove existing resource and add new resource */ + resourcesToRemove.put(resource.getId(), existingResource); resourcesToAdd.put(resource.getId(), resource); - idResourceMap.put(resource.getId(), resource); } } else { // resource deleted - boolean isAddedResource = resourcesToAdd.remove(existingResource.getId()) == existingResource; - - if (!isAddedResource) { - resourcesToRemove.put(existingResource.getId(), existingResource); - } + resourcesToRemove.put(resource.getId(), existingResource); - idResourceMap.remove(existingResource.getId()); resourceToTagIds.remove(existingResource.getId()); } } else { // resource added if (StringUtils.isNotEmpty(resource.getResourceSignature())) { resourcesToAdd.put(resource.getId(), resource); - - idResourceMap.put(resource.getId(), resource); } } } if (!resourcesToRemove.isEmpty()) { for (ListIterator<RangerServiceResource> iter = serviceResources.listIterator(); iter.hasNext(); ) { - RangerServiceResource resource = iter.next(); - RangerServiceResource replacedResource = resourcesToRemove.get(resource.getId()); + RangerServiceResource resource = iter.next(); + RangerServiceResource deletedResource = resourcesToRemove.get(resource.getId()); + RangerServiceResource addedResource = resourcesToAdd.get(resource.getId()); - if (replacedResource == resource) { + if (addedResource == null && deletedResource == resource) { iter.remove(); } } @@ -208,16 +216,33 @@ public class RangerServiceTagsDeltaUtil { resourceToTagIds.putAll(delta.getResourceToTagIds()); + if (MapUtils.isEmpty(resourceToTagIds)) { + if (LOG.isDebugEnabled()) { + LOG.debug("There are no resource->tag mappings!!"); + } + if (MapUtils.isNotEmpty(ret.getTags())) { + LOG.warn("There are no resource->tag mappings, but there are tags in the ServiceTags!! Cleaning up"); + ret.getTags().clear(); + } + if (supportsTagsDedup) { + ret.cachedTags.clear(); + } + } + // Ensure that any modified service-resources are at head of list of service-resources in delta // So that in setServiceTags(), they get cleaned out first, and service-resource with new spec gets added - if (!resourcesToAdd.isEmpty()) { - List<RangerServiceResource> deltaServiceResources = new ArrayList<>(resourcesToAdd.values()); - deltaServiceResources.addAll(delta.getServiceResources()); - - delta.setServiceResources(deltaServiceResources); + List<RangerServiceResource> deltaServiceResources = new ArrayList<>(); + for (RangerServiceResource resourceToRemove : resourcesToRemove.values()) { + resourceToRemove.setResourceSignature(null); + deltaServiceResources.add(resourceToRemove); + } + if (!resourcesToAdd.isEmpty()) { + deltaServiceResources.addAll(resourcesToAdd.values()); } + delta.setServiceResources(deltaServiceResources); + if (LOG.isDebugEnabled()) { LOG.debug("RangerServiceTagsDeltaUtil.applyDelta(): delta(tagDefs={}, tags={}, resources={}), " + "resources(total={}, added={}, removed={}), " + @@ -235,7 +260,7 @@ public class RangerServiceTagsDeltaUtil { } if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerServiceTagsDeltaUtil.applyDelta()"); + LOG.debug("<== RangerServiceTagsDeltaUtil.applyDelta(): serviceTags:[" + ret + "], delta:[" + delta + "], supportsTagsDedup:[" + supportsTagsDedup + "]"); } RangerPerfTracer.log(perf); @@ -312,13 +337,4 @@ public class RangerServiceTagsDeltaUtil { } } - public static boolean isSupportsTagsDedup() { - if (!SUPPORTS_TAGS_DEDUP_INITIALIZED) { - RangerAdminConfig config = RangerAdminConfig.getInstance(); - - SUPPORTS_TAGS_DEDUP = config.getBoolean("ranger.admin" + RangerCommonConstants.RANGER_ADMIN_SUPPORTS_TAGS_DEDUP, RangerCommonConstants.RANGER_ADMIN_SUPPORTS_TAGS_DEDUP_DEFAULT); - SUPPORTS_TAGS_DEDUP_INITIALIZED = true; - } - return SUPPORTS_TAGS_DEDUP; - } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceTags.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceTags.java index 39110357d..cc2ebe53a 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceTags.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceTags.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.HashMap; import java.util.ArrayList; +import org.apache.commons.lang3.tuple.MutablePair; import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.model.RangerServiceResource; import org.apache.ranger.plugin.model.RangerTag; @@ -61,9 +62,11 @@ public class ServiceTags implements java.io.Serializable { private Map<Long, List<Long>> resourceToTagIds; private Boolean isDelta; private TagsChangeExtent tagsChangeExtent; + private Boolean isTagsDeduped; + // MutablePair.left is the tag-id, MutablePair.right is the reference-count @JsonIgnore - Map<RangerTag, Long> cachedTags = new HashMap<>(); + Map<RangerTag, MutablePair<Long, Long>> cachedTags = new HashMap<>(); public ServiceTags() { this(OP_ADD_OR_UPDATE, null, 0L, null, null, null, null, null); @@ -71,10 +74,10 @@ public class ServiceTags implements java.io.Serializable { public ServiceTags(String op, String serviceName, Long tagVersion, Date tagUpdateTime, Map<Long, RangerTagDef> tagDefinitions, Map<Long, RangerTag> tags, List<RangerServiceResource> serviceResources, Map<Long, List<Long>> resourceToTagIds) { - this(op, serviceName, tagVersion, tagUpdateTime, tagDefinitions, tags, serviceResources, resourceToTagIds, false, TagsChangeExtent.ALL); + this(op, serviceName, tagVersion, tagUpdateTime, tagDefinitions, tags, serviceResources, resourceToTagIds, false, TagsChangeExtent.ALL, false); } public ServiceTags(String op, String serviceName, Long tagVersion, Date tagUpdateTime, Map<Long, RangerTagDef> tagDefinitions, - Map<Long, RangerTag> tags, List<RangerServiceResource> serviceResources, Map<Long, List<Long>> resourceToTagIds, Boolean isDelta, TagsChangeExtent tagsChangeExtent) { + Map<Long, RangerTag> tags, List<RangerServiceResource> serviceResources, Map<Long, List<Long>> resourceToTagIds, Boolean isDelta, TagsChangeExtent tagsChangeExtent, Boolean isTagsDeduped) { setOp(op); setServiceName(serviceName); setTagVersion(tagVersion); @@ -85,6 +88,7 @@ public class ServiceTags implements java.io.Serializable { setResourceToTagIds(resourceToTagIds); setIsDelta(isDelta); setTagsChangeExtent(tagsChangeExtent); + setIsTagsDeduped(isTagsDeduped); } public ServiceTags(ServiceTags other) { @@ -97,6 +101,7 @@ public class ServiceTags implements java.io.Serializable { setServiceResources(other.getServiceResources() != null ? new ArrayList<>(other.getServiceResources()) : null); setResourceToTagIds(other.getResourceToTagIds() != null ? new HashMap<>(other.getResourceToTagIds()) : null); setIsDelta(other.getIsDelta()); + setIsTagsDeduped(other.getIsTagsDeduped()); setTagsChangeExtent(other.getTagsChangeExtent()); this.cachedTags = new HashMap<>(other.cachedTags); @@ -198,6 +203,14 @@ public class ServiceTags implements java.io.Serializable { this.isDelta = isDelta; } + public Boolean getIsTagsDeduped() { + return isTagsDeduped == null ? Boolean.FALSE : isTagsDeduped; + } + + public void setIsTagsDeduped(Boolean isTagsDeduped) { + this.isTagsDeduped = isTagsDeduped; + } + public TagsChangeExtent getTagsChangeExtent() { return tagsChangeExtent; } @@ -225,6 +238,8 @@ public class ServiceTags implements java.io.Serializable { .append(", serviceResources={").append(serviceResources).append("}") .append(", tags={").append(tags).append("}") .append(", resourceToTagIds={").append(resourceToTagIds).append("}") + .append(", isTagsDeduped={").append(isTagsDeduped).append("}") + .append(", cachedTags={").append(cachedTags).append("}") .append("}"); return sb; @@ -234,31 +249,51 @@ public class ServiceTags implements java.io.Serializable { final int ret; final Map<Long, Long> replacedIds = new HashMap<>(); final int initialTagsCount = tags.size(); + final List<Long> tagIdsToRemove = new ArrayList<>(); for (Iterator<Map.Entry<Long, RangerTag>> iter = tags.entrySet().iterator(); iter.hasNext(); ) { Map.Entry<Long, RangerTag> entry = iter.next(); Long tagId = entry.getKey(); RangerTag tag = entry.getValue(); - Long cachedTagId = cachedTags.get(tag); + MutablePair<Long, Long> cachedTag = cachedTags.get(tag); - if (cachedTagId == null) { - cachedTags.put(tag, tagId); + if (cachedTag == null) { + cachedTags.put(tag, new MutablePair<>(tagId, 0L)); // reference count will be incremented later } else { - replacedIds.put(tagId, cachedTagId); - iter.remove(); + if (tagId < cachedTag.left) { + replacedIds.put(cachedTag.left, tagId); + tagIdsToRemove.add(cachedTag.left); + cachedTag.left = tagId; + } else { + replacedIds.put(tagId, cachedTag.left); + iter.remove(); + } } } + for (Long tagIdToRemove : tagIdsToRemove) { + tags.remove(tagIdToRemove); + } final int finalTagsCount = tags.size(); for (Map.Entry<Long, List<Long>> resourceEntry : resourceToTagIds.entrySet()) { for (ListIterator<Long> listIter = resourceEntry.getValue().listIterator(); listIter.hasNext(); ) { Long tagId = listIter.next(); - Long replacerTagId = replacedIds.get(tagId); - if (replacerTagId != null) { - listIter.set(replacerTagId); + for (Long replacerTagId = replacedIds.get(tagId); replacerTagId != null; replacerTagId = replacedIds.get(tagId)) { + tagId = replacerTagId; } + + listIter.set(tagId); + + RangerTag tag = tags.get(tagId); + if (tag != null) { // This should always be true + MutablePair<Long, Long> cachedTag = cachedTags.get(tag); + if (cachedTag != null) { // This should always be true + cachedTag.right++; + } + } + } } diff --git a/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java index 9ecbb14ac..9134e3988 100755 --- a/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java @@ -1033,7 +1033,9 @@ public class TagDBStore extends AbstractTagStore { ret.setServiceResources(resources); ret.setResourceToTagIds(resourceToTagIds); - if (RangerServiceTagsDeltaUtil.isSupportsTagsDedup()) { + ret.setIsTagsDeduped(isSupportsTagsDedup()); + + if (isSupportsTagsDedup()) { final int countOfDuplicateTags = ret.dedupTags(); if (LOG.isDebugEnabled()) { LOG.debug("Number of duplicate tags removed from the received serviceTags:[" + countOfDuplicateTags + "]. Number of tags in the de-duplicated serviceTags :[" + ret.getTags().size() + "]."); @@ -1243,6 +1245,7 @@ public class TagDBStore extends AbstractTagStore { if (CollectionUtils.isNotEmpty(serviceResourceIds) || CollectionUtils.isNotEmpty(tagIds)) { ret = new ServiceTags(); ret.setIsDelta(true); + ret.setIsTagsDeduped(isSupportsTagsDedup()); ServiceTags.TagsChangeExtent tagsChangeExtent = ServiceTags.TagsChangeExtent.TAGS; @@ -1457,4 +1460,17 @@ public class TagDBStore extends AbstractTagStore { return ret; } + + private static boolean SUPPORTS_TAGS_DEDUP_INITIALIZED = false; + private static boolean SUPPORTS_TAGS_DEDUP = false; + + public static boolean isSupportsTagsDedup() { + if (!SUPPORTS_TAGS_DEDUP_INITIALIZED) { + RangerAdminConfig config = RangerAdminConfig.getInstance(); + + SUPPORTS_TAGS_DEDUP = config.getBoolean("ranger.admin" + RangerCommonConstants.RANGER_SUPPORTS_TAGS_DEDUP, RangerCommonConstants.RANGER_SUPPORTS_TAGS_DEDUP_DEFAULT); + SUPPORTS_TAGS_DEDUP_INITIALIZED = true; + } + return SUPPORTS_TAGS_DEDUP; + } } diff --git a/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java b/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java index 2aecc4388..ec0ff7083 100644 --- a/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java +++ b/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java @@ -22,6 +22,7 @@ package org.apache.ranger.common; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig; +import org.apache.ranger.biz.TagDBStore; import org.apache.ranger.plugin.store.TagStore; import org.apache.ranger.plugin.util.RangerServiceTagsDeltaUtil; @@ -376,7 +377,8 @@ public class RangerServiceTagsCache { LOG.debug("Retrieved tag-deltas from database. These will be applied on top of ServiceTags version:[" + cachedServiceTagsVersion + "], tag-deltas:[" + serviceTagsFromDb.getTagVersion() + "]"); } - this.serviceTags = RangerServiceTagsDeltaUtil.applyDelta(serviceTags, serviceTagsFromDb); + boolean supportsTagsDedeup = TagDBStore.isSupportsTagsDedup(); + this.serviceTags = RangerServiceTagsDeltaUtil.applyDelta(serviceTags, serviceTagsFromDb, supportsTagsDedeup); this.deltaCache = new ServiceTagsDeltasCache(cachedServiceTagsVersion, serviceTagsFromDb); } } else {