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

liuxun pushed a commit to branch fix-cache
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit a8bdb4118dfac2cba3feebd311429a5bd65b1865
Author: Xun <[email protected]>
AuthorDate: Wed Aug 27 10:31:33 2025 +0800

    [#7804] fix(cache): Fix metadata cache data consistency error
---
 build.gradle.kts                                   |   8 +-
 .../gravitino/cache/CaffeineEntityCache.java       | 270 +--------------------
 .../apache/gravitino/cache/ReverseIndexCache.java  | 111 +++++++++
 .../apache/gravitino/cache/ReverseIndexRules.java  | 114 +++++++++
 .../storage/relational/RelationalEntityStore.java  |  19 +-
 5 files changed, 243 insertions(+), 279 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index d4d17d28d6..d506e4be93 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -355,7 +355,7 @@ subprojects {
           "-Xlint:finally",
           "-Xlint:overrides",
           "-Xlint:static",
-//          "-Werror"
+          "-Werror"
         )
       )
     }
@@ -569,9 +569,9 @@ subprojects {
       exclude("test/**")
     }
   }
-//  tasks.named("compileJava").configure {
-//    dependsOn("spotlessCheck")
-//  }
+  tasks.named("compileJava").configure {
+    dependsOn("spotlessCheck")
+  }
 }
 
 tasks.rat {
diff --git 
a/core/src/main/java/org/apache/gravitino/cache/CaffeineEntityCache.java 
b/core/src/main/java/org/apache/gravitino/cache/CaffeineEntityCache.java
index 756b31bb7d..95a2d7b33b 100644
--- a/core/src/main/java/org/apache/gravitino/cache/CaffeineEntityCache.java
+++ b/core/src/main/java/org/apache/gravitino/cache/CaffeineEntityCache.java
@@ -45,20 +45,13 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.ArrayUtils;
 import org.apache.gravitino.Config;
 import org.apache.gravitino.Configs;
 import org.apache.gravitino.Entity;
 import org.apache.gravitino.HasIdentifier;
 import org.apache.gravitino.NameIdentifier;
-import org.apache.gravitino.Namespace;
 import org.apache.gravitino.SupportsRelationOperations;
-import org.apache.gravitino.hook.CatalogHookDispatcher;
-import org.apache.gravitino.meta.GroupEntity;
 import org.apache.gravitino.meta.ModelVersionEntity;
-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;
 
@@ -94,7 +87,7 @@ public class CaffeineEntityCache extends BaseEntityCache {
    * catalog1 -> [tab1, tab2] reverseIndex[0] = catalog1-KEY -> Role1 
reverseIndex[1] = catalog2-KEY
    * -> Role1 reverseIndex[3] = tab1-KEY -> catalog1 reverseIndex[4] = 
tab2-KEY -> catalog1
    */
-  private RadixTree<EntityCacheKey> reverseIndex;
+  private ReverseIndexCache reverseIndex;
 
   /**
    * Cache Index structure. cacheData[0] = Role1 -> [catalog1, catalog2] 
cacheData[1] = catalog1 ->
@@ -112,7 +105,7 @@ public class CaffeineEntityCache extends BaseEntityCache {
   public CaffeineEntityCache(Config cacheConfig) {
     super(cacheConfig);
     this.cacheIndex = new ConcurrentRadixTree<>(new 
DefaultCharArrayNodeFactory());
-    this.reverseIndex = new ConcurrentRadixTree<>(new 
DefaultCharArrayNodeFactory());
+    this.reverseIndex = new ReverseIndexCache();
 
     Caffeine<EntityCacheKey, List<Entity>> cacheDataBuilder = 
newBaseBuilder(cacheConfig);
 
@@ -213,7 +206,7 @@ public class CaffeineEntityCache extends BaseEntityCache {
     withLock(
         () -> {
           cacheData.invalidateAll();
-          reverseIndex = new ConcurrentRadixTree<>(new 
DefaultCharArrayNodeFactory());
+          reverseIndex = new ReverseIndexCache();
           cacheIndex = new ConcurrentRadixTree<>(new 
DefaultCharArrayNodeFactory());
         });
   }
@@ -293,7 +286,7 @@ public class CaffeineEntityCache extends BaseEntityCache {
   protected void invalidateExpiredItem(EntityCacheKey key) {
     withLock(
         () -> {
-          reverseIndex.remove(key.toString());
+          reverseIndex.remove(key);
           cacheIndex.remove(key.toString());
         });
   }
@@ -314,160 +307,15 @@ public class CaffeineEntityCache extends BaseEntityCache 
{
       newEntities = new ArrayList<>(merged);
     }
 
-    List<String> allCacheIndexKeys1 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allCacheIndexKeys1.add(k.toString());
-            });
-
-    List<String> allReverseIndexKeys1 = Lists.newArrayList();
-    reverseIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allReverseIndexKeys1.add(k.toString());
-            });
-
-    // DEBUG code
-    check_cache();
-
     cacheData.put(key, newEntities);
 
     for (Entity entity : newEntities) {
-      if (entity instanceof UserEntity) {
-        // UserEntity is not supported in the cache, skip it.
-        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);
-                    putReverseIndex(nameIdentifier, Entity.EntityType.ROLE, 
key);
-                  });
-        }
-      } else if (entity instanceof GroupEntity) {
-        // UserEntity is not supported in the cache, skip it.
-        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);
-                    putReverseIndex(nameIdentifier, Entity.EntityType.ROLE, 
key);
-                  });
-        }
-      } else if (entity instanceof RoleEntity) {
-        // UserEntity is not supported in the cache, skip it.
-        RoleEntity roleEntity = (RoleEntity) entity;
-        if (roleEntity.securableObjects() != null) {
-          roleEntity
-              .securableObjects()
-              .forEach(
-                  securableObject -> {
-                    Namespace namespace = Namespace.empty();
-                    //                      Namespace nsParent =
-                    // Namespace.fromString(securableObject.parent());
-                    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:
-                        LOG.error("syncEntitiesToCache: Unprocessed securable 
object type: " + securableObject.type());
-//                        throw new IllegalStateException(
-//                            "Unprocessed securable object type: " + 
securableObject.type());
-                    }
-                    Namespace so_namespace = Namespace.of(namespace.levels());
-                    NameIdentifier nameIdentifier =
-                        NameIdentifier.of(so_namespace, 
securableObject.name());
-                    putReverseIndex(nameIdentifier, entityType, key);
-                  });
-        }
-      }
-
-      //      Namespace ns = NamespaceUtil.ofRole(ident.namespace().level(0));
-      //      NameIdentifier nameIdentifier = NameIdentifier.of(ns, role);
-
-      putReverseIndex(entity, key);
+      reverseIndex.indexEntity(entity, key);
     }
 
     if (cacheData.policy().getIfPresentQuietly(key) != null) {
       cacheIndex.put(key.toString(), key);
     }
-
-    List<String> allCacheIndexKeys2 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allCacheIndexKeys2.add(k.toString());
-            });
-
-    List<String> allReverseIndexKeys2 = Lists.newArrayList();
-    reverseIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allReverseIndexKeys2.add(k.toString());
-            });
-
-    // DEBUG code
-    check_cache();
-  }
-
-  private void check_cache() {
-    // DEBUG code
-    List<String> allCacheIndexKeys1 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allCacheIndexKeys1.add(k.toString());
-            });
-
-    List<String> allReverseIndexKeys1 = Lists.newArrayList();
-    reverseIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allReverseIndexKeys1.add(k.toString());
-            });
-
-    Set<EntityCacheRelationKey> allCacheDataKeys1 = cacheData.asMap().keySet();
-    List<String> allCacheDataKeysStrings1 =
-        
allCacheDataKeys1.stream().map(Object::toString).collect(Collectors.toList());
-
-    long cacheDataSize = cacheData.estimatedSize();
-    int cacheIndexSize = cacheIndex.size();
-    int reverseIndexSize = reverseIndex.size();
-    //    if (cacheDataSize != cacheIndexSize/*
-    //            || cacheDataSize != reverseIndexSize
-    //            || cacheIndexSize != reverseIndexSize*/) {
-    //      throw new IllegalStateException(
-    //              String.format(
-    //                      "Cache data size (%d) does not match cache index 
size (%d).",
-    //                      cacheDataSize, cacheIndexSize));
-    //    }
   }
 
   /**
@@ -507,80 +355,18 @@ public class CaffeineEntityCache extends BaseEntityCache {
     return nameIdent;
   }
 
-  private EntityCacheKey makeEntityCacheKey(Entity entity) {
-    NameIdentifier nameIdent = getNameIdentifier(entity);
-    EntityCacheKey entityCacheKey = EntityCacheKey.of(nameIdent, 
entity.type());
-    return entityCacheKey;
-  }
-
-  public void putReverseIndex(
-      NameIdentifier nameIdentifier, Entity.EntityType type, 
EntityCacheRelationKey key) {
-    //    EntityCacheKey entityCacheKey = makeEntityCacheKey(entity);
-    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 putReverseIndex(Entity entity, EntityCacheRelationKey key) {
-    Preconditions.checkArgument(entity != null, "EntityCacheRelationKey cannot 
be null");
-
-    if (entity instanceof HasIdentifier) {
-      EntityCacheKey entityCacheKey = makeEntityCacheKey(entity);
-      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);
-    }
-  }
-
   /**
    * Invalidates the entities by the given cache key.
    *
    * @param identifier The identifier of the entity to invalidate
    */
   private boolean invalidateEntities(NameIdentifier identifier) {
-    List<String> allCacheIndexKeys1 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allCacheIndexKeys1.add(k.toString());
-            });
-
-    List<String> matchCacheIndex2 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith(identifier.toString())
-        .forEach(
-            key -> {
-              matchCacheIndex2.add(key.toString());
-            });
-
-    List<String> allReverseIndexKeys1 = Lists.newArrayList();
-    reverseIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allReverseIndexKeys1.add(k.toString());
-            });
-
-    Set<EntityCacheRelationKey> allCacheDataKeys1 = cacheData.asMap().keySet();
-    List<String> allCacheDataKeysStrings1 =
-        
allCacheDataKeys1.stream().map(Object::toString).collect(Collectors.toList());
-
     List<EntityCacheKey> entityKeysToRemove =
         
Lists.newArrayList(cacheIndex.getValuesForKeysStartingWith(identifier.toString()));
 
-    // DEBUG code
-    check_cache();
-
     Map<EntityCacheRelationKey, List<Entity>> relationEnitiesMap =
         cacheData.getAllPresent(entityKeysToRemove);
+
     // SCENE[1]
     // RECORD1 = Role1 -> [catalog1, catalog2]
     // RECORD2 = catalog1 -> [tab1, tab2]
@@ -615,7 +401,7 @@ public class CaffeineEntityCache extends BaseEntityCache {
         key -> {
           // If the key is the same as the entity key, we can remove it from 
the cache.
           cacheData.invalidate(key);
-          boolean removed1 = cacheIndex.remove(key.toString());
+          cacheIndex.remove(key.toString());
           // Remove from reverse index
           // Convert EntityCacheRelationKey to EntityCacheKey
           EntityCacheKey reverseKey = EntityCacheKey.of(key.identifier(), 
key.entityType());
@@ -623,50 +409,12 @@ public class CaffeineEntityCache extends BaseEntityCache {
               .getKeysStartingWith(reverseKey.toString())
               .forEach(
                   reverseIndexKey -> {
-                    boolean removed2 = 
reverseIndex.remove(reverseIndexKey.toString());
+                    reverseIndex.remove(reverseIndexKey.toString());
                   });
         });
 
-    long cacheDataSize = cacheData.estimatedSize();
-    int cacheIndexSize = cacheIndex.size();
-    int reverseIndexSize = reverseIndex.size();
-
     cacheData.invalidateAll(entityKeysToRemove);
-
-    long cacheDataSize1 = cacheData.estimatedSize();
-    int cacheIndexSize1 = cacheIndex.size();
-    int reverseIndexSize1 = reverseIndex.size();
-
-    List<String> allCacheIndexKeys11 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allCacheIndexKeys11.add(k.toString());
-            });
-
-    List<String> matchCacheIndex21 = Lists.newArrayList();
-    cacheIndex
-        .getKeysStartingWith(identifier.toString())
-        .forEach(
-            key -> {
-              matchCacheIndex21.add(key.toString());
-            });
-
-    List<String> allReverseIndexKeys11 = Lists.newArrayList();
-    reverseIndex
-        .getKeysStartingWith("")
-        .forEach(
-            k -> {
-              allReverseIndexKeys11.add(k.toString());
-            });
-
-    Set<EntityCacheRelationKey> allCacheDataKeys2 = cacheData.asMap().keySet();
-    List<String> allCacheDataKeysStrings2 =
-            
allCacheDataKeys2.stream().map(Object::toString).collect(Collectors.toList());
-
-    // DEBUG code
-    check_cache();
+    entityKeysToRemove.forEach(key -> cacheIndex.remove(key.toString()));
 
     return !entityKeysToRemove.isEmpty();
   }
diff --git 
a/core/src/main/java/org/apache/gravitino/cache/ReverseIndexCache.java 
b/core/src/main/java/org/apache/gravitino/cache/ReverseIndexCache.java
new file mode 100644
index 0000000000..1cc52b3e6f
--- /dev/null
+++ b/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);
+    }
+
+    // Common processing for all entities
+    put(entity, key);
+  }
+
+  /** Functional interface for processing reverse index rules. */
+  @FunctionalInterface
+  public interface ReverseIndexRule {
+    void indexEntity(Entity entity, EntityCacheRelationKey key, 
ReverseIndexCache cache);
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/cache/ReverseIndexRules.java 
b/core/src/main/java/org/apache/gravitino/cache/ReverseIndexRules.java
new file mode 100644
index 0000000000..2b37bd8509
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/cache/ReverseIndexRules.java
@@ -0,0 +1,114 @@
+/*
+ * 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:
+                        LOG.info("Unprocessed securable object type: " + 
securableObject.type());
+                    }
+                    Namespace so_namespace = Namespace.of(namespace.levels());
+                    NameIdentifier nameIdentifier =
+                        NameIdentifier.of(so_namespace, 
securableObject.name());
+                    reverseIndexCache.put(nameIdentifier, entityType, key);
+                  });
+        }
+      };
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
index bce18b982a..a80f892301 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
@@ -40,7 +40,6 @@ import org.apache.gravitino.cache.CacheFactory;
 import org.apache.gravitino.cache.EntityCache;
 import org.apache.gravitino.cache.NoOpsCache;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
-import org.apache.gravitino.meta.RoleEntity;
 import org.apache.gravitino.meta.TagEntity;
 import org.apache.gravitino.tag.SupportsTagOperations;
 import org.apache.gravitino.utils.Executable;
@@ -126,22 +125,14 @@ public class RelationalEntityStore
       List<String> roles,
       Function<E, E> updater)
       throws IOException, NoSuchEntityException, EntityAlreadyExistsException {
-    cache.invalidate(ident, entityType);
-
     roles.forEach(
-        role -> {
-          Namespace ns = NamespaceUtil.ofRole(ident.namespace().level(0));
-          NameIdentifier nameIdentifier = NameIdentifier.of(ns, role);
-
-          //          RoleEntity roleEntity = RoleEntity.builder()
-          //          .withId(1L)
-          //          .withName(role)
-          //          
.withNamespace(NamespaceUtil.ofRole(ident.namespace().level(0)))
-          //          .build();
-          cache.invalidate(nameIdentifier, Entity.EntityType.ROLE);
+        roleName -> {
+          Namespace namespaceRole = 
NamespaceUtil.ofRole(ident.namespace().level(0));
+          NameIdentifier nameIdentifierRole = NameIdentifier.of(namespaceRole, 
roleName);
+          cache.invalidate(nameIdentifierRole, Entity.EntityType.ROLE);
         });
 
-    return backend.update(ident, entityType, updater);
+    return update(ident, type, entityType, updater);
   }
 
   public <E extends Entity & HasIdentifier> E update(

Reply via email to