Search in sources :

Example 26 with SessionEntityWrapper

use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.

the class ConcurrencyDistributedRemoveSessionTest method main.

public static void main(String[] args) throws Exception {
    Cache<String, SessionEntityWrapper<UserSessionEntity>> cache1 = DistributedCacheConcurrentWritesTest.createManager("node1").getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
    Cache<String, SessionEntityWrapper<UserSessionEntity>> cache2 = DistributedCacheConcurrentWritesTest.createManager("node2").getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
    // Create caches, listeners and finally worker threads
    Thread worker1 = createWorker(cache1, 1);
    Thread worker2 = createWorker(cache2, 2);
    Thread worker3 = createWorker(cache1, 1);
    Thread worker4 = createWorker(cache2, 2);
    // Create 100 initial sessions
    for (int i = 0; i < ITERATIONS; i++) {
        String sessionId = String.valueOf(i);
        SessionEntityWrapper<UserSessionEntity> wrappedSession = createSessionEntity(sessionId);
        cache1.put(sessionId, wrappedSession);
        removalCounts.put(sessionId, new AtomicInteger(0));
    }
    logger.info("SESSIONS CREATED");
    // Create 100 initial sessions
    for (int i = 0; i < ITERATIONS; i++) {
        String sessionId = String.valueOf(i);
        SessionEntityWrapper loadedWrapper = cache2.get(sessionId);
        Assert.assertNotNull("Loaded wrapper for key " + sessionId, loadedWrapper);
    }
    logger.info("SESSIONS AVAILABLE ON DC2");
    long start = System.currentTimeMillis();
    try {
        worker1.start();
        worker2.start();
        worker3.start();
        worker4.start();
        worker1.join();
        worker2.join();
        worker3.join();
        worker4.join();
        logger.info("SESSIONS REMOVED");
        Map<Integer, Integer> histogram = new HashMap<>();
        for (Map.Entry<String, AtomicInteger> entry : removalCounts.entrySet()) {
            int count = entry.getValue().get();
            int current = histogram.get(count) == null ? 0 : histogram.get(count);
            current++;
            histogram.put(count, current);
        }
        logger.infof("Histogram: %s", histogram.toString());
        logger.infof("Errors: %d", errorsCounter.get());
        long took = System.currentTimeMillis() - start;
        logger.infof("took %d ms", took);
    } finally {
        Thread.sleep(2000);
        // Finish JVM
        cache1.getCacheManager().stop();
        cache2.getCacheManager().stop();
    }
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Map(java.util.Map) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Example 27 with SessionEntityWrapper

use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.

the class InfinispanUserSessionProvider method getUserSessionsCount.

protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
    if (offline && loadOfflineSessionsFromDatabase) {
        // fetch the actual offline user session count from the database
        UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
        return persister.getUserSessionsCount(realm, client, true);
    }
    Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
    cache = CacheDecorators.skipCacheLoaders(cache);
    final String clientUuid = client.getId();
    return cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).client(clientUuid)).count();
}
Also used : UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)

Example 28 with SessionEntityWrapper

use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.

the class InfinispanUserSessionProvider method importUserSessions.

@Override
public void importUserSessions(Collection<UserSessionModel> persistentUserSessions, boolean offline) {
    if (persistentUserSessions == null || persistentUserSessions.isEmpty()) {
        return;
    }
    Map<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsById = new HashMap<>();
    Map<String, SessionEntityWrapper<UserSessionEntity>> sessionsById = persistentUserSessions.stream().map((UserSessionModel persistentUserSession) -> {
        UserSessionEntity userSessionEntityToImport = createUserSessionEntityInstance(persistentUserSession);
        for (Map.Entry<String, AuthenticatedClientSessionModel> entry : persistentUserSession.getAuthenticatedClientSessions().entrySet()) {
            String clientUUID = entry.getKey();
            AuthenticatedClientSessionModel clientSession = entry.getValue();
            AuthenticatedClientSessionEntity clientSessionToImport = createAuthenticatedClientSessionInstance(clientSession, userSessionEntityToImport.getRealmId(), offline);
            // Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
            clientSessionToImport.setTimestamp(userSessionEntityToImport.getLastSessionRefresh());
            clientSessionsById.put(clientSessionToImport.getId(), new SessionEntityWrapper<>(clientSessionToImport));
            // Update userSession entity with the clientSession
            AuthenticatedClientSessionStore clientSessions = userSessionEntityToImport.getAuthenticatedClientSessions();
            clientSessions.put(clientUUID, clientSessionToImport.getId());
        }
        return userSessionEntityToImport;
    }).map(SessionEntityWrapper::new).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
    // Directly put all entities to the infinispan cache
    Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = CacheDecorators.skipCacheLoaders(getCache(offline));
    boolean importWithExpiration = sessionsById.size() == 1;
    if (importWithExpiration) {
        importSessionsWithExpiration(sessionsById, cache, offline ? SessionTimeouts::getOfflineSessionLifespanMs : SessionTimeouts::getUserSessionLifespanMs, offline ? SessionTimeouts::getOfflineSessionMaxIdleMs : SessionTimeouts::getUserSessionMaxIdleMs);
    } else {
        cache.putAll(sessionsById);
    }
    // put all entities to the remoteCache (if exists)
    RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache);
    if (remoteCache != null) {
        Map<String, SessionEntityWrapper<UserSessionEntity>> sessionsByIdForTransport = sessionsById.values().stream().map(SessionEntityWrapper::forTransport).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
        if (importWithExpiration) {
            importSessionsWithExpiration(sessionsByIdForTransport, remoteCache, offline ? SessionTimeouts::getOfflineSessionLifespanMs : SessionTimeouts::getUserSessionLifespanMs, offline ? SessionTimeouts::getOfflineSessionMaxIdleMs : SessionTimeouts::getUserSessionMaxIdleMs);
        } else {
            Retry.executeWithBackoff((int iteration) -> {
                try {
                    remoteCache.putAll(sessionsByIdForTransport);
                } catch (HotRodClientException re) {
                    if (log.isDebugEnabled()) {
                        log.debugf(re, "Failed to put import %d sessions to remoteCache. Iteration '%s'. Will try to retry the task", sessionsByIdForTransport.size(), iteration);
                    }
                    // Rethrow the exception. Retry will take care of handle the exception and eventually retry the operation.
                    throw re;
                }
            }, 10, 10);
        }
    }
    // Import client sessions
    Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessCache = offline ? offlineClientSessionCache : clientSessionCache;
    clientSessCache = CacheDecorators.skipCacheLoaders(clientSessCache);
    if (importWithExpiration) {
        importSessionsWithExpiration(clientSessionsById, clientSessCache, offline ? SessionTimeouts::getOfflineClientSessionLifespanMs : SessionTimeouts::getClientSessionLifespanMs, offline ? SessionTimeouts::getOfflineClientSessionMaxIdleMs : SessionTimeouts::getClientSessionMaxIdleMs);
    } else {
        clientSessCache.putAll(clientSessionsById);
    }
    // put all entities to the remoteCache (if exists)
    RemoteCache remoteCacheClientSessions = InfinispanUtil.getRemoteCache(clientSessCache);
    if (remoteCacheClientSessions != null) {
        Map<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> sessionsByIdForTransport = clientSessionsById.values().stream().map(SessionEntityWrapper::forTransport).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
        if (importWithExpiration) {
            importSessionsWithExpiration(sessionsByIdForTransport, remoteCacheClientSessions, offline ? SessionTimeouts::getOfflineClientSessionLifespanMs : SessionTimeouts::getClientSessionLifespanMs, offline ? SessionTimeouts::getOfflineClientSessionMaxIdleMs : SessionTimeouts::getClientSessionMaxIdleMs);
        } else {
            Retry.executeWithBackoff((int iteration) -> {
                try {
                    remoteCacheClientSessions.putAll(sessionsByIdForTransport);
                } catch (HotRodClientException re) {
                    if (log.isDebugEnabled()) {
                        log.debugf(re, "Failed to put import %d client sessions to remoteCache. Iteration '%s'. Will try to retry the task", sessionsByIdForTransport.size(), iteration);
                    }
                    // Rethrow the exception. Retry will take care of handle the exception and eventually retry the operation.
                    throw re;
                }
            }, 10, 10);
        }
    }
}
Also used : UserSessionProvider(org.keycloak.models.UserSessionProvider) RemoveUserSessionsEvent(org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent) BiFunction(java.util.function.BiFunction) Cache(org.infinispan.Cache) RemoteCache(org.infinispan.client.hotrod.RemoteCache) FuturesHelper(org.keycloak.models.sessions.infinispan.util.FuturesHelper) ClusterProvider(org.keycloak.cluster.ClusterProvider) PersisterLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore) Future(java.util.concurrent.Future) RealmRemovedSessionEvent(org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) Map(java.util.Map) SessionEntity(org.keycloak.models.sessions.infinispan.entities.SessionEntity) Time(org.keycloak.common.util.Time) InfinispanUtil(org.keycloak.connections.infinispan.InfinispanUtil) OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) RealmModel(org.keycloak.models.RealmModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) CrossDCLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore) SessionPredicate(org.keycloak.models.sessions.infinispan.stream.SessionPredicate) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) Objects(java.util.Objects) UserProvider(org.keycloak.models.UserProvider) InfinispanChangelogBasedTransaction(org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction) Stream(java.util.stream.Stream) Flag(org.infinispan.context.Flag) AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) DeviceActivityManager(org.keycloak.device.DeviceActivityManager) ClientModel(org.keycloak.models.ClientModel) Mappers(org.keycloak.models.sessions.infinispan.stream.Mappers) InfinispanKeyGenerator(org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator) Logger(org.jboss.logging.Logger) UserSessionSpi(org.keycloak.models.UserSessionSpi) HashMap(java.util.HashMap) Function(java.util.function.Function) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException) UserModel(org.keycloak.models.UserModel) AuthenticatedClientSessionStore(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore) SessionTimeouts(org.keycloak.models.sessions.infinispan.util.SessionTimeouts) BasicCache(org.infinispan.commons.api.BasicCache) UserSessionPredicate(org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate) StreamSupport(java.util.stream.StreamSupport) Retry(org.keycloak.common.util.Retry) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity) RemoteCacheInvoker(org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker) Iterator(java.util.Iterator) SessionUpdateTask(org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask) KeycloakSession(org.keycloak.models.KeycloakSession) UserSessionModel(org.keycloak.models.UserSessionModel) CacheCollectors(org.infinispan.stream.CacheCollectors) Comparators(org.keycloak.models.sessions.infinispan.stream.Comparators) Tasks(org.keycloak.models.sessions.infinispan.changes.Tasks) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) ModelException(org.keycloak.models.ModelException) StreamsUtil.paginatedStream(org.keycloak.utils.StreamsUtil.paginatedStream) SessionEventsSenderTransaction(org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction) Collections(java.util.Collections) OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) UserSessionModel(org.keycloak.models.UserSessionModel) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) RemoteCache(org.infinispan.client.hotrod.RemoteCache) UUID(java.util.UUID) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AuthenticatedClientSessionStore(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Example 29 with SessionEntityWrapper

use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.

the class AuthenticatedClientSessionAdapter method setTimestamp.

@Override
public void setTimestamp(int timestamp) {
    ClientSessionUpdateTask task = new ClientSessionUpdateTask() {

        @Override
        public void runUpdate(AuthenticatedClientSessionEntity entity) {
            entity.setTimestamp(timestamp);
        }

        @Override
        public CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper<AuthenticatedClientSessionEntity> sessionWrapper) {
            return new CrossDCLastSessionRefreshChecker(provider.getLastSessionRefreshStore(), provider.getOfflineLastSessionRefreshStore()).shouldSaveClientSessionToRemoteCache(kcSession, client.getRealm(), sessionWrapper, userSession, offline, timestamp);
        }

        @Override
        public String toString() {
            return "setTimestamp(" + timestamp + ')';
        }
    };
    update(task);
}
Also used : AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) ClientSessionUpdateTask(org.keycloak.models.sessions.infinispan.changes.ClientSessionUpdateTask) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) CrossDCLastSessionRefreshChecker(org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshChecker)

Example 30 with SessionEntityWrapper

use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.

the class AuthenticatedClientSessionEntity method mergeRemoteEntityWithLocalEntity.

@Override
public SessionEntityWrapper mergeRemoteEntityWithLocalEntity(SessionEntityWrapper localEntityWrapper) {
    int timestampRemote = getTimestamp();
    SessionEntityWrapper entityWrapper;
    if (localEntityWrapper == null) {
        entityWrapper = new SessionEntityWrapper<>(this);
    } else {
        AuthenticatedClientSessionEntity localClientSession = (AuthenticatedClientSessionEntity) localEntityWrapper.getEntity();
        // local timestamp should always contain the bigger
        if (timestampRemote < localClientSession.getTimestamp()) {
            setTimestamp(localClientSession.getTimestamp());
        }
        entityWrapper = new SessionEntityWrapper<>(localEntityWrapper.getLocalMetadata(), this);
    }
    entityWrapper.putLocalMetadataNoteInt(LAST_TIMESTAMP_REMOTE, timestampRemote);
    logger.debugf("Updating client session entity %s. timestamp=%d, timestampRemote=%d", getId(), getTimestamp(), timestampRemote);
    return entityWrapper;
}
Also used : SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)

Aggregations

SessionEntityWrapper (org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)30 UserSessionEntity (org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)13 RemoteCache (org.infinispan.client.hotrod.RemoteCache)9 AuthenticatedClientSessionEntity (org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity)8 HashMap (java.util.HashMap)5 UUID (java.util.UUID)5 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)5 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)5 InfinispanConnectionProvider (org.keycloak.connections.infinispan.InfinispanConnectionProvider)5 UserSessionPersisterProvider (org.keycloak.models.session.UserSessionPersisterProvider)5 Map (java.util.Map)4 Cache (org.infinispan.Cache)4 RealmModel (org.keycloak.models.RealmModel)4 Set (java.util.Set)3 Future (java.util.concurrent.Future)3 TimeUnit (java.util.concurrent.TimeUnit)3 BiFunction (java.util.function.BiFunction)3 Stream (java.util.stream.Stream)3 HotRodClientException (org.infinispan.client.hotrod.exceptions.HotRodClientException)3 Flag (org.infinispan.context.Flag)3