-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
BuildCompiledExecutionPlan.scala
121 lines (105 loc) · 5.94 KB
/
BuildCompiledExecutionPlan.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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 Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.compatibility.v3_3.runtime.compiled
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.compiled.ExecutionPlanBuilder.DescriptionProvider
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.compiled.codegen._
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.executionplan._
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.phases.CompilationState
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.{TaskCloser, _}
import org.neo4j.cypher.internal.compiler.v3_3.phases.LogicalPlanState
import org.neo4j.cypher.internal.compiler.v3_3.planDescription.InternalPlanDescription
import org.neo4j.cypher.internal.compiler.v3_3.planDescription.InternalPlanDescription.Arguments
import org.neo4j.cypher.internal.compiler.v3_3.planner.CantCompileQueryException
import org.neo4j.cypher.internal.compiler.v3_3.planner.logical.plans.IndexUsage
import org.neo4j.cypher.internal.compiler.v3_3.spi.{GraphStatistics, PlanContext}
import org.neo4j.cypher.internal.frontend.v3_3.PlannerName
import org.neo4j.cypher.internal.frontend.v3_3.notification.InternalNotification
import org.neo4j.cypher.internal.frontend.v3_3.phases.CompilationPhaseTracer.CompilationPhase.CODE_GENERATION
import org.neo4j.cypher.internal.frontend.v3_3.phases.Phase
import org.neo4j.cypher.internal.spi.v3_3.QueryContext
import org.neo4j.cypher.internal.v3_3.codegen.profiling.ProfilingTracer
object BuildCompiledExecutionPlan extends Phase[EnterpriseRuntimeContext, LogicalPlanState, CompilationState] {
override def phase = CODE_GENERATION
override def description = "creates runnable byte code"
override def postConditions = Set.empty// Can't yet guarantee that we can build an execution plan
override def process(from: LogicalPlanState, context: EnterpriseRuntimeContext): CompilationState = {
val runtimeSuccessRateMonitor = context.monitors.newMonitor[NewRuntimeSuccessRateMonitor]()
try {
val codeGen = new CodeGenerator(context.codeStructure, context.clock, CodeGenConfiguration(context.debugOptions))
val compiled: CompiledPlan = codeGen.generate(from.logicalPlan, context.planContext, from.semanticTable, from.plannerName)
val executionPlan: ExecutionPlan = createExecutionPlan(context, compiled)
runtimeSuccessRateMonitor.newPlanSeen(from.logicalPlan)
new CompilationState(from, Some(executionPlan))
} catch {
case e: CantCompileQueryException =>
runtimeSuccessRateMonitor.unableToHandlePlan(from.logicalPlan, e)
new CompilationState(from, None)
}
}
private def createExecutionPlan(context: EnterpriseRuntimeContext, compiled: CompiledPlan) = new ExecutionPlan {
private val fingerprint = context.createFingerprintReference(compiled.fingerprint)
override def isStale(lastTxId: () => Long, statistics: GraphStatistics): Boolean = fingerprint.isStale(lastTxId, statistics)
override def run(queryContext: QueryContext,
executionMode: ExecutionMode, params: Map[String, Any]): InternalExecutionResult = {
val taskCloser = new TaskCloser
taskCloser.addTask(queryContext.transactionalContext.close)
try {
if (executionMode == ExplainMode) {
//close all statements
taskCloser.close(success = true)
ExplainExecutionResult(compiled.columns.toList,
compiled.planDescription, READ_ONLY, context.notificationLogger.notifications)
} else
compiled.executionResultBuilder(queryContext, executionMode, createTracer(executionMode, queryContext), params, taskCloser)
} catch {
case (t: Throwable) =>
taskCloser.close(success = false)
throw t
}
}
override def plannerUsed: PlannerName = compiled.plannerUsed
override def isPeriodicCommit: Boolean = compiled.periodicCommit.isDefined
override def runtimeUsed = CompiledRuntimeName
override def notifications(planContext: PlanContext): Seq[InternalNotification] = Seq.empty
override def plannedIndexUsage: Seq[IndexUsage] = compiled.plannedIndexUsage
}
private def createTracer(mode: ExecutionMode, queryContext: QueryContext): DescriptionProvider = mode match {
case ProfileMode =>
val tracer = new ProfilingTracer(queryContext.transactionalContext.kernelStatisticProvider)
(description: InternalPlanDescription) =>
(new Provider[InternalPlanDescription] {
override def get(): InternalPlanDescription = description.map {
plan: InternalPlanDescription =>
val data = tracer.get(plan.id)
plan.
addArgument(Arguments.DbHits(data.dbHits())).
addArgument(Arguments.PageCacheHits(data.pageCacheHits())).
addArgument(Arguments.PageCacheMisses(data.pageCacheMisses())).
addArgument(Arguments.PageCacheHitRatio(data.pageCacheHitRatio())).
addArgument(Arguments.Rows(data.rows())).
addArgument(Arguments.Time(data.time()))
}
}, Some(tracer))
case _ => (description: InternalPlanDescription) =>
(new Provider[InternalPlanDescription] {
override def get(): InternalPlanDescription = description
}, None)
}
}