keycloak-memoizeit

Merge pull request #3055 from mposolda/master KEYCLOAK-3344

7/21/2016 9:18:49 AM

Details

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 784438c..431a638 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
@@ -37,7 +37,9 @@ import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
 import org.keycloak.connections.jpa.util.JpaUtils;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakSessionTask;
 import org.keycloak.models.dblock.DBLockProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.provider.ServerInfoAwareProviderFactory;
 import org.keycloak.models.dblock.DBLockManager;
 import org.keycloak.timer.TimerProvider;
@@ -93,8 +95,6 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
                 if (emf == null) {
                     logger.debug("Initializing JPA connections");
 
-                    Connection connection = null;
-
                     Map<String, Object> properties = new HashMap<String, Object>();
 
                     String unitName = "keycloak-default";
@@ -126,23 +126,26 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
                     }
 
 
-                    String databaseSchema = config.get("databaseSchema");
-                    if (databaseSchema == null) {
+                    String databaseSchema;
+                    String databaseSchemaConf = config.get("databaseSchema");
+                    if (databaseSchemaConf == null) {
                         throw new RuntimeException("Property 'databaseSchema' needs to be specified in the configuration");
                     }
                     
-                    if (databaseSchema.equals("development-update")) {
+                    if (databaseSchemaConf.equals("development-update")) {
                         properties.put("hibernate.hbm2ddl.auto", "update");
                         databaseSchema = null;
-                    } else if (databaseSchema.equals("development-validate")) {
+                    } else if (databaseSchemaConf.equals("development-validate")) {
                         properties.put("hibernate.hbm2ddl.auto", "validate");
                         databaseSchema = null;
+                    } else {
+                        databaseSchema = databaseSchemaConf;
                     }
 
                     properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
                     properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
 
-                    connection = getConnection();
+                    Connection connection = getConnection();
                     try{ 
 	                    prepareOperationalInfo(connection);
 
@@ -161,19 +164,27 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
 
                             // Check if having DBLock before trying to initialize hibernate
                             DBLockProvider dbLock = new DBLockManager(session).getDBLock();
-                            if (!dbLock.hasLock()) {
-                                throw new IllegalStateException("Trying to update database, but don't have a DB lock acquired");
+                            if (dbLock.hasLock()) {
+                                updateOrValidateDB(databaseSchema, connection, updater, schema);
+                            } else {
+                                logger.trace("Don't have DBLock retrieved before upgrade. Needs to acquire lock first in separate transaction");
+
+                                KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+
+                                    @Override
+                                    public void run(KeycloakSession lockSession) {
+                                        DBLockManager dbLockManager = new DBLockManager(lockSession);
+                                        DBLockProvider dbLock2 = dbLockManager.getDBLock();
+                                        dbLock2.waitForLock();
+                                        try {
+                                            updateOrValidateDB(databaseSchema, connection, updater, schema);
+                                        } finally {
+                                            dbLock2.releaseLock();
+                                        }
+                                    }
+
+                                });
                             }
-	
-	                        if (databaseSchema.equals("update")) {
-                                updater.update(connection, schema);
-	                        } else if (databaseSchema.equals("validate")) {
-	                            updater.validate(connection, schema);
-	                        } else {
-	                            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
-	                        }
-	
-	                        logger.trace("Database update completed");
 	                    }
 
                         int globalStatsInterval = config.getInt("globalStatsInterval", -1);
@@ -272,6 +283,20 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
     }
 
 
+    // Needs to be called with acquired DBLock
+    protected void updateOrValidateDB(String databaseSchema, Connection connection, JpaUpdaterProvider updater, String schema) {
+        if (databaseSchema.equals("update")) {
+            updater.update(connection, schema);
+            logger.trace("Database update completed");
+        } else if (databaseSchema.equals("validate")) {
+            updater.validate(connection, schema);
+            logger.trace("Database validation completed");
+        } else {
+            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+        }
+    }
+
+
     @Override
     public Connection getConnection() {
         try {
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 7fc3439..d8d87f5 100755
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -34,8 +34,10 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati
 import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakSessionTask;
 import org.keycloak.models.dblock.DBLockManager;
 import org.keycloak.models.dblock.DBLockProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.provider.ServerInfoAwareProviderFactory;
 
 import com.mongodb.DB;
@@ -174,8 +176,26 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
             }
 
             DBLockProvider dbLock = new DBLockManager(session).getDBLock();
-            if (!dbLock.hasLock()) {
-                throw new IllegalStateException("Trying to update database, but don't have a DB lock acquired");
+            if (dbLock.hasLock()) {
+                updateOrValidateDB(databaseSchema, session, mongoUpdater);
+            } else {
+                logger.trace("Don't have DBLock retrieved before upgrade. Needs to acquire lock first in separate transaction");
+
+                KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+
+                    @Override
+                    public void run(KeycloakSession lockSession) {
+                        DBLockManager dbLockManager = new DBLockManager(lockSession);
+                        DBLockProvider dbLock2 = dbLockManager.getDBLock();
+                        dbLock2.waitForLock();
+                        try {
+                            updateOrValidateDB(databaseSchema, session, mongoUpdater);
+                        } finally {
+                            dbLock2.releaseLock();
+                        }
+                    }
+
+                });
             }
 
             if (databaseSchema.equals("update")) {
@@ -197,6 +217,16 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
         return entityClasses;
     }
 
+    protected void updateOrValidateDB(String databaseSchema, KeycloakSession session, MongoUpdaterProvider mongoUpdater) {
+        if (databaseSchema.equals("update")) {
+            mongoUpdater.update(session, db);
+        } else if (databaseSchema.equals("validate")) {
+            mongoUpdater.validate(session, db);
+        } else {
+            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+        }
+    }
+
     @Override
     public void close() {
         if (client != null) {