Skip to content

Commit

Permalink
Refactor some code related to the transaction manager
Browse files Browse the repository at this point in the history
Removed the deprecation mark as it is natural to expose methods related
to a transaction like getting the entity manager or checking if one is
in a transaction through the transaction manager interface.
  • Loading branch information
jianglai committed Mar 13, 2024
1 parent d0b0362 commit 5829dd0
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 56 deletions.
7 changes: 3 additions & 4 deletions core/src/main/java/google/registry/bsa/BsaTransactions.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import static com.google.common.base.Verify.verify;
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ;
import static google.registry.persistence.transaction.JpaTransactionManagerImpl.isInTransaction;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;

Expand All @@ -36,18 +35,18 @@ public final class BsaTransactions {

@CanIgnoreReturnValue
public static <T> T bsaTransact(Callable<T> work) {
verify(!isInTransaction(), "May only be used for top-level transactions.");
verify(!tm().inTransaction(), "May only be used for top-level transactions.");
return tm().transact(TRANSACTION_REPEATABLE_READ, work);
}

public static void bsaTransact(ThrowingRunnable work) {
verify(!isInTransaction(), "May only be used for top-level transactions.");
verify(!tm().inTransaction(), "May only be used for top-level transactions.");
tm().transact(TRANSACTION_REPEATABLE_READ, work);
}

@CanIgnoreReturnValue
public static <T> T bsaQuery(Callable<T> work) {
verify(!isInTransaction(), "May only be used for top-level transactions.");
verify(!tm().inTransaction(), "May only be used for top-level transactions.");
// TRANSACTION_REPEATABLE_READ is default on replica.
return replicaTm().transact(work);
}
Expand Down
24 changes: 15 additions & 9 deletions core/src/main/java/google/registry/bsa/persistence/Queries.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import static com.google.common.base.Verify.verify;
import static google.registry.bsa.BsaStringUtils.DOMAIN_SPLITTER;
import static google.registry.bsa.BsaTransactions.bsaQuery;
import static google.registry.persistence.transaction.JpaTransactionManagerImpl.em;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
Expand All @@ -39,7 +39,7 @@ private Queries() {}
* JpaTransactionManagerImpl}.
*/
private static Object detach(Object obj) {
em().detach(obj);
tm().getEntityManager().detach(obj);
return obj;
}

Expand All @@ -49,7 +49,8 @@ public static ImmutableList<String> batchReadBsaLabelText(
return ImmutableList.copyOf(
bsaQuery(
() ->
em().createQuery(
tm().getEntityManager()
.createQuery(
"SELECT b.label FROM BsaLabel b WHERE b.label > :lastRead ORDER BY b.label",
String.class)
.setParameter("lastRead", lastRead.orElse(""))
Expand All @@ -60,7 +61,8 @@ public static ImmutableList<String> batchReadBsaLabelText(
static Stream<BsaUnblockableDomain> queryBsaUnblockableDomainByLabels(
ImmutableCollection<String> labels) {
return ((Stream<?>)
em().createQuery("FROM BsaUnblockableDomain WHERE label in (:labels)")
tm().getEntityManager()
.createQuery("FROM BsaUnblockableDomain WHERE label in (:labels)")
.setParameter("labels", labels)
.getResultStream())
.map(Queries::detach)
Expand All @@ -69,15 +71,17 @@ static Stream<BsaUnblockableDomain> queryBsaUnblockableDomainByLabels(

static Stream<BsaLabel> queryBsaLabelByLabels(ImmutableCollection<String> labels) {
return ((Stream<?>)
em().createQuery("FROM BsaLabel where label in (:labels)")
tm().getEntityManager()
.createQuery("FROM BsaLabel where label in (:labels)")
.setParameter("labels", labels)
.getResultStream())
.map(Queries::detach)
.map(BsaLabel.class::cast);
}

static int deleteBsaLabelByLabels(ImmutableCollection<String> labels) {
return em().createQuery("DELETE FROM BsaLabel where label IN (:deleted_labels)")
return tm().getEntityManager()
.createQuery("DELETE FROM BsaLabel where label IN (:deleted_labels)")
.setParameter("deleted_labels", labels)
.executeUpdate();
}
Expand All @@ -87,7 +91,8 @@ static ImmutableList<BsaUnblockableDomain> batchReadUnblockables(
return ImmutableList.copyOf(
bsaQuery(
() ->
em().createQuery(
tm().getEntityManager()
.createQuery(
"FROM BsaUnblockableDomain d WHERE d.label > :label OR (d.label = :label"
+ " AND d.tld > :tld) ORDER BY d.tld, d.label ")
.setParameter("label", lastRead.map(d -> d.label).orElse(""))
Expand All @@ -111,13 +116,14 @@ static ImmutableSet<String> queryUnblockablesByNames(ImmutableSet<String> domain
"SELECT CONCAT(d.label, '.', d.tld) FROM \"BsaUnblockableDomain\" d "
+ "WHERE (d.label, d.tld) IN (%s)",
labelTldParis);
return ImmutableSet.copyOf(em().createNativeQuery(sql).getResultList());
return ImmutableSet.copyOf(tm().getEntityManager().createNativeQuery(sql).getResultList());
}

static ImmutableSet<String> queryNewlyCreatedDomains(
ImmutableCollection<String> tlds, DateTime minCreationTime, DateTime now) {
return ImmutableSet.copyOf(
em().createQuery(
tm().getEntityManager()
.createQuery(
"SELECT domainName FROM Domain WHERE creationTime >= :minCreationTime "
+ "AND deletionTime > :now "
+ "AND tld in (:tlds)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ public interface JpaTransactionManager extends TransactionManager {
*
* <p>The returned instance is closed when the current transaction completes.
*
* @deprecated Use the static {@link JpaTransactionManagerImpl#em} method for now. In current
* implementation the entity manager is obtained from a static {@code ThreadLocal} object that
* is set up by the outermost {@link #transact} call. As an instance method, this method gives
* the illusion that the call site has control over which database instance to use.
* <p>Note that in the current implementation the entity manager is obtained from a static {@code
* ThreadLocal} object that is set up by the outermost {@link #transact} call. Nested call sites
* have no control over which database instance to use.
*/
@Deprecated // See Javadoc above.
EntityManager getEntityManager();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,6 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
private static final ThreadLocal<TransactionInfo> transactionInfo =
ThreadLocal.withInitial(TransactionInfo::new);

/** Returns true if inside a transaction; returns false otherwise. */
public static boolean isInTransaction() {
return transactionInfo.get().inTransaction;
}

/**
* Returns the {@link EntityManager} for the current database transaction.
*
* <p>This method must be call from inside a transaction.
*/
public static EntityManager em() {
EntityManager entityManager = transactionInfo.get().entityManager;
if (entityManager == null) {
throw new PersistenceException(
"No EntityManager has been initialized. getEntityManager() must be invoked in the scope"
+ " of a transaction");
}
return entityManager;
}

public JpaTransactionManagerImpl(EntityManagerFactory emf, Clock clock, boolean readOnly) {
this.emf = emf;
this.clock = clock;
Expand All @@ -131,16 +111,10 @@ public EntityManager getStandaloneEntityManager() {
return emf.createEntityManager();
}

@Deprecated // See Javadoc of interface method.
@Override
public EntityManager getEntityManager() {
EntityManager entityManager = transactionInfo.get().entityManager;
if (entityManager == null) {
throw new PersistenceException(
"No EntityManager has been initialized. getEntityManager() must be invoked in the scope"
+ " of a transaction");
}
return entityManager;
assertInTransaction();
return transactionInfo.get().entityManager;
}

@Override
Expand All @@ -158,7 +132,6 @@ public Query query(String sqlString) {
return getEntityManager().createQuery(sqlString);
}

@Deprecated // See Javadoc of instance method.
@Override
public boolean inTransaction() {
return transactionInfo.get().inTransaction;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,10 @@ public interface TransactionManager {
/**
* Returns {@code true} if the caller is in a transaction.
*
* <p>Note that this function is kept for backward compatibility. We will review the use case
* later when adding the cloud sql implementation.
*
* @deprecated Use the static {@link JpaTransactionManagerImpl#isInTransaction()} method for now.
* In current implementation the entity manager is obtained from a static {@code ThreadLocal}
* object that is set up by the outermost {@link #transact} call. As an instance method, this
* method gives the illusion that the call site has control over which database instance to
* use.
* <p>Note that in the current implementation the entity manager is obtained from a static {@code
* ThreadLocal} object that is set up by the outermost {@link #transact} call. Nested call sites
* have no control over which database instance to use.
*/
@Deprecated // See Javadoc above.
boolean inTransaction();

/**
Expand Down

0 comments on commit 5829dd0

Please sign in to comment.