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

emaynard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new 78842c1bb Refactor EntityCache into an interface (#1193)
78842c1bb is described below

commit 78842c1bb7197bb8cbbe42853e92d404b3965a27
Author: Andrew Guterman <[email protected]>
AuthorDate: Mon Apr 28 17:03:03 2025 -0700

    Refactor EntityCache into an interface (#1193)
    
    * Refactor EntityCache to an interface
    
    * fix
    
    * spotless
---
 .../jdbc/JdbcMetaStoreManagerFactory.java          |   4 +-
 .../LocalPolarisMetaStoreManagerFactory.java       |   4 +-
 .../core/persistence/cache/EntityCache.java        | 418 +--------------------
 .../{EntityCache.java => InMemoryEntityCache.java} |  10 +-
 ...CacheTest.java => InMemoryEntityCacheTest.java} |  14 +-
 .../polaris/core/persistence/BaseResolverTest.java |  24 +-
 .../quarkus/catalog/CatalogNoEntityCacheTest.java  |   4 +-
 .../quarkus/catalog/GenericTableCatalogTest.java   |  10 +-
 .../quarkus/catalog/IcebergCatalogTest.java        |   9 +-
 .../quarkus/catalog/IcebergCatalogViewTest.java    |   6 +-
 .../catalog/PolarisCatalogWithEntityCacheTest.java |   6 +-
 .../service/quarkus/catalog/PolicyCatalogTest.java |  10 +-
 12 files changed, 70 insertions(+), 449 deletions(-)

diff --git 
a/extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcMetaStoreManagerFactory.java
 
b/extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcMetaStoreManagerFactory.java
index 0f981a99b..f19194f33 100644
--- 
a/extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcMetaStoreManagerFactory.java
+++ 
b/extension/persistence/relational-jdbc/src/main/java/org/apache/polaris/extension/persistence/relational/jdbc/JdbcMetaStoreManagerFactory.java
@@ -46,6 +46,7 @@ import 
org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.PrincipalSecretsGenerator;
 import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
 import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.BaseResult;
 import org.apache.polaris.core.persistence.dao.entity.EntityResult;
 import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
@@ -209,7 +210,8 @@ public class JdbcMetaStoreManagerFactory implements 
MetaStoreManagerFactory {
   public synchronized EntityCache getOrCreateEntityCache(RealmContext 
realmContext) {
     if (!entityCacheMap.containsKey(realmContext.getRealmIdentifier())) {
       PolarisMetaStoreManager metaStoreManager = 
getOrCreateMetaStoreManager(realmContext);
-      entityCacheMap.put(realmContext.getRealmIdentifier(), new 
EntityCache(metaStoreManager));
+      entityCacheMap.put(
+          realmContext.getRealmIdentifier(), new 
InMemoryEntityCache(metaStoreManager));
     }
 
     return entityCacheMap.get(realmContext.getRealmIdentifier());
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
index b005d411f..85288f0dd 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
@@ -34,6 +34,7 @@ import org.apache.polaris.core.entity.PolarisEntitySubType;
 import org.apache.polaris.core.entity.PolarisEntityType;
 import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
 import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.BaseResult;
 import org.apache.polaris.core.persistence.dao.entity.EntityResult;
 import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
@@ -190,7 +191,8 @@ public abstract class 
LocalPolarisMetaStoreManagerFactory<StoreType>
   public synchronized EntityCache getOrCreateEntityCache(RealmContext 
realmContext) {
     if (!entityCacheMap.containsKey(realmContext.getRealmIdentifier())) {
       PolarisMetaStoreManager metaStoreManager = 
getOrCreateMetaStoreManager(realmContext);
-      entityCacheMap.put(realmContext.getRealmIdentifier(), new 
EntityCache(metaStoreManager));
+      entityCacheMap.put(
+          realmContext.getRealmIdentifier(), new 
InMemoryEntityCache(metaStoreManager));
     }
 
     return entityCacheMap.get(realmContext.getRealmIdentifier());
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
index 752342ffe..cd438c995 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
@@ -18,235 +18,21 @@
  */
 package org.apache.polaris.core.persistence.cache;
 
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.github.benmanes.caffeine.cache.RemovalListener;
 import jakarta.annotation.Nonnull;
 import jakarta.annotation.Nullable;
-import java.util.AbstractMap;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
 import org.apache.polaris.core.PolarisCallContext;
-import org.apache.polaris.core.config.BehaviorChangeConfiguration;
-import org.apache.polaris.core.config.FeatureConfiguration;
-import org.apache.polaris.core.config.PolarisConfiguration;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisEntityType;
-import org.apache.polaris.core.entity.PolarisGrantRecord;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.ResolvedPolarisEntity;
-import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult;
-
-/** The entity cache, can be private or shared */
-public class EntityCache {
-
-  // cache mode
-  private EntityCacheMode cacheMode;
-
-  // the meta store manager
-  private final PolarisMetaStoreManager polarisMetaStoreManager;
-
-  // Caffeine cache to keep entries by id
-  private final Cache<Long, ResolvedPolarisEntity> byId;
-
-  // index by name
-  private final AbstractMap<EntityCacheByNameKey, ResolvedPolarisEntity> 
byName;
-
-  /**
-   * Constructor. Cache can be private or shared
-   *
-   * @param polarisMetaStoreManager the meta store manager implementation
-   */
-  public EntityCache(@Nonnull PolarisMetaStoreManager polarisMetaStoreManager) 
{
-
-    // by name cache
-    this.byName = new ConcurrentHashMap<>();
-
-    // When an entry is removed, we simply remove it from the byName map
-    RemovalListener<Long, ResolvedPolarisEntity> removalListener =
-        (key, value, cause) -> {
-          if (value != null) {
-            // compute name key
-            EntityCacheByNameKey nameKey = new 
EntityCacheByNameKey(value.getEntity());
-
-            // if it is still active, remove it from the name key
-            this.byName.remove(nameKey, value);
-          }
-        };
-
-    long weigherTarget =
-        
PolarisConfiguration.loadConfig(FeatureConfiguration.ENTITY_CACHE_WEIGHER_TARGET);
-    Caffeine<Long, ResolvedPolarisEntity> byIdBuilder =
-        Caffeine.newBuilder()
-            .maximumWeight(weigherTarget)
-            .weigher(EntityWeigher.asWeigher())
-            .expireAfterAccess(1, TimeUnit.HOURS) // Expire entries after 1 
hour of no access
-            .removalListener(removalListener); // Set the removal listener
-
-    if 
(PolarisConfiguration.loadConfig(BehaviorChangeConfiguration.ENTITY_CACHE_SOFT_VALUES))
 {
-      byIdBuilder.softValues();
-    }
-
-    // use a Caffeine cache to purge entries when those have not been used for 
a long time.
-    this.byId = byIdBuilder.build();
-
-    // remember the meta store manager
-    this.polarisMetaStoreManager = polarisMetaStoreManager;
-
-    // enabled by default
-    this.cacheMode = EntityCacheMode.ENABLE;
-  }
 
+/** Interface for a Polaris entity cache */
+public interface EntityCache {
   /**
    * Remove the specified cache entry from the cache
    *
    * @param cacheEntry cache entry to remove
    */
-  public void removeCacheEntry(@Nonnull ResolvedPolarisEntity cacheEntry) {
-    // compute name key
-    EntityCacheByNameKey nameKey = new 
EntityCacheByNameKey(cacheEntry.getEntity());
-
-    // remove this old entry, this will immediately remove the named entry
-    this.byId.asMap().remove(cacheEntry.getEntity().getId(), cacheEntry);
-
-    // remove it from the name key
-    this.byName.remove(nameKey, cacheEntry);
-  }
-
-  /**
-   * Cache new entry
-   *
-   * @param cacheEntry new cache entry
-   */
-  private void cacheNewEntry(@Nonnull ResolvedPolarisEntity cacheEntry) {
-
-    // compute name key
-    EntityCacheByNameKey nameKey = new 
EntityCacheByNameKey(cacheEntry.getEntity());
-
-    // get old value if one exist
-    ResolvedPolarisEntity oldCacheEntry = 
this.byId.getIfPresent(cacheEntry.getEntity().getId());
-
-    // put new entry, only if really newer one
-    this.byId
-        .asMap()
-        .merge(
-            cacheEntry.getEntity().getId(),
-            cacheEntry,
-            (oldValue, newValue) -> this.isNewer(newValue, oldValue) ? 
newValue : oldValue);
-
-    // only update the name key if this entity was not dropped
-    if (!cacheEntry.getEntity().isDropped()) {
-      // here we don't really care about concurrent update to the key. 
Basically if we are
-      // pointing to the wrong entry, we will detect this and fix the issue
-      this.byName.put(nameKey, cacheEntry);
-    }
-
-    // remove old name if it has changed
-    if (oldCacheEntry != null) {
-      // old name
-      EntityCacheByNameKey oldNameKey = new 
EntityCacheByNameKey(oldCacheEntry.getEntity());
-      if (!oldNameKey.equals(nameKey)) {
-        this.byName.remove(oldNameKey, oldCacheEntry);
-      }
-    }
-  }
-
-  /**
-   * Determine if the newer value is really newer
-   *
-   * @param newValue new cache entry
-   * @param oldValue old cache entry
-   * @return true if the newer cache entry
-   */
-  private boolean isNewer(ResolvedPolarisEntity newValue, 
ResolvedPolarisEntity oldValue) {
-    return (newValue.getEntity().getEntityVersion() > 
oldValue.getEntity().getEntityVersion()
-        || newValue.getEntity().getGrantRecordsVersion()
-            > oldValue.getEntity().getGrantRecordsVersion());
-  }
-
-  /**
-   * Replace an old entry with a new one
-   *
-   * @param oldCacheEntry old entry
-   * @param newCacheEntry new entry
-   */
-  private void replaceCacheEntry(
-      @Nullable ResolvedPolarisEntity oldCacheEntry, @Nonnull 
ResolvedPolarisEntity newCacheEntry) {
-
-    // need to remove old?
-    if (oldCacheEntry != null) {
-      // only replace if there is a difference
-      if (this.entityNameKeyMismatch(oldCacheEntry.getEntity(), 
newCacheEntry.getEntity())
-          || oldCacheEntry.getEntity().getEntityVersion()
-              < newCacheEntry.getEntity().getEntityVersion()
-          || oldCacheEntry.getEntity().getGrantRecordsVersion()
-              < newCacheEntry.getEntity().getGrantRecordsVersion()) {
-        // write new one
-        this.cacheNewEntry(newCacheEntry);
-
-        // delete the old one assuming it has not been replaced by the above 
new entry
-        this.removeCacheEntry(oldCacheEntry);
-      }
-    } else {
-      // write new one
-      this.cacheNewEntry(newCacheEntry);
-    }
-  }
-
-  /**
-   * Check if two entities have different cache keys (either by id or by name)
-   *
-   * @param entity the entity
-   * @param otherEntity the other entity
-   * @return true if there is a mismatch
-   */
-  private boolean entityNameKeyMismatch(
-      @Nonnull PolarisBaseEntity entity, @Nonnull PolarisBaseEntity 
otherEntity) {
-    return entity.getId() != otherEntity.getId()
-        || entity.getParentId() != otherEntity.getParentId()
-        || !entity.getName().equals(otherEntity.getName())
-        || entity.getTypeCode() != otherEntity.getTypeCode();
-  }
-
-  /**
-   * Get the current cache mode
-   *
-   * @return the cache mode
-   */
-  public EntityCacheMode getCacheMode() {
-    return cacheMode;
-  }
-
-  /**
-   * Allows to change the caching mode for testing
-   *
-   * @param cacheMode the cache mode
-   */
-  public void setCacheMode(EntityCacheMode cacheMode) {
-    this.cacheMode = cacheMode;
-  }
-
-  /**
-   * Get a cache entity entry given the id of the entity
-   *
-   * @param entityId entity id
-   * @return the cache entry or null if not found
-   */
-  public @Nullable ResolvedPolarisEntity getEntityById(long entityId) {
-    return byId.getIfPresent(entityId);
-  }
-
-  /**
-   * Get a cache entity entry given the name key of the entity
-   *
-   * @param entityNameKey entity name key
-   * @return the cache entry or null if not found
-   */
-  public @Nullable ResolvedPolarisEntity getEntityByName(
-      @Nonnull EntityCacheByNameKey entityNameKey) {
-    return byName.get(entityNameKey);
-  }
+  void removeCacheEntry(@Nonnull ResolvedPolarisEntity cacheEntry);
 
   /**
    * Refresh the cache if needs be with a version of the entity/grant records 
matching the minimum
@@ -260,106 +46,12 @@ public class EntityCache {
    *     records should be reloaded if needed
    * @return the cache entry for the entity or null if the specified entity 
does not exist
    */
-  public @Nullable ResolvedPolarisEntity getAndRefreshIfNeeded(
+  @Nullable
+  ResolvedPolarisEntity getAndRefreshIfNeeded(
       @Nonnull PolarisCallContext callContext,
       @Nonnull PolarisBaseEntity entityToValidate,
       int entityMinVersion,
-      int entityGrantRecordsMinVersion) {
-    long entityCatalogId = entityToValidate.getCatalogId();
-    long entityId = entityToValidate.getId();
-    PolarisEntityType entityType = entityToValidate.getType();
-
-    // first lookup the cache to find the existing cache entry
-    ResolvedPolarisEntity existingCacheEntry = this.getEntityById(entityId);
-
-    // the caller's fetched entity may have come from a stale lookup byName; 
we should consider
-    // the existingCacheEntry to be the older of the two for purposes of 
invalidation to make
-    // sure when we replaceCacheEntry we're also removing the old name if it's 
no longer valid
-    EntityCacheByNameKey nameKey = new EntityCacheByNameKey(entityToValidate);
-    ResolvedPolarisEntity existingCacheEntryByName = 
this.getEntityByName(nameKey);
-    if (existingCacheEntryByName != null
-        && existingCacheEntry != null
-        && isNewer(existingCacheEntry, existingCacheEntryByName)) {
-      existingCacheEntry = existingCacheEntryByName;
-    }
-
-    // the new one to be returned
-    final ResolvedPolarisEntity newCacheEntry;
-
-    // see if we need to load or refresh that entity
-    if (existingCacheEntry == null
-        || existingCacheEntry.getEntity().getEntityVersion() < entityMinVersion
-        || existingCacheEntry.getEntity().getGrantRecordsVersion() < 
entityGrantRecordsMinVersion) {
-
-      // the refreshed entity
-      final ResolvedEntityResult refreshedCacheEntry;
-
-      // was not found in the cache?
-      final PolarisBaseEntity entity;
-      final List<PolarisGrantRecord> grantRecords;
-      final int grantRecordsVersion;
-      if (existingCacheEntry == null) {
-        // try to load it
-        refreshedCacheEntry =
-            this.polarisMetaStoreManager.loadResolvedEntityById(
-                callContext, entityCatalogId, entityId, entityType);
-        if (refreshedCacheEntry.isSuccess()) {
-          entity = refreshedCacheEntry.getEntity();
-          grantRecords = refreshedCacheEntry.getEntityGrantRecords();
-          grantRecordsVersion = refreshedCacheEntry.getGrantRecordsVersion();
-        } else {
-          return null;
-        }
-      } else {
-        // refresh it
-        refreshedCacheEntry =
-            this.polarisMetaStoreManager.refreshResolvedEntity(
-                callContext,
-                existingCacheEntry.getEntity().getEntityVersion(),
-                existingCacheEntry.getEntity().getGrantRecordsVersion(),
-                entityType,
-                entityCatalogId,
-                entityId);
-        if (refreshedCacheEntry.isSuccess()) {
-          entity =
-              (refreshedCacheEntry.getEntity() != null)
-                  ? refreshedCacheEntry.getEntity()
-                  : existingCacheEntry.getEntity();
-          if (refreshedCacheEntry.getEntityGrantRecords() != null) {
-            grantRecords = refreshedCacheEntry.getEntityGrantRecords();
-            grantRecordsVersion = refreshedCacheEntry.getGrantRecordsVersion();
-          } else {
-            grantRecords = existingCacheEntry.getAllGrantRecords();
-            grantRecordsVersion = 
existingCacheEntry.getEntity().getGrantRecordsVersion();
-          }
-        } else {
-          // entity has been purged, remove it
-          this.removeCacheEntry(existingCacheEntry);
-          return null;
-        }
-      }
-
-      // assert that entity, grant records and version are all set
-      callContext.getDiagServices().checkNotNull(entity, 
"unexpected_null_entity");
-      callContext.getDiagServices().checkNotNull(grantRecords, 
"unexpected_null_grant_records");
-      callContext
-          .getDiagServices()
-          .check(grantRecordsVersion > 0, 
"unexpected_null_grant_records_version");
-
-      // create new cache entry
-      newCacheEntry =
-          new ResolvedPolarisEntity(
-              callContext.getDiagServices(), entity, grantRecords, 
grantRecordsVersion);
-
-      // insert cache entry
-      this.replaceCacheEntry(existingCacheEntry, newCacheEntry);
-    } else {
-      // found it in the cache and it is up-to-date, simply return it
-      newCacheEntry = existingCacheEntry;
-    }
-
-    return newCacheEntry;
-  }
+      int entityGrantRecordsMinVersion);
 
   /**
    * Get the specified entity by name and load it if it is not found.
@@ -370,52 +62,12 @@ public class EntityCache {
    * @return null if the entity does not exist or was dropped. Else return the 
entry for that
    *     entity, either as found in the cache or loaded from the backend
    */
-  public @Nullable EntityCacheLookupResult getOrLoadEntityById(
+  @Nullable
+  EntityCacheLookupResult getOrLoadEntityById(
       @Nonnull PolarisCallContext callContext,
       long entityCatalogId,
       long entityId,
-      PolarisEntityType entityType) {
-
-    // if it exists, we are set
-    ResolvedPolarisEntity entry = this.getEntityById(entityId);
-    final boolean cacheHit;
-
-    // we need to load it if it does not exist
-    if (entry == null) {
-      // this is a miss
-      cacheHit = false;
-
-      // load it
-      ResolvedEntityResult result =
-          polarisMetaStoreManager.loadResolvedEntityById(
-              callContext, entityCatalogId, entityId, entityType);
-
-      // not found, exit
-      if (!result.isSuccess()) {
-        return null;
-      }
-
-      // if found, setup entry
-      callContext.getDiagServices().checkNotNull(result.getEntity(), 
"entity_should_loaded");
-      callContext
-          .getDiagServices()
-          .checkNotNull(result.getEntityGrantRecords(), 
"entity_grant_records_should_loaded");
-      entry =
-          new ResolvedPolarisEntity(
-              callContext.getDiagServices(),
-              result.getEntity(),
-              result.getEntityGrantRecords(),
-              result.getGrantRecordsVersion());
-
-      // the above loading could take a long time so check again if the entry 
exists and only
-      this.cacheNewEntry(entry);
-    } else {
-      cacheHit = true;
-    }
-
-    // return what we found
-    return new EntityCacheLookupResult(entry, cacheHit);
-  }
+      PolarisEntityType entityType);
 
   /**
    * Get the specified entity by name and load it if it is not found.
@@ -425,53 +77,7 @@ public class EntityCache {
    * @return null if the entity does not exist or was dropped. Else return the 
entry for that
    *     entity, either as found in the cache or loaded from the backend
    */
-  public @Nullable EntityCacheLookupResult getOrLoadEntityByName(
-      @Nonnull PolarisCallContext callContext, @Nonnull EntityCacheByNameKey 
entityNameKey) {
-
-    // if it exists, we are set
-    ResolvedPolarisEntity entry = this.getEntityByName(entityNameKey);
-    final boolean cacheHit;
-
-    // we need to load it if it does not exist
-    if (entry == null) {
-      // this is a miss
-      cacheHit = false;
-
-      // load it
-      ResolvedEntityResult result =
-          polarisMetaStoreManager.loadResolvedEntityByName(
-              callContext,
-              entityNameKey.getCatalogId(),
-              entityNameKey.getParentId(),
-              entityNameKey.getType(),
-              entityNameKey.getName());
-
-      // not found, exit
-      if (!result.isSuccess()) {
-        return null;
-      }
-
-      // validate return
-      callContext.getDiagServices().checkNotNull(result.getEntity(), 
"entity_should_loaded");
-      callContext
-          .getDiagServices()
-          .checkNotNull(result.getEntityGrantRecords(), 
"entity_grant_records_should_loaded");
-
-      // if found, setup entry
-      entry =
-          new ResolvedPolarisEntity(
-              callContext.getDiagServices(),
-              result.getEntity(),
-              result.getEntityGrantRecords(),
-              result.getGrantRecordsVersion());
-
-      // the above loading could take a long time so check again if the entry 
exists and only
-      this.cacheNewEntry(entry);
-    } else {
-      cacheHit = true;
-    }
-
-    // return what we found
-    return new EntityCacheLookupResult(entry, cacheHit);
-  }
+  @Nullable
+  EntityCacheLookupResult getOrLoadEntityByName(
+      @Nonnull PolarisCallContext callContext, @Nonnull EntityCacheByNameKey 
entityNameKey);
 }
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCache.java
similarity index 98%
copy from 
polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
copy to 
polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCache.java
index 752342ffe..4599f4aed 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/EntityCache.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCache.java
@@ -38,8 +38,8 @@ import 
org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.ResolvedPolarisEntity;
 import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult;
 
-/** The entity cache, can be private or shared */
-public class EntityCache {
+/** An in-memory entity cache with a limit of 100k entities and a 1h TTL. */
+public class InMemoryEntityCache implements EntityCache {
 
   // cache mode
   private EntityCacheMode cacheMode;
@@ -58,7 +58,7 @@ public class EntityCache {
    *
    * @param polarisMetaStoreManager the meta store manager implementation
    */
-  public EntityCache(@Nonnull PolarisMetaStoreManager polarisMetaStoreManager) 
{
+  public InMemoryEntityCache(@Nonnull PolarisMetaStoreManager 
polarisMetaStoreManager) {
 
     // by name cache
     this.byName = new ConcurrentHashMap<>();
@@ -103,6 +103,7 @@ public class EntityCache {
    *
    * @param cacheEntry cache entry to remove
    */
+  @Override
   public void removeCacheEntry(@Nonnull ResolvedPolarisEntity cacheEntry) {
     // compute name key
     EntityCacheByNameKey nameKey = new 
EntityCacheByNameKey(cacheEntry.getEntity());
@@ -260,6 +261,7 @@ public class EntityCache {
    *     records should be reloaded if needed
    * @return the cache entry for the entity or null if the specified entity 
does not exist
    */
+  @Override
   public @Nullable ResolvedPolarisEntity getAndRefreshIfNeeded(
       @Nonnull PolarisCallContext callContext,
       @Nonnull PolarisBaseEntity entityToValidate,
@@ -370,6 +372,7 @@ public class EntityCache {
    * @return null if the entity does not exist or was dropped. Else return the 
entry for that
    *     entity, either as found in the cache or loaded from the backend
    */
+  @Override
   public @Nullable EntityCacheLookupResult getOrLoadEntityById(
       @Nonnull PolarisCallContext callContext,
       long entityCatalogId,
@@ -425,6 +428,7 @@ public class EntityCache {
    * @return null if the entity does not exist or was dropped. Else return the 
entry for that
    *     entity, either as found in the cache or loaded from the backend
    */
+  @Override
   public @Nullable EntityCacheLookupResult getOrLoadEntityByName(
       @Nonnull PolarisCallContext callContext, @Nonnull EntityCacheByNameKey 
entityNameKey) {
 
diff --git 
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/EntityCacheTest.java
 
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCacheTest.java
similarity index 98%
rename from 
polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/EntityCacheTest.java
rename to 
polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCacheTest.java
index c21bef002..72b75ad05 100644
--- 
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/EntityCacheTest.java
+++ 
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/cache/InMemoryEntityCacheTest.java
@@ -45,7 +45,7 @@ import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
 /** Unit testing of the entity cache */
-public class EntityCacheTest {
+public class InMemoryEntityCacheTest {
 
   // diag services
   private final PolarisDiagnostics diagServices;
@@ -87,7 +87,7 @@ public class EntityCacheTest {
    * - P2(PR2)
    * </pre>
    */
-  public EntityCacheTest() {
+  public InMemoryEntityCacheTest() {
     diagServices = new PolarisDefaultDiagServiceImpl();
     store = new TreeMapMetaStore(diagServices);
     metaStore = new TreeMapTransactionalPersistenceImpl(store, Mockito.mock(), 
RANDOM_SECRETS);
@@ -102,14 +102,14 @@ public class EntityCacheTest {
   /**
    * @return new cache for the entity store
    */
-  EntityCache allocateNewCache() {
-    return new EntityCache(this.metaStoreManager);
+  InMemoryEntityCache allocateNewCache() {
+    return new InMemoryEntityCache(this.metaStoreManager);
   }
 
   @Test
   void testGetOrLoadEntityByName() {
     // get a new cache
-    EntityCache cache = this.allocateNewCache();
+    InMemoryEntityCache cache = this.allocateNewCache();
 
     // should exist and no cache hit
     EntityCacheLookupResult lookup =
@@ -278,7 +278,7 @@ public class EntityCacheTest {
   @Test
   void testRefresh() {
     // allocate a new cache
-    EntityCache cache = this.allocateNewCache();
+    InMemoryEntityCache cache = this.allocateNewCache();
 
     // should exist and no cache hit
     EntityCacheLookupResult lookup =
@@ -423,7 +423,7 @@ public class EntityCacheTest {
   @Test
   void testRenameAndCacheDestinationBeforeLoadingSource() {
     // get a new cache
-    EntityCache cache = this.allocateNewCache();
+    InMemoryEntityCache cache = this.allocateNewCache();
 
     EntityCacheLookupResult lookup =
         cache.getOrLoadEntityByName(
diff --git 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BaseResolverTest.java
 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BaseResolverTest.java
index 108db5a6d..728187a38 100644
--- 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BaseResolverTest.java
+++ 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BaseResolverTest.java
@@ -40,7 +40,7 @@ import org.apache.polaris.core.entity.PolarisGrantRecord;
 import org.apache.polaris.core.entity.PolarisPrivilege;
 import org.apache.polaris.core.entity.PrincipalEntity;
 import org.apache.polaris.core.entity.PrincipalRoleEntity;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.EntityResult;
 import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult;
 import org.apache.polaris.core.persistence.resolver.Resolver;
@@ -57,7 +57,7 @@ public abstract class BaseResolverTest {
   protected PolarisBaseEntity P1;
 
   // cache we are using
-  protected EntityCache cache;
+  protected InMemoryEntityCache cache;
 
   // whenever constructing a new Resolver instance, if false, disable cache 
for that Resolver
   // instance by giving it a null cache regardless of the current state of the 
test-level
@@ -433,7 +433,7 @@ public abstract class BaseResolverTest {
    * @return new resolver to test with
    */
   @Nonnull
-  private Resolver allocateResolver(@Nullable EntityCache cache) {
+  private Resolver allocateResolver(@Nullable InMemoryEntityCache cache) {
     return this.allocateResolver(cache, null);
   }
 
@@ -447,7 +447,7 @@ public abstract class BaseResolverTest {
    */
   @Nonnull
   private Resolver allocateResolver(
-      @Nullable EntityCache cache, @Nullable String referenceCatalogName) {
+      @Nullable InMemoryEntityCache cache, @Nullable String 
referenceCatalogName) {
     return this.allocateResolver(cache, null, referenceCatalogName);
   }
 
@@ -462,13 +462,13 @@ public abstract class BaseResolverTest {
    */
   @Nonnull
   private Resolver allocateResolver(
-      @Nullable EntityCache cache,
+      @Nullable InMemoryEntityCache cache,
       Set<String> principalRolesScope,
       @Nullable String referenceCatalogName) {
 
     // create a new cache if needs be
     if (cache == null) {
-      this.cache = new EntityCache(metaStoreManager());
+      this.cache = new InMemoryEntityCache(metaStoreManager());
     }
     boolean allRoles = principalRolesScope == null;
     Optional<List<PrincipalRoleEntity>> roleEntities =
@@ -531,7 +531,7 @@ public abstract class BaseResolverTest {
    * @param principalRoleName name of the principal role, should exist
    */
   private void resolvePrincipalAndPrincipalRole(
-      EntityCache cache, String principalName, boolean exists, String 
principalRoleName) {
+      InMemoryEntityCache cache, String principalName, boolean exists, String 
principalRoleName) {
     Resolver resolver = allocateResolver(cache);
 
     // for a principal creation, we simply want to test if the principal we 
are creating exists
@@ -600,7 +600,7 @@ public abstract class BaseResolverTest {
    * @return resolver we created and which has been validated.
    */
   private Resolver resolveDriver(
-      EntityCache cache,
+      InMemoryEntityCache cache,
       Set<String> principalRolesScope,
       String principalName,
       boolean isPrincipalNameOptional,
@@ -631,7 +631,7 @@ public abstract class BaseResolverTest {
    * @return resolver we created and which has been validated.
    */
   private Resolver resolveDriver(
-      EntityCache cache,
+      InMemoryEntityCache cache,
       String catalogName,
       ResolverPath path,
       List<ResolverPath> paths,
@@ -651,7 +651,7 @@ public abstract class BaseResolverTest {
    * @return resolver we created and which has been validated.
    */
   private Resolver resolveDriver(
-      EntityCache cache,
+      InMemoryEntityCache cache,
       Set<String> principalRolesScope,
       String catalogName,
       Set<String> expectedActivatedCatalogRoles) {
@@ -679,7 +679,7 @@ public abstract class BaseResolverTest {
    * @return resolver we created and which has been validated.
    */
   private Resolver resolveDriver(
-      EntityCache cache,
+      InMemoryEntityCache cache,
       String catalogName,
       String catalogRoleName,
       ResolverStatus.StatusEnum expectedStatus) {
@@ -715,7 +715,7 @@ public abstract class BaseResolverTest {
    * @return resolver we created and which has been validated.
    */
   private Resolver resolveDriver(
-      EntityCache cache,
+      InMemoryEntityCache cache,
       Set<String> principalRolesScope,
       String principalName,
       boolean isPrincipalNameOptional,
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/CatalogNoEntityCacheTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/CatalogNoEntityCacheTest.java
index 7e92b97b5..895b6ab81 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/CatalogNoEntityCacheTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/CatalogNoEntityCacheTest.java
@@ -22,7 +22,7 @@ import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.TestProfile;
 import jakarta.annotation.Nullable;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 
 @QuarkusTest
 @TestProfile(IcebergCatalogTest.Profile.class)
@@ -30,7 +30,7 @@ public class CatalogNoEntityCacheTest extends 
IcebergCatalogTest {
 
   @Nullable
   @Override
-  protected EntityCache createEntityCache(PolarisMetaStoreManager 
metaStoreManager) {
+  protected InMemoryEntityCache createEntityCache(PolarisMetaStoreManager 
metaStoreManager) {
     return null;
   }
 }
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/GenericTableCatalogTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/GenericTableCatalogTest.java
index 462cc7bb7..96b1010b4 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/GenericTableCatalogTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/GenericTableCatalogTest.java
@@ -63,7 +63,7 @@ import 
org.apache.polaris.core.persistence.MetaStoreManagerFactory;
 import org.apache.polaris.core.persistence.PolarisEntityManager;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.BaseResult;
 import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
 import 
org.apache.polaris.core.persistence.transactional.TransactionalPersistence;
@@ -171,7 +171,9 @@ public class GenericTableCatalogTest {
             Clock.systemDefaultZone());
     entityManager =
         new PolarisEntityManager(
-            metaStoreManager, new StorageCredentialCache(), new 
EntityCache(metaStoreManager));
+            metaStoreManager,
+            new StorageCredentialCache(),
+            new InMemoryEntityCache(metaStoreManager));
 
     callContext = CallContext.of(realmContext, polarisContext);
 
@@ -293,8 +295,8 @@ public class GenericTableCatalogTest {
       }
 
       @Override
-      public EntityCache getOrCreateEntityCache(RealmContext realmContext) {
-        return new EntityCache(metaStoreManager);
+      public InMemoryEntityCache getOrCreateEntityCache(RealmContext 
realmContext) {
+        return new InMemoryEntityCache(metaStoreManager);
       }
 
       @Override
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java
index 39c8950fe..5a83330a5 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java
@@ -94,7 +94,7 @@ import 
org.apache.polaris.core.persistence.PolarisEntityManager;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
 import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.BaseResult;
 import org.apache.polaris.core.persistence.dao.entity.EntityResult;
 import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
@@ -219,7 +219,8 @@ public abstract class IcebergCatalogTest extends 
CatalogTests<IcebergCatalog> {
   }
 
   @Nullable
-  protected abstract EntityCache createEntityCache(PolarisMetaStoreManager 
metaStoreManager);
+  protected abstract InMemoryEntityCache createEntityCache(
+      PolarisMetaStoreManager metaStoreManager);
 
   @BeforeEach
   @SuppressWarnings("unchecked")
@@ -401,8 +402,8 @@ public abstract class IcebergCatalogTest extends 
CatalogTests<IcebergCatalog> {
       }
 
       @Override
-      public EntityCache getOrCreateEntityCache(RealmContext realmContext) {
-        return new EntityCache(metaStoreManager);
+      public InMemoryEntityCache getOrCreateEntityCache(RealmContext 
realmContext) {
+        return new InMemoryEntityCache(metaStoreManager);
       }
 
       @Override
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java
index 127dd7f23..25089d5c4 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java
@@ -57,7 +57,7 @@ import org.apache.polaris.core.entity.PrincipalEntity;
 import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
 import org.apache.polaris.core.persistence.PolarisEntityManager;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.secrets.UserSecretsManager;
 import org.apache.polaris.core.secrets.UserSecretsManagerFactory;
 import org.apache.polaris.core.storage.cache.StorageCredentialCache;
@@ -158,7 +158,9 @@ public class IcebergCatalogViewTest extends 
ViewCatalogTests<IcebergCatalog> {
 
     PolarisEntityManager entityManager =
         new PolarisEntityManager(
-            metaStoreManager, new StorageCredentialCache(), new 
EntityCache(metaStoreManager));
+            metaStoreManager,
+            new StorageCredentialCache(),
+            new InMemoryEntityCache(metaStoreManager));
 
     CallContext callContext = CallContext.of(realmContext, polarisContext);
     CallContext.setCurrentContext(callContext);
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisCatalogWithEntityCacheTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisCatalogWithEntityCacheTest.java
index 64c96bb5b..079b02bef 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisCatalogWithEntityCacheTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisCatalogWithEntityCacheTest.java
@@ -22,7 +22,7 @@ import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.TestProfile;
 import jakarta.annotation.Nullable;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 
 @QuarkusTest
 @TestProfile(IcebergCatalogTest.Profile.class)
@@ -30,7 +30,7 @@ public class PolarisCatalogWithEntityCacheTest extends 
IcebergCatalogTest {
 
   @Nullable
   @Override
-  protected EntityCache createEntityCache(PolarisMetaStoreManager 
metaStoreManager) {
-    return new EntityCache(metaStoreManager);
+  protected InMemoryEntityCache createEntityCache(PolarisMetaStoreManager 
metaStoreManager) {
+    return new InMemoryEntityCache(metaStoreManager);
   }
 }
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java
index 966d56457..57bd52132 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java
@@ -71,7 +71,7 @@ import 
org.apache.polaris.core.persistence.PolarisEntityManager;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
 import org.apache.polaris.core.persistence.PolicyMappingAlreadyExistsException;
 import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
-import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.cache.InMemoryEntityCache;
 import org.apache.polaris.core.persistence.dao.entity.BaseResult;
 import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
 import 
org.apache.polaris.core.persistence.transactional.TransactionalPersistence;
@@ -194,7 +194,9 @@ public class PolicyCatalogTest {
             Clock.systemDefaultZone());
     entityManager =
         new PolarisEntityManager(
-            metaStoreManager, new StorageCredentialCache(), new 
EntityCache(metaStoreManager));
+            metaStoreManager,
+            new StorageCredentialCache(),
+            new InMemoryEntityCache(metaStoreManager));
 
     callContext = CallContext.of(realmContext, polarisContext);
 
@@ -315,8 +317,8 @@ public class PolicyCatalogTest {
       }
 
       @Override
-      public EntityCache getOrCreateEntityCache(RealmContext realmContext) {
-        return new EntityCache(metaStoreManager);
+      public InMemoryEntityCache getOrCreateEntityCache(RealmContext 
realmContext) {
+        return new InMemoryEntityCache(metaStoreManager);
       }
 
       @Override


Reply via email to