yuqi1129 commented on code in PR #8297:
URL: https://github.com/apache/gravitino/pull/8297#discussion_r2305987817


##########
core/src/main/java/org/apache/gravitino/cache/ReverseIndexCache.java:
##########
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.cache;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.googlecode.concurrenttrees.radix.ConcurrentRadixTree;
+import com.googlecode.concurrenttrees.radix.RadixTree;
+import 
com.googlecode.concurrenttrees.radix.node.concrete.DefaultCharArrayNodeFactory;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.RoleEntity;
+import org.apache.gravitino.meta.UserEntity;
+
+/**
+ * Reverse index cache for managing entity relationships. This cache uses a 
radix tree to
+ * efficiently store and retrieve relationships between entities based on 
their keys.
+ */
+public class ReverseIndexCache {
+  private final RadixTree<EntityCacheKey> reverseIndex;
+
+  public ReverseIndexCache() {
+    this.reverseIndex = new ConcurrentRadixTree<>(new 
DefaultCharArrayNodeFactory());
+
+    registerReverseRule(UserEntity.class, ReverseIndexRules.USER_REVERSE_RULE);
+    registerReverseRule(GroupEntity.class, 
ReverseIndexRules.GROUP_REVERSE_RULE);
+    registerReverseRule(RoleEntity.class, ReverseIndexRules.ROLE_REVERSE_RULE);
+  }
+
+  public boolean remove(EntityCacheKey key) {
+    return reverseIndex.remove(key.toString());
+  }
+
+  public Iterable<EntityCacheKey> getValuesForKeysStartingWith(String 
keyPrefix) {
+    return reverseIndex.getValuesForKeysStartingWith(keyPrefix);
+  }
+
+  public Iterable<CharSequence> getKeysStartingWith(String keyPrefix) {
+    return reverseIndex.getKeysStartingWith(keyPrefix);
+  }
+
+  public boolean remove(String key) {
+    return reverseIndex.remove(key);
+  }
+
+  public void put(
+      NameIdentifier nameIdentifier, Entity.EntityType type, 
EntityCacheRelationKey key) {
+    EntityCacheKey entityCacheKey = EntityCacheKey.of(nameIdentifier, type);
+    String strEntityCacheKey = entityCacheKey.toString();
+    List<EntityCacheKey> entityKeysToRemove =
+        
Lists.newArrayList(reverseIndex.getValuesForKeysStartingWith(strEntityCacheKey));
+    String strEntityCacheKeyNo =
+        String.format("%s-%d", strEntityCacheKey, entityKeysToRemove.size());
+    reverseIndex.put(strEntityCacheKeyNo, key);
+  }
+
+  public void put(Entity entity, EntityCacheRelationKey key) {
+    Preconditions.checkArgument(entity != null, "EntityCacheRelationKey cannot 
be null");
+
+    if (entity instanceof HasIdentifier) {
+      NameIdentifier nameIdent =
+          NameIdentifier.of(((HasIdentifier) entity).namespace(), 
((HasIdentifier) entity).name());
+      put(nameIdent, entity.type(), key);
+    }
+  }
+
+  /** Registers a processor for a specific entity class. */
+  private final Map<Class<? extends Entity>, ReverseIndexRule> 
reverseIndexRules = new HashMap<>();
+
+  public void registerReverseRule(Class<? extends Entity> entityClass, 
ReverseIndexRule rule) {
+    reverseIndexRules.put(entityClass, rule);
+  }
+
+  /** Processes an entity and updates the reverse index accordingly. */
+  public void indexEntity(Entity entity, EntityCacheRelationKey key) {
+    ReverseIndexRule rule = reverseIndexRules.get(entity.getClass());
+    if (rule != null) {
+      rule.indexEntity(entity, key, this);
+    }

Review Comment:
   Why was it necessary to store a reversed index if there was no rule?



##########
core/src/main/java/org/apache/gravitino/cache/ReverseIndexRules.java:
##########
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.cache;
+
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.RoleEntity;
+import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.utils.NamespaceUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reverse index rules for different entity types. This class defines how to 
process reverse
+ * indexing for UserEntity, GroupEntity, and RoleEntity. <br>
+ * For example: - UserEntity role is 
{metalake-name}.system.user.{user-name}:USER-{serial-number} -
+ * UserEntity role is 
{metalake-name}.system.group.{group-name}:GROUP-{serial-number} - RoleEntity
+ * role is {metalake-name}.system.role.{role-name}:ROLE-{serial-number} - 
{serial-number}: Because
+ */
+public class ReverseIndexRules {
+  private static final Logger LOG = 
LoggerFactory.getLogger(ReverseIndexRules.class.getName());
+
+  /** UserEntity reverse index processor */
+  public static final ReverseIndexCache.ReverseIndexRule USER_REVERSE_RULE =
+      (entity, key, reverseIndexCache) -> {
+        UserEntity userEntity = (UserEntity) entity;
+        if (userEntity.roleNames() != null) {
+          userEntity
+              .roleNames()
+              .forEach(
+                  role -> {
+                    Namespace ns = 
NamespaceUtil.ofRole(userEntity.namespace().level(0));
+                    NameIdentifier nameIdentifier = NameIdentifier.of(ns, 
role);
+                    reverseIndexCache.put(nameIdentifier, 
Entity.EntityType.ROLE, key);
+                  });
+        }
+      };
+
+  /** GroupEntity reverse index processor */
+  public static final ReverseIndexCache.ReverseIndexRule GROUP_REVERSE_RULE =
+      (entity, key, reverseIndexCache) -> {
+        GroupEntity groupEntity = (GroupEntity) entity;
+        if (groupEntity.roleNames() != null) {
+          groupEntity
+              .roleNames()
+              .forEach(
+                  role -> {
+                    Namespace ns = 
NamespaceUtil.ofRole(groupEntity.namespace().level(0));
+                    NameIdentifier nameIdentifier = NameIdentifier.of(ns, 
role);
+                    reverseIndexCache.put(nameIdentifier, 
Entity.EntityType.ROLE, key);
+                  });
+        }
+      };
+
+  /** * RoleEntity reverse index processor */
+  public static final ReverseIndexCache.ReverseIndexRule ROLE_REVERSE_RULE =
+      (entity, key, reverseIndexCache) -> {
+        RoleEntity roleEntity = (RoleEntity) entity;
+        if (roleEntity.securableObjects() != null) {
+          roleEntity
+              .securableObjects()
+              .forEach(
+                  securableObject -> {
+                    Namespace namespace = Namespace.empty();
+                    Entity.EntityType entityType = Entity.EntityType.METALAKE;
+                    switch (securableObject.type()) {
+                      case METALAKE:
+                        entityType = Entity.EntityType.METALAKE;
+                        namespace = NamespaceUtil.ofMetalake();
+                        break;
+                      case CATALOG:
+                        entityType = Entity.EntityType.CATALOG;
+                        namespace = 
NamespaceUtil.ofCatalog(roleEntity.namespace().level(0));
+                        break;
+                      case FILESET:
+                        entityType = Entity.EntityType.FILESET;
+                        Namespace nsParent = 
Namespace.fromString(securableObject.parent());
+                        namespace =
+                            NamespaceUtil.ofFileset(
+                                roleEntity.namespace().level(0),
+                                nsParent.level(0),
+                                nsParent.level(1));
+                        break;
+                      default:

Review Comment:
   Do we only support `metalake`, `catalog` and `fileset` here?  What about 
type `table`,`schema`?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to