Skip to content

Commit c9df6f9

Browse files
committed
add testsuite for thriftserver ui and fix some style issue
1 parent 9830199 commit c9df6f9

File tree

8 files changed

+202
-68
lines changed

8 files changed

+202
-68
lines changed

sql/core/src/main/scala/org/apache/spark/sql/SQLConf.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ private[spark] object SQLConf {
5151

5252
// This is only used for the thriftserver
5353
val THRIFTSERVER_POOL = "spark.sql.thriftserver.scheduler.pool"
54+
val THRIFTSERVER_UI_STATEMENT_LIMIT = "spark.sql.thriftserver.ui.retainedStatements"
55+
val THRIFTSERVER_UI_SESSION_LIMIT = "spark.sql.thriftserver.ui.retainedSessions"
5456

5557
// This is used to set the default data source
5658
val DEFAULT_DATA_SOURCE_NAME = "spark.sql.sources.default"

sql/hive-thriftserver/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<dependency>
4545
<groupId>com.google.guava</groupId>
4646
<artifactId>guava</artifactId>
47+
<scope>runtime</scope>
4748
</dependency>
4849
<dependency>
4950
<groupId>${hive.group}</groupId>
@@ -57,6 +58,18 @@
5758
<groupId>${hive.group}</groupId>
5859
<artifactId>hive-beeline</artifactId>
5960
</dependency>
61+
<!-- Added for selenium: -->
62+
<dependency>
63+
<groupId>org.seleniumhq.selenium</groupId>
64+
<artifactId>selenium-java</artifactId>
65+
<scope>test</scope>
66+
<exclusions>
67+
<exclusion>
68+
<groupId>io.netty</groupId>
69+
<artifactId>netty</artifactId>
70+
</exclusion>
71+
</exclusions>
72+
</dependency>
6073
</dependencies>
6174
<build>
6275
<outputDirectory>target/scala-${scala.binary.version}/classes</outputDirectory>

sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/HiveThriftServer2.scala

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.apache.hadoop.hive.conf.HiveConf
2222
import org.apache.hadoop.hive.conf.HiveConf.ConfVars
2323
import org.apache.hive.service.cli.thrift.{ThriftBinaryCLIService, ThriftHttpCLIService}
2424
import org.apache.hive.service.server.{HiveServer2, ServerOptionsProcessor}
25+
import org.apache.spark.sql.SQLConf
2526

2627
import org.apache.spark.{SparkContext, SparkConf, Logging}
2728
import org.apache.spark.annotation.DeveloperApi
@@ -52,7 +53,7 @@ object HiveThriftServer2 extends Logging {
5253
val server = new HiveThriftServer2(sqlContext)
5354
server.init(sqlContext.hiveconf)
5455
server.start()
55-
listener = new HiveThriftServer2Listener(server, sqlContext.sparkContext.conf)
56+
listener = new HiveThriftServer2Listener(server, sqlContext.conf)
5657
sqlContext.sparkContext.addSparkListener(listener)
5758
uiTab = if (sqlContext.sparkContext.getConf.getBoolean("spark.ui.enabled", true)) {
5859
Some(new ThriftServerTab(sqlContext.sparkContext))
@@ -80,7 +81,7 @@ object HiveThriftServer2 extends Logging {
8081
server.init(SparkSQLEnv.hiveContext.hiveconf)
8182
server.start()
8283
logInfo("HiveThriftServer2 started")
83-
listener = new HiveThriftServer2Listener(server, SparkSQLEnv.sparkContext.conf)
84+
listener = new HiveThriftServer2Listener(server, SparkSQLEnv.hiveContext.conf)
8485
SparkSQLEnv.sparkContext.addSparkListener(listener)
8586
uiTab = if (SparkSQLEnv.sparkContext.getConf.getBoolean("spark.ui.enabled", true)) {
8687
Some(new ThriftServerTab(SparkSQLEnv.sparkContext))
@@ -100,10 +101,10 @@ object HiveThriftServer2 extends Logging {
100101
val ip: String,
101102
val userName: String) {
102103
var finishTimestamp: Long = 0L
103-
var totalExecute: Int = 0
104+
var totalExecution: Int = 0
104105
def totalTime: Long = {
105106
if (finishTimestamp == 0L) {
106-
System.currentTimeMillis() - startTimestamp
107+
System.currentTimeMillis - startTimestamp
107108
} else {
108109
finishTimestamp - startTimestamp
109110
}
@@ -139,43 +140,37 @@ object HiveThriftServer2 extends Logging {
139140
/**
140141
* A inner sparkListener called in sc.stop to clean up the HiveThriftServer2
141142
*/
142-
class HiveThriftServer2Listener(
143+
private[thriftserver] class HiveThriftServer2Listener(
143144
val server: HiveServer2,
144-
val conf: SparkConf) extends SparkListener {
145+
val conf: SQLConf) extends SparkListener {
145146

146147
override def onApplicationEnd(applicationEnd: SparkListenerApplicationEnd): Unit = {
147148
server.stop()
148149
}
149150

150-
val sessionList = new mutable.HashMap[String, SessionInfo]
151-
val executeList = new mutable.HashMap[String, ExecutionInfo]
151+
val sessionList = new mutable.LinkedHashMap[String, SessionInfo]
152+
val executionList = new mutable.LinkedHashMap[String, ExecutionInfo]
152153
val retainedStatements =
153-
conf.getInt("spark.thriftserver.ui.retainedStatements", 200)
154+
conf.getConf(SQLConf.THRIFTSERVER_UI_STATEMENT_LIMIT, "200").toInt
154155
val retainedSessions =
155-
conf.getInt("spark.thriftserver.ui.retainedSessions", 200)
156+
conf.getConf(SQLConf.THRIFTSERVER_UI_SESSION_LIMIT, "200").toInt
156157
var totalRunning = 0
157158

158159
override def onJobStart(jobStart: SparkListenerJobStart): Unit = {
159-
val jobGroup = for (
160-
props <- Option(jobStart.properties);
161-
statement <- Option(props.getProperty(SparkContext.SPARK_JOB_GROUP_ID))
162-
) yield statement
163-
164-
jobGroup.map( groupId => {
165-
val ret = executeList.find( _ match {
166-
case (id: String, info: ExecutionInfo) => info.groupId == groupId
167-
})
168-
if (ret.isDefined) {
169-
ret.get._2.jobId += jobStart.jobId.toString
170-
ret.get._2.groupId = groupId
171-
}
172-
})
160+
for {
161+
props <- Option(jobStart.properties)
162+
groupId <- Option(props.getProperty(SparkContext.SPARK_JOB_GROUP_ID))
163+
(_, info) <- executionList if info.groupId == groupId
164+
} {
165+
info.jobId += jobStart.jobId.toString
166+
info.groupId = groupId
167+
}
173168
}
174169

175170
def onSessionCreated(ip: String, sessionId: String, userName: String = "UNKNOWN"): Unit = {
176171
val info = new SessionInfo(sessionId, System.currentTimeMillis, ip, userName)
177-
sessionList(sessionId) = info
178-
trimSessionIfNecessary
172+
sessionList.put(sessionId, info)
173+
trimSessionIfNecessary()
179174
}
180175

181176
def onSessionClosed(sessionId: String): Unit = {
@@ -190,44 +185,44 @@ object HiveThriftServer2 extends Logging {
190185
userName: String = "UNKNOWN"): Unit = {
191186
val info = new ExecutionInfo(statement, sessionId, System.currentTimeMillis, userName)
192187
info.state = ExecutionState.STARTED
193-
executeList(id) = info
194-
trimExecutionIfNecessary
195-
sessionList(sessionId).totalExecute += 1
196-
executeList(id).groupId = groupId
188+
executionList.put(id, info)
189+
trimExecutionIfNecessary()
190+
sessionList(sessionId).totalExecution += 1
191+
executionList(id).groupId = groupId
197192
totalRunning += 1
198193
}
199194

200-
def onStatementParse(id: String, executePlan: String): Unit = {
201-
executeList(id).executePlan = executePlan
202-
executeList(id).state = ExecutionState.COMPILED
195+
def onStatementParsed(id: String, executionPlan: String): Unit = {
196+
executionList(id).executePlan = executionPlan
197+
executionList(id).state = ExecutionState.COMPILED
203198
}
204199

205200
def onStatementError(id: String, errorMessage: String, errorTrace: String): Unit = {
206-
executeList(id).finishTimestamp = System.currentTimeMillis
207-
executeList(id).detail = errorMessage
208-
executeList(id).state = ExecutionState.FAILED
201+
executionList(id).finishTimestamp = System.currentTimeMillis
202+
executionList(id).detail = errorMessage
203+
executionList(id).state = ExecutionState.FAILED
209204
totalRunning -= 1
210205
}
211206

212207
def onStatementFinish(id: String): Unit = {
213-
executeList(id).finishTimestamp = System.currentTimeMillis
214-
executeList(id).state = ExecutionState.FINISHED
208+
executionList(id).finishTimestamp = System.currentTimeMillis
209+
executionList(id).state = ExecutionState.FINISHED
215210
totalRunning -= 1
216211
}
217212

218-
private def trimExecutionIfNecessary = synchronized {
219-
if (executeList.size > retainedStatements) {
213+
private def trimExecutionIfNecessary() = synchronized {
214+
if (executionList.size > retainedStatements) {
220215
val toRemove = math.max(retainedStatements / 10, 1)
221-
executeList.toList.sortBy(_._2.startTimestamp).take(toRemove).foreach { s =>
222-
executeList.remove(s._1)
216+
executionList.take(toRemove).foreach { s =>
217+
executionList.remove(s._1)
223218
}
224219
}
225220
}
226221

227-
private def trimSessionIfNecessary = synchronized {
222+
private def trimSessionIfNecessary() = synchronized {
228223
if (sessionList.size > retainedSessions) {
229224
val toRemove = math.max(retainedSessions / 10, 1)
230-
sessionList.toList.sortBy(_._2.startTimestamp).take(toRemove).foreach { s =>
225+
sessionList.take(toRemove).foreach { s =>
231226
sessionList.remove(s._1)
232227
}
233228
}

sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/ui/ThriftServerPage.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ package org.apache.spark.sql.hive.thriftserver.ui
2020
import java.util.Calendar
2121
import javax.servlet.http.HttpServletRequest
2222

23+
import scala.xml.Node
24+
2325
import org.apache.commons.lang3.StringEscapeUtils
2426
import org.apache.spark.Logging
2527
import org.apache.spark.sql.hive.thriftserver.HiveThriftServer2.{SessionInfo, ExecutionState, ExecutionInfo}
2628
import org.apache.spark.ui.UIUtils._
2729
import org.apache.spark.ui._
2830

29-
import scala.xml.Node
3031

3132
/** Page for Spark Web UI that shows statistics of a streaming job */
3233
private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage("") with Logging {
@@ -41,8 +42,8 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
4142
generateBasicStats() ++
4243
<br/> ++
4344
<h4>
44-
Total {listener.sessionList.size} session online,
45-
Total {listener.totalRunning} sql running
45+
{listener.sessionList.size} session(s) are online,
46+
running {listener.totalRunning} SQL statement(s)
4647
</h4> ++
4748
generateSessionStatsTable() ++
4849
generateSQLStatsTable()
@@ -64,11 +65,11 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
6465

6566
/** Generate stats of batch statements of the thrift server program */
6667
private def generateSQLStatsTable(): Seq[Node] = {
67-
val numStatement = listener.executeList.size
68+
val numStatement = listener.executionList.size
6869
val table = if (numStatement > 0) {
6970
val headerRow = Seq("User", "JobID", "GroupID", "Start Time", "Finish Time", "Duration",
7071
"Statement", "State", "Detail")
71-
val dataRows = listener.executeList.values.toSeq.sortBy(_.startTimestamp).reverse
72+
val dataRows = listener.executionList.values
7273

7374
def generateDataRow(info: ExecutionInfo): Seq[Node] = {
7475
val jobLink = info.jobId.map { id: String =>
@@ -99,7 +100,7 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
99100
}
100101

101102
val content =
102-
<h5>SQL Statistics</h5> ++
103+
<h5 id="sqlstat">SQL Statistics</h5> ++
103104
<div>
104105
<ul class="unstyled">
105106
{table.getOrElse("No statistics have been generated yet.")}
@@ -138,7 +139,7 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
138139
val numBatches = listener.sessionList.size
139140
val table = if (numBatches > 0) {
140141
val dataRows =
141-
listener.sessionList.values.toSeq.sortBy(_.startTimestamp).reverse
142+
listener.sessionList.values
142143
val headerRow = Seq("User", "IP", "Session ID", "Start Time", "Finish Time", "Duration",
143144
"Total Execute")
144145
def generateDataRow(session: SessionInfo): Seq[Node] = {
@@ -151,7 +152,7 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
151152
<td> {formatDate(session.startTimestamp)} </td>
152153
<td> {if(session.finishTimestamp > 0) formatDate(session.finishTimestamp)} </td>
153154
<td> {formatDurationOption(Some(session.totalTime))} </td>
154-
<td> {session.totalExecute.toString} </td>
155+
<td> {session.totalExecution.toString} </td>
155156
</tr>
156157
}
157158
Some(UIUtils.listingTable(headerRow, generateDataRow, dataRows, true, None, Seq(null), false))
@@ -160,7 +161,7 @@ private[ui] class ThriftServerPage(parent: ThriftServerTab) extends WebUIPage(""
160161
}
161162

162163
val content =
163-
<h5>Session Statistics</h5> ++
164+
<h5 id="sessionstat">Session Statistics</h5> ++
164165
<div>
165166
<ul class="unstyled">
166167
{table.getOrElse("No statistics have been generated yet.")}

sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/ui/ThriftServerSessionPage.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ package org.apache.spark.sql.hive.thriftserver.ui
2020
import java.util.Calendar
2121
import javax.servlet.http.HttpServletRequest
2222

23+
import scala.xml.Node
24+
2325
import org.apache.commons.lang3.StringEscapeUtils
2426
import org.apache.spark.Logging
2527
import org.apache.spark.sql.hive.thriftserver.HiveThriftServer2.{ExecutionInfo, ExecutionState}
2628
import org.apache.spark.ui.UIUtils._
2729
import org.apache.spark.ui._
2830

29-
import scala.xml.Node
30-
3131
/** Page for Spark Web UI that shows statistics of a streaming job */
3232
private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
3333
extends WebUIPage("session") with Logging {
@@ -52,7 +52,7 @@ private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
5252
User {sessionStat._2.userName},
5353
IP {sessionStat._2.ip},
5454
Session created at {formatDate(sessionStat._2.startTimestamp)},
55-
Total run {sessionStat._2.totalExecute} SQL
55+
Total run {sessionStat._2.totalExecution} SQL
5656
</h4> ++
5757
generateSQLStatsTable(sessionStat._2.sessionId)
5858
UIUtils.headerSparkPage("ThriftServer", content, parent, Some(5000))
@@ -73,7 +73,7 @@ private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
7373

7474
/** Generate stats of batch statements of the thrift server program */
7575
private def generateSQLStatsTable(sessionID: String): Seq[Node] = {
76-
val executionList = listener.executeList
76+
val executionList = listener.executionList
7777
.filter(_._2.sessionId == sessionID)
7878
val numStatement = executionList.size
7979
val table = if (numStatement > 0) {
@@ -157,7 +157,7 @@ private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
157157
formatDate(session.startTimestamp),
158158
formatDate(session.finishTimestamp),
159159
formatDurationOption(Some(session.totalTime)),
160-
session.totalExecute.toString
160+
session.totalExecution.toString
161161
)
162162
).toSeq
163163
val headerRow = Seq("User", "IP", "Session ID", "Start Time", "Finish Time", "Duration",

0 commit comments

Comments
 (0)