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); 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); addInvalidations(InClientPredicate.create().client(clientUUID), invalidations);
} }
public void invalidateCacheKey(String key, Set<String> invalidations) {
invalidations.add(key);
}
@Override @Override
protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) { protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) {
invalidations.add(event.getId()); invalidations.add(event.getId());

View file

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

View file

@ -24,6 +24,7 @@ import org.keycloak.credential.CredentialInput;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.CredentialValidationOutput; import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.cache.infinispan.events.CacheKeyInvalidatedEvent;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent; import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.common.constants.ServiceAccountConstants; import org.keycloak.common.constants.ServiceAccountConstants;
import org.keycloak.component.ComponentModel; 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()) || .anyMatch((org) -> (organizationProvider.isEnabled() && org.isManaged(delegate) && !org.isEnabled()) ||
(!organizationProvider.isEnabled() && org.isManaged(delegate))); (!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) { private boolean isInvalid(String cacheKey) {
return realmCache.getInvalidations().contains(cacheKey); return realmCache.isInvalid(cacheKey);
} }
private IdentityProviderModel createOrganizationAwareIdentityProviderModel(IdentityProviderModel idp) { 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.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CacheRealmProvider; 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.CachedCount;
import org.keycloak.models.cache.infinispan.RealmCacheSession; import org.keycloak.models.cache.infinispan.RealmCacheSession;
import org.keycloak.models.cache.infinispan.UserCacheSession;
import org.keycloak.organization.OrganizationProvider; import org.keycloak.organization.OrganizationProvider;
import static org.keycloak.models.cache.infinispan.idp.InfinispanIdentityProviderStorageProvider.cacheKeyOrgId; 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 static final String ORG_MEMBERS_COUNT_KEY_SUFFIX = ".members.count";
private final KeycloakSession session; private final KeycloakSession session;
private final UserCacheSession userCache;
private OrganizationProvider orgDelegate; private OrganizationProvider orgDelegate;
private final RealmCacheSession realmCache; private final RealmCacheSession realmCache;
private final Map<String, OrganizationAdapter> managedOrganizations = new HashMap<>(); private final Map<String, OrganizationAdapter> managedOrganizations = new HashMap<>();
@ -45,6 +48,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
public InfinispanOrganizationProvider(KeycloakSession session) { public InfinispanOrganizationProvider(KeycloakSession session) {
this.session = session; this.session = session;
this.realmCache = (RealmCacheSession) session.getProvider(CacheRealmProvider.class); this.realmCache = (RealmCacheSession) session.getProvider(CacheRealmProvider.class);
this.userCache = (UserCacheSession) session.getProvider(UserCache.class);
} }
private static String cacheKeyOrgCount(RealmModel realm) { private static String cacheKeyOrgCount(RealmModel realm) {
@ -201,14 +205,14 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
return getDelegate().getMemberById(organization, user.getId()); 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) { if (cached == null) {
boolean isManaged = getDelegate().isManagedMember(organization, user); 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()); UserModel member = getDelegate().getMemberById(organization, user.getId());
cached = new CachedMembership(loaded, cacheKey, realm, isManaged, member != null); 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; return cached.isMember() ? user : null;
@ -222,13 +226,13 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
return getDelegate().getByMember(member); return getDelegate().getByMember(member);
} }
CachedOrganizationIds cached = realmCache.getCache().get(cacheKey, CachedOrganizationIds.class); CachedOrganizationIds cached = userCache.getCache().get(cacheKey, CachedOrganizationIds.class);
if (cached == null) { if (cached == null) {
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey); Long loaded = userCache.getCache().getCurrentRevision(cacheKey);
Stream<OrganizationModel> model = getDelegate().getByMember(member); Stream<OrganizationModel> model = getDelegate().getByMember(member);
cached = new CachedOrganizationIds(loaded, cacheKey, getRealm(), model); 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); return cached.getOrgIds().stream().map(this::getById);
@ -241,7 +245,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
} }
String cacheKey = cacheKeyMembership(getRealm(), organization, user); 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)) { 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 // 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) { void registerMemberInvalidation(OrganizationModel organization, UserModel member) {
realmCache.registerInvalidation(cacheKeyByMember(member)); userCache.registerInvalidation(cacheKeyByMember(member));
realmCache.registerInvalidation(cacheKeyMembership(getRealm(), organization, member)); userCache.registerInvalidation(cacheKeyMembership(getRealm(), organization, member));
realmCache.registerInvalidation(cacheKeyOrgMemberCount(getRealm(), organization)); realmCache.registerInvalidation(cacheKeyOrgMemberCount(getRealm(), organization));
} }
private boolean isInvalid(String cacheKey) { private boolean isInvalid(String cacheKey) {
return realmCache.getInvalidations().contains(cacheKey); return realmCache.isInvalid(cacheKey) || userCache.isInvalid(cacheKey);
} }
} }