Skip to content

Commit

Permalink
QueryEngine result cache (#1279)
Browse files Browse the repository at this point in the history
* Add QueryEngine cache API

* Remove outdated javadoc text
  • Loading branch information
john-karp authored May 7, 2020
1 parent 977271f commit a98f8f9
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void createObject(Object entity, RequestScope scope) {
@Override
public Iterable<Object> loadObjects(EntityProjection entityProjection, RequestScope scope) {
Query query = buildQuery(entityProjection, scope);
return queryEngine.executeQuery(query);
return queryEngine.executeQuery(query, true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.yahoo.elide.datastores.aggregation.metadata.models.Metric;
import com.yahoo.elide.datastores.aggregation.metadata.models.Table;
import com.yahoo.elide.datastores.aggregation.metadata.models.TimeDimension;
import com.yahoo.elide.datastores.aggregation.query.Cache;
import com.yahoo.elide.datastores.aggregation.query.ColumnProjection;
import com.yahoo.elide.datastores.aggregation.query.MetricProjection;
import com.yahoo.elide.datastores.aggregation.query.Query;
Expand Down Expand Up @@ -65,8 +66,6 @@
* </pre>
* Implementor must assume that {@link DataStoreTransaction} will never keep reference to any internal state of a
* {@link QueryEngine} object. This ensures the plugability of various {@link QueryEngine} implementations.
* <p>
* This is a {@link java.util.function functional interface} whose functional method is {@link #executeQuery(Query)}.
*/
public abstract class QueryEngine {
@Getter
Expand All @@ -77,18 +76,26 @@ public abstract class QueryEngine {

private final Map<String, Table> tables;

protected final Cache cache;

/**
* QueryEngine is constructed with a metadata store and is responsible for constructing all Tables and Entities
* metadata in this metadata store.
*
* @param metaDataStore a metadata store
* @param cache the cache for query results, or null
*/
public QueryEngine(MetaDataStore metaDataStore) {
public QueryEngine(MetaDataStore metaDataStore, Cache cache) {
this.metaDataStore = metaDataStore;
this.metadataDictionary = metaDataStore.getDictionary();
populateMetaData(metaDataStore);
this.tables = metaDataStore.getMetaData(Table.class).stream()
.collect(Collectors.toMap(Table::getId, Functions.identity()));
if (cache != null) {
this.cache = cache;
} else {
this.cache = new NoCache();
}
}

/**
Expand Down Expand Up @@ -154,13 +161,13 @@ private void populateMetaData(MetaDataStore metaDataStore) {

/**
* Executes the specified {@link Query} against a specific persistent storage, which understand the provided
* {@link Query}.
*
* @param query The query customized for a particular persistent storage or storage client
* {@link Query}. Results may be taken from a cache, if configured.
*
* @param query The query customized for a particular persistent storage or storage client
* @param useCache Whether to use the cache, if configured
* @return query results
*/
public abstract Iterable<Object> executeQuery(Query query);
public abstract Iterable<Object> executeQuery(Query query, boolean useCache);

/**
* Returns the schema for a given entity class.
Expand All @@ -170,4 +177,16 @@ private void populateMetaData(MetaDataStore metaDataStore) {
public Table getTable(String classAlias) {
return tables.get(classAlias);
}

private static class NoCache implements Cache {
@Override
public Iterable<Object> get(Object key) {
return null;
}

@Override
public void put(Object key, Iterable<Object> result) {
// Do nothing
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2020, Yahoo Inc.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/
package com.yahoo.elide.datastores.aggregation.query;

/**
* A cache for Query results.
*/
public interface Cache {
/**
* Load Query result from cache. Exceptions should be passed through.
*
* @param key a key to look up in the cache.
* @return query results from cache, or null if not found.
*/
Iterable<Object> get(Object key);

/**
* Insert results into cache.
*
* @param key the key to associate with the query
* @param result the result to cache with the key
*/
void put(Object key, Iterable<Object> result);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import java.util.stream.Collectors;

/**
* {@link AbstractEntityHydrator} hydrates the entity loaded by {@link QueryEngine#executeQuery(Query)}.
* {@link AbstractEntityHydrator} hydrates the entity loaded by {@link QueryEngine#executeQuery(Query, boolean)}.
* <p>
* {@link AbstractEntityHydrator} is not thread-safe and should be accessed by only 1 thread in this application,
* because it uses {@link StitchList}. See {@link StitchList} for more details.
Expand All @@ -49,8 +49,8 @@ public abstract class AbstractEntityHydrator {
/**
* Constructor.
*
* @param results The loaded objects from {@link QueryEngine#executeQuery(Query)}
* @param query The query passed to {@link QueryEngine#executeQuery(Query)} to load the objects
* @param results The loaded objects from {@link QueryEngine#executeQuery(Query, boolean)}
* @param query The query passed to {@link QueryEngine#executeQuery(Query, boolean)} to load the objects
* @param entityDictionary An object that sets entity instance values and provides entity metadata info
*/
public AbstractEntityHydrator(List<Object> results, Query query, EntityDictionary entityDictionary) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import javax.persistence.EntityManager;

/**
* {@link SQLEntityHydrator} hydrates the entity loaded by {@link SQLQueryEngine#executeQuery(Query)}.
* {@link SQLEntityHydrator} hydrates the entity loaded by {@link SQLQueryEngine#executeQuery(Query, boolean)}.
*/
public class SQLEntityHydrator extends AbstractEntityHydrator {

Expand All @@ -32,8 +32,8 @@ public class SQLEntityHydrator extends AbstractEntityHydrator {
/**
* Constructor.
*
* @param results The loaded objects from {@link SQLQueryEngine#executeQuery(Query)}
* @param query The query passed to {@link SQLQueryEngine#executeQuery(Query)} to load the objects
* @param results The loaded objects from {@link SQLQueryEngine#executeQuery(Query, boolean)}
* @param query The query passed to {@link SQLQueryEngine#executeQuery(Query, boolean)} to load the objects
* @param entityDictionary An object that sets entity instance values and provides entity metadata info
* @param entityManager An service that issues JPQL queries to load relationship objects
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.yahoo.elide.datastores.aggregation.metadata.models.Metric;
import com.yahoo.elide.datastores.aggregation.metadata.models.Table;
import com.yahoo.elide.datastores.aggregation.metadata.models.TimeDimension;
import com.yahoo.elide.datastores.aggregation.query.Cache;
import com.yahoo.elide.datastores.aggregation.query.ColumnProjection;
import com.yahoo.elide.datastores.aggregation.query.MetricProjection;
import com.yahoo.elide.datastores.aggregation.query.Query;
Expand Down Expand Up @@ -61,8 +62,8 @@ public class SQLQueryEngine extends QueryEngine {

private final SQLReferenceTable referenceTable;

public SQLQueryEngine(MetaDataStore metaDataStore, EntityManagerFactory entityManagerFactory) {
super(metaDataStore);
public SQLQueryEngine(MetaDataStore metaDataStore, EntityManagerFactory entityManagerFactory, Cache cache) {
super(metaDataStore, cache);
this.entityManagerFactory = entityManagerFactory;
this.referenceTable = new SQLReferenceTable(metaDataStore);
}
Expand Down Expand Up @@ -114,7 +115,7 @@ public MetricProjection constructMetricProjection(Metric metric,
}

@Override
public Iterable<Object> executeQuery(Query query) {
public Iterable<Object> executeQuery(Query query, boolean useCache) {
EntityManager entityManager = null;
EntityTransaction transaction = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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());
Expand All @@ -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";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public AggregationDataStoreTestHarness(EntityManagerFactory entityManagerFactory
public DataStore getDataStore() {
MetaDataStore metaDataStore = new MetaDataStore();

QueryEngine sqlQueryEngine = new SQLQueryEngine(metaDataStore, entityManagerFactory);
QueryEngine sqlQueryEngine = new SQLQueryEngine(metaDataStore, entityManagerFactory, null);

AggregationDataStore aggregationDataStore = new AggregationDataStore(sqlQueryEngine);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static void init() {

metaDataStore.populateEntityDictionary(dictionary);

engine = new SQLQueryEngine(metaDataStore, emf);
engine = new SQLQueryEngine(metaDataStore, emf, null);
playerStatsTable = engine.getTable("playerStats");

ASIA.setName("Asia");
Expand Down
Loading

0 comments on commit a98f8f9

Please sign in to comment.