org.squeryl.logging.StatsSchema.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squeryl_2.13 Show documentation
Show all versions of squeryl_2.13 Show documentation
A Scala ORM and DSL for talking with Databases using minimum verbosity and maximum type safety
The newest version!
/*******************************************************************************
* Copyright 2010 Maxime Lévesque
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.squeryl.logging
import org.squeryl.KeyedEntity
import org.squeryl.Schema
import org.squeryl.dsl.{CompositeKey2, TypedExpression, TOptionFloat}
object StatsSchemaTypeMode extends org.squeryl.PrimitiveTypeMode
import StatsSchemaTypeMode._
/**
* id is a UUID generatted by java.util.UUID
*/
class StatementInvocation(
val id: String,
val start: Long,
val end: Long,
val statementHash: Int,
val statementHashCollisionNumber: Int,
val hostId: Int,
val sessionId: Int,
val rowCount: Option[Int],
val iterationEndTime: Option[Long]
) extends KeyedEntity[String] {
def this(se: StatementInvocationEvent, _statementHash: Int, _hCollision: Int) =
this(se.uuid, se.start, se.end, _statementHash, _hCollision, 0, 0, None, None)
def this() =
this(null, 0, 0, 0, 0, 0, 0, Some(0), Some(0))
def statementId =
CompositeKey2(statementHash, statementHashCollisionNumber)
def executeTime =
end - start
}
object StatementHasher {
private case class StatementCaseClass4HashGeneration(sql: String, definitionOrCallSite: String)
def hash(sql: String, definitionOrCallSite: String): Int =
StatementCaseClass4HashGeneration(sql, definitionOrCallSite).hashCode()
}
class Statement(val sql: String, val definitionOrCallSite: String, val hash: Int, var statementHashCollisionNumber: Int)
extends KeyedEntity[CompositeKey2[Int, Int]] {
def this(sql: String, definitionOrCallSite: String) = {
// TODO: support defining truncation rule in schena (on/declare)
this(sql, definitionOrCallSite, StatementHasher.hash(sql, definitionOrCallSite), 0)
}
def this() = this("", "", 0, 0)
def id =
CompositeKey2(hash, statementHashCollisionNumber)
}
class StatLine(
val statement: Statement,
val avgExecTime: Double,
val invocationCount: Long,
val cumulativeExecutionTime: Long,
val avgRowCount: Float
) {
def definitionSite =
statement.definitionOrCallSite
}
object Measure extends Enumeration {
type Measure = Value
val AvgExecTime, InvocationCount, CumulativeExecutionTime, AvgResultSetSize = Value
}
object StatsSchema extends Schema {
override def drop = super.drop
val statements = table[Statement]("Statementz")
val statementInvocations = table[StatementInvocation]()
def invocationStats =
from(statementInvocations)((si) =>
groupBy(si.statementHash, si.statementHashCollisionNumber).compute[Option[Double], Long, Option[Long], Float](
avg(si.executeTime),
count,
sum(si.executeTime),
nvl(avg(si.rowCount): TypedExpression[Option[Float], TOptionFloat], 0)
)
)
import Measure._
def topRankingStatements(topN: Int, measure: Measure) =
from(invocationStats, statements)((si, s) =>
where(si.key._1 === s.hash and si.key._2 === s.statementHashCollisionNumber)
.select(new StatLine(s, si.measures._1.get, si.measures._2, si.measures._3.get, si.measures._4))
.orderBy(measure match {
case AvgExecTime => si.measures._1.desc
case InvocationCount => si.measures._2.desc
case CumulativeExecutionTime => si.measures._3.desc
case AvgResultSetSize => si.measures._4.desc
})
).page(0, topN)
on(statements)(s =>
declare(
s.sql is (dbType("clob")),
s.definitionOrCallSite is (dbType("varchar(512)"))
)
)
def recordStatementInvocation(sie: StatementInvocationEvent) = {
val statementK = _lookupOrCreateStatementAndReturnKey(sie)
val si = new StatementInvocation(sie, statementK.a1, statementK.a2)
statementInvocations.insert(si)
si.id
}
def recordEndOfIteration(
statementInvocationId: String,
iterationEndTime: Long,
rowCount: Int,
iterationCompleted: Boolean
) = {
update(statementInvocations)(si =>
where(si.id === statementInvocationId)
.set(si.iterationEndTime := Some(iterationEndTime), si.rowCount := Some(rowCount))
)
}
private def _lookupOrCreateStatementAndReturnKey(se: StatementInvocationEvent) = {
val s = new Statement(se.jdbcStatement, se.definitionOrCallSite)
val storedStatement = statements.lookup(s.id)
val result =
if (storedStatement.isEmpty) {
statements.insert(s)
s
} else {
val q =
from(statements)(st => where(st.hash === s.hash).select(st).orderBy(st.statementHashCollisionNumber))
var lastCollisionNum = -1
val mathingStatement =
q.find(st => {
lastCollisionNum = st.statementHashCollisionNumber
st == s
})
if (mathingStatement.isDefined)
mathingStatement.get
else {
s.statementHashCollisionNumber = lastCollisionNum + 1
statements.insert(s)
s
}
}
result.id
}
}