Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import org.apache.polaris.core.persistence.dao.entity.EntityResult;
import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -70,7 +69,6 @@ public class JdbcMetaStoreManagerFactory implements MetaStoreManagerFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(JdbcMetaStoreManagerFactory.class);

final Map<String, PolarisMetaStoreManager> metaStoreManagerMap = new HashMap<>();
final Map<String, StorageCredentialCache> storageCredentialCacheMap = new HashMap<>();
final Map<String, EntityCache> entityCacheMap = new HashMap<>();
final Map<String, Supplier<BasePersistence>> sessionSupplierMap = new HashMap<>();
protected final PolarisDiagnostics diagServices = new PolarisDefaultDiagServiceImpl();
Expand Down Expand Up @@ -183,7 +181,6 @@ public Map<String, BaseResult> purgeRealms(Iterable<String> realms) {
BaseResult result = metaStoreManager.purge(callContext);
results.put(realm, result);

storageCredentialCacheMap.remove(realm);
sessionSupplierMap.remove(realm);
metaStoreManagerMap.remove(realm);
}
Expand Down Expand Up @@ -218,17 +215,6 @@ public synchronized Supplier<BasePersistence> getOrCreateSessionSupplier(
return sessionSupplierMap.get(realmContext.getRealmIdentifier());
}

@Override
public synchronized StorageCredentialCache getOrCreateStorageCredentialCache(
RealmContext realmContext, RealmConfig realmConfig) {
if (!storageCredentialCacheMap.containsKey(realmContext.getRealmIdentifier())) {
storageCredentialCacheMap.put(
realmContext.getRealmIdentifier(), new StorageCredentialCache());
}

return storageCredentialCacheMap.get(realmContext.getRealmIdentifier());
}

@Override
public synchronized EntityCache getOrCreateEntityCache(
RealmContext realmContext, RealmConfig realmConfig) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
import org.apache.polaris.core.persistence.transactional.TransactionalMetaStoreManagerImpl;
import org.apache.polaris.core.persistence.transactional.TransactionalPersistence;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -54,7 +53,6 @@ public abstract class LocalPolarisMetaStoreManagerFactory<StoreType>
implements MetaStoreManagerFactory {

final Map<String, PolarisMetaStoreManager> metaStoreManagerMap = new HashMap<>();
final Map<String, StorageCredentialCache> storageCredentialCacheMap = new HashMap<>();
final Map<String, EntityCache> entityCacheMap = new HashMap<>();
final Map<String, StoreType> backingStoreMap = new HashMap<>();
final Map<String, Supplier<TransactionalPersistence>> sessionSupplierMap = new HashMap<>();
Expand Down Expand Up @@ -138,7 +136,6 @@ public Map<String, BaseResult> purgeRealms(Iterable<String> realms) {
BaseResult result = metaStoreManager.purge(callContext);
results.put(realm, result);

storageCredentialCacheMap.remove(realm);
backingStoreMap.remove(realm);
sessionSupplierMap.remove(realm);
metaStoreManagerMap.remove(realm);
Expand Down Expand Up @@ -172,17 +169,6 @@ public synchronized Supplier<TransactionalPersistence> getOrCreateSessionSupplie
return sessionSupplierMap.get(realmContext.getRealmIdentifier());
}

@Override
public synchronized StorageCredentialCache getOrCreateStorageCredentialCache(
RealmContext realmContext, RealmConfig realmConfig) {
if (!storageCredentialCacheMap.containsKey(realmContext.getRealmIdentifier())) {
storageCredentialCacheMap.put(
realmContext.getRealmIdentifier(), new StorageCredentialCache());
}

return storageCredentialCacheMap.get(realmContext.getRealmIdentifier());
}

@Override
public synchronized EntityCache getOrCreateEntityCache(
RealmContext realmContext, RealmConfig realmConfig) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.apache.polaris.core.persistence.cache.EntityCache;
import org.apache.polaris.core.persistence.dao.entity.BaseResult;
import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;

/** Configuration interface for configuring the {@link PolarisMetaStoreManager}. */
public interface MetaStoreManagerFactory {
Expand All @@ -36,9 +35,6 @@ public interface MetaStoreManagerFactory {

Supplier<? extends BasePersistence> getOrCreateSessionSupplier(RealmContext realmContext);

StorageCredentialCache getOrCreateStorageCredentialCache(
RealmContext realmContext, RealmConfig realmConfig);

EntityCache getOrCreateEntityCache(RealmContext realmContext, RealmConfig realmConfig);

Map<String, PrincipalSecretsResult> bootstrapRealms(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,13 @@ public class StorageCredentialCache {

private static final Logger LOGGER = LoggerFactory.getLogger(StorageCredentialCache.class);

private static final long CACHE_MAX_NUMBER_OF_ENTRIES = 10_000L;

private final LoadingCache<StorageCredentialCacheKey, StorageCredentialCacheEntry> cache;

/** Initialize the creds cache */
public StorageCredentialCache() {
public StorageCredentialCache(StorageCredentialCacheConfig cacheConfig) {
cache =
Caffeine.newBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind making the max cache size (by entries) configurable? Now that the caches is shared across realms, configuring its side is more important to users, I guess.

I suppose the cache size has to be a global configuration (maybe a constructor parameter injected via CDI producers + Quarkus config).

Copy link
Contributor Author

@XN137 XN137 Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've added a commit for this, is this what you had in mind?
please double check the naming, module and package.

also imo this raises some questions:

a) how should the new cache config relate to FeatureConfiguration.STORAGE_CREDENTIAL_CACHE_DURATION_SECONDS and FeatureConfiguration.STORAGE_CREDENTIAL_DURATION_SECONDS ?

b) what to do with the InMemoryEntityCache which seems to deal with a single realm? (and thus its max size cant be configured at the application level)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InMemoryEntityCache

I was thinking about that one, too. And I suspect it should be refactored in a similar way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InMemoryEntityCache -> +1 to similar refactoring (better control over heap usage)

.maximumSize(CACHE_MAX_NUMBER_OF_ENTRIES)
.maximumSize(cacheConfig.maxEntries())
.expireAfter(
Expiry.creating(
(StorageCredentialCacheKey key, StorageCredentialCacheEntry entry) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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.polaris.core.storage.cache;

public interface StorageCredentialCacheConfig {

long maxEntries();
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@

public class StorageCredentialCacheTest {

// polaris call context
private final PolarisCallContext callCtx;

// the meta store manager
private final StorageCredentialCacheConfig storageCredentialCacheConfig;
private final PolarisMetaStoreManager metaStoreManager;

private StorageCredentialCache storageCredentialCache;
Expand All @@ -71,12 +69,13 @@ public StorageCredentialCacheTest() {
TransactionalPersistence metaStore =
new TreeMapTransactionalPersistenceImpl(store, Mockito.mock(), RANDOM_SECRETS);
callCtx = new PolarisCallContext(() -> "testRealm", metaStore, diagServices);
storageCredentialCacheConfig = () -> 10_000;
metaStoreManager = Mockito.mock(PolarisMetaStoreManager.class);
storageCredentialCache = newStorageCredentialCache();
}

private StorageCredentialCache newStorageCredentialCache() {
return new StorageCredentialCache();
return new StorageCredentialCache(storageCredentialCacheConfig);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.apache.polaris.core.secrets.UserSecretsManager;
import org.apache.polaris.core.secrets.UserSecretsManagerFactory;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.apache.polaris.core.storage.cache.StorageCredentialCacheConfig;
import org.apache.polaris.service.auth.ActiveRolesProvider;
import org.apache.polaris.service.auth.AuthenticationType;
import org.apache.polaris.service.auth.Authenticator;
Expand Down Expand Up @@ -100,8 +101,9 @@ public Clock clock() {

@Produces
@ApplicationScoped
public StorageCredentialCache storageCredentialCache() {
return new StorageCredentialCache();
public StorageCredentialCache storageCredentialCache(
StorageCredentialCacheConfig storageCredentialCacheConfig) {
return new StorageCredentialCache(storageCredentialCacheConfig);
}

@Produces
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.polaris.service.quarkus.storage;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;
import jakarta.validation.constraints.Min;
import org.apache.polaris.core.storage.cache.StorageCredentialCacheConfig;

@ConfigMapping(prefix = "polaris.storage-credential-cache")
public interface QuarkusStorageCredentialCacheConfig extends StorageCredentialCacheConfig {
@WithName("max-entries")
@WithDefault("10000")
@Min(0)
@Override
long maxEntries();
}
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ public void testSendNotificationSufficientPrivileges() {

PolarisCallContextCatalogFactory factory =
new PolarisCallContextCatalogFactory(
new RealmEntityManagerFactory(null, null) {
new RealmEntityManagerFactory(null, null, null) {
@Override
public PolarisEntityManager getOrCreateEntityManager(RealmContext realmContext) {
return entityManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
import org.apache.polaris.core.storage.aws.AwsCredentialsStorageIntegration;
import org.apache.polaris.core.storage.aws.AwsStorageConfigurationInfo;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.apache.polaris.core.storage.cache.StorageCredentialCacheConfig;
import org.apache.polaris.service.admin.PolarisAdminService;
import org.apache.polaris.service.catalog.PolarisPassthroughResolutionView;
import org.apache.polaris.service.catalog.iceberg.CatalogHandlerUtils;
Expand Down Expand Up @@ -237,6 +238,7 @@ public Map<String, String> getConfigOverrides() {

@Inject MetaStoreManagerFactory metaStoreManagerFactory;
@Inject PolarisConfigurationStore configurationStore;
@Inject StorageCredentialCacheConfig storageCredentialCacheConfig;
@Inject PolarisStorageIntegrationProvider storageIntegrationProvider;
@Inject UserSecretsManagerFactory userSecretsManagerFactory;
@Inject PolarisDiagnostics diagServices;
Expand All @@ -248,6 +250,7 @@ public Map<String, String> getConfigOverrides() {
private UserSecretsManager userSecretsManager;
private PolarisCallContext polarisContext;
private PolarisAdminService adminService;
private StorageCredentialCache storageCredentialCache;
private PolarisEntityManager entityManager;
private FileIOFactory fileIOFactory;
private InMemoryFileIO fileIO;
Expand Down Expand Up @@ -286,10 +289,12 @@ public void before(TestInfo testInfo) {
configurationStore,
Clock.systemDefaultZone());

storageCredentialCache = new StorageCredentialCache(storageCredentialCacheConfig);

entityManager =
new PolarisEntityManager(
metaStoreManager,
new StorageCredentialCache(),
storageCredentialCache,
createEntityCache(polarisContext.getRealmConfig(), metaStoreManager));

PrincipalEntity rootEntity =
Expand Down Expand Up @@ -352,7 +357,8 @@ public void before(TestInfo testInfo) {
.asCatalog()));

RealmEntityManagerFactory realmEntityManagerFactory =
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore);
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache);
this.fileIOFactory =
new DefaultFileIOFactory(realmEntityManagerFactory, metaStoreManagerFactory);

Expand Down Expand Up @@ -986,7 +992,8 @@ public void testValidateNotificationFailToCreateFileIO() {
FileIOFactory fileIOFactory =
spy(
new DefaultFileIOFactory(
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore),
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache),
metaStoreManagerFactory));
IcebergCatalog catalog =
new IcebergCatalog(
Expand Down Expand Up @@ -1877,7 +1884,8 @@ public void testDropTableWithPurge() {
FileIO fileIO =
new TaskFileIOSupplier(
new DefaultFileIOFactory(
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore),
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache),
metaStoreManagerFactory))
.apply(taskEntity, polarisContext);
Assertions.assertThat(fileIO).isNotNull().isInstanceOf(ExceptionMappingFileIO.class);
Expand Down Expand Up @@ -2021,7 +2029,8 @@ public void testFileIOWrapper() {

MeasuredFileIOFactory measured =
new MeasuredFileIOFactory(
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore),
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache),
metaStoreManagerFactory);
IcebergCatalog catalog =
new IcebergCatalog(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import org.apache.polaris.core.secrets.UserSecretsManager;
import org.apache.polaris.core.secrets.UserSecretsManagerFactory;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.apache.polaris.core.storage.cache.StorageCredentialCacheConfig;
import org.apache.polaris.service.admin.PolarisAdminService;
import org.apache.polaris.service.catalog.PolarisPassthroughResolutionView;
import org.apache.polaris.service.catalog.iceberg.IcebergCatalog;
Expand Down Expand Up @@ -130,6 +131,7 @@ public Map<String, String> getConfigOverrides() {
@Inject MetaStoreManagerFactory metaStoreManagerFactory;
@Inject UserSecretsManagerFactory userSecretsManagerFactory;
@Inject PolarisConfigurationStore configurationStore;
@Inject StorageCredentialCacheConfig storageCredentialCacheConfig;
@Inject PolarisDiagnostics diagServices;
@Inject PolarisEventListener polarisEventListener;

Expand Down Expand Up @@ -176,10 +178,12 @@ public void before(TestInfo testInfo) {
configurationStore,
Clock.systemDefaultZone());

StorageCredentialCache storageCredentialCache =
new StorageCredentialCache(storageCredentialCacheConfig);
PolarisEntityManager entityManager =
new PolarisEntityManager(
metaStoreManager,
new StorageCredentialCache(),
storageCredentialCache,
new InMemoryEntityCache(polarisContext.getRealmConfig(), metaStoreManager));

CallContext.setCurrentContext(polarisContext);
Expand Down Expand Up @@ -236,7 +240,8 @@ public void before(TestInfo testInfo) {
polarisContext, entityManager, securityContext, CATALOG_NAME);
FileIOFactory fileIOFactory =
new DefaultFileIOFactory(
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore),
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache),
metaStoreManagerFactory);

testPolarisEventListener = (TestPolarisEventListener) polarisEventListener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.apache.polaris.core.storage.aws.AwsCredentialsStorageIntegration;
import org.apache.polaris.core.storage.aws.AwsStorageConfigurationInfo;
import org.apache.polaris.core.storage.cache.StorageCredentialCache;
import org.apache.polaris.core.storage.cache.StorageCredentialCacheConfig;
import org.apache.polaris.service.admin.PolarisAdminService;
import org.apache.polaris.service.catalog.PolarisPassthroughResolutionView;
import org.apache.polaris.service.catalog.generic.PolarisGenericTableCatalog;
Expand Down Expand Up @@ -120,6 +121,7 @@ public Map<String, String> getConfigOverrides() {
@Inject MetaStoreManagerFactory metaStoreManagerFactory;
@Inject UserSecretsManagerFactory userSecretsManagerFactory;
@Inject PolarisConfigurationStore configurationStore;
@Inject StorageCredentialCacheConfig storageCredentialCacheConfig;
@Inject PolarisStorageIntegrationProvider storageIntegrationProvider;
@Inject PolarisDiagnostics diagServices;

Expand Down Expand Up @@ -168,10 +170,12 @@ public void before(TestInfo testInfo) {
diagServices,
configurationStore,
Clock.systemDefaultZone());
StorageCredentialCache storageCredentialCache =
new StorageCredentialCache(storageCredentialCacheConfig);
entityManager =
new PolarisEntityManager(
metaStoreManager,
new StorageCredentialCache(),
storageCredentialCache,
new InMemoryEntityCache(polarisContext.getRealmConfig(), metaStoreManager));

PrincipalEntity rootEntity =
Expand Down Expand Up @@ -237,7 +241,8 @@ public void before(TestInfo testInfo) {
polarisContext, entityManager, securityContext, CATALOG_NAME);
TaskExecutor taskExecutor = Mockito.mock();
RealmEntityManagerFactory realmEntityManagerFactory =
new RealmEntityManagerFactory(metaStoreManagerFactory, configurationStore);
new RealmEntityManagerFactory(
metaStoreManagerFactory, configurationStore, storageCredentialCache);
this.fileIOFactory =
new DefaultFileIOFactory(realmEntityManagerFactory, metaStoreManagerFactory);

Expand Down
Loading
Loading