concurrency

This commit is contained in:
Bill Burke 2016-02-10 14:09:29 -05:00
parent 0b54838f31
commit 84949bb51f
31 changed files with 123 additions and 40 deletions

View 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"
} }
} }

View file

@ -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);
} }

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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);
} }
} }

View file

@ -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;
} }

View file

@ -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)) {

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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")

View file

@ -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;

View file

@ -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;

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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")

View file

@ -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")

View file

@ -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)

View 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}",

View file

@ -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("*********************************************");
} }

View 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"/>