From 4e62b2af27edb70188c9e0b17f785f77f907ffbd Mon Sep 17 00:00:00 2001 From: Rkr1992 <65733786+Rkr1992@users.noreply.github.com> Date: Wed, 17 Jun 2020 11:26:09 -0500 Subject: [PATCH] implement cancel function (#1367) * implement cancel function * addressing comments * addressing comments * Future implementation * Future implementation * Future implementation * Future implementation * Future implementation * adding Future Task * adding Future Task * adding Future Task * fixing future implementation * fixing future implementation * fixing future implementation * fixing future implementation * fixing future implementation * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing issues * fixing bugs * fixing issues * fixing issues * fixing issues * fixing issues * fixing bugs * fixing bugs * fixing bugs * fixing bugs * fixing bugs * fixing bugs * fixing bugs * fixing bugs * ExecutionException * fixing issues * aggregation changes * aggregation changes * aggregation changes * fixing bugs * fixing bugs * fixing bugs * rebasing * adddressing comments * adddressing comments * addressing comments * addressing comments Co-authored-by: Ramsha Rao --- .../elide/core/DataStoreTransaction.java | 6 +++++ .../inmemory/HashMapStoreTransaction.java | 5 ++++ .../inmemory/InMemoryStoreTransaction.java | 5 ++++ .../datastore/wrapped/TransactionWrapper.java | 5 ++++ .../elide/core/DataStoreTransactionTest.java | 5 ++++ .../elide/core/EntityDictionaryTest.java | 1 - .../AggregationDataStoreTransaction.java | 5 ++++ .../datastores/aggregation/QueryEngine.java | 6 ++++- .../queryengines/sql/SQLQueryEngine.java | 23 +++++++++++----- .../DimensionFormulaTest.java | 6 ++--- .../metricformula/MetricFormulaTest.java | 2 +- .../AggregationDataStoreTestHarness.java | 10 +++++-- .../aggregation/framework/SQLUnitTest.java | 5 +++- .../queryengines/sql/QueryEngineTest.java | 26 +++++++++---------- .../queryengines/sql/ViewTest.java | 2 +- .../hibernate3/HibernateTransaction.java | 5 ++++ .../hibernate5/HibernateTransaction.java | 5 ++++ .../transaction/AbstractJpaTransaction.java | 10 ++++++- .../jpa/transaction/JtaTransaction.java | 9 ++++--- .../jpa/transaction/NonJtaTransaction.java | 5 ++-- .../datastores/jpa/JpaDataStoreHarness.java | 6 ++++- .../multiplex/MultiplexTransaction.java | 5 ++++ .../datastores/multiplex/TestDataStore.java | 5 ++++ .../bridgeable/BridgeableRedisStore.java | 5 ++++ .../datastores/noop/NoopTransaction.java | 8 ++++++ .../datastores/search/DependencyBinder.java | 7 ++++- .../spring/config/ElideAutoConfiguration.java | 10 +++++-- .../config/ElideStandaloneSettings.java | 10 ++++--- pom.xml | 3 ++- 29 files changed, 161 insertions(+), 44 deletions(-) diff --git a/elide-core/src/main/java/com/yahoo/elide/core/DataStoreTransaction.java b/elide-core/src/main/java/com/yahoo/elide/core/DataStoreTransaction.java index 3ccd5f4af3..deaf38cc8b 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/DataStoreTransaction.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/DataStoreTransaction.java @@ -268,4 +268,10 @@ default boolean supportsPagination(Class entityClass, FilterExpression expres * @return UUID id */ UUID getRequestId(); + + /** + * Cancel running transaction. + * Implementation must be thread-safe. + */ + void cancel(); } diff --git a/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/HashMapStoreTransaction.java b/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/HashMapStoreTransaction.java index d1c919c06d..86010d3458 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/HashMapStoreTransaction.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/HashMapStoreTransaction.java @@ -182,4 +182,9 @@ public boolean supportsPagination(Class entityClass, FilterExpression express private boolean containsObject(Object obj) { return dataStore.get(obj.getClass()).containsValue(obj); } + + @Override + public void cancel() { + //nothing to cancel in HashMap store transaction + } } diff --git a/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/InMemoryStoreTransaction.java b/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/InMemoryStoreTransaction.java index e3a52f67a6..f5421417b6 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/InMemoryStoreTransaction.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/datastore/inmemory/InMemoryStoreTransaction.java @@ -468,4 +468,9 @@ private Pair, Optional> splitPagination( return Pair.of(pagination, Optional.empty()); } } + + @Override + public void cancel() { + tx.cancel(); + } } diff --git a/elide-core/src/main/java/com/yahoo/elide/core/datastore/wrapped/TransactionWrapper.java b/elide-core/src/main/java/com/yahoo/elide/core/datastore/wrapped/TransactionWrapper.java index dc840aafe9..b061e77514 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/datastore/wrapped/TransactionWrapper.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/datastore/wrapped/TransactionWrapper.java @@ -125,4 +125,9 @@ public Iterable loadObjects(EntityProjection projection, RequestScope sc public void close() throws IOException { tx.close(); } + + @Override + public void cancel() { + tx.cancel(); + } } diff --git a/elide-core/src/test/java/com/yahoo/elide/core/DataStoreTransactionTest.java b/elide-core/src/test/java/com/yahoo/elide/core/DataStoreTransactionTest.java index 725ef746c9..1b41b5c583 100644 --- a/elide-core/src/test/java/com/yahoo/elide/core/DataStoreTransactionTest.java +++ b/elide-core/src/test/java/com/yahoo/elide/core/DataStoreTransactionTest.java @@ -160,4 +160,9 @@ public void commit(RequestScope scope) { public void createObject(Object entity, RequestScope scope) { // nothing } + + @Override + public void cancel() { + //nothing + } } diff --git a/elide-core/src/test/java/com/yahoo/elide/core/EntityDictionaryTest.java b/elide-core/src/test/java/com/yahoo/elide/core/EntityDictionaryTest.java index a0fcdacf83..f07a9c7dac 100644 --- a/elide-core/src/test/java/com/yahoo/elide/core/EntityDictionaryTest.java +++ b/elide-core/src/test/java/com/yahoo/elide/core/EntityDictionaryTest.java @@ -1005,7 +1005,6 @@ public void testGetBoundByVersion() { assertEquals(3, models.size()); //Also includes com.yahoo.elide inner classes from this file. assertTrue(models.contains(BookV2.class)); - models = getBoundClassesByVersion(NO_VERSION); assertEquals(14, models.size()); } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStoreTransaction.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStoreTransaction.java index 494daa6ef7..50b5e9aaa0 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStoreTransaction.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStoreTransaction.java @@ -99,4 +99,9 @@ Query buildQuery(EntityProjection entityProjection, RequestScope scope) { scope.getDictionary()); return translator.getQuery(); } + + @Override + public void cancel() { + queryEngineTransaction.cancel(); + } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java index 2e7a94a11d..74c41318f6 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.stream.Collectors; - /** * A {@link QueryEngine} is an abstraction that an AggregationDataStore leverages to run analytic queries (OLAP style) * against an underlying persistence layer. @@ -157,6 +156,11 @@ private void populateMetaData(MetaDataStore metaDataStore) { public interface Transaction extends AutoCloseable { @Override void close(); + + /** + * Cancels running transaction + */ + void cancel(); } public abstract Transaction beginTransaction(); diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryEngine.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryEngine.java index 7c335531d7..869de2d9c5 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryEngine.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryEngine.java @@ -49,6 +49,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; @@ -60,13 +61,14 @@ @Slf4j public class SQLQueryEngine extends QueryEngine { private final EntityManagerFactory entityManagerFactory; - + private final Consumer transactionCancel; private final SQLReferenceTable referenceTable; - public SQLQueryEngine(MetaDataStore metaDataStore, EntityManagerFactory entityManagerFactory) { + public SQLQueryEngine(MetaDataStore metaDataStore, EntityManagerFactory eMFactory, Consumer txC) { super(metaDataStore); - this.entityManagerFactory = entityManagerFactory; + this.entityManagerFactory = eMFactory; this.referenceTable = new SQLReferenceTable(metaDataStore); + this.transactionCancel = txC; } @Override @@ -118,14 +120,17 @@ public MetricProjection constructMetricProjection(Metric metric, /** * State needed for SQLQueryEngine to execute queries. */ - static class SqlTransaction implements QueryEngine.Transaction { + static class SqlTransaction implements QueryEngine.Transaction { private final EntityManager entityManager; private final EntityTransaction transaction; + private final Consumer transactionCancel; + + SqlTransaction(EntityManagerFactory emf, Consumer transactionCancel) { - SqlTransaction(EntityManagerFactory emf) { entityManager = emf.createEntityManager(); transaction = entityManager.getTransaction(); + this.transactionCancel = transactionCancel; if (!transaction.isActive()) { transaction.begin(); } @@ -140,11 +145,17 @@ public void close() { entityManager.close(); } } + + @Override + public void cancel() { + transactionCancel.accept(entityManager); + } + } @Override public QueryEngine.Transaction beginTransaction() { - return new SqlTransaction(entityManagerFactory); + return new SqlTransaction(entityManagerFactory, transactionCancel); } @Override diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/dimensionformula/DimensionFormulaTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/dimensionformula/DimensionFormulaTest.java index df0b1937a9..750e6b2fb3 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/dimensionformula/DimensionFormulaTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/dimensionformula/DimensionFormulaTest.java @@ -24,7 +24,7 @@ public void testReferenceLoop() { IllegalArgumentException exception = assertThrows( IllegalArgumentException.class, - () -> new SQLQueryEngine(metaDataStore, null)); + () -> new SQLQueryEngine(metaDataStore, null, null)); assertEquals( "Formula reference loop found: loop.playerLevel->loop.playerLevel", exception.getMessage()); @@ -36,7 +36,7 @@ public void testJoinToLoop() { IllegalArgumentException exception = assertThrows( IllegalArgumentException.class, - () -> new SQLQueryEngine(metaDataStore, null)); + () -> new SQLQueryEngine(metaDataStore, null, null)); assertEquals( "Formula reference loop found: joinToLoop.playerLevel->joinToLoop.playerLevel", exception.getMessage()); @@ -49,7 +49,7 @@ public void testCrossClassReferenceLoop() { IllegalArgumentException exception = assertThrows( IllegalArgumentException.class, - () -> new SQLQueryEngine(metaDataStore, null)); + () -> new SQLQueryEngine(metaDataStore, null, null)); String exception1 = "Formula reference loop found: loopCountryA.inUsa->loopCountryB.inUsa->loopCountryA.inUsa"; diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/metricformula/MetricFormulaTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/metricformula/MetricFormulaTest.java index eee27f6c5f..31dcd62bca 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/metricformula/MetricFormulaTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/annotation/metricformula/MetricFormulaTest.java @@ -21,7 +21,7 @@ public void testReferenceLoop() { IllegalArgumentException exception = assertThrows( IllegalArgumentException.class, - () -> new SQLQueryEngine(metaDataStore, null)); + () -> new SQLQueryEngine(metaDataStore, null, null)); assertEquals( "Formula reference loop found: loop.highScore->loop.highScore", exception.getMessage()); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/AggregationDataStoreTestHarness.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/AggregationDataStoreTestHarness.java index 95f39d5a9c..44ca681891 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/AggregationDataStoreTestHarness.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/AggregationDataStoreTestHarness.java @@ -14,6 +14,11 @@ import com.yahoo.elide.datastores.jpa.transaction.NonJtaTransaction; import com.yahoo.elide.datastores.multiplex.MultiplexManager; +import org.hibernate.Session; + +import java.util.function.Consumer; + +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; public class AggregationDataStoreTestHarness implements DataStoreTestHarness { @@ -26,14 +31,15 @@ public AggregationDataStoreTestHarness(EntityManagerFactory entityManagerFactory @Override public DataStore getDataStore() { MetaDataStore metaDataStore = new MetaDataStore(); + Consumer txCancel = (em) -> { em.unwrap(Session.class).cancelQuery(); }; AggregationDataStore aggregationDataStore = AggregationDataStore.builder() - .queryEngine(new SQLQueryEngine(metaDataStore, entityManagerFactory)) + .queryEngine(new SQLQueryEngine(metaDataStore, entityManagerFactory, txCancel)) .build(); DataStore jpaStore = new JpaDataStore( () -> entityManagerFactory.createEntityManager(), - NonJtaTransaction::new + (em) -> { return new NonJtaTransaction(em, txCancel); } ); return new MultiplexManager(jpaStore, metaDataStore, aggregationDataStore); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/SQLUnitTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/SQLUnitTest.java index 015663e950..f0ec82c218 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/SQLUnitTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/framework/SQLUnitTest.java @@ -30,12 +30,14 @@ import com.yahoo.elide.request.Argument; import com.yahoo.elide.utils.ClassScanner; +import org.hibernate.Session; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -83,8 +85,9 @@ public static void init() { filterParser = new RSQLFilterDialect(dictionary); metaDataStore.populateEntityDictionary(dictionary); + Consumer txCancel = (entityManager) -> { entityManager.unwrap(Session.class).cancelQuery(); }; + engine = new SQLQueryEngine(metaDataStore, emf, txCancel); - engine = new SQLQueryEngine(metaDataStore, emf); playerStatsTable = engine.getTable("playerStats"); ASIA.setName("Asia"); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java index 078151173d..38d7951059 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java @@ -46,7 +46,7 @@ public static void init() { * Test loading all three records from the table. */ @Test - public void testFullTableLoad() { + public void testFullTableLoad() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("lowScore"))) @@ -84,7 +84,7 @@ public void testFullTableLoad() { * Test loading records using {@link FromSubquery} */ @Test - public void testFromSubQuery() { + public void testFromSubQuery() throws Exception { Query query = Query.builder() .table(playerStatsViewTable) .metric(invoke(playerStatsViewTable.getMetric("highScore"))) @@ -185,7 +185,7 @@ public void testNotProjectedFilter() throws Exception { } @Test - public void testSortAggregatedMetric() { + public void testSortAggregatedMetric() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("lowScore", Sorting.SortOrder.desc); @@ -217,7 +217,7 @@ public void testSortAggregatedMetric() { * Test sorting by dimension attribute which is not present in the query. */ @Test - public void testSortJoin() { + public void testSortJoin() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("playerName", Sorting.SortOrder.asc); @@ -259,7 +259,7 @@ public void testSortJoin() { * Test pagination. */ @Test - public void testPagination() { + public void testPagination() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("lowScore"))) @@ -349,7 +349,7 @@ public void testHavingClauseJoin() throws Exception { * Test sorting by two different columns-one metric and one dimension. */ @Test - public void testSortByMultipleColumns() { + public void testSortByMultipleColumns() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("lowScore", Sorting.SortOrder.desc); sortMap.put("playerName", Sorting.SortOrder.asc); @@ -392,7 +392,7 @@ public void testSortByMultipleColumns() { * Test grouping by a dimension with a JoinTo annotation. */ @Test - public void testJoinToGroupBy() { + public void testJoinToGroupBy() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) @@ -452,7 +452,7 @@ public void testJoinToFilter() throws Exception { * Test grouping by a dimension with a JoinTo annotation. */ @Test - public void testJoinToSort() { + public void testJoinToSort() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("countryIsoCode", Sorting.SortOrder.asc); sortMap.put("highScore", Sorting.SortOrder.asc); @@ -495,7 +495,7 @@ public void testJoinToSort() { * Test month grain query. */ @Test - public void testTotalScoreByMonth() { + public void testTotalScoreByMonth() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) @@ -517,7 +517,7 @@ public void testTotalScoreByMonth() { * Test filter by time dimension. */ @Test - public void testFilterByTemporalDimension() { + public void testFilterByTemporalDimension() throws Exception { FilterPredicate predicate = new FilterPredicate( new Path(PlayerStats.class, dictionary, "recordedDate"), Operator.IN, @@ -542,7 +542,7 @@ public void testFilterByTemporalDimension() { } @Test - public void testAmbiguousFields() { + public void testAmbiguousFields() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("lowScore", Sorting.SortOrder.asc); @@ -581,7 +581,7 @@ public void testAmbiguousFields() { } @Test - public void testNullJoinToStringValue() { + public void testNullJoinToStringValue() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) @@ -606,7 +606,7 @@ public void testNullJoinToStringValue() { } @Test - public void testNullJoinToIntValue() { + public void testNullJoinToIntValue() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java index 6a19a4bc26..66663290fc 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java @@ -33,7 +33,7 @@ public static void init() { } @Test - public void testViewAttribute() { + public void testViewAttribute() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("countryViewIsoCode", Sorting.SortOrder.desc); diff --git a/elide-datastore/elide-datastore-hibernate3/src/main/java/com/yahoo/elide/datastores/hibernate3/HibernateTransaction.java b/elide-datastore/elide-datastore-hibernate3/src/main/java/com/yahoo/elide/datastores/hibernate3/HibernateTransaction.java index d462b69ea3..5b436aba23 100644 --- a/elide-datastore/elide-datastore-hibernate3/src/main/java/com/yahoo/elide/datastores/hibernate3/HibernateTransaction.java +++ b/elide-datastore/elide-datastore-hibernate3/src/main/java/com/yahoo/elide/datastores/hibernate3/HibernateTransaction.java @@ -305,4 +305,9 @@ public Integer getQueryLimit() { // no limit return null; } + + @Override + public void cancel() { + session.cancelQuery(); + } } diff --git a/elide-datastore/elide-datastore-hibernate5/src/main/java/com/yahoo/elide/datastores/hibernate5/HibernateTransaction.java b/elide-datastore/elide-datastore-hibernate5/src/main/java/com/yahoo/elide/datastores/hibernate5/HibernateTransaction.java index dc1b7fd20c..d42113691c 100644 --- a/elide-datastore/elide-datastore-hibernate5/src/main/java/com/yahoo/elide/datastores/hibernate5/HibernateTransaction.java +++ b/elide-datastore/elide-datastore-hibernate5/src/main/java/com/yahoo/elide/datastores/hibernate5/HibernateTransaction.java @@ -301,4 +301,9 @@ public void close() throws IOException { throw new IOException("Transaction not closed"); } } + + @Override + public void cancel() { + session.cancelQuery(); + } } diff --git a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/AbstractJpaTransaction.java b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/AbstractJpaTransaction.java index 89e91bb2d6..17aee3e98f 100644 --- a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/AbstractJpaTransaction.java +++ b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/AbstractJpaTransaction.java @@ -38,6 +38,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Predicate; import javax.persistence.EntityManager; @@ -56,10 +57,12 @@ public abstract class AbstractJpaTransaction extends DataStoreTransactionImpleme protected final EntityManager em; private final EntityManagerWrapper emWrapper; private final LinkedHashSet deferredTasks = new LinkedHashSet<>(); + private final Consumer jpaTransactionCancel; - protected AbstractJpaTransaction(EntityManager em) { + protected AbstractJpaTransaction(EntityManager em, Consumer jpaTransactionCancel) { this.em = em; this.emWrapper = new EntityManagerWrapper(em); + this.jpaTransactionCancel = jpaTransactionCancel; } @Override @@ -307,4 +310,9 @@ private Long getTotalRecords(AbstractHQLQueryBuilder.Relationship relationsh return (Long) query.getQuery().getSingleResult(); } + + @Override + public void cancel() { + jpaTransactionCancel.accept(em); + } } diff --git a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/JtaTransaction.java b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/JtaTransaction.java index a96a95992b..131e4a5b2d 100644 --- a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/JtaTransaction.java +++ b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/JtaTransaction.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; +import java.util.function.Consumer; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.persistence.EntityManager; @@ -22,12 +23,12 @@ @Slf4j public class JtaTransaction extends AbstractJpaTransaction { private final UserTransaction transaction; - public JtaTransaction(EntityManager entityManager) { - this(entityManager, lookupUserTransaction()); + public JtaTransaction(EntityManager entityManager, Consumer txCancel) { + this(entityManager, lookupUserTransaction(), txCancel); } - public JtaTransaction(EntityManager entityManager, UserTransaction transaction) { - super(entityManager); + public JtaTransaction(EntityManager entityManager, UserTransaction transaction, Consumer txCancel) { + super(entityManager, txCancel); this.transaction = transaction; } diff --git a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/NonJtaTransaction.java b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/NonJtaTransaction.java index a65b5cebeb..bc44f5c86f 100644 --- a/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/NonJtaTransaction.java +++ b/elide-datastore/elide-datastore-jpa/src/main/java/com/yahoo/elide/datastores/jpa/transaction/NonJtaTransaction.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import java.io.IOException; +import java.util.function.Consumer; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; @@ -19,8 +20,8 @@ @Slf4j public class NonJtaTransaction extends AbstractJpaTransaction { private final EntityTransaction transaction; - public NonJtaTransaction(EntityManager entityManager) { - super(entityManager); + public NonJtaTransaction(EntityManager entityManager, Consumer jpaTransactionCancel) { + super(entityManager, jpaTransactionCancel); this.transaction = entityManager.getTransaction(); entityManager.clear(); } diff --git a/elide-datastore/elide-datastore-jpa/src/test/java/com/yahoo/elide/datastores/jpa/JpaDataStoreHarness.java b/elide-datastore/elide-datastore-jpa/src/test/java/com/yahoo/elide/datastores/jpa/JpaDataStoreHarness.java index 05ffdf6289..7c95080ca1 100644 --- a/elide-datastore/elide-datastore-jpa/src/test/java/com/yahoo/elide/datastores/jpa/JpaDataStoreHarness.java +++ b/elide-datastore/elide-datastore-jpa/src/test/java/com/yahoo/elide/datastores/jpa/JpaDataStoreHarness.java @@ -16,6 +16,7 @@ import example.models.triggers.Invoice; import example.models.versioned.BookV2; import org.hibernate.MappingException; +import org.hibernate.Session; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; @@ -28,7 +29,9 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import javax.persistence.Entity; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; @@ -42,6 +45,7 @@ public class JpaDataStoreHarness implements DataStoreTestHarness { private DataStore store; private MetadataImplementor metadataImplementor; + private final Consumer txCancel = (em) -> { em.unwrap(Session.class).cancelQuery(); }; public JpaDataStoreHarness() { Map options = new HashMap<>(); @@ -96,7 +100,7 @@ public JpaDataStoreHarness() { store = new JpaDataStore( () -> { return emf.createEntityManager(); }, - (entityManager) -> { return new NonJtaTransaction(entityManager); } + (entityManager) -> { return new NonJtaTransaction(entityManager, txCancel); } ); } diff --git a/elide-datastore/elide-datastore-multiplex/src/main/java/com/yahoo/elide/datastores/multiplex/MultiplexTransaction.java b/elide-datastore/elide-datastore-multiplex/src/main/java/com/yahoo/elide/datastores/multiplex/MultiplexTransaction.java index 7956b38eb4..09e166f5f1 100644 --- a/elide-datastore/elide-datastore-multiplex/src/main/java/com/yahoo/elide/datastores/multiplex/MultiplexTransaction.java +++ b/elide-datastore/elide-datastore-multiplex/src/main/java/com/yahoo/elide/datastores/multiplex/MultiplexTransaction.java @@ -236,4 +236,9 @@ private Serializable extractId(FilterExpression filterExpression, .map(p -> (Serializable) p.getValues().get(0)) .orElse(null); } + + @Override + public void cancel() { + transactions.values().forEach(dataStoreTransaction -> dataStoreTransaction.cancel()); + } } diff --git a/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/TestDataStore.java b/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/TestDataStore.java index a219367314..fc0bb8a7dc 100644 --- a/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/TestDataStore.java +++ b/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/TestDataStore.java @@ -78,4 +78,9 @@ public Iterable loadObjects( RequestScope scope) { throw new TransactionException(null); } + + @Override + public void cancel() { + // Nothing + } } diff --git a/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/bridgeable/BridgeableRedisStore.java b/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/bridgeable/BridgeableRedisStore.java index b084b9bb95..913d36c8b0 100644 --- a/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/bridgeable/BridgeableRedisStore.java +++ b/elide-datastore/elide-datastore-multiplex/src/test/java/com/yahoo/elide/datastores/multiplex/bridgeable/BridgeableRedisStore.java @@ -243,6 +243,11 @@ public void createObject(Object entity, RequestScope scope) { public T createNewObject(Class entityClass) { return null; } + + @Override + public void cancel() { + // Nothing + } } /** diff --git a/elide-datastore/elide-datastore-noop/src/main/java/com/yahoo/elide/datastores/noop/NoopTransaction.java b/elide-datastore/elide-datastore-noop/src/main/java/com/yahoo/elide/datastores/noop/NoopTransaction.java index 5a12533313..629321f348 100644 --- a/elide-datastore/elide-datastore-noop/src/main/java/com/yahoo/elide/datastores/noop/NoopTransaction.java +++ b/elide-datastore/elide-datastore-noop/src/main/java/com/yahoo/elide/datastores/noop/NoopTransaction.java @@ -118,4 +118,12 @@ public Iterable loadObjects(EntityProjection projection, public void close() throws IOException { // No-op transaction, do nothing. } + + /** + * No-op transaction, do nothing. + */ + @Override + public void cancel() { + // No-op transaction, do nothing. + } } diff --git a/elide-datastore/elide-datastore-search/src/test/java/com/yahoo/elide/datastores/search/DependencyBinder.java b/elide-datastore/elide-datastore-search/src/test/java/com/yahoo/elide/datastores/search/DependencyBinder.java index dc58445c3a..c58bfc324f 100644 --- a/elide-datastore/elide-datastore-search/src/test/java/com/yahoo/elide/datastores/search/DependencyBinder.java +++ b/elide-datastore/elide-datastore-search/src/test/java/com/yahoo/elide/datastores/search/DependencyBinder.java @@ -19,11 +19,14 @@ import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.server.ResourceConfig; +import org.hibernate.Session; import java.io.File; import java.util.HashMap; import java.util.TimeZone; +import java.util.function.Consumer; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; @@ -45,10 +48,12 @@ protected void configure() { indexOnStartup = true; } + Consumer txCancel = (em) -> { em.unwrap(Session.class).cancelQuery(); }; EntityManagerFactory emf = Persistence.createEntityManagerFactory("searchDataStoreTest"); DataStore jpaStore = new JpaDataStore( emf::createEntityManager, - NonJtaTransaction::new); + (em) -> { return new NonJtaTransaction(em, txCancel); } + ); EntityDictionary dictionary = new EntityDictionary(new HashMap<>()); diff --git a/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java b/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java index ef88b343e9..e0dcca581d 100644 --- a/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java +++ b/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java @@ -25,6 +25,7 @@ import com.yahoo.elide.datastores.jpa.transaction.NonJtaTransaction; import com.yahoo.elide.datastores.multiplex.MultiplexManager; +import org.hibernate.Session; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -39,6 +40,8 @@ import java.util.HashMap; import java.util.Set; import java.util.TimeZone; +import java.util.function.Consumer; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; /** @@ -56,6 +59,9 @@ public class ElideAutoConfiguration { * @return An instance of ElideDynamicEntityCompiler. * @throws Exception Exception thrown. */ + + private final Consumer txCancel = (em) -> { em.unwrap(Session.class).cancelQuery(); }; + @Bean @ConditionalOnMissingBean public ElideDynamicEntityCompiler buildElideDynamicEntityCompiler(ElideConfigProperties settings) throws Exception { @@ -152,7 +158,7 @@ public QueryEngine buildQueryEngine(EntityManagerFactory entityManagerFactory, metaDataStore = new MetaDataStore(); } - return new SQLQueryEngine(metaDataStore, entityManagerFactory); + return new SQLQueryEngine(metaDataStore, entityManagerFactory, txCancel); } /** @@ -181,7 +187,7 @@ public DataStore buildDataStore(EntityManagerFactory entityManagerFactory, Query JpaDataStore jpaDataStore = new JpaDataStore( () -> { return entityManagerFactory.createEntityManager(); }, - (em -> { return new NonJtaTransaction(em); })); + (em) -> { return new NonJtaTransaction(em, txCancel); }); // meta data store needs to be put at first to populate meta data models return new MultiplexManager(jpaDataStore, queryEngine.getMetaDataStore(), aggregationDataStore); diff --git a/elide-standalone/src/main/java/com/yahoo/elide/standalone/config/ElideStandaloneSettings.java b/elide-standalone/src/main/java/com/yahoo/elide/standalone/config/ElideStandaloneSettings.java index 7ace3df1c6..7e9a2aeb87 100644 --- a/elide-standalone/src/main/java/com/yahoo/elide/standalone/config/ElideStandaloneSettings.java +++ b/elide-standalone/src/main/java/com/yahoo/elide/standalone/config/ElideStandaloneSettings.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.jersey.server.ResourceConfig; +import org.hibernate.Session; import io.swagger.models.Info; import io.swagger.models.Swagger; @@ -49,6 +50,7 @@ import java.util.Set; import java.util.TimeZone; import java.util.function.Consumer; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; /** @@ -56,6 +58,9 @@ */ public interface ElideStandaloneSettings { /* Elide settings */ + + public final Consumer TXCANCEL = (em) -> { em.unwrap(Session.class).cancelQuery(); }; + /** * A map containing check mappings for security across Elide. If not provided, then an empty map is used. * In case of an empty map, checks can be referenced by their fully qualified class names. @@ -376,10 +381,9 @@ default Optional getDynamicCompiler() { */ default DataStore getDataStore(MetaDataStore metaDataStore, AggregationDataStore aggregationDataStore, EntityManagerFactory entityManagerFactory) { - DataStore jpaDataStore = new JpaDataStore( () -> { return entityManagerFactory.createEntityManager(); }, - (em -> { return new NonJtaTransaction(em); })); + (em) -> { return new NonJtaTransaction(em, TXCANCEL); }); DataStore dataStore = new MultiplexManager(jpaDataStore, metaDataStore, aggregationDataStore); @@ -463,7 +467,7 @@ default MetaDataStore getMetaDataStore(Optional opti * @return QueryEngine object initialized. */ default QueryEngine getQueryEngine(MetaDataStore metaDataStore, EntityManagerFactory entityManagerFactory) { - return new SQLQueryEngine(metaDataStore, entityManagerFactory); + return new SQLQueryEngine(metaDataStore, entityManagerFactory, TXCANCEL); } static Set> getDynamicClassesIfAvailable(Optional optionalCompiler, diff --git a/pom.xml b/pom.xml index 96f82c5186..71b4c20857 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ - 3.0.0 + 3.6.3 @@ -394,6 +394,7 @@ all,-missing + ${source.jdk.version}