concurrency
This commit is contained in:
parent
0b54838f31
commit
84949bb51f
31 changed files with 123 additions and 40 deletions
16
distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
Normal file → Executable file
16
distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
Normal file → Executable file
|
@ -28,12 +28,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"realmCache": {
|
|
||||||
"infinispan" : {
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"userSessionPersister": {
|
"userSessionPersister": {
|
||||||
"provider": "jpa"
|
"provider": "jpa"
|
||||||
},
|
},
|
||||||
|
@ -67,8 +61,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"realmCache": {
|
||||||
|
"provider": "infinispan-locking",
|
||||||
|
"infinispan-locking" : {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"connectionsInfinispan": {
|
"connectionsInfinispan": {
|
||||||
"default" : {
|
"provider": "locking",
|
||||||
|
"locking": {
|
||||||
"cacheContainer" : "java:comp/env/infinispan/Keycloak"
|
"cacheContainer" : "java:comp/env/infinispan/Keycloak"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,6 @@ import org.keycloak.models.cache.CacheRealmProvider;
|
||||||
import org.keycloak.models.cache.CacheRealmProviderFactory;
|
import org.keycloak.models.cache.CacheRealmProviderFactory;
|
||||||
import org.keycloak.models.cache.entities.CachedClient;
|
import org.keycloak.models.cache.entities.CachedClient;
|
||||||
import org.keycloak.models.cache.entities.CachedRealm;
|
import org.keycloak.models.cache.entities.CachedRealm;
|
||||||
import org.keycloak.models.cache.infinispan.DefaultCacheRealmProvider;
|
|
||||||
import org.keycloak.models.cache.infinispan.InfinispanRealmCache;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@ -64,7 +62,7 @@ public class RevisionedCacheRealmProviderFactory implements CacheRealmProviderFa
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (realmCache == null) {
|
if (realmCache == null) {
|
||||||
Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
|
Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
|
||||||
Cache<String, Long> counterCache = session.getProvider(InfinispanConnectionProvider.class).getCache(RevisionedConnectionProviderFactory.COUNTER_CACHE_NAME);
|
Cache<String, Long> counterCache = session.getProvider(InfinispanConnectionProvider.class).getCache(RevisionedConnectionProviderFactory.VERSION_CACHE_NAME);
|
||||||
cache.addListener(new CacheListener());
|
cache.addListener(new CacheListener());
|
||||||
realmCache = new RevisionedRealmCache(cache, counterCache, realmLookup);
|
realmCache = new RevisionedRealmCache(cache, counterCache, realmLookup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFa
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class RevisionedConnectionProviderFactory extends DefaultInfinispanConnectionProviderFactory {
|
public class RevisionedConnectionProviderFactory extends DefaultInfinispanConnectionProviderFactory {
|
||||||
public static final String COUNTER_CACHE_NAME = "COUNTER_CACHE";
|
public static final String VERSION_CACHE_NAME = "realmVersions";
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(RevisionedConnectionProviderFactory.class);
|
protected static final Logger logger = Logger.getLogger(RevisionedConnectionProviderFactory.class);
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ public class RevisionedConnectionProviderFactory extends DefaultInfinispanConnec
|
||||||
ConfigurationBuilder counterConfigBuilder = new ConfigurationBuilder();
|
ConfigurationBuilder counterConfigBuilder = new ConfigurationBuilder();
|
||||||
Configuration counterCacheConfiguration = counterConfigBuilder.build();
|
Configuration counterCacheConfiguration = counterConfigBuilder.build();
|
||||||
|
|
||||||
cacheManager.defineConfiguration(COUNTER_CACHE_NAME, counterCacheConfiguration);
|
cacheManager.defineConfiguration(VERSION_CACHE_NAME, counterCacheConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class LockingCacheRealmProviderFactory implements CacheRealmProviderFacto
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (realmCache == null) {
|
if (realmCache == null) {
|
||||||
Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
|
Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
|
||||||
Cache<String, Long> counterCache = session.getProvider(InfinispanConnectionProvider.class).getCache(LockingConnectionProviderFactory.COUNTER_CACHE_NAME);
|
Cache<String, Long> counterCache = session.getProvider(InfinispanConnectionProvider.class).getCache(LockingConnectionProviderFactory.VERSION_CACHE_NAME);
|
||||||
cache.addListener(new CacheListener());
|
cache.addListener(new CacheListener());
|
||||||
realmCache = new LockingRealmCache(cache, counterCache, realmLookup);
|
realmCache = new LockingRealmCache(cache, counterCache, realmLookup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFa
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class LockingConnectionProviderFactory extends DefaultInfinispanConnectionProviderFactory {
|
public class LockingConnectionProviderFactory extends DefaultInfinispanConnectionProviderFactory {
|
||||||
public static final String COUNTER_CACHE_NAME = "COUNTER_CACHE";
|
public static final String VERSION_CACHE_NAME = "realmVersions";
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(LockingConnectionProviderFactory.class);
|
protected static final Logger logger = Logger.getLogger(LockingConnectionProviderFactory.class);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class LockingConnectionProviderFactory extends DefaultInfinispanConnectio
|
||||||
counterConfigBuilder.transaction().lockingMode(LockingMode.PESSIMISTIC);
|
counterConfigBuilder.transaction().lockingMode(LockingMode.PESSIMISTIC);
|
||||||
Configuration counterCacheConfiguration = counterConfigBuilder.build();
|
Configuration counterCacheConfiguration = counterConfigBuilder.build();
|
||||||
|
|
||||||
cacheManager.defineConfiguration(COUNTER_CACHE_NAME, counterCacheConfiguration);
|
cacheManager.defineConfiguration(VERSION_CACHE_NAME, counterCacheConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class RepeatableReadWriteSkewRealmCache implements RealmCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.info("Failed to commit invalidate");
|
logger.trace("Failed to commit invalidate");
|
||||||
}
|
}
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
logger.trace("returning new cached realm");
|
logger.trace("returning new cached realm");
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
} else if (realmInvalidations.contains(id)) {
|
} else if (realmInvalidations.contains(id)) {
|
||||||
|
@ -256,7 +256,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
logger.trace("returning new cached realm: " + cached.getName());
|
logger.trace("returning new cached realm: " + cached.getName());
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
} else if (realmInvalidations.contains(cached.getId())) {
|
} else if (realmInvalidations.contains(cached.getId())) {
|
||||||
|
@ -340,7 +340,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
batchEnded = true;
|
batchEnded = true;
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
batchEnded = true;
|
batchEnded = true;
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +416,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
batchEnded = true;
|
batchEnded = true;
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
} else if (appInvalidations.contains(id)) {
|
} else if (appInvalidations.contains(id)) {
|
||||||
|
@ -452,7 +452,7 @@ public class RepeatableReadWriteSkewRealmCacheProvider implements CacheRealmProv
|
||||||
batchEnded = true;
|
batchEnded = true;
|
||||||
cache.endBatch(true);
|
cache.endBatch(true);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.info("failed to add to cache", exception);
|
logger.trace("failed to add to cache", exception);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
} else if (clientTemplateInvalidations.contains(id)) {
|
} else if (clientTemplateInvalidations.contains(id)) {
|
||||||
|
|
|
@ -633,7 +633,7 @@ public class ClientAdapter implements ClientModel {
|
||||||
roleEntity.setClient(entity);
|
roleEntity.setClient(entity);
|
||||||
roleEntity.setClientRole(true);
|
roleEntity.setClientRole(true);
|
||||||
roleEntity.setRealmId(realm.getId());
|
roleEntity.setRealmId(realm.getId());
|
||||||
//entity.getRoles().add(roleEntity);
|
entity.getRoles().add(roleEntity);
|
||||||
em.persist(roleEntity);
|
em.persist(roleEntity);
|
||||||
em.flush();
|
em.flush();
|
||||||
return new RoleAdapter(realm, em, roleEntity);
|
return new RoleAdapter(realm, em, roleEntity);
|
||||||
|
@ -650,7 +650,7 @@ public class ClientAdapter implements ClientModel {
|
||||||
RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em);
|
RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em);
|
||||||
if (!role.isClientRole()) return false;
|
if (!role.isClientRole()) return false;
|
||||||
|
|
||||||
//entity.getRoles().remove(role);
|
entity.getRoles().remove(role);
|
||||||
entity.getDefaultRoles().remove(role);
|
entity.getDefaultRoles().remove(role);
|
||||||
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
||||||
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", role).executeUpdate();
|
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", role).executeUpdate();
|
||||||
|
@ -673,7 +673,6 @@ public class ClientAdapter implements ClientModel {
|
||||||
for (RoleEntity entity : roles) {
|
for (RoleEntity entity : roles) {
|
||||||
list.add(new RoleAdapter(realm, em, entity));
|
list.add(new RoleAdapter(realm, em, entity));
|
||||||
}
|
}
|
||||||
return list;
|
|
||||||
*/
|
*/
|
||||||
TypedQuery<RoleEntity> query = em.createNamedQuery("getClientRoles", RoleEntity.class);
|
TypedQuery<RoleEntity> query = em.createNamedQuery("getClientRoles", RoleEntity.class);
|
||||||
query.setParameter("client", entity);
|
query.setParameter("client", entity);
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
import org.keycloak.models.AuthenticationExecutionModel;
|
import org.keycloak.models.AuthenticationExecutionModel;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -43,6 +45,7 @@ import javax.persistence.Table;
|
||||||
public class AuthenticationExecutionEntity {
|
public class AuthenticationExecutionEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -44,6 +46,7 @@ import java.util.Collection;
|
||||||
public class AuthenticationFlowEntity {
|
public class AuthenticationFlowEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -40,6 +42,7 @@ import java.util.Map;
|
||||||
public class AuthenticatorConfigEntity {
|
public class AuthenticatorConfigEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="ALIAS")
|
@Column(name="ALIAS")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
@ -53,6 +55,7 @@ public class ClientEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
private String id;
|
private String id;
|
||||||
@Column(name = "NAME")
|
@Column(name = "NAME")
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -151,8 +154,8 @@ public class ClientEntity {
|
||||||
@Column(name="NODE_REREG_TIMEOUT")
|
@Column(name="NODE_REREG_TIMEOUT")
|
||||||
private int nodeReRegistrationTimeout;
|
private int nodeReRegistrationTimeout;
|
||||||
|
|
||||||
//@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, mappedBy = "client")
|
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, mappedBy = "client")
|
||||||
//Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
||||||
|
|
||||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
|
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
|
||||||
@JoinTable(name="CLIENT_DEFAULT_ROLES", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")})
|
@JoinTable(name="CLIENT_DEFAULT_ROLES", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")})
|
||||||
|
@ -348,7 +351,6 @@ public class ClientEntity {
|
||||||
this.managementUrl = managementUrl;
|
this.managementUrl = managementUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public Collection<RoleEntity> getRoles() {
|
public Collection<RoleEntity> getRoles() {
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +358,6 @@ public class ClientEntity {
|
||||||
public void setRoles(Collection<RoleEntity> roles) {
|
public void setRoles(Collection<RoleEntity> roles) {
|
||||||
this.roles = roles;
|
this.roles = roles;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
public Collection<RoleEntity> getDefaultRoles() {
|
public Collection<RoleEntity> getDefaultRoles() {
|
||||||
return defaultRoles;
|
return defaultRoles;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
@ -48,6 +50,7 @@ public class ClientTemplateEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
private String id;
|
private String id;
|
||||||
@Column(name = "NAME")
|
@Column(name = "NAME")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -42,6 +44,7 @@ import javax.persistence.Table;
|
||||||
public class CredentialEntity {
|
public class CredentialEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="TYPE")
|
@Column(name="TYPE")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -42,6 +44,7 @@ public class GroupAttributeEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch= FetchType.LAZY)
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -47,6 +49,7 @@ import java.util.Collection;
|
||||||
public class GroupEntity {
|
public class GroupEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name = "NAME")
|
@Column(name = "NAME")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -44,6 +46,7 @@ public class IdentityProviderEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="INTERNAL_ID", length = 36)
|
@Column(name="INTERNAL_ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String internalId;
|
protected String internalId;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -39,6 +41,7 @@ public class IdentityProviderMapperEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="NAME")
|
@Column(name="NAME")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -37,6 +39,7 @@ public class MigrationModelEntity {
|
||||||
public static final String SINGLETON_ID = "SINGLETON";
|
public static final String SINGLETON_ID = "SINGLETON";
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@Column(name="VERSION", length = 36)
|
@Column(name="VERSION", length = 36)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -39,6 +41,7 @@ public class ProtocolMapperEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="NAME")
|
@Column(name="NAME")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
@ -53,6 +55,7 @@ import java.util.Set;
|
||||||
public class RealmEntity {
|
public class RealmEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="NAME", unique = true)
|
@Column(name="NAME", unique = true)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -42,6 +44,7 @@ import java.util.Map;
|
||||||
public class RequiredActionProviderEntity {
|
public class RequiredActionProviderEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="ALIAS")
|
@Column(name="ALIAS")
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.DynamicInsert;
|
||||||
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -37,6 +42,8 @@ import java.util.Collection;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
|
//@DynamicInsert
|
||||||
|
//@DynamicUpdate
|
||||||
@Table(name="KEYCLOAK_ROLE", uniqueConstraints = {
|
@Table(name="KEYCLOAK_ROLE", uniqueConstraints = {
|
||||||
@UniqueConstraint(columnNames = { "NAME", "CLIENT_REALM_CONSTRAINT" })
|
@UniqueConstraint(columnNames = { "NAME", "CLIENT_REALM_CONSTRAINT" })
|
||||||
})
|
})
|
||||||
|
@ -49,6 +56,7 @@ import java.util.Collection;
|
||||||
public class RoleEntity {
|
public class RoleEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@Column(name = "NAME")
|
@Column(name = "NAME")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -48,6 +50,7 @@ public class UserAttributeEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch= FetchType.LAZY)
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.keycloak.models.jpa.entities;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -51,6 +53,7 @@ public class UserConsentEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch= FetchType.LAZY)
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -59,6 +61,7 @@ import java.util.Collection;
|
||||||
public class UserEntity {
|
public class UserEntity {
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name = "USERNAME")
|
@Column(name = "USERNAME")
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -41,6 +43,7 @@ public class UserFederationMapperEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@Column(name="NAME")
|
@Column(name="NAME")
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.CollectionTable;
|
import javax.persistence.CollectionTable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -39,6 +41,7 @@ public class UserFederationProviderEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
@Column(name="ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
|
||||||
protected String id;
|
protected String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
|
29
testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
Normal file → Executable file
29
testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
Normal file → Executable file
|
@ -26,14 +26,6 @@
|
||||||
"provider": "${keycloak.userSessionPersister.provider:jpa}"
|
"provider": "${keycloak.userSessionPersister.provider:jpa}"
|
||||||
},
|
},
|
||||||
|
|
||||||
"userSessions": {
|
|
||||||
"provider" : "${keycloak.userSessions.provider:infinispan}"
|
|
||||||
},
|
|
||||||
|
|
||||||
"realmCache": {
|
|
||||||
"provider": "${keycloak.realm.cache.provider:infinispan}"
|
|
||||||
},
|
|
||||||
|
|
||||||
"userCache": {
|
"userCache": {
|
||||||
"provider": "${keycloak.user.cache.provider:infinispan}",
|
"provider": "${keycloak.user.cache.provider:infinispan}",
|
||||||
"mem": {
|
"mem": {
|
||||||
|
@ -41,6 +33,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"userSessions": {
|
||||||
|
"provider" : "${keycloak.userSessions.provider:infinispan}"
|
||||||
|
},
|
||||||
|
|
||||||
"timer": {
|
"timer": {
|
||||||
"provider": "basic"
|
"provider": "basic"
|
||||||
},
|
},
|
||||||
|
@ -99,6 +95,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"realmCache": {
|
||||||
|
"provider": "infinispan-locking",
|
||||||
|
"infinispan-locking" : {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"connectionsInfinispan": {
|
||||||
|
"provider": "locking",
|
||||||
|
"locking": {
|
||||||
|
"clustered": "${keycloak.connectionsInfinispan.clustered:false}",
|
||||||
|
"async": "${keycloak.connectionsInfinispan.async:true}",
|
||||||
|
"sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:2}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
"truststore": {
|
"truststore": {
|
||||||
"file": {
|
"file": {
|
||||||
"file": "${keycloak.truststore.file:src/main/keystore/keycloak.truststore}",
|
"file": "${keycloak.truststore.file:src/main/keystore/keycloak.truststore}",
|
||||||
|
|
|
@ -42,13 +42,12 @@ import static org.junit.Assert.*;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
@Ignore
|
|
||||||
public class ConcurrencyTest extends AbstractClientTest {
|
public class ConcurrencyTest extends AbstractClientTest {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(ConcurrencyTest.class);
|
private static final Logger log = Logger.getLogger(ConcurrencyTest.class);
|
||||||
|
|
||||||
private static final int DEFAULT_THREADS = 10;
|
private static final int DEFAULT_THREADS = 1;
|
||||||
private static final int DEFAULT_ITERATIONS = 100;
|
private static final int DEFAULT_ITERATIONS = 5;
|
||||||
|
|
||||||
// If enabled only one request is allowed at the time. Useful for checking that test is working.
|
// If enabled only one request is allowed at the time. Useful for checking that test is working.
|
||||||
private static final boolean SYNCHRONIZED = false;
|
private static final boolean SYNCHRONIZED = false;
|
||||||
|
@ -146,6 +145,8 @@ public class ConcurrencyTest extends AbstractClientTest {
|
||||||
final String clientId = ApiUtil.getCreatedId(response);
|
final String clientId = ApiUtil.getCreatedId(response);
|
||||||
response.close();
|
response.close();
|
||||||
|
|
||||||
|
System.out.println("*********************************************");
|
||||||
|
|
||||||
run(new KeycloakRunnable() {
|
run(new KeycloakRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
|
public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
|
||||||
|
@ -160,6 +161,7 @@ public class ConcurrencyTest extends AbstractClientTest {
|
||||||
});
|
});
|
||||||
long end = System.currentTimeMillis() - start;
|
long end = System.currentTimeMillis() - start;
|
||||||
System.out.println("createClientRole took " + end);
|
System.out.println("createClientRole took " + end);
|
||||||
|
System.out.println("*********************************************");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
Normal file → Executable file
6
wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
Normal file → Executable file
|
@ -30,6 +30,9 @@
|
||||||
<local-cache name="sessions"/>
|
<local-cache name="sessions"/>
|
||||||
<local-cache name="offlineSessions"/>
|
<local-cache name="offlineSessions"/>
|
||||||
<local-cache name="loginFailures"/>
|
<local-cache name="loginFailures"/>
|
||||||
|
<local-cache name="realmVersions">
|
||||||
|
<transaction mode="BATCH" locking="PESSIMISTIC"/>
|
||||||
|
</local-cache>
|
||||||
</cache-container>
|
</cache-container>
|
||||||
<cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
|
<cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
|
||||||
<local-cache name="default">
|
<local-cache name="default">
|
||||||
|
@ -87,6 +90,9 @@
|
||||||
<distributed-cache name="sessions" mode="SYNC" owners="1"/>
|
<distributed-cache name="sessions" mode="SYNC" owners="1"/>
|
||||||
<distributed-cache name="offlineSessions" mode="SYNC" owners="1"/>
|
<distributed-cache name="offlineSessions" mode="SYNC" owners="1"/>
|
||||||
<distributed-cache name="loginFailures" mode="SYNC" owners="1"/>
|
<distributed-cache name="loginFailures" mode="SYNC" owners="1"/>
|
||||||
|
<local-cache name="realmVersions">
|
||||||
|
<transaction mode="BATCH" locking="PESSIMISTIC"/>
|
||||||
|
</local-cache>
|
||||||
</cache-container>
|
</cache-container>
|
||||||
<cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
|
<cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
|
||||||
<transport lock-timeout="60000"/>
|
<transport lock-timeout="60000"/>
|
||||||
|
|
Loading…
Reference in a new issue