|
34 | 34 | import org.infinispan.transaction.lookup.EmbeddedTransactionManagerLookup; |
35 | 35 | import org.jboss.logging.Logger; |
36 | 36 | import org.keycloak.Config; |
37 | | -import org.keycloak.connections.infinispan.InfinispanConnectionProvider; |
38 | 37 |
|
| 38 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.ACTION_TOKEN_CACHE; |
| 39 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.ALL_CACHES_NAME; |
| 40 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME; |
39 | 41 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME; |
40 | 42 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX; |
41 | 43 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME; |
42 | 44 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.CLIENT_SESSION_CACHE_NAME; |
| 45 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.CLUSTERED_CACHE_NAMES; |
| 46 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.CRL_CACHE_DEFAULT_MAX; |
43 | 47 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.CRL_CACHE_NAME; |
44 | 48 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.LOCAL_CACHE_NAMES; |
45 | 49 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.LOCAL_MAX_COUNT_CACHES; |
| 50 | +import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME; |
46 | 51 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME; |
47 | 52 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME; |
48 | 53 | import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.REALM_CACHE_NAME; |
@@ -102,7 +107,7 @@ public static void configureLocalCaches(Config.Scope keycloakConfig, Configurati |
102 | 107 | */ |
103 | 108 | public static void applyDefaultConfiguration(ConfigurationBuilderHolder holder) { |
104 | 109 | var configs = holder.getNamedConfigurationBuilders(); |
105 | | - for (var name : InfinispanConnectionProvider.ALL_CACHES_NAME) { |
| 110 | + for (var name : ALL_CACHES_NAME) { |
106 | 111 | configs.computeIfAbsent(name, cacheName -> DEFAULT_CONFIGS.getOrDefault(cacheName, TO_NULL).get()); |
107 | 112 | } |
108 | 113 | } |
@@ -157,7 +162,7 @@ public static void validateWorkCacheConfiguration(ConfigurationBuilderHolder hol |
157 | 162 | */ |
158 | 163 | public static void removeClusteredCaches(ConfigurationBuilderHolder holder) { |
159 | 164 | logger.debug("Removing clustered caches"); |
160 | | - Arrays.stream(InfinispanConnectionProvider.CLUSTERED_CACHE_NAMES).forEach(holder.getNamedConfigurationBuilders()::remove); |
| 165 | + Arrays.stream(CLUSTERED_CACHE_NAMES).forEach(holder.getNamedConfigurationBuilders()::remove); |
161 | 166 | } |
162 | 167 |
|
163 | 168 | /** |
@@ -234,6 +239,34 @@ public static void configureSessionsCachesForVolatileSessions(ConfigurationBuild |
234 | 239 | } |
235 | 240 | } |
236 | 241 |
|
| 242 | + /** |
| 243 | + * Configures the caches "actionToken", "authenticationSessions", and "loginFailures" with the minimum number of |
| 244 | + * owners to prevent data loss in a single instance crash. |
| 245 | + * <p> |
| 246 | + * The data in those caches only exist in memory, therefore they must have more than one owner configured. |
| 247 | + * |
| 248 | + * @param holder The {@link ConfigurationBuilderHolder} where the caches are configured. |
| 249 | + * @throws IllegalStateException if an Infinispan cache is not defined in the {@code holder}. This could indicate a |
| 250 | + * missing or incorrect configuration. |
| 251 | + */ |
| 252 | + public static void ensureMinimumOwners(ConfigurationBuilderHolder holder) { |
| 253 | + for (var name : Arrays.asList( |
| 254 | + LOGIN_FAILURE_CACHE_NAME, |
| 255 | + AUTHENTICATION_SESSIONS_CACHE_NAME, |
| 256 | + ACTION_TOKEN_CACHE)) { |
| 257 | + var builder = holder.getNamedConfigurationBuilders().get(name); |
| 258 | + if (builder == null) { |
| 259 | + throw cacheNotFound(name); |
| 260 | + } |
| 261 | + var hashConfig = builder.clustering().hash(); |
| 262 | + var owners = hashConfig.attributes().attribute(HashConfiguration.NUM_OWNERS).get(); |
| 263 | + if (owners < 2) { |
| 264 | + logger.infof("Setting num_owners=2 (configured value is %s) for cache '%s' to prevent data loss.", owners, name); |
| 265 | + hashConfig.numOwners(2); |
| 266 | + } |
| 267 | + } |
| 268 | + } |
| 269 | + |
237 | 270 | // private methods below |
238 | 271 |
|
239 | 272 | private static void configureRevisionCache(ConfigurationBuilderHolder holder, String baseCache, String revisionCache, long defaultMaxEntries) { |
@@ -267,7 +300,7 @@ private static IllegalStateException cacheNotFound(String cache) { |
267 | 300 |
|
268 | 301 | public static ConfigurationBuilder getCrlCacheConfig() { |
269 | 302 | var builder = createCacheConfigurationBuilder(); |
270 | | - builder.memory().whenFull(EvictionStrategy.REMOVE).maxCount(InfinispanConnectionProvider.CRL_CACHE_DEFAULT_MAX); |
| 303 | + builder.memory().whenFull(EvictionStrategy.REMOVE).maxCount(CRL_CACHE_DEFAULT_MAX); |
271 | 304 | return builder; |
272 | 305 | } |
273 | 306 |
|
|
0 commit comments