Allow BEAM pipeline to choose JDBC isolation levels (#916)

* Allow BEAM pipeline to choose JDBC isolation levels

Some BEAM pipelines may only perform READ-ONLY (e.g., reporting) or
blind-write (datastore to sql data migration) operations, which do not
need the default TRANSACTION_SERIALIZABLE isolation level. In such
cases, a less strict level allows better performance.
This commit is contained in:
Weimin Yu 2021-01-07 11:00:36 -05:00 committed by GitHub
parent 6a1e86ff33
commit 7a62aa0602
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 8 deletions

View file

@ -15,10 +15,24 @@
package google.registry.persistence;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import dagger.Component;
import google.registry.beam.initsql.BeamJpaModule;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.keyring.kms.KmsModule;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
import google.registry.privileges.secretmanager.SecretManagerModule;
import google.registry.testing.DatastoreEntityExtension;
import google.registry.util.UtilsModule;
import java.util.Optional;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.hibernate.cfg.Environment;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -29,7 +43,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
/** Unit tests for {@link PersistenceModule}. */
@Testcontainers
public class PersistenceModuleTest {
class PersistenceModuleTest {
@Container
private final PostgreSQLContainer database =
@ -64,4 +78,61 @@ public class PersistenceModuleTest {
assertThat(em.isOpen()).isTrue();
em.close();
}
@Test
void appengineIsolation() {
assertThat(PersistenceModule.provideDefaultDatabaseConfigs().get(Environment.ISOLATION))
.isEqualTo(TransactionIsolationLevel.TRANSACTION_SERIALIZABLE.name());
}
@Test
void beamIsolation_default() {
Optional<Provider<TransactionIsolationLevel>> injected =
DaggerPersistenceModuleTest_BeamConfigTestComponent.builder()
.beamJpaModule(new BeamJpaModule(null, null))
.build()
.getIsolationOverride();
assertThat(injected).isNotNull();
assertThat(injected.get().get()).isNull();
assertThat(
PersistenceModule.provideBeamPipelineCloudSqlConfigs(
"", "", PersistenceModule.provideDefaultDatabaseConfigs(), injected)
.get(Environment.ISOLATION))
.isEqualTo(TransactionIsolationLevel.TRANSACTION_SERIALIZABLE.name());
}
@Test
void beamIsolation_override() {
Optional<Provider<TransactionIsolationLevel>> injected =
DaggerPersistenceModuleTest_BeamConfigTestComponent.builder()
.beamJpaModule(
new BeamJpaModule(
null, null, TransactionIsolationLevel.TRANSACTION_READ_UNCOMMITTED))
.build()
.getIsolationOverride();
assertThat(injected).isNotNull();
assertThat(injected.get().get())
.isEqualTo(TransactionIsolationLevel.TRANSACTION_READ_UNCOMMITTED);
assertThat(
PersistenceModule.provideBeamPipelineCloudSqlConfigs(
"", "", PersistenceModule.provideDefaultDatabaseConfigs(), injected)
.get(Environment.ISOLATION))
.isEqualTo(TransactionIsolationLevel.TRANSACTION_READ_UNCOMMITTED.name());
}
@Singleton
@Component(
modules = {
BeamJpaModule.class,
ConfigModule.class,
CredentialModule.class,
KmsModule.class,
PersistenceModule.class,
SecretManagerModule.class,
UtilsModule.class
})
public interface BeamConfigTestComponent {
@Config("beamIsolationOverride")
Optional<Provider<TransactionIsolationLevel>> getIsolationOverride();
}
}