Skip to content

Commit 5b02ff5

Browse files
committed
Better management lifetime of treebuilder's cached data.
1 parent 6d1c036 commit 5b02ff5

File tree

5 files changed

+74
-14
lines changed

5 files changed

+74
-14
lines changed

codepulse/src/main/scala/com/secdec/codepulse/tracer/AkkaTracingTarget.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import reactive.EventStream
3333
import com.secdec.codepulse.data.jsp.JspMapper
3434
import com.secdec.codepulse.data.trace.TraceId
3535
import com.secdec.codepulse.data.trace.TraceData
36-
import com.secdec.codepulse.data.trace.TreeBuilder
3736
import akka.actor.PoisonPill
3837

3938
//sealed trait TracingTargetEvent
@@ -77,7 +76,6 @@ trait TracingTarget {
7776

7877
def traceData: TraceData
7978
def transientData: TransientTraceData
80-
def treeBuilder: TreeBuilder
8179

8280
def requestDeletion(): Unit
8381
def notifyFinishedLoading(): Unit
@@ -102,7 +100,7 @@ object AkkaTracingTarget {
102100
// implicit Timeout used for the Akka ask (?) method in getState
103101
private implicit val timeout = new Timeout(5000)
104102

105-
private class TracingTargetImpl(val id: TraceId, actor: ActorRef, val traceData: TraceData, val transientData: TransientTraceData, val treeBuilder: TreeBuilder) extends TracingTarget with AskSupport {
103+
private class TracingTargetImpl(val id: TraceId, actor: ActorRef, val traceData: TraceData, val transientData: TransientTraceData) extends TracingTarget with AskSupport {
106104
def subscribeToStateChanges(sub: EventStream[TracingTargetState] => Unit) = actor ! Subscribe(sub)
107105
def requestNewTraceConnection() = actor ! RequestTraceConnect
108106
def requestTraceEnd() = actor ! RequestTraceEnd
@@ -114,10 +112,10 @@ object AkkaTracingTarget {
114112
def notifyFinishedLoading() = actor ! FinishedLoading
115113
}
116114

117-
def apply(actorSystem: ActorSystem, traceId: TraceId, traceData: TraceData, transientTraceData: TransientTraceData, treeBuilder: TreeBuilder, jspMapper: Option[JspMapper]): TracingTarget = {
115+
def apply(actorSystem: ActorSystem, traceId: TraceId, traceData: TraceData, transientTraceData: TransientTraceData, jspMapper: Option[JspMapper]): TracingTarget = {
118116
val props = Props { new AkkaTracingTarget(traceId, traceData, transientTraceData, jspMapper) }
119117
val actorRef = actorSystem.actorOf(props)
120-
new TracingTargetImpl(traceId, actorRef, traceData, transientTraceData, treeBuilder)
118+
new TracingTargetImpl(traceId, actorRef, traceData, transientTraceData)
121119
}
122120

123121
}

codepulse/src/main/scala/com/secdec/codepulse/tracer/TraceAPIServer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import net.liftweb.json.JsonDSL._
3939
import net.liftweb.util.Helpers.AsBoolean
4040
import net.liftweb.util.Helpers.AsInt
4141

42-
class TraceAPIServer(manager: TraceManager) extends RestHelper with Loggable {
42+
class TraceAPIServer(manager: TraceManager, treeBuilderManager: TreeBuilderManager) extends RestHelper with Loggable {
4343

4444
import ActivityRequest._
4545

@@ -289,14 +289,14 @@ class TraceAPIServer(manager: TraceManager) extends RestHelper with Loggable {
289289

290290
// GET the trace's package tree as json
291291
case Paths.PackageTree(target) Get req =>
292-
PackageTreeStreamer.streamPackageTree(target.treeBuilder.packageTree)
292+
PackageTreeStreamer.streamPackageTree(treeBuilderManager.get(target.id).packageTree)
293293

294294
// stream a projected treemap based on the POSTed selected packages
295295
case Paths.Treemap(target) Post req =>
296296
req.param("nodes") match {
297297
case Full(packages) =>
298298
val ids = packages.split(',').flatMap(AsInt.unapply).toSet
299-
val tree = target.treeBuilder.projectTree(ids)
299+
val tree = treeBuilderManager.get(target.id).projectTree(ids)
300300
TreemapDataStreamer.streamTreemapData(target.traceData.treeNodeData, tree)
301301

302302
case _ => BadResponse()

codepulse/src/main/scala/com/secdec/codepulse/tracer/TraceManager.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import com.secdec.codepulse.data.jsp.JasperJspMapper
3535
import com.secdec.codepulse.data.trace.TraceId
3636
import com.secdec.codepulse.data.trace.TraceDataProvider
3737
import com.secdec.codepulse.data.trace.TraceData
38-
import com.secdec.codepulse.data.trace.TreeBuilder
3938

4039
object TraceManager {
4140
lazy val defaultActorSystem = {
@@ -88,9 +87,7 @@ class TraceManager(val actorSystem: ActorSystem) extends Observing {
8887
private def registerTrace(traceId: TraceId, traceData: TraceData, jspMapper: Option[JspMapper]) = {
8988
registerTraceId(traceId)
9089

91-
val treeBuilder = new TreeBuilder(traceData.treeNodeData)
92-
93-
val target = AkkaTracingTarget(actorSystem, traceId, traceData, transientDataProvider get traceId, treeBuilder, jspMapper)
90+
val target = AkkaTracingTarget(actorSystem, traceId, traceData, transientDataProvider get traceId, jspMapper)
9491
traces.put(traceId, target)
9592

9693
// cause a traceListUpdate when this trace's name changes
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Code Pulse: A real-time code coverage testing tool. For more information
3+
* see http://code-pulse.com
4+
*
5+
* Copyright (C) 2014 Applied Visions - http://securedecisions.avi.com
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package com.secdec.codepulse.tracer
21+
22+
import com.secdec.codepulse.data.trace.TraceDataProvider
23+
import com.secdec.codepulse.data.trace.TraceId
24+
import com.secdec.codepulse.data.trace.TreeBuilder
25+
26+
/** Manages a single TreeBuilder instance, such that we're only holding an
27+
* entire trace tree for a single trace at a time.
28+
*
29+
* @author robertf
30+
*/
31+
class TreeBuilderManager(dataProvider: TraceDataProvider) {
32+
private val lock = new Object
33+
private var cachedId = None: Option[TraceId]
34+
private var current = None: Option[TreeBuilder]
35+
36+
private def changeTrace(newTrace: TraceId) = {
37+
cachedId = None
38+
val data = dataProvider.getTrace(newTrace)
39+
val builder = new TreeBuilder(data.treeNodeData)
40+
current = Some(builder)
41+
cachedId = Some(newTrace)
42+
builder
43+
}
44+
45+
def get(trace: TraceId): TreeBuilder = {
46+
lock.synchronized {
47+
if (cachedId.exists(_ == trace))
48+
current.getOrElse(changeTrace(trace))
49+
else
50+
changeTrace(trace)
51+
}
52+
}
53+
54+
def clear() {
55+
lock.synchronized {
56+
cachedId = None
57+
current = None
58+
}
59+
}
60+
}

codepulse/src/main/scala/com/secdec/codepulse/tracer/package.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,25 @@ package object tracer {
4343
val traceManager = new BootVar[TraceManager]
4444
val traceDataProvider = new BootVar[TraceDataProvider]
4545
val transientTraceDataProvider = new BootVar[TransientTraceDataProvider]
46+
val treeBuilderManager = new BootVar[TreeBuilderManager]
4647
val traceFileUploadServer = new BootVar[TraceFileUploadHandler]
4748
val traceAPIServer = new BootVar[TraceAPIServer]
4849

4950
def boot() {
5051
val as = TraceManager.defaultActorSystem
5152

52-
traceDataProvider set new SlickH2TraceDataProvider(TraceDataProvider.DefaultStorageDir, as)
53+
val dataProvider = new SlickH2TraceDataProvider(TraceDataProvider.DefaultStorageDir, as)
54+
traceDataProvider set dataProvider
5355
transientTraceDataProvider set new TransientTraceDataProvider
5456

57+
val tbm = new TreeBuilderManager(dataProvider)
58+
treeBuilderManager set tbm
59+
5560
val tm = new TraceManager(as)
5661

5762
traceActorSystem set as
5863
traceManager set tm
5964
traceFileUploadServer set new TraceFileUploadHandler(tm).initializeServer
60-
traceAPIServer set new TraceAPIServer(tm).initializeServer
65+
traceAPIServer set new TraceAPIServer(tm, tbm).initializeServer
6166
}
6267
}

0 commit comments

Comments
 (0)