diff --git a/core/build.gradle b/core/build.gradle index 624b2feca..d77c1186d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -218,7 +218,6 @@ dependencies { compile deps['org.bouncycastle:bcpg-jdk15on'] testCompile deps['org.bouncycastle:bcpkix-jdk15on'] compile deps['org.bouncycastle:bcprov-jdk15on'] - compile deps['org.hibernate:hibernate-core'] compile deps['org.joda:joda-money'] compile deps['org.json:json'] testCompile deps['org.mortbay.jetty:jetty'] @@ -254,7 +253,7 @@ dependencies { testCompile deps['org.hamcrest:hamcrest-all'] testCompile deps['org.hamcrest:hamcrest-core'] testCompile deps['org.hamcrest:hamcrest-library'] - compile deps['org.hibernate:hibernate-core'] + compile deps['org.hibernate:hibernate-hikaricp'] testCompile deps['junit:junit'] testCompile deps['org.mockito:mockito-core'] runtime deps['org.postgresql:postgresql'] diff --git a/core/src/main/java/google/registry/config/RegistryConfig.java b/core/src/main/java/google/registry/config/RegistryConfig.java index 4100c7f3d..3518f9467 100644 --- a/core/src/main/java/google/registry/config/RegistryConfig.java +++ b/core/src/main/java/google/registry/config/RegistryConfig.java @@ -112,7 +112,7 @@ public final class RegistryConfig { } /** - * The product name of this specific registry. Used throughout the registrar console. + * The product name of this specific registry. Used throughout the registrar console. * * @see google.registry.ui.server.registrar.ConsoleUiAction */ @@ -123,11 +123,11 @@ public final class RegistryConfig { } /** - * Returns the roid suffix to be used for the roids of all contacts and hosts. E.g. a value of + * Returns the roid suffix to be used for the roids of all contacts and hosts. E.g. a value of * "ROID" would end up creating roids that look like "ABC123-ROID". * * @see - * Extensible Provisioning Protocol (EPP) Repository Identifiers + * Extensible Provisioning Protocol (EPP) Repository Identifiers */ @Provides @Config("contactAndHostRoidSuffix") @@ -136,7 +136,7 @@ public final class RegistryConfig { } /** - * The e-mail address for questions about integrating with the registry. Used in the + * The e-mail address for questions about integrating with the registry. Used in the * "contact-us" section of the registrar console. * * @see google.registry.ui.server.registrar.ConsoleUiAction @@ -148,7 +148,7 @@ public final class RegistryConfig { } /** - * The e-mail address for general support. Used in the "contact-us" section of the registrar + * The e-mail address for general support. Used in the "contact-us" section of the registrar * console. * * @see google.registry.ui.server.registrar.ConsoleUiAction @@ -160,7 +160,7 @@ public final class RegistryConfig { } /** - * The "From" e-mail address for announcements. Used in the "contact-us" section of the + * The "From" e-mail address for announcements. Used in the "contact-us" section of the * registrar console. * * @see google.registry.ui.server.registrar.ConsoleUiAction @@ -172,7 +172,7 @@ public final class RegistryConfig { } /** - * The contact phone number. Used in the "contact-us" section of the registrar console. + * The contact phone number. Used in the "contact-us" section of the registrar console. * * @see google.registry.ui.server.registrar.ConsoleUiAction */ @@ -1040,8 +1040,8 @@ public final class RegistryConfig { } /** - * The global automatic transfer length for contacts. After this amount of time has - * elapsed, the transfer is automatically approved. + * The global automatic transfer length for contacts. After this amount of time has elapsed, the + * transfer is automatically approved. * * @see google.registry.flows.contact.ContactTransferRequestFlow */ @@ -1196,7 +1196,7 @@ public final class RegistryConfig { /** * Provides the OAuth scopes that authentication logic should detect on access tokens. * - *
This list should be a superset of the required OAuth scope set provided below. Note that + *
This list should be a superset of the required OAuth scope set provided below. Note that
* ideally, this setting would not be required and all scopes on an access token would be
* detected automatically, but that is not the case due to the way {@code OAuthService} works.
*
@@ -1297,9 +1297,7 @@ public final class RegistryConfig {
}
}
- /**
- * Returns the App Engine project ID, which is based off the environment name.
- */
+ /** Returns the App Engine project ID, which is based off the environment name. */
public static String getProjectId() {
return CONFIG_SETTINGS.get().appEngine.projectId;
}
@@ -1451,20 +1449,51 @@ public final class RegistryConfig {
return CONFIG_SETTINGS.get().registryPolicy.defaultRegistrarWhoisServer;
}
- /**
- * Returns the number of {@code EppResourceIndex} buckets to be used.
- */
+ /** Returns the number of {@code EppResourceIndex} buckets to be used. */
public static int getEppResourceIndexBucketCount() {
return CONFIG_SETTINGS.get().datastore.eppResourceIndexBucketsNum;
}
- /**
- * Returns the base retry duration that gets doubled after each failure within {@code Ofy}.
- */
+ /** Returns the base retry duration that gets doubled after each failure within {@code Ofy}. */
public static Duration getBaseOfyRetryDuration() {
return Duration.millis(CONFIG_SETTINGS.get().datastore.baseOfyRetryMillis);
}
+ /** Returns the default database transaction isolation. */
+ public static String getHibernateConnectionIsolation() {
+ return CONFIG_SETTINGS.get().hibernate.connectionIsolation;
+ }
+
+ /** Returns true if hibernate.show_sql is enabled. */
+ public static String getHibernateLogSqlQueries() {
+ return CONFIG_SETTINGS.get().hibernate.logSqlQueries;
+ }
+
+ /** Returns true if schema modification is allowed. */
+ public static String getHibernateHbm2ddlAuto() {
+ return CONFIG_SETTINGS.get().hibernate.hbm2ddlAuto;
+ }
+
+ /** Returns the connection timeout for HikariCP. */
+ public static String getHibernateHikariConnectionTimeout() {
+ return CONFIG_SETTINGS.get().hibernate.hikariConnectionTimeout;
+ }
+
+ /** Returns the minimum idle connections for HikariCP. */
+ public static String getHibernateHikariMinimumIdle() {
+ return CONFIG_SETTINGS.get().hibernate.hikariMinimumIdle;
+ }
+
+ /** Returns the maximum pool size for HikariCP. */
+ public static String getHibernateHikariMaximumPoolSize() {
+ return CONFIG_SETTINGS.get().hibernate.hikariMaximumPoolSize;
+ }
+
+ /** Returns the idle timeout for HikariCP. */
+ public static String getHibernateHikariIdleTimeout() {
+ return CONFIG_SETTINGS.get().hibernate.hikariIdleTimeout;
+ }
+
/** Returns the roid suffix to be used for the roids of all contacts and hosts. */
public static String getContactAndHostRoidSuffix() {
return CONFIG_SETTINGS.get().registryPolicy.contactAndHostRoidSuffix;
diff --git a/core/src/main/java/google/registry/config/RegistryConfigSettings.java b/core/src/main/java/google/registry/config/RegistryConfigSettings.java
index 7392d341d..3d802cb59 100644
--- a/core/src/main/java/google/registry/config/RegistryConfigSettings.java
+++ b/core/src/main/java/google/registry/config/RegistryConfigSettings.java
@@ -25,6 +25,7 @@ public class RegistryConfigSettings {
public CredentialOAuth credentialOAuth;
public RegistryPolicy registryPolicy;
public Datastore datastore;
+ public Hibernate hibernate;
public CloudDns cloudDns;
public Caching caching;
public IcannReporting icannReporting;
@@ -105,6 +106,17 @@ public class RegistryConfigSettings {
public int baseOfyRetryMillis;
}
+ /** Configuration for Hibernate. */
+ public static class Hibernate {
+ public String connectionIsolation;
+ public String logSqlQueries;
+ public String hbm2ddlAuto;
+ public String hikariConnectionTimeout;
+ public String hikariMinimumIdle;
+ public String hikariMaximumPoolSize;
+ public String hikariIdleTimeout;
+ }
+
/** Configuration for Apache Beam (Cloud Dataflow). */
public static class Beam {
public String defaultJobZone;
diff --git a/core/src/main/java/google/registry/config/files/default-config.yaml b/core/src/main/java/google/registry/config/files/default-config.yaml
index 09f7ec9dd..cc41f28b4 100644
--- a/core/src/main/java/google/registry/config/files/default-config.yaml
+++ b/core/src/main/java/google/registry/config/files/default-config.yaml
@@ -191,6 +191,26 @@ datastore:
# doubles after each failure).
baseOfyRetryMillis: 100
+hibernate:
+ # Make 'SERIALIZABLE' the default isolation level to ensure correctness.
+ #
+ # Entities that are never involved in multi-table transactions may use optimistic
+ # locks and a less strict isolation level. We may lower individual transaction's
+ # isolation level using a framework-dependent method.
+ #
+ # Alternatively, if a use case calls for, we may also use a lower isolation level
+ # but lock tables explicitly, either using framework-dependent API, or execute
+ # "select table for update" statements directly.
+ connectionIsolation: TRANSACTION_SERIALIZABLE
+ # Whether to log all SQL queries to App Engine logs. Overridable at runtime.
+ logSqlQueries: false
+
+ # Connection pool configurations.
+ hikariConnectionTimeout: 20000
+ hikariMinimumIdle: 0
+ hikariMaximumPoolSize: 20
+ hikariIdleTimeout: 300000
+
cloudDns:
# Set both properties to null in Production.
# The root url for the Cloud DNS API. Set this to a non-null value to
diff --git a/core/src/main/java/google/registry/persistence/EntityManagerFactoryProvider.java b/core/src/main/java/google/registry/persistence/EntityManagerFactoryProvider.java
new file mode 100644
index 000000000..ed61e89ac
--- /dev/null
+++ b/core/src/main/java/google/registry/persistence/EntityManagerFactoryProvider.java
@@ -0,0 +1,67 @@
+// Copyright 2019 The Nomulus Authors. All Rights Reserved.
+//
+// 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 google.registry.persistence;
+
+import static google.registry.config.RegistryConfig.getHibernateConnectionIsolation;
+import static google.registry.config.RegistryConfig.getHibernateHikariConnectionTimeout;
+import static google.registry.config.RegistryConfig.getHibernateHikariIdleTimeout;
+import static google.registry.config.RegistryConfig.getHibernateHikariMaximumPoolSize;
+import static google.registry.config.RegistryConfig.getHibernateHikariMinimumIdle;
+import static google.registry.config.RegistryConfig.getHibernateLogSqlQueries;
+
+import com.google.common.collect.ImmutableMap;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import org.hibernate.cfg.Environment;
+
+/** Factory class to provide {@link EntityManagerFactory} instance. */
+public class EntityManagerFactoryProvider {
+ // This name must be the same as the one defined in persistence.xml.
+ public static final String PERSISTENCE_UNIT_NAME = "nomulus";
+ public static final String HIKARI_CONNECTION_TIMEOUT = "hibernate.hikari.connectionTimeout";
+ public static final String HIKARI_MINIMUM_IDLE = "hibernate.hikari.minimumIdle";
+ public static final String HIKARI_MAXIMUM_POOL_SIZE = "hibernate.hikari.maximumPoolSize";
+ public static final String HIKARI_IDLE_TIMEOUT = "hibernate.hikari.idleTimeout";
+
+ private static ImmutableMap