From b9f47817db4b2ea35f568ee9a1ca524cb6814def Mon Sep 17 00:00:00 2001 From: Satia Herfert Date: Tue, 24 Jul 2018 13:41:24 +0200 Subject: [PATCH] Code cleanups and ignore unused parameter types --- .../org/neo4j/cypher/QueryInvalidationIT.java | 9 +- .../org/neo4j/cypher/QueryCachingTest.scala | 4 +- ...CypherCompilerAstCacheAcceptanceTest.scala | 117 ++++++++++++++---- .../javacompat/MonitoringCacheTracer.java | 9 +- .../cypher/PlanCacheMetricsMonitor.scala | 3 +- .../org/neo4j/cypher/internal/Compiler.scala | 4 +- .../cypher/internal/ExecutionEngine.scala | 9 +- .../cypher/internal/MasterCompiler.scala | 18 +-- .../neo4j/cypher/internal/QueryCache.scala | 64 +++------- .../compatibility/AstLogicalPlanCache.scala | 4 +- .../internal/compatibility/BasePlanner.scala | 1 + .../compatibility/CypherCurrentCompiler.scala | 15 +-- .../compatibility/CypherPlanner.scala | 3 +- .../compatibility/v2_3/Cypher23Compiler.scala | 5 +- .../compatibility/v3_1/Cypher31Compiler.scala | 5 +- .../compatibility/v3_4/Cypher34Planner.scala | 12 +- .../compatibility/v3_5/Cypher35Planner.scala | 16 ++- .../internal/ParameterTypeMapTest.scala | 88 ------------- ...rStringCacheMonitoringAcceptanceTest.scala | 3 +- 19 files changed, 181 insertions(+), 208 deletions(-) delete mode 100644 community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/ParameterTypeMapTest.scala diff --git a/community/community-it/cypher-it/src/test/java/org/neo4j/cypher/QueryInvalidationIT.java b/community/community-it/cypher-it/src/test/java/org/neo4j/cypher/QueryInvalidationIT.java index 3158d8fbb8752..138b275996f37 100644 --- a/community/community-it/cypher-it/src/test/java/org/neo4j/cypher/QueryInvalidationIT.java +++ b/community/community-it/cypher-it/src/test/java/org/neo4j/cypher/QueryInvalidationIT.java @@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import org.neo4j.cypher.internal.ParameterTypeMap; import org.neo4j.cypher.internal.compatibility.CypherCacheHitMonitor; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Result; @@ -188,7 +187,7 @@ private static int randomInt( int max ) return ThreadLocalRandom.current().nextInt( max ); } - private static class TestMonitor implements CypherCacheHitMonitor> + private static class TestMonitor implements CypherCacheHitMonitor>>> { private final AtomicInteger hits = new AtomicInteger(); private final AtomicInteger misses = new AtomicInteger(); @@ -196,19 +195,19 @@ private static class TestMonitor implements CypherCacheHitMonitor key ) + public void cacheHit( Pair>> key ) { hits.incrementAndGet(); } @Override - public void cacheMiss( Pair key ) + public void cacheMiss( Pair>> key ) { misses.incrementAndGet(); } @Override - public void cacheDiscard( Pair key, String ignored, int secondsSinceReplan ) + public void cacheDiscard( Pair>> key, String ignored, int secondsSinceReplan ) { discards.incrementAndGet(); waitTime.addAndGet( secondsSinceReplan ); diff --git a/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/QueryCachingTest.scala b/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/QueryCachingTest.scala index e68ae698c6073..95e233f81fa77 100644 --- a/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/QueryCachingTest.scala +++ b/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/QueryCachingTest.scala @@ -19,7 +19,8 @@ */ package org.neo4j.cypher -import org.neo4j.cypher.internal.{ParameterTypeMap, StringCacheMonitor} +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap +import org.neo4j.cypher.internal.StringCacheMonitor import org.neo4j.graphdb.Label import org.neo4j.helpers.collection.Pair import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge @@ -145,7 +146,6 @@ class QueryCachingTest extends CypherFunSuite with GraphDatabaseTestSupport with s"cacheHit: (CYPHER 3.5 $query, Map(n -> class org.neo4j.values.storable.StringWrappingStringValue))") actual should equal(expected) - } private class LoggingStringCacheListener extends StringCacheMonitor { diff --git a/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_5/CypherCompilerAstCacheAcceptanceTest.scala b/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_5/CypherCompilerAstCacheAcceptanceTest.scala index e1d7cab25a18e..1e79c9cf2f1fd 100644 --- a/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_5/CypherCompilerAstCacheAcceptanceTest.scala +++ b/community/community-it/cypher-it/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_5/CypherCompilerAstCacheAcceptanceTest.scala @@ -23,13 +23,16 @@ import java.time.{Clock, Instant, ZoneOffset} import org.neo4j.cypher import org.neo4j.cypher._ -import org.neo4j.cypher.internal.compatibility.{CommunityRuntimeContextCreator, CypherCurrentCompiler, RuntimeContext} +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap +import org.neo4j.cypher.internal.compatibility.v3_4.Cypher34Planner +import org.neo4j.cypher.internal.compatibility.{CommunityRuntimeContextCreator, CypherCurrentCompiler, CypherPlanner, RuntimeContext} import org.neo4j.cypher.internal.compiler.v3_5.{CypherPlannerConfiguration, StatsDivergenceCalculator} import org.neo4j.cypher.internal.runtime.interpreted.CSVResources -import org.neo4j.cypher.internal.{CacheTracer, CommunityRuntimeFactory, ParameterTypeMap, PreParsedQuery} +import org.neo4j.cypher.internal.{CacheTracer, CommunityRuntimeFactory, PreParsedQuery} import org.neo4j.graphdb.config.Setting import org.neo4j.graphdb.factory.GraphDatabaseSettings import org.neo4j.helpers.collection.Pair +import org.neo4j.kernel.impl.util.ValueUtils import org.neo4j.logging.AssertableLogProvider.inLog import org.neo4j.logging.{AssertableLogProvider, Log, NullLog} import org.opencypher.v9_0.frontend.phases.CompilationPhaseTracer @@ -43,7 +46,6 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData def createCompiler(queryCacheSize: Int = 128, statsDivergenceThreshold: Double = 0.5, queryPlanTTL: Long = 1000, clock: Clock = Clock.systemUTC(), log: Log = NullLog.getInstance): CypherCurrentCompiler[RuntimeContext] = { - val config = CypherPlannerConfiguration( queryCacheSize, StatsDivergenceCalculator.divergenceNoDecayCalculator(statsDivergenceThreshold, queryPlanTTL), @@ -57,14 +59,20 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData nonIndexedLabelWarningThreshold = 10000L, planWithMinimumCardinalityEstimates = true ) + val planner = Cypher35Planner(config, + clock, + kernelMonitors, + log, + cypher.CypherPlannerOption.default, + CypherUpdateStrategy.default, + () => 1) + createCompiler(planner, config) + } + + def createCompiler(planner: CypherPlanner, config: CypherPlannerConfiguration): + CypherCurrentCompiler[RuntimeContext] = { CypherCurrentCompiler( - Cypher35Planner(config, - clock, - kernelMonitors, - log, - cypher.CypherPlannerOption.default, - CypherUpdateStrategy.default, - () => 1), + planner, CommunityRuntimeFactory.getRuntime(CypherRuntimeOption.default, disallowFallback = true), CommunityRuntimeContextCreator, kernelMonitors) @@ -75,12 +83,12 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData override def toString = s"hits = $hits, misses = $misses, flushes = $flushes, evicted = $evicted" } - class CacheCounter(var counts: CacheCounts = CacheCounts()) extends CacheTracer[Pair[AnyRef,ParameterTypeMap]] { - override def queryCacheHit(key: Pair[AnyRef,ParameterTypeMap], metaData: String) { + class CacheCounter(var counts: CacheCounts = CacheCounts()) extends CacheTracer[Pair[AnyRef, ParameterTypeMap]] { + override def queryCacheHit(key: Pair[AnyRef, ParameterTypeMap], metaData: String) { counts = counts.copy(hits = counts.hits + 1) } - override def queryCacheMiss(key: Pair[AnyRef,ParameterTypeMap], metaData: String) { + override def queryCacheMiss(key: Pair[AnyRef, ParameterTypeMap], metaData: String) { counts = counts.copy(misses = counts.misses + 1) } @@ -88,7 +96,7 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData counts = counts.copy(flushes = counts.flushes + 1) } - override def queryCacheStale(key: Pair[AnyRef,ParameterTypeMap], secondsSincePlan: Int, metaData: String): Unit = { + override def queryCacheStale(key: Pair[AnyRef, ParameterTypeMap], secondsSincePlan: Int, metaData: String): Unit = { counts = counts.copy(evicted = counts.evicted + 1) } } @@ -97,27 +105,55 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData var counter: CacheCounter = _ var compiler: CypherCurrentCompiler[RuntimeContext] = _ + var compiler3_4: CypherCurrentCompiler[RuntimeContext] = _ override protected def beforeEach(): Unit = { super.beforeEach() counter = new CacheCounter() compiler = createCompiler() - compiler.kernelMonitors.addMonitorListener(counter) + + val config3_4 = CypherPlannerConfiguration( + 128, + StatsDivergenceCalculator.divergenceNoDecayCalculator(0.5, 1000), + useErrorsOverWarnings = false, + idpMaxTableSize = 128, + idpIterationDuration = 1000, + errorIfShortestPathFallbackUsedAtRuntime = false, + errorIfShortestPathHasCommonNodesAtRuntime = true, + legacyCsvQuoteEscaping = false, + csvBufferSize = CSVResources.DEFAULT_BUFFER_SIZE, + nonIndexedLabelWarningThreshold = 10000L, + planWithMinimumCardinalityEstimates = true + ) + val planner3_4 = Cypher34Planner(config3_4, + Clock.systemUTC(), + kernelMonitors, + NullLog.getInstance, + cypher.CypherPlannerOption.default, + CypherUpdateStrategy.default, + () => 1) + + compiler3_4 = createCompiler(planner3_4, config3_4) + + kernelMonitors.addMonitorListener(counter) + } - private def runQuery(query: String, debugOptions: Set[String] = Set.empty, params: scala.Predef.Map[String, Any] = Map.empty): Unit = { + private def runQuery(query: String, debugOptions: Set[String] = Set.empty, params: scala.Predef.Map[String, AnyRef] = Map.empty, compiler: CypherCurrentCompiler[RuntimeContext] = compiler): Unit = { + import collection.JavaConverters._ + graph.withTx { tx => val noTracing = CompilationPhaseTracer.NO_TRACING val context = graph.transactionalContext(query = query -> params) compiler.compile(PreParsedQuery(query, DummyPosition(0), query, - isPeriodicCommit = false, - CypherVersion.default, - CypherExecutionMode.default, - CypherPlannerOption.default, - CypherRuntimeOption.default, - CypherUpdateStrategy.default, - debugOptions), - noTracing, Set.empty, context) + isPeriodicCommit = false, + CypherVersion.default, + CypherExecutionMode.default, + CypherPlannerOption.default, + CypherRuntimeOption.default, + CypherUpdateStrategy.default, + debugOptions), + noTracing, Set.empty, context, ValueUtils.asParameterMapValue(params.asJava)) context.close(true) } } @@ -250,7 +286,7 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData // then logProvider.assertExactly( - inLog(logName).info( s"Discarded stale query from the query cache after 0 seconds: $query" ) + inLog(logName).info(s"Discarded stale query from the query cache after 0 seconds: $query") ) } @@ -262,11 +298,38 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData } test("should not find query in cache with different parameter types") { - val map1: scala.Predef.Map[String, Any] = scala.Predef.Map("number" -> 42) - val map2: scala.Predef.Map[String, Any] = scala.Predef.Map("number" -> "nope") + val map1: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(42)) + val map2: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> "nope") runQuery("return $number", params = map1) runQuery("return $number", params = map2) counter.counts should equal(CacheCounts(hits = 0, misses = 2, flushes = 1)) } + + test("should find query in cache with different parameter types in 3.4") { + val map1: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(42)) + val map2: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> "nope") + runQuery("return $number", params = map1, compiler = compiler3_4) + runQuery("return $number", params = map2, compiler = compiler3_4) + + counter.counts should equal(CacheCounts(hits = 1, misses = 1, flushes = 1)) + } + + test("should find query in cache with same parameter types") { + val map1: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(42)) + val map2: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(43)) + runQuery("return $number", params = map1) + runQuery("return $number", params = map2) + + counter.counts should equal(CacheCounts(hits = 1, misses = 1, flushes = 1)) + } + + test("should find query in cache with same parameter types, ignoring unused parameters") { + val map1: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(42), "foo" -> "bar") + val map2: scala.Predef.Map[String, AnyRef] = scala.Predef.Map("number" -> new Integer(43), "bar" -> new Integer(10)) + runQuery("return $number", params = map1) + runQuery("return $number", params = map2) + + counter.counts should equal(CacheCounts(hits = 1, misses = 1, flushes = 1)) + } } diff --git a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/MonitoringCacheTracer.java b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/MonitoringCacheTracer.java index a77cfe74e612e..e6bf96050a8fa 100644 --- a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/MonitoringCacheTracer.java +++ b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/MonitoringCacheTracer.java @@ -20,14 +20,13 @@ package org.neo4j.cypher.internal.javacompat; import org.neo4j.cypher.internal.CacheTracer; -import org.neo4j.cypher.internal.ParameterTypeMap; import org.neo4j.cypher.internal.StringCacheMonitor; import org.neo4j.helpers.collection.Pair; /** * Adapter for passing CacheTraces into the Monitoring infrastructure. */ -public class MonitoringCacheTracer implements CacheTracer> +public class MonitoringCacheTracer implements CacheTracer>>> { private final StringCacheMonitor monitor; @@ -37,19 +36,19 @@ public MonitoringCacheTracer( StringCacheMonitor monitor ) } @Override - public void queryCacheHit( Pair queryKey, String metaData ) + public void queryCacheHit( Pair>> queryKey, String metaData ) { monitor.cacheHit( queryKey ); } @Override - public void queryCacheMiss( Pair queryKey, String metaData ) + public void queryCacheMiss( Pair>> queryKey, String metaData ) { monitor.cacheMiss( queryKey ); } @Override - public void queryCacheStale( Pair queryKey, int secondsSincePlan, String metaData ) + public void queryCacheStale( Pair>> queryKey, int secondsSincePlan, String metaData ) { monitor.cacheDiscard( queryKey, metaData, secondsSincePlan ); } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/PlanCacheMetricsMonitor.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/PlanCacheMetricsMonitor.scala index 92c948a88ab6c..3587f4197f94c 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/PlanCacheMetricsMonitor.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/PlanCacheMetricsMonitor.scala @@ -21,7 +21,8 @@ package org.neo4j.cypher import java.util.concurrent.atomic.AtomicLong -import org.neo4j.cypher.internal.{ParameterTypeMap, StringCacheMonitor} +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap +import org.neo4j.cypher.internal.StringCacheMonitor import org.neo4j.helpers.collection.Pair class PlanCacheMetricsMonitor extends StringCacheMonitor { diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/Compiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/Compiler.scala index ec7e4e8bbb73f..d56ae0444a1a4 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/Compiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/Compiler.scala @@ -21,6 +21,7 @@ package org.neo4j.cypher.internal import org.neo4j.cypher.CypherException import org.neo4j.kernel.impl.query.TransactionalContext +import org.neo4j.values.virtual.MapValue import org.opencypher.v9_0.frontend.phases.CompilationPhaseTracer /** @@ -42,6 +43,7 @@ trait Compiler { def compile(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[org.neo4j.graphdb.Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): ExecutableQuery } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/ExecutionEngine.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/ExecutionEngine.scala index 1bcb56bf7c577..cbc9c239b3b3a 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/ExecutionEngine.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/ExecutionEngine.scala @@ -21,6 +21,7 @@ package org.neo4j.cypher.internal import java.time.Clock +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap import org.neo4j.cypher.internal.compatibility.CypherCacheMonitor import org.neo4j.cypher.internal.runtime.interpreted.LastCommittedTxIdProvider import org.neo4j.cypher.internal.tracing.CompilationTracer @@ -73,8 +74,8 @@ class ExecutionEngine(val queryService: GraphDatabaseQueryService, config.statsDivergenceCalculator, lastCommittedTxIdProvider, planReusabilitiy) - private val queryCache: QueryCache[String,Pair[String, MapValue], ExecutableQuery] = - new QueryCache[String, Pair[String, MapValue], ExecutableQuery](config.queryCacheSize, planStalenessCaller, cacheTracer) + private val queryCache: QueryCache[String,Pair[String, ParameterTypeMap], ExecutableQuery] = + new QueryCache[String, Pair[String, ParameterTypeMap], ExecutableQuery](config.queryCacheSize, planStalenessCaller, cacheTracer) private val masterCompiler: MasterCompiler = new MasterCompiler(queryService, kernelMonitors, config, logProvider, new CompilerLibrary(compatibilityFactory)) @@ -119,7 +120,7 @@ class ExecutionEngine(val queryService: GraphDatabaseQueryService, tracer: QueryCompilationEvent, params: MapValue ): ExecutableQuery = { - val cacheKey = Pair.of(preParsedQuery.statementWithVersionAndPlanner, params) + val cacheKey = Pair.of(preParsedQuery.statementWithVersionAndPlanner, QueryCache.extractParameterTypeMap(params)) // create transaction and query context val tc = context.getOrBeginNewIfClosed() @@ -132,7 +133,7 @@ class ExecutionEngine(val queryService: GraphDatabaseQueryService, val schemaToken = schemaHelper.readSchemaToken(tc) val cacheLookup = queryCache.computeIfAbsentOrStale(cacheKey, tc, - () => masterCompiler.compile(preParsedQuery, tracer, tc), + () => masterCompiler.compile(preParsedQuery, tracer, tc, params), preParsedQuery.rawStatement) cacheLookup match { case _: CacheHit[_] | diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/MasterCompiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/MasterCompiler.scala index 78550f3ba4e7f..dd5e1a3d98f44 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/MasterCompiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/MasterCompiler.scala @@ -31,6 +31,7 @@ import org.neo4j.kernel.configuration.Config import org.neo4j.kernel.impl.query.TransactionalContext import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.{Log, LogProvider} +import org.neo4j.values.virtual.MapValue import org.opencypher.v9_0.frontend.phases.CompilationPhaseTracer import org.opencypher.v9_0.util.{InputPosition, SyntaxException => InternalSyntaxException} @@ -91,7 +92,8 @@ class MasterCompiler(graph: GraphDatabaseQueryService, */ def compile(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): ExecutableQuery = { var notifications = Set.newBuilder[org.neo4j.graphdb.Notification] @@ -114,11 +116,11 @@ class MasterCompiler(graph: GraphDatabaseQueryService, * @param preParsedQuery the query to compile * @return the compiled query */ - def innerCompile(preParsedQuery: PreParsedQuery): ExecutableQuery = { + def innerCompile(preParsedQuery: PreParsedQuery, params: MapValue): ExecutableQuery = { if ((preParsedQuery.version == CypherVersion.v3_4 || preParsedQuery.version == CypherVersion.v3_5) && preParsedQuery.planner == CypherPlannerOption.rule) { notifications += rulePlannerUnavailableFallbackNotification(preParsedQuery.offset) - innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1)) + innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1), params) } else if (preParsedQuery.version == CypherVersion.v3_5) { val compiler3_5 = compilerLibrary.selectCompiler(preParsedQuery.version, @@ -128,20 +130,20 @@ class MasterCompiler(graph: GraphDatabaseQueryService, compilerConfig) try { - compiler3_5.compile(preParsedQuery, tracer, notifications.result(), transactionalContext) + compiler3_5.compile(preParsedQuery, tracer, notifications.result(), transactionalContext, params) } catch { case ex: SyntaxException if ex.getMessage.startsWith("CREATE UNIQUE") => val ex3_5 = ex.getCause.asInstanceOf[InternalSyntaxException] notifications += createUniqueNotification(ex3_5, inputPosition) assertSupportedRuntime(ex3_5, preParsedQuery.runtime) - innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1, runtime = CypherRuntimeOption.interpreted)) + innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1, runtime = CypherRuntimeOption.interpreted), params) case ex: SyntaxException if ex.getMessage.startsWith("START is deprecated") => val ex3_5 = ex.getCause.asInstanceOf[InternalSyntaxException] notifications += createStartUnavailableNotification(ex3_5, inputPosition) notifications += createStartDeprecatedNotification(ex3_5, inputPosition) assertSupportedRuntime(ex3_5, preParsedQuery.runtime) - innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1, runtime = CypherRuntimeOption.interpreted)) + innerCompile(preParsedQuery.copy(version = CypherVersion.v3_1, runtime = CypherRuntimeOption.interpreted), params) } } else { @@ -152,12 +154,12 @@ class MasterCompiler(graph: GraphDatabaseQueryService, preParsedQuery.updateStrategy, compilerConfig) - compiler.compile(preParsedQuery, tracer, notifications.result(), transactionalContext) + compiler.compile(preParsedQuery, tracer, notifications.result(), transactionalContext, params) } } // Do the compilation - innerCompile(preParsedQuery) + innerCompile(preParsedQuery, params) } private def createStartUnavailableNotification(ex: InternalSyntaxException, inputPosition: InputPosition) = { diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/QueryCache.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/QueryCache.scala index 288da0977878b..9efa8eb851ca2 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/QueryCache.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/QueryCache.scala @@ -20,12 +20,12 @@ package org.neo4j.cypher.internal import com.github.benmanes.caffeine.cache.{Cache, Caffeine} +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap import org.neo4j.helpers.collection.Pair import org.neo4j.kernel.impl.query.TransactionalContext import org.neo4j.values.virtual.MapValue import scala.collection.JavaConversions._ -import scala.collection.mutable /** * The result of one cache lookup. @@ -61,24 +61,14 @@ trait CacheTracer[QUERY_KEY] { * @param stalenessCaller Decided whether CachedExecutionPlans are stale * @param tracer Traces cache activity */ -class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, MapValue], EXECUTABLE_QUERY <: AnyRef](val maximumSize: Int, +class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, ParameterTypeMap], EXECUTABLE_QUERY <: AnyRef](val maximumSize: Int, val stalenessCaller: PlanStalenessCaller[EXECUTABLE_QUERY], val tracer: CacheTracer[Pair[QUERY_REP, ParameterTypeMap]]) { - type Cache_Key = Pair[QUERY_REP, ParameterTypeMap] - val inner: Cache[Cache_Key, EXECUTABLE_QUERY] = Caffeine.newBuilder().maximumSize(maximumSize).build[Cache_Key, EXECUTABLE_QUERY]() + val inner: Cache[QUERY_KEY, EXECUTABLE_QUERY] = Caffeine.newBuilder().maximumSize(maximumSize).build[QUERY_KEY, EXECUTABLE_QUERY]() import QueryCache.NOT_PRESENT - - private def extractParameterTypeMap(value: MapValue) = { - val resultMap = new ParameterTypeMap() - for( key <- value.keySet().iterator()) { - resultMap.put(key, value.get(key).getClass) - } - resultMap - } - /** * Retrieve the CachedExecutionPlan associated with the given queryKey, or compile, cache and * return the query if it is not in the cache, or the cached execution plan is stale. @@ -97,18 +87,17 @@ class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, MapValue], EX if (maximumSize == 0) CacheDisabled(compile()) else { - val actualKey = Pair.of(queryKey.first(), extractParameterTypeMap(queryKey.other())) - inner.getIfPresent(actualKey) match { + inner.getIfPresent(queryKey) match { case NOT_PRESENT => - compileAndCache(actualKey, tc, compile, metaData) + compileAndCache(queryKey, tc, compile, metaData) case executableQuery => stalenessCaller.staleness(tc, executableQuery) match { case NotStale => - hit(actualKey, executableQuery, metaData) + hit(queryKey, executableQuery, metaData) case Stale(secondsSincePlan) => - tracer.queryCacheStale(actualKey, secondsSincePlan, metaData) - compileAndCache(actualKey, tc, compile, metaData) + tracer.queryCacheStale(queryKey, secondsSincePlan, metaData) + compileAndCache(queryKey, tc, compile, metaData) } } } @@ -122,7 +111,7 @@ class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, MapValue], EX * first. Regardless of who does it, this is treated as a cache miss, because it will * take a long time. */ - private def compileAndCache(key: Cache_Key, + private def compileAndCache(key: QUERY_KEY, tc: TransactionalContext, compile: () => EXECUTABLE_QUERY, metaData: String @@ -132,14 +121,14 @@ class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, MapValue], EX miss(key, newExecutableQuery, metaData) } - private def hit(key: Cache_Key, + private def hit(key: QUERY_KEY, executableQuery: EXECUTABLE_QUERY, metaData: String) = { tracer.queryCacheHit(key, metaData) CacheHit(executableQuery) } - private def miss(key: Cache_Key, + private def miss(key: QUERY_KEY, newExecutableQuery: EXECUTABLE_QUERY, metaData: String) = { tracer.queryCacheMiss(key, metaData) @@ -162,29 +151,16 @@ class QueryCache[QUERY_REP <: AnyRef, QUERY_KEY <: Pair[QUERY_REP, MapValue], EX object QueryCache { val NOT_PRESENT: ExecutableQuery = null -} + type ParameterTypeMap = Map[String, Class[_]] -/* - The whole point of this class is to have a map that in addition to key equality, also checks its values for type equality - */ -class ParameterTypeMap extends mutable.HashMap[String, Class[_]] { - override def equals(that: Any): Boolean = { - if (!that.isInstanceOf[ParameterTypeMap]) - return false - - val other = that.asInstanceOf[ParameterTypeMap] - - if ( this.size != other.size ) - return false - - for ( key <- this.keys ) - { - val oneType = this (key) - val otherType = other(key) - if (!(oneType == otherType)) { - return false - } + /** + * Use this method to extract ParameterTypeMap from MapValue that represents parameters + */ + def extractParameterTypeMap(value: MapValue): ParameterTypeMap = { + val resultMap = Map.newBuilder[String, Class[_]] + for(key <- value.keySet().iterator()) { + resultMap += ((key, value.get(key).getClass)) } - true + resultMap.result() } } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/AstLogicalPlanCache.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/AstLogicalPlanCache.scala index 43d91abed0776..224082c6521c7 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/AstLogicalPlanCache.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/AstLogicalPlanCache.scala @@ -21,11 +21,11 @@ package org.neo4j.cypher.internal.compatibility import java.time.Clock +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap import org.neo4j.cypher.internal._ import org.neo4j.cypher.internal.compiler.v3_5.StatsDivergenceCalculator import org.neo4j.cypher.internal.compiler.v3_5.phases.LogicalPlanState import org.neo4j.helpers.collection.Pair -import org.neo4j.values.virtual.MapValue /** * Cache which stores logical plans indexed by an AST statement. @@ -42,7 +42,7 @@ class AstLogicalPlanCache[STATEMENT <: AnyRef](override val maximumSize: Int, clock: Clock, divergence: StatsDivergenceCalculator, lastCommittedTxIdProvider: () => Long -) extends QueryCache[STATEMENT,Pair[STATEMENT,MapValue], CacheableLogicalPlan](maximumSize, +) extends QueryCache[STATEMENT,Pair[STATEMENT,ParameterTypeMap], CacheableLogicalPlan](maximumSize, AstLogicalPlanCache.stalenessCaller(clock, divergence, lastCommittedTxIdProvider), tracer) object AstLogicalPlanCache { diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/BasePlanner.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/BasePlanner.scala index 3f1023099bf2f..a778beb1237aa 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/BasePlanner.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/BasePlanner.scala @@ -21,6 +21,7 @@ package org.neo4j.cypher.internal.compatibility import java.time.Clock +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap import org.neo4j.cypher.internal._ import org.neo4j.cypher.internal.compatibility.v3_5.{WrappedMonitors => WrappedMonitorsv3_5} import org.neo4j.cypher.internal.compiler.v3_5._ diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherCurrentCompiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherCurrentCompiler.scala index 257acbb423178..07dca004dec8a 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherCurrentCompiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherCurrentCompiler.scala @@ -20,17 +20,17 @@ package org.neo4j.cypher.internal.compatibility import org.neo4j.cypher.exceptionHandler.runSafely +import org.neo4j.cypher.internal._ import org.neo4j.cypher.internal.compatibility.v3_5.ExceptionTranslatingQueryContext -import org.neo4j.cypher.{CypherException, CypherExecutionMode} +import org.neo4j.cypher.internal.compatibility.v3_5.runtime.RuntimeName import org.neo4j.cypher.internal.compatibility.v3_5.runtime.executionplan.{ExecutionPlan => ExecutionPlan_v3_5} +import org.neo4j.cypher.internal.compiler.v3_5.phases.LogicalPlanState import org.neo4j.cypher.internal.javacompat.ExecutionResult -import org.neo4j.cypher.internal.runtime.{ExecutableQuery => _, _} import org.neo4j.cypher.internal.runtime.interpreted.TransactionBoundQueryContext.IndexSearchMonitor import org.neo4j.cypher.internal.runtime.interpreted.{TransactionBoundQueryContext, TransactionalContextWrapper} +import org.neo4j.cypher.internal.runtime.{ExecutableQuery => _, _} import org.neo4j.cypher.internal.v3_5.logical.plans._ -import org.neo4j.cypher.internal._ -import org.neo4j.cypher.internal.compatibility.v3_5.runtime.RuntimeName -import org.neo4j.cypher.internal.compiler.v3_5.phases.LogicalPlanState +import org.neo4j.cypher.{CypherException, CypherExecutionMode} import org.neo4j.graphdb.{Notification, Result} import org.neo4j.kernel.api.query.{CompilerInfo, ExplicitIndexUsage, SchemaIndexUsage} import org.neo4j.kernel.impl.query.{QueryExecutionMonitor, TransactionalContext} @@ -69,10 +69,11 @@ case class CypherCurrentCompiler[CONTEXT <: RuntimeContext](planner: CypherPlann override def compile(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[Notification], - transactionalContext: TransactionalContext): ExecutableQuery = { + transactionalContext: TransactionalContext, + params: MapValue): ExecutableQuery = { val logicalPlanResult = - planner.parseAndPlan(preParsedQuery, tracer, preParsingNotifications, transactionalContext) + planner.parseAndPlan(preParsedQuery, tracer, preParsingNotifications, transactionalContext, params) val planState = logicalPlanResult.logicalPlanState val logicalPlan = planState.logicalPlan diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherPlanner.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherPlanner.scala index f68735b3962dd..a65cb5b567584 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherPlanner.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/CypherPlanner.scala @@ -46,7 +46,8 @@ trait CypherPlanner { def parseAndPlan(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[org.neo4j.graphdb.Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): LogicalPlanResult def name: PlannerName diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v2_3/Cypher23Compiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v2_3/Cypher23Compiler.scala index ec66667be263e..05662a8ba8499 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v2_3/Cypher23Compiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v2_3/Cypher23Compiler.scala @@ -37,7 +37,7 @@ import org.neo4j.cypher.internal.spi.v2_3.{TransactionBoundGraphStatistics, Tran import org.neo4j.function.ThrowingBiConsumer import org.neo4j.graphdb.{Node, Relationship, Result} import org.neo4j.kernel.GraphDatabaseQueryService -import org.neo4j.kernel.api.query.{IndexUsage, CompilerInfo} +import org.neo4j.kernel.api.query.{CompilerInfo, IndexUsage} import org.neo4j.kernel.impl.core.EmbeddedProxySPI import org.neo4j.kernel.impl.query.{QueryExecutionMonitor, TransactionalContext} import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} @@ -123,7 +123,8 @@ trait Cypher23Compiler extends CachingPlanner[PreparedQuery] with Compiler { override def compile(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[org.neo4j.graphdb.Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): ExecutableQuery = { exceptionHandler.runSafely { diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_1/Cypher31Compiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_1/Cypher31Compiler.scala index 3306f37d066be..26c08114841a6 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_1/Cypher31Compiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_1/Cypher31Compiler.scala @@ -37,7 +37,7 @@ import org.neo4j.cypher.internal.spi.v3_1.{TransactionalContextWrapper => Transa import org.neo4j.function.ThrowingBiConsumer import org.neo4j.graphdb.Result import org.neo4j.kernel.GraphDatabaseQueryService -import org.neo4j.kernel.api.query.{IndexUsage, CompilerInfo} +import org.neo4j.kernel.api.query.{CompilerInfo, IndexUsage} import org.neo4j.kernel.impl.query.{QueryExecutionMonitor, TransactionalContext} import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.Log @@ -125,7 +125,8 @@ trait Cypher31Compiler extends CachingPlanner[PreparedQuerySyntax] with Compiler override def compile(preParsedQuery: PreParsedQuery, tracer: v3_5.phases.CompilationPhaseTracer, preParsingNotifications: Set[org.neo4j.graphdb.Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): ExecutableQuery = { exceptionHandler.runSafely { diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/Cypher34Planner.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/Cypher34Planner.scala index b6e765ee3f28c..0fe8f13e2bc8c 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/Cypher34Planner.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/Cypher34Planner.scala @@ -51,6 +51,7 @@ import org.neo4j.helpers.collection.Pair import org.neo4j.kernel.impl.query.TransactionalContext import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.Log +import org.neo4j.values.virtual.MapValue import org.opencypher.v9_0.frontend.PlannerName import org.opencypher.v9_0.frontend.phases.{CompilationPhaseTracer, RecordingNotificationLogger => RecordingNotificationLoggerv3_5} import org.opencypher.v9_0.util.attribution.SequentialIdGen @@ -117,7 +118,8 @@ case class Cypher34Planner(configv3_5: CypherPlannerConfiguration, override def parseAndPlan(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): LogicalPlanResult = { val inputPositionV3_4 = as3_4(preParsedQuery.offset) @@ -206,10 +208,12 @@ case class Cypher34Planner(configv3_5: CypherPlannerConfiguration, CacheableLogicalPlan(logicalPlanStatev3_5, reusabilityState) } - val params = ValueConversion.asValues(preparedQuery.extractedParams()) + // 3.4 does not produce different plans for different parameter types. + // Therefore, we always use an empty map as ParameterTypeMap + val cacheableLogicalPlan = if (preParsedQuery.debugOptions.isEmpty) - planCache.computeIfAbsentOrStale(Pair.of(syntacticQuery.statement(), params), + planCache.computeIfAbsentOrStale(Pair.of(syntacticQuery.statement(), Map.empty), transactionalContext, createPlan, syntacticQuery.queryText).executableQuery @@ -222,7 +226,7 @@ case class Cypher34Planner(configv3_5: CypherPlannerConfiguration, LogicalPlanResult( cacheableLogicalPlan.logicalPlanState, queryParamNames, - params, + ValueConversion.asValues(preparedQuery.extractedParams()), cacheableLogicalPlan.reusability, contextv3_5) } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_5/Cypher35Planner.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_5/Cypher35Planner.scala index 8ec372ee369a9..76a5ba9148e8c 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_5/Cypher35Planner.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_5/Cypher35Planner.scala @@ -20,6 +20,7 @@ package org.neo4j.cypher.internal.compatibility.v3_5 import java.time.Clock +import java.util.function.BiFunction import org.neo4j.cypher._ import org.neo4j.cypher.exceptionHandler.runSafely @@ -38,6 +39,8 @@ import org.neo4j.helpers.collection.Pair import org.neo4j.kernel.impl.query.TransactionalContext import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.Log +import org.neo4j.values.AnyValue +import org.neo4j.values.virtual.MapValue import org.opencypher.v9_0.ast.Statement import org.opencypher.v9_0.expressions.Parameter import org.opencypher.v9_0.frontend.PlannerName @@ -106,7 +109,8 @@ case class Cypher35Planner(config: CypherPlannerConfiguration, override def parseAndPlan(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer, preParsingNotifications: Set[Notification], - transactionalContext: TransactionalContext + transactionalContext: TransactionalContext, + params: MapValue ): LogicalPlanResult = { val notificationLogger = new RecordingNotificationLogger(Some(preParsedQuery.offset)) @@ -153,10 +157,14 @@ case class Cypher35Planner(config: CypherPlannerConfiguration, CacheableLogicalPlan(logicalPlanState, reusabilityState) } - val params = ValueConversion.asValues(preparedQuery.extractedParams()) + // Filter the parameters to retain only those that are actually used in the query + val filteredParams = params.filter(new BiFunction[String, AnyValue, java.lang.Boolean] { + override def apply(name: String, value: AnyValue): java.lang.Boolean = queryParamNames.contains(name) + }) + val cacheableLogicalPlan = if (preParsedQuery.debugOptions.isEmpty) - planCache.computeIfAbsentOrStale(Pair.of(syntacticQuery.statement(), params), + planCache.computeIfAbsentOrStale(Pair.of(syntacticQuery.statement(), QueryCache.extractParameterTypeMap(filteredParams)), transactionalContext, createPlan, syntacticQuery.queryText).executableQuery @@ -166,7 +174,7 @@ case class Cypher35Planner(config: CypherPlannerConfiguration, LogicalPlanResult( cacheableLogicalPlan.logicalPlanState, queryParamNames, - params, + ValueConversion.asValues(preparedQuery.extractedParams()), cacheableLogicalPlan.reusability, context) } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/ParameterTypeMapTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/ParameterTypeMapTest.scala deleted file mode 100644 index d8a3b9821892e..0000000000000 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/ParameterTypeMapTest.scala +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2002-2018 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.cypher.internal - -import org.neo4j.values.storable.Values._ -import org.opencypher.v9_0.util.test_helpers.CypherFunSuite - -class ParameterTypeMapTest extends CypherFunSuite { - test("maps should be equal on value types") { - val v1 = stringValue("value").getClass - val v2 = intValue(1).getClass - val v3 = longValue(1L).getClass - val v4 = booleanArray(Array[Boolean](true)).getClass - val v5 = stringArray("hi").getClass - - val map = new ParameterTypeMap - map.put("prop1", v1) - map.put("prop2", v2) - map.put("prop3", v3) - map.put("prop4", v4) - map.put("prop5", v5) - - map should equal(map) - - val other = new ParameterTypeMap() - other.put("prop1", v1) - other.put("prop2", v2) - other.put("prop3", v3) - other.put("prop4", v4) - other.put("prop5", v5) - - map should equal(other) - other should equal(map) - } - - test ("maps should not be equal on different value types") { - val map1 = new ParameterTypeMap() - map1.put("prop1", stringValue("value").getClass) - map1.put("prop2", intValue(1).getClass) - map1.put("prop3", longValue(1L).getClass) - map1.put("prop4", booleanArray(Array[Boolean](true)).getClass) - map1.put("prop5", stringArray("hi").getClass) - - val map2 = new ParameterTypeMap() - - map1 should not equal map2 - map2 should not equal map1 - - // Compare with almost the same maps - // -> not all keys - val map3 = new ParameterTypeMap() - map3.put("prop1", stringValue("value").getClass) - map3.put("prop2", intValue(1).getClass) - map3.put("prop4", booleanArray(Array[Boolean](true)).getClass) - map3.put("prop3", longValue(1L).getClass) - - map1 should not equal map3 - map3 should not equal map1 - - // -> some different value types - val map4 = new ParameterTypeMap() - map4.put("prop1", stringValue("value").getClass) - map4.put("prop2", longValue(1L).getClass) - map4.put("prop4", booleanArray(Array[Boolean](true)).getClass) - map4.put("prop3", intValue(1).getClass) - map4.put("prop5", stringArray("hi").getClass) - - map1 should not equal map4 - map4 should not equal map1 - } -} diff --git a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/CypherCompilerStringCacheMonitoringAcceptanceTest.scala b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/CypherCompilerStringCacheMonitoringAcceptanceTest.scala index 6782a1752d3de..581ff26a4dd19 100644 --- a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/CypherCompilerStringCacheMonitoringAcceptanceTest.scala +++ b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/CypherCompilerStringCacheMonitoringAcceptanceTest.scala @@ -25,7 +25,8 @@ package org.neo4j.internal.cypher.acceptance import org.hamcrest.Matchers import org.neo4j.cypher.ExecutionEngineFunSuite import org.neo4j.cypher.ExecutionEngineHelper.createEngine -import org.neo4j.cypher.internal.{ExecutionEngine, ParameterTypeMap, StringCacheMonitor} +import org.neo4j.cypher.internal.QueryCache.ParameterTypeMap +import org.neo4j.cypher.internal.{ExecutionEngine, StringCacheMonitor} import org.neo4j.graphdb.config.Setting import org.neo4j.graphdb.factory.GraphDatabaseSettings import org.neo4j.helpers.collection.Pair