keycloak-aplcache

Details

diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
index 9d3237d..b2b1e5f 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
@@ -207,6 +207,15 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
                         </listitem>
                     </varlistentry>
                     <varlistentry>
+                        <term>globalStatsInterval</term>
+                        <listitem>
+                            <para>
+                                Will log global statistics from Hibernate about executed DB queries and other things. Statistics are always reported
+                                to server log at specified interval (in seconds) and are cleared after each report.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
                         <term>schema</term>
                         <listitem>
                             <para>
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
index 444e891..25401f6 100755
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
@@ -40,6 +40,8 @@ import org.keycloak.connections.jpa.util.JpaUtils;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.provider.ServerInfoAwareProviderFactory;
+import org.keycloak.services.scheduled.ScheduledTaskRunner;
+import org.keycloak.timer.TimerProvider;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -179,11 +181,20 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
 	
 	                        logger.trace("Database update completed");
 	                    }
-	
+
+                        int globalStatsInterval = config.getInt("globalStatsInterval", -1);
+                        if (globalStatsInterval != -1) {
+                            properties.put("hibernate.generate_statistics", true);
+                        }
+
 	                    logger.trace("Creating EntityManagerFactory");
 	                    emf = Persistence.createEntityManagerFactory(unitName, properties);
 	                    logger.trace("EntityManagerFactory created");
 
+                        if (globalStatsInterval != -1) {
+                            startGlobalStats(session, globalStatsInterval);
+                        }
+
                     } catch (Exception e) {
                         // Safe rollback
                         if (connection != null) {
@@ -260,6 +271,12 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
         }
     }
 
+    protected void startGlobalStats(KeycloakSession session, int globalStatsIntervalSecs) {
+        logger.debugf("Started Hibernate statistics with the interval %s seconds", globalStatsIntervalSecs);
+        TimerProvider timer = session.getProvider(TimerProvider.class);
+        timer.schedule(new ScheduledTaskRunner(session.getKeycloakSessionFactory(), new HibernateStatsReporter(emf)), globalStatsIntervalSecs * 1000, "ReportHibernateGlobalStats");
+    }
+
 
     @Override
     public Connection getConnection() {
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/HibernateStatsReporter.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/HibernateStatsReporter.java
new file mode 100644
index 0000000..fbe09ae
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/HibernateStatsReporter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
+import org.hibernate.stat.QueryStatistics;
+import org.hibernate.stat.Statistics;
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.scheduled.ScheduledTask;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class HibernateStatsReporter implements ScheduledTask {
+
+    private final EntityManagerFactory emf;
+    private static final Logger logger = Logger.getLogger(HibernateStatsReporter.class);
+
+    public HibernateStatsReporter(EntityManagerFactory emf) {
+        this.emf = emf;
+    }
+
+
+    @Override
+    public void run(KeycloakSession session) {
+        SessionFactory sessionFactory = ((EntityManagerFactoryImpl) emf).getSessionFactory();
+        Statistics stats = sessionFactory.getStatistics();
+
+        logStats(stats);
+
+        stats.clear(); // For now, clear stats after each iteration
+    }
+
+
+    protected void logStats(Statistics stats) {
+        String lineSep = System.getProperty("line.separator");
+        StringBuilder builder = new StringBuilder(lineSep).append(stats.toString()).append(lineSep);
+        builder.append(lineSep).append("Queries statistics: ").append(lineSep).append(lineSep);
+
+        for (String query : stats.getQueries()) {
+            QueryStatistics queryStats = stats.getQueryStatistics(query);
+
+            builder.append(query).append(lineSep)
+                    .append("executionCount=" + queryStats.getExecutionCount()).append(lineSep)
+                    .append("executionAvgTime=" + queryStats.getExecutionAvgTime()).append(" ms").append(lineSep)
+                    .append(lineSep);
+
+            builder.append(lineSep);
+        }
+
+        logger.infof(builder.toString());
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
index 0e0dea2..f253684 100755
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
@@ -28,7 +28,7 @@ public interface JpaUpdaterProvider extends Provider {
 
     public String FIRST_VERSION = "1.0.0.Final";
 
-    public String LAST_VERSION = "1.9.0";
+    public String LAST_VERSION = "1.9.2";
 
     public String getCurrentVersionSql(String defaultSchema);
 
diff --git a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
index a69e443..2d0117e 100644
--- a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
@@ -31,4 +31,5 @@
     <include file="META-INF/db2-jpa-changelog-1.8.0.xml"/>
     <include file="META-INF/jpa-changelog-1.9.0.xml"/>
     <include file="META-INF/db2-jpa-changelog-1.9.1.xml"/>
+    <include file="META-INF/jpa-changelog-1.9.2.xml"/>
 </databaseChangeLog>
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-1.9.2.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-1.9.2.xml
new file mode 100644
index 0000000..141d7cb
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-1.9.2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+    <changeSet author="keycloak" id="1.9.2">
+
+        <!-- Optimized as lookup user by email is often operation -->
+        <createIndex indexName="IDX_USER_EMAIL" tableName="USER_ENTITY">
+            <column name="EMAIL" type="VARCHAR(255)"/>
+        </createIndex>
+
+    </changeSet>
+</databaseChangeLog>
\ No newline at end of file
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
index c107b8e..fd1f0f6 100755
--- a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -31,4 +31,5 @@
     <include file="META-INF/jpa-changelog-1.8.0.xml"/>
     <include file="META-INF/jpa-changelog-1.9.0.xml"/>
     <include file="META-INF/jpa-changelog-1.9.1.xml"/>
+    <include file="META-INF/jpa-changelog-1.9.2.xml"/>
 </databaseChangeLog>
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index fd730de..f5b3e24 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -52,6 +52,9 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase
 # log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
 # log4j.logger.org.keycloak.migration.MigrationModelManager=debug
 
+# Enable to view hibernate statistics
+log4j.logger.org.keycloak.connections.jpa.HibernateStatsReporter=debug
+
 # Enable to view kerberos/spnego logging
 # log4j.logger.org.keycloak.federation.kerberos=trace
 
diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
index e9bb97f..ec76904 100755
--- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
@@ -63,7 +63,8 @@
             "password": "${keycloak.connectionsJpa.password:}",
             "databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
             "showSql": "${keycloak.connectionsJpa.showSql:false}",
-            "formatSql": "${keycloak.connectionsJpa.formatSql:true}"
+            "formatSql": "${keycloak.connectionsJpa.formatSql:true}",
+            "globalStatsInterval": "${keycloak.connectionsJpa.globalStatsInterval:-1}"
         }
     },
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
index ae0f5f9..111d510 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -83,7 +83,8 @@
             "password": "${keycloak.connectionsJpa.password:}",
             "databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
             "showSql": "${keycloak.connectionsJpa.showSql:false}",
-            "formatSql": "${keycloak.connectionsJpa.formatSql:true}"
+            "formatSql": "${keycloak.connectionsJpa.formatSql:true}",
+            "globalStatsInterval": "${keycloak.connectionsJpa.globalStatsInterval:-1}"
         }
     },
 
diff --git a/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/java/org/keycloak/testsuite/user/ManyUsersTest.java b/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/java/org/keycloak/testsuite/user/ManyUsersTest.java
index 914f748..f882879 100644
--- a/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/java/org/keycloak/testsuite/user/ManyUsersTest.java
+++ b/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/java/org/keycloak/testsuite/user/ManyUsersTest.java
@@ -66,9 +66,7 @@ public class ManyUsersTest extends AbstractUserTest {
         }
 
         realmTimer.reset("create realm before test");
-        RealmRepresentation realm = new RealmRepresentation();
-        realm.setRealm(REALM);
-        realmsResouce().create(realm);
+        createRealm(REALM);
 
         refreshToken();
     }
diff --git a/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/resources/log4j.properties b/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/resources/log4j.properties
new file mode 100644
index 0000000..9795846
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/jpa-performance/src/test/resources/log4j.properties
@@ -0,0 +1,61 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+log4j.rootLogger=info
+
+log4j.appender.keycloak=org.apache.log4j.ConsoleAppender
+log4j.appender.keycloak.layout=org.apache.log4j.PatternLayout
+log4j.appender.keycloak.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
+
+log4j.appender.testsuite=org.apache.log4j.ConsoleAppender
+log4j.appender.testsuite.layout=org.apache.log4j.PatternLayout
+log4j.appender.testsuite.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %m%n
+
+log4j.logger.org.keycloak=off, keycloak
+
+log4j.logger.org.keycloak.testsuite=debug, testsuite
+log4j.additivity.org.keycloak.testsuite=false
+
+# Enable to view events
+# log4j.logger.org.keycloak.events=debug
+
+# Enable to view loaded SPI and Providers
+# log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
+# log4j.logger.org.keycloak.provider.ProviderManager=debug
+# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
+
+# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
+keycloak.liquibase.logging.level=info
+log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase.logging.level}
+log4j.logger.org.keycloak.connections.jpa=debug
+
+# Enable to view database updates
+# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
+# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
+
+# Enable to view kerberos/spnego logging
+# log4j.logger.org.keycloak.broker.kerberos=trace
+
+# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
+# log4j.logger.org.apache.directory.server.kerberos=debug
+
+log4j.logger.org.xnio=off
+log4j.logger.org.hibernate=off
+log4j.logger.org.jboss.resteasy=warn
+log4j.logger.org.apache.directory.api=warn
+log4j.logger.org.apache.directory.server.core=warn
\ No newline at end of file