Move organization membership cache entries to the user cache

Closes #33412

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2024-10-03 08:45:28 -03:00
parent 2be2b2ffe5
commit 13111daceb
6 changed files with 38 additions and 18 deletions

View file

@ -226,4 +226,7 @@ public abstract class CacheManager {
protected abstract void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations);
public void invalidateCacheKey(String key, Set<String> invalidations) {
invalidations.add(key);
}
}

View file

@ -120,10 +120,6 @@ public class RealmCacheManager extends CacheManager {
addInvalidations(InClientPredicate.create().client(clientUUID), invalidations);
}
public void invalidateCacheKey(String key, Set<String> invalidations) {
invalidations.add(key);
}
@Override
protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) {
invalidations.add(event.getId());

View file

@ -17,7 +17,6 @@
package org.keycloak.models.cache.infinispan;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@ -221,8 +220,8 @@ public class RealmCacheSession implements CacheRealmProvider {
return groupDelegate;
}
public Set<String> getInvalidations() {
return Collections.unmodifiableSet(invalidations);
public boolean isInvalid(String key) {
return invalidations.contains(key);
}
public RealmCacheManager getCache() {

View file

@ -24,6 +24,7 @@ import org.keycloak.credential.CredentialInput;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.cache.infinispan.events.CacheKeyInvalidatedEvent;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.common.constants.ServiceAccountConstants;
import org.keycloak.component.ComponentModel;
@ -996,4 +997,21 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
.anyMatch((org) -> (organizationProvider.isEnabled() && org.isManaged(delegate) && !org.isEnabled()) ||
(!organizationProvider.isEnabled() && org.isManaged(delegate)));
}
public UserCacheManager getCache() {
return cache;
}
public long getStartupRevision() {
return startupRevision;
}
public void registerInvalidation(String id) {
cache.invalidateCacheKey(id, invalidations);
invalidationEvents.add(new CacheKeyInvalidatedEvent(id));
}
public boolean isInvalid(String key) {
return invalidations.contains(key);
}
}

View file

@ -426,7 +426,7 @@ public class InfinispanIdentityProviderStorageProvider implements IdentityProvid
}
private boolean isInvalid(String cacheKey) {
return realmCache.getInvalidations().contains(cacheKey);
return realmCache.isInvalid(cacheKey);
}
private IdentityProviderModel createOrganizationAwareIdentityProviderModel(IdentityProviderModel idp) {

View file

@ -26,8 +26,10 @@ import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache;
import org.keycloak.models.cache.infinispan.CachedCount;
import org.keycloak.models.cache.infinispan.RealmCacheSession;
import org.keycloak.models.cache.infinispan.UserCacheSession;
import org.keycloak.organization.OrganizationProvider;
import static org.keycloak.models.cache.infinispan.idp.InfinispanIdentityProviderStorageProvider.cacheKeyOrgId;
@ -38,6 +40,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
private static final String ORG_MEMBERS_COUNT_KEY_SUFFIX = ".members.count";
private final KeycloakSession session;
private final UserCacheSession userCache;
private OrganizationProvider orgDelegate;
private final RealmCacheSession realmCache;
private final Map<String, OrganizationAdapter> managedOrganizations = new HashMap<>();
@ -45,6 +48,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
public InfinispanOrganizationProvider(KeycloakSession session) {
this.session = session;
this.realmCache = (RealmCacheSession) session.getProvider(CacheRealmProvider.class);
this.userCache = (UserCacheSession) session.getProvider(UserCache.class);
}
private static String cacheKeyOrgCount(RealmModel realm) {
@ -201,14 +205,14 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
return getDelegate().getMemberById(organization, user.getId());
}
CachedMembership cached = realmCache.getCache().get(cacheKey, CachedMembership.class);
CachedMembership cached = userCache.getCache().get(cacheKey, CachedMembership.class);
if (cached == null) {
boolean isManaged = getDelegate().isManagedMember(organization, user);
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey);
Long loaded = userCache.getCache().getCurrentRevision(cacheKey);
UserModel member = getDelegate().getMemberById(organization, user.getId());
cached = new CachedMembership(loaded, cacheKey, realm, isManaged, member != null);
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
userCache.getCache().addRevisioned(cached, userCache.getStartupRevision());
}
return cached.isMember() ? user : null;
@ -222,13 +226,13 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
return getDelegate().getByMember(member);
}
CachedOrganizationIds cached = realmCache.getCache().get(cacheKey, CachedOrganizationIds.class);
CachedOrganizationIds cached = userCache.getCache().get(cacheKey, CachedOrganizationIds.class);
if (cached == null) {
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey);
Long loaded = userCache.getCache().getCurrentRevision(cacheKey);
Stream<OrganizationModel> model = getDelegate().getByMember(member);
cached = new CachedOrganizationIds(loaded, cacheKey, getRealm(), model);
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
userCache.getCache().addRevisioned(cached, userCache.getStartupRevision());
}
return cached.getOrgIds().stream().map(this::getById);
@ -241,7 +245,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
}
String cacheKey = cacheKeyMembership(getRealm(), organization, user);
CachedMembership cached = realmCache.getCache().get(cacheKey, CachedMembership.class);
CachedMembership cached = userCache.getCache().get(cacheKey, CachedMembership.class);
if (cached == null || isInvalid(cacheKey)) {
// this will not cache the result as calling getMemberById() to have a full caching entry would lead to a recursion
@ -351,12 +355,12 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
}
void registerMemberInvalidation(OrganizationModel organization, UserModel member) {
realmCache.registerInvalidation(cacheKeyByMember(member));
realmCache.registerInvalidation(cacheKeyMembership(getRealm(), organization, member));
userCache.registerInvalidation(cacheKeyByMember(member));
userCache.registerInvalidation(cacheKeyMembership(getRealm(), organization, member));
realmCache.registerInvalidation(cacheKeyOrgMemberCount(getRealm(), organization));
}
private boolean isInvalid(String cacheKey) {
return realmCache.getInvalidations().contains(cacheKey);
return realmCache.isInvalid(cacheKey) || userCache.isInvalid(cacheKey);
}
}