Follow up for #3188 Fix findFutureList() and findFutureIds() when txn in scope

Apply the same fix to findFutureList() and findFutureIds()
This commit is contained in:
Rob Bygrave
2023-08-25 20:56:55 +12:00
parent 60a2626f61
commit 4f18dc339f
8 changed files with 106 additions and 61 deletions
@@ -378,20 +378,11 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
*/
<T> List<T> findList(SpiQuery<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
*/
<T> FutureRowCount<T> findFutureCount(SpiQuery<T> query);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
*/
<T> FutureIds<T> findFutureIds(SpiQuery<T> query, Transaction transaction);
<T> FutureIds<T> findFutureIds(SpiQuery<T> query);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
*/
<T> FutureList<T> findFutureList(SpiQuery<T> query, Transaction transaction);
<T> FutureList<T> findFutureList(SpiQuery<T> query);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
@@ -877,17 +877,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
boolean isDisableReadAudit();
/**
* Return true if this is a query executing in the background.
*/
boolean isFutureFetch();
/**
* Set to true to indicate the query is executing in a background thread
* asynchronously.
*/
void setFutureFetch(boolean futureFetch);
/**
* Set the readEvent for future queries (as prepared in foreground thread).
*/
@@ -1272,7 +1272,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> FutureRowCount<T> findFutureCount(SpiQuery<T> query) {
SpiQuery<T> copy = query.copy();
copy.setFutureFetch(true);
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
@@ -1288,19 +1287,25 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@Override
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query, Transaction transaction) {
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
SpiQuery<T> copy = query.copy();
copy.setFutureFetch(true);
Transaction newTxn = createTransaction();
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(new CallableQueryIds<>(this, copy, newTxn));
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
}
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(new CallableQueryIds<>(this, copy, transaction, createdTransaction));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <T> FutureList<T> findFutureList(SpiQuery<T> query, Transaction transaction) {
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
SpiQuery<T> spiQuery = query.copy();
spiQuery.setFutureFetch(true);
// FutureList query always run in it's own persistence content
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
if (!spiQuery.isDisableReadAudit()) {
@@ -1308,8 +1313,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
desc.readAuditFutureList(spiQuery);
}
// Create a new transaction solely to execute the findList() at some future time
Transaction newTxn = createTransaction();
QueryFutureList<T> queryFuture = new QueryFutureList<>(new CallableQueryList<>(this, spiQuery, newTxn));
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
}
QueryFutureList<T> queryFuture = new QueryFutureList<>(new CallableQueryList<>(this, spiQuery, transaction, createdTransaction));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@@ -12,9 +12,11 @@ import java.util.concurrent.Callable;
*/
public final class CallableQueryIds<T> extends CallableQuery<T> implements Callable<List<Object>> {
private final boolean createdTransaction;
public CallableQueryIds(SpiEbeanServer server, SpiQuery<T> query, Transaction t) {
public CallableQueryIds(SpiEbeanServer server, SpiQuery<T> query, Transaction t, boolean createdTransaction) {
super(server, query, t);
this.createdTransaction = createdTransaction;
}
/**
@@ -28,7 +30,9 @@ public final class CallableQueryIds<T> extends CallableQuery<T> implements Calla
try {
return server.findIdsWithCopy(query, transaction);
} finally {
transaction.end();
if (createdTransaction) {
transaction.end();
}
}
}
@@ -9,13 +9,14 @@ import java.util.concurrent.Callable;
/**
* Represent the findList query as a Callable.
*
* @param <T> the entity bean type
*/
public final class CallableQueryList<T> extends CallableQuery<T> implements Callable<List<T>> {
public CallableQueryList(SpiEbeanServer server, SpiQuery<T> query, Transaction t) {
private final boolean createdTransaction;
public CallableQueryList(SpiEbeanServer server, SpiQuery<T> query, Transaction t, boolean createdTransaction) {
super(server, query, t);
this.createdTransaction = createdTransaction;
}
/**
@@ -26,10 +27,10 @@ public final class CallableQueryList<T> extends CallableQuery<T> implements Call
try {
return server.findList(query, transaction);
} finally {
// cleanup the underlying connection
transaction.end();
if (createdTransaction) {
transaction.end();
}
}
}
}
@@ -86,11 +86,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
*/
private boolean distinct;
/**
* Set to true if this is a future fetch using background threads.
*/
private boolean futureFetch;
/**
* Only used for read auditing with findFutureList() query.
*/
@@ -1549,12 +1544,12 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
@Override
public final FutureIds<T> findFutureIds() {
return server.findFutureIds(this, transaction);
return server.findFutureIds(this);
}
@Override
public final FutureList<T> findFutureList() {
return server.findFutureList(this, transaction);
return server.findFutureList(this);
}
@Override
@@ -1922,16 +1917,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return disableReadAudit;
}
@Override
public final boolean isFutureFetch() {
return futureFetch;
}
@Override
public final void setFutureFetch(boolean backgroundFetch) {
this.futureFetch = backgroundFetch;
}
@Override
public final void setFutureFetchAudit(ReadEvent event) {
this.futureFetchAudit = event;
@@ -661,12 +661,12 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
}
@Override
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query, Transaction transaction) {
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
return null;
}
@Override
public <T> FutureList<T> findFutureList(SpiQuery<T> query, Transaction transaction) {
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
return null;
}
@@ -1,12 +1,12 @@
package org.tests.query;
import io.ebean.DB;
import io.ebean.FutureRowCount;
import io.ebean.Transaction;
import io.ebean.*;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.EBasic;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class TestFindFutureRowCount extends BaseTestCase {
@@ -46,4 +46,66 @@ class TestFindFutureRowCount extends BaseTestCase {
assertThat(futureCountUsingTxn.get()).isEqualTo(1);
}
}
@Test
void findFutureIds_when_inTransaction() throws Exception {
try (Transaction transaction = DB.beginTransaction()) {
EBasic basic = new EBasic("findFutureIds_when_inTransaction");
DB.save(basic);
List<Object> ids = DB.find(EBasic.class)
.where().eq("name", "findFutureIds_when_inTransaction")
.findIds();
Object expectedIdValue = ids.get(0);
FutureIds<EBasic> futureIds = DB.find(EBasic.class)
.where().eq("name", "findFutureIds_when_inTransaction")
.findFutureIds();
List<Object> fids = futureIds.get();
assertThat(fids).hasSize(1);
assertThat(fids.get(0)).isEqualTo(expectedIdValue);
FutureIds<EBasic> futureIdsUsingTxn = DB.find(EBasic.class)
.usingTransaction(transaction)
.where().eq("name", "findFutureIds_when_inTransaction")
.findFutureIds();
List<Object> fids2 = futureIdsUsingTxn.get();
assertThat(fids2).hasSize(1);
assertThat(fids2.get(0)).isEqualTo(expectedIdValue);
}
}
@Test
void findFutureList_when_inTransaction() throws Exception {
try (Transaction transaction = DB.beginTransaction()) {
EBasic basic = new EBasic("findFutureList_when_inTransaction");
DB.save(basic);
List<EBasic> list = DB.find(EBasic.class)
.where().eq("name", "findFutureList_when_inTransaction")
.findList();
Object expectedIdValue = list.get(0).getId();
FutureList<EBasic> futureIds = DB.find(EBasic.class)
.where().eq("name", "findFutureList_when_inTransaction")
.findFutureList();
List<EBasic> fids = futureIds.get();
assertThat(fids).hasSize(1);
assertThat(fids.get(0).getId()).isEqualTo(expectedIdValue);
FutureList<EBasic> futureUsingTxn = DB.find(EBasic.class)
.usingTransaction(transaction)
.where().eq("name", "findFutureList_when_inTransaction")
.findFutureList();
List<EBasic> fids2 = futureUsingTxn.get();
assertThat(fids2).hasSize(1);
assertThat(fids2.get(0).getId()).isEqualTo(expectedIdValue);
}
}
}