Skip to content

Commit 2ea5139

Browse files
committed
Store project/trace metadata in a single database (performance related)
1 parent 0fda848 commit 2ea5139

File tree

5 files changed

+93
-23
lines changed

5 files changed

+93
-23
lines changed

codepulse/src/main/scala/com/secdec/codepulse/data/trace/slick/SlickH2TraceDataProvider.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,24 @@ class SlickH2TraceDataProvider(folder: File, actorSystem: ActorSystem) extends T
5353
}
5454
}
5555

56+
private val masterData = {
57+
val needsInit = !(folder / "master.h2.db").exists
58+
59+
val db = Database.forURL(s"jdbc:h2:file:${(folder / "master").getCanonicalPath};DB_CLOSE_DELAY=10", driver = "org.h2.Driver")
60+
val data = new SlickMasterData(db, H2Driver)
61+
62+
if (needsInit) data.init
63+
64+
data
65+
}
66+
5667
def getTrace(id: TraceId): TraceData = getTraceInternal(id)
5768

5869
private def getTraceInternal(id: TraceId, suppressInit: Boolean = false) = cache.getOrElseUpdate(id, {
5970
val needsInit = !(folder / TraceFilename(id)).exists
6071

6172
val db = Database.forURL(s"jdbc:h2:file:${(folder / TraceFilename.getDbName(id)).getCanonicalPath};DB_CLOSE_DELAY=10", driver = "org.h2.Driver")
62-
val data = new SlickTraceData(db, H2Driver, EncountersBufferSize, EncountersFlushInterval, actorSystem)
73+
val data = new SlickTraceData(db, H2Driver, masterData.metadataMaster get id.num, EncountersBufferSize, EncountersFlushInterval, actorSystem)
6374

6475
if (!suppressInit && needsInit) data.init
6576

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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.data.trace.slick
21+
22+
import scala.slick.driver.JdbcProfile
23+
import scala.slick.jdbc.JdbcBackend.Database
24+
25+
/** Main access to centralized trace metadata, using Slick, with `db` and `driver`.
26+
*
27+
* @author robertf
28+
*/
29+
private[slick] class SlickMasterData(val db: Database, val driver: JdbcProfile) {
30+
private val metadataDao = new TraceMetadataDao(driver)
31+
private val metadataAccess = new SlickTraceMetadataMaster(metadataDao, db)
32+
33+
def metadataMaster: SlickTraceMetadataMaster = metadataAccess
34+
35+
/** Initialize a blank DB for use. */
36+
private[slick] def init() = db withTransaction { implicit transaction =>
37+
metadataDao.create
38+
}
39+
}

codepulse/src/main/scala/com/secdec/codepulse/data/trace/slick/SlickTraceData.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ import com.secdec.codepulse.data.trace._
3131
*
3232
* @author robertf
3333
*/
34-
private[slick] class SlickTraceData(val db: Database, val driver: JdbcProfile, encounterBufferSize: Int, encounterFlushInterval: FiniteDuration, actorSystem: ActorSystem) extends TraceData {
35-
private val traceMetadataDao = new TraceMetadataDao(driver)
36-
private val metadataAccess = new SlickTraceMetadataAccess(traceMetadataDao, db) with DefaultTraceMetadataUpdates with TraceMetadata
37-
34+
private[slick] class SlickTraceData(val db: Database, val driver: JdbcProfile, metadataAccess: SlickTraceMetadataAccess with TraceMetadata, encounterBufferSize: Int, encounterFlushInterval: FiniteDuration, actorSystem: ActorSystem) extends TraceData {
3835
private val treeNodeDataDao = new TreeNodeDataDao(driver)
3936
private val treeNodeDataAccess = new SlickTreeNodeDataAccess(treeNodeDataDao, db)
4037

@@ -51,7 +48,6 @@ private[slick] class SlickTraceData(val db: Database, val driver: JdbcProfile, e
5148

5249
/** Initialize a blank DB for use. */
5350
private[slick] def init() = db withTransaction { implicit transaction =>
54-
traceMetadataDao.create
5551
treeNodeDataDao.create
5652
recordingMetadataDao.create
5753
encountersDao.create
@@ -66,6 +62,8 @@ private[slick] class SlickTraceData(val db: Database, val driver: JdbcProfile, e
6662
}
6763

6864
def delete() {
65+
metadataAccess.delete
66+
6967
close
7068

7169
db withTransaction { implicit session =>

codepulse/src/main/scala/com/secdec/codepulse/data/trace/slick/SlickTraceMetadataAccess.scala

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,38 @@
2020
package com.secdec.codepulse.data.trace.slick
2121

2222
import scala.slick.jdbc.JdbcBackend.{ Database, Session }
23-
import com.secdec.codepulse.data.trace.TraceMetadataAccess
23+
import com.secdec.codepulse.data.trace.{ DefaultTraceMetadataUpdates, TraceMetadataAccess, TraceMetadata }
2424
import net.liftweb.util.Helpers.AsLong
2525
import net.liftweb.util.Helpers.AsBoolean
2626

27+
/** Master controller for centralized Slick-backed metadata access.
28+
*
29+
* @author robertf
30+
*/
31+
private[slick] class SlickTraceMetadataMaster(dao: TraceMetadataDao, db: Database) {
32+
def get(traceId: Int) = new SlickTraceMetadataAccess(traceId, dao, db) with DefaultTraceMetadataUpdates with TraceMetadata
33+
}
34+
2735
/** Slick-backed TraceMetadataAccess implementation.
2836
*
2937
* @author robertf
3038
*/
31-
private[slick] class SlickTraceMetadataAccess(dao: TraceMetadataDao, db: Database) extends TraceMetadataAccess {
39+
private[slick] class SlickTraceMetadataAccess(traceId: Int, dao: TraceMetadataDao, db: Database) extends TraceMetadataAccess {
3240
private val cache = collection.mutable.Map.empty[String, Option[String]]
3341

34-
private def get(key: String)(implicit session: Session) = cache.getOrElseUpdate(key, dao get key)
42+
private def get(key: String)(implicit session: Session) = cache.getOrElseUpdate(key, dao.get(traceId, key))
3543
private def set(key: String, value: String)(implicit session: Session): Unit = set(key, Some(value))
3644
private def set(key: String, value: Option[String])(implicit session: Session) {
37-
dao.set(key, value)
45+
dao.set(traceId, key, value)
3846
cache += key -> value
3947
}
4048

49+
def delete() {
50+
db withSession { implicit session =>
51+
dao delete traceId
52+
}
53+
}
54+
4155
def name = db withSession { implicit session =>
4256
get("name")
4357
} getOrElse "Untitled"

codepulse/src/main/scala/com/secdec/codepulse/data/trace/slick/TraceMetadataDao.scala

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,34 +29,42 @@ import com.secdec.codepulse.data.trace._
2929
private[slick] class TraceMetadataDao(val driver: JdbcProfile) {
3030
import driver.simple._
3131

32-
class TraceMetadata(tag: Tag) extends Table[(String, String)](tag, "trace_metadata") {
33-
def key = column[String]("key", O.PrimaryKey, O.NotNull)
32+
class TraceMetadata(tag: Tag) extends Table[(Int, String, String)](tag, "trace_metadata") {
33+
def traceId = column[Int]("trace_id", O.NotNull)
34+
def key = column[String]("key", O.NotNull)
3435
def value = column[String]("value", O.NotNull)
35-
def * = key -> value
36+
def pk = primaryKey("pk_trace_metadata", (traceId, key))
37+
def * = (traceId, key, value)
3638
}
3739
val traceMetadata = TableQuery[TraceMetadata]
3840

3941
def create(implicit session: Session) = traceMetadata.ddl.create
4042

41-
def getMap()(implicit session: Session): Map[String, String] = traceMetadata.list.toMap
43+
def getMap()(implicit session: Session): Map[Int, Map[String, String]] = traceMetadata.list.groupBy(_._1) mapValues {
44+
entries => (entries map { case (_, key, value) => key -> value }).toMap
45+
}
4246

43-
def get(key: String)(implicit session: Session): Option[String] =
44-
(for (r <- traceMetadata if r.key === key) yield r.value).firstOption
47+
def get(traceId: Int, key: String)(implicit session: Session): Option[String] =
48+
(for (r <- traceMetadata if r.traceId === traceId && r.key === key) yield r.value).firstOption
4549

46-
def set(key: String, value: String)(implicit session: Session) {
47-
set(key, Some(value))
50+
def set(traceId: Int, key: String, value: String)(implicit session: Session) {
51+
set(traceId, key, Some(value))
4852
}
4953

50-
def set(key: String, value: Option[String])(implicit session: Session) {
54+
def set(traceId: Int, key: String, value: Option[String])(implicit session: Session) {
5155
value match {
5256
case Some(value) =>
53-
get(key) match {
54-
case Some(_) => (for (r <- traceMetadata if r.key === key) yield r.value).update(value)
55-
case None => traceMetadata += key -> value
57+
get(traceId, key) match {
58+
case Some(_) => (for (r <- traceMetadata if r.traceId === traceId && r.key === key) yield r.value).update(value)
59+
case None => traceMetadata += (traceId, key, value)
5660
}
5761

5862
case None =>
59-
(for (r <- traceMetadata if r.key === key) yield r).delete
63+
(for (r <- traceMetadata if r.traceId === traceId && r.key === key) yield r).delete
6064
}
6165
}
66+
67+
def delete(traceId: Int)(implicit session: Session) {
68+
(for (r <- traceMetadata if r.traceId === traceId) yield r).delete
69+
}
6270
}

0 commit comments

Comments
 (0)