From a7964a588baafd6e8b83f6485204b22ce8704005 Mon Sep 17 00:00:00 2001 From: Alexander Schwartz Date: Tue, 20 Aug 2024 16:03:41 +0200 Subject: [PATCH] Avoid n+1 SQL selects to load sessions Closes #32273 Signed-off-by: Alexander Schwartz --- .../PersistentUserSessionProvider.java | 24 +++++++++---------- ...onPersistentChangelogBasedTransaction.java | 16 +++++++------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java index 032c9f2a75..74946d9f64 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java @@ -223,7 +223,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi if (userSession.isOffline()) { // If this is an offline session, and the referred online session doesn't exist anymore, don't register the client session in the transaction. // Instead keep it transient and it will be added to the offline session only afterward. This is expected by SessionTimeoutsTest.testOfflineUserClientIdleTimeoutSmallerThanSessionOneRefresh. - if (sessionTx.get(realm, userSession.getId(), false) == null) { + if (sessionTx.get(realm, userSession.getId(), userSession, false) == null) { return adapter; } } @@ -279,23 +279,23 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi @Override public UserSessionModel getUserSession(RealmModel realm, String id) { - return getUserSession(realm, id, false); + return getUserSession(realm, id, null, false); } - private UserSessionAdapter getUserSession(RealmModel realm, String id, boolean offline) { - SessionEntityWrapper entityWrapper = sessionTx.get(realm, id, offline); + private UserSessionAdapter getUserSession(RealmModel realm, String id, UserSessionModel userSession, boolean offline) { + SessionEntityWrapper entityWrapper = sessionTx.get(realm, id, userSession, offline); return entityWrapper != null ? wrap(realm, entityWrapper.getEntity(), offline) : null; } private UserSessionEntity getUserSessionEntity(RealmModel realm, String id, boolean offline) { - SessionEntityWrapper entityWrapper = sessionTx.get(realm, id, offline); + SessionEntityWrapper entityWrapper = sessionTx.get(realm, id, null, offline); return entityWrapper != null ? entityWrapper.getEntity() : null; } private Stream getUserSessionsFromPersistenceProviderStream(RealmModel realm, UserModel user) { UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); return persister.loadUserSessionsStream(realm, user, true, 0, null) - .map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), true)) + .map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), persistentUserSession, true)) .filter(Objects::nonNull); } @@ -318,7 +318,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi if (user != null) { return persister.loadUserSessionsStream(realm, user, offline, 0, null) .filter(predicate.toModelPredicate()) - .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), offline)) + .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), s, offline)) .filter(Objects::nonNull); } else { return Stream.empty(); @@ -337,7 +337,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi return userModel != null ? persister.loadUserSessionsStream(realm, userModel, offline, 0, null) .filter(predicate.toModelPredicate()) - .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), offline)) + .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), s, offline)) .filter(Objects::nonNull) : Stream.empty(); } @@ -346,7 +346,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi ClientModel client = session.clients().getClientById(realm, predicate.getClient()); return persister.loadUserSessionsStream(realm, client, offline, 0, null) .filter(predicate.toModelPredicate()) - .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), offline)) + .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), s, offline)) .filter(Objects::nonNull); } @@ -354,7 +354,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi // we haven't yet migrated the old offline entries, so they don't have a brokerSessionId yet return Stream.of(persister.loadUserSessionsStreamByBrokerSessionId(realm, predicate.getBrokerSessionId(), false)) .filter(predicate.toModelPredicate()) - .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), false)) + .map(s -> (UserSessionModel) getUserSession(realm, s.getId(), s, false)) .filter(Objects::nonNull); } @@ -412,7 +412,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi @Override public UserSessionModel getUserSessionWithPredicate(RealmModel realm, String id, boolean offline, Predicate predicate) { - UserSessionModel userSession = getUserSession(realm, id, offline); + UserSessionModel userSession = getUserSession(realm, id, null, offline); if (userSession == null) { return null; } @@ -680,7 +680,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi @Override public UserSessionAdapter getOfflineUserSession(RealmModel realm, String userSessionId) { - return getUserSession(realm, userSessionId, true); + return getUserSession(realm, userSessionId, null, true); } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionPersistentChangelogBasedTransaction.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionPersistentChangelogBasedTransaction.java index 3de896c6a0..d1b2e50a84 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionPersistentChangelogBasedTransaction.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionPersistentChangelogBasedTransaction.java @@ -52,7 +52,7 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe super(session, USER_SESSION_CACHE_NAME, cache, offlineCache, remoteCacheInvoker, lifespanMsLoader, maxIdleTimeMsLoader, offlineLifespanMsLoader, offlineMaxIdleTimeMsLoader, batchingQueue, serializerOnline, serializerOffline); } - public SessionEntityWrapper get(RealmModel realm, String key, boolean offline) { + public SessionEntityWrapper get(RealmModel realm, String key, UserSessionModel userSession, boolean offline) { SessionUpdatesList myUpdates = getUpdates(offline).get(key); if (myUpdates == null) { SessionEntityWrapper wrappedEntity = null; @@ -63,7 +63,7 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe if (wrappedEntity == null) { LOG.debugf("user-session not found in cache for sessionId=%s offline=%s, loading from persister", key, offline); - wrappedEntity = getSessionEntityFromPersister(realm, key, offline); + wrappedEntity = getSessionEntityFromPersister(realm, key, userSession, offline); } else { LOG.debugf("user-session found in cache for sessionId=%s offline=%s %s", key, offline, wrappedEntity.getEntity().getLastSessionRefresh()); } @@ -96,15 +96,17 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe } } - private SessionEntityWrapper getSessionEntityFromPersister(RealmModel realm, String key, boolean offline) { - UserSessionPersisterProvider persister = kcSession.getProvider(UserSessionPersisterProvider.class); - UserSessionModel persistentUserSession = persister.loadUserSession(realm, key, offline); + private SessionEntityWrapper getSessionEntityFromPersister(RealmModel realm, String key, UserSessionModel userSession, boolean offline) { + if (userSession == null) { + UserSessionPersisterProvider persister = kcSession.getProvider(UserSessionPersisterProvider.class); + userSession = persister.loadUserSession(realm, key, offline); + } - if (persistentUserSession == null) { + if (userSession == null) { return null; } - return importUserSession(persistentUserSession); + return importUserSession(userSession); } private SessionEntityWrapper importUserSession(UserSessionModel persistentUserSession) {