Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
22bd4bd
Merge pull request #1 from apache/master
DaveDeCaprio Nov 27, 2018
b7f964d
Added a configurable limit on the maximum length of a plan debug string.
DaveDeCaprio Nov 28, 2018
3f4fe1f
Removed unneeded imports
DaveDeCaprio Nov 28, 2018
30e4348
Moved withSizeLimitedWriter to treeString function that uses StringWr…
DaveDeCaprio Nov 28, 2018
5528ca1
Fixed formatting
DaveDeCaprio Nov 28, 2018
3171cf3
Coverted to javadoc style multiline comment
DaveDeCaprio Nov 28, 2018
3ffdc6a
Fixed scalastyle formatting of imports
DaveDeCaprio Nov 28, 2018
45a60fc
Have size limit cut off right at the correct number of characters.
DaveDeCaprio Nov 29, 2018
9678799
Changed name to remove the debug from the config parameter name
DaveDeCaprio Nov 29, 2018
a5af842
Fixed formatting error
DaveDeCaprio Nov 29, 2018
a4be985
Changed length default to Long.MaxValue to turn off behavior unless i…
DaveDeCaprio Dec 3, 2018
f0f75c2
Merge branch 'master' of https://github.com/apache/spark into text-pl…
DaveDeCaprio Dec 3, 2018
1b692a0
Added test case for not limiting plan length and tested with a defaul…
DaveDeCaprio Dec 4, 2018
22fe117
Correctly added test case missed in the previous commit
DaveDeCaprio Dec 4, 2018
be3f265
Added more documentation of the plan length parameter.
DaveDeCaprio Dec 8, 2018
f6d0efc
Merge branch 'master' of https://github.com/apache/spark into text-pl…
DaveDeCaprio Dec 8, 2018
855f540
Removed tab
DaveDeCaprio Dec 8, 2018
e83f5f2
Merge branch 'master' of https://github.com/apache/spark into text-pl…
DaveDeCaprio Jan 5, 2019
db663b7
Merge branch 'master' of https://github.com/apache/spark into text-pl…
DaveDeCaprio Jan 20, 2019
2eecbfa
Added plan size limits to StringConcat
DaveDeCaprio Jan 21, 2019
4082aa3
Scalastyle
DaveDeCaprio Jan 21, 2019
f9085e7
Incorporated changes from code review
DaveDeCaprio Jan 21, 2019
b3d43b7
Missed one error
DaveDeCaprio Jan 21, 2019
e470ab2
Cleaned up append function and added tracking of the full plan length.
DaveDeCaprio Jan 21, 2019
35bc1d5
Got rid of unneeded "availableLength" flag.
DaveDeCaprio Jan 21, 2019
5ec58c8
Fixed errors missed
DaveDeCaprio Jan 21, 2019
bdfaf28
Updated to handle nulls again.
DaveDeCaprio Jan 22, 2019
0cfcb4e
Tabs to spaces
DaveDeCaprio Jan 22, 2019
eb69888
Remove useless test.
DaveDeCaprio Jan 22, 2019
daf02f2
Addressed code review comments.
DaveDeCaprio Mar 8, 2019
7d89388
Missed some Boolean->Unit updates
DaveDeCaprio Mar 8, 2019
4f56e48
Missed some Boolean->Unit updates
DaveDeCaprio Mar 8, 2019
a090fbb
Code formatting
DaveDeCaprio Mar 8, 2019
dcb4eb0
Fixed Fatal Warning.
DaveDeCaprio Mar 8, 2019
b4cb7bf
Fixed failing unit tests
DaveDeCaprio Mar 9, 2019
4fec590
Style/formatting issues from code review
DaveDeCaprio Mar 11, 2019
db0db18
Style/formatting issues from code review
DaveDeCaprio Mar 11, 2019
b5b30f3
Changed plan string length to bytesConf and gave a better message for…
DaveDeCaprio Mar 13, 2019
e4afa26
Tabs to spaces
DaveDeCaprio Mar 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import org.apache.spark.sql.catalyst.errors._
import org.apache.spark.sql.catalyst.expressions._
import org.apache.spark.sql.catalyst.plans.JoinType
import org.apache.spark.sql.catalyst.plans.physical.{BroadcastMode, Partitioning}
import org.apache.spark.sql.catalyst.util.truncatedString
import org.apache.spark.sql.catalyst.util.{truncatedString, withSizeLimitedWriter}
import org.apache.spark.sql.types._
import org.apache.spark.storage.StorageLevel

Expand Down Expand Up @@ -473,7 +473,9 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
def treeString(verbose: Boolean, addSuffix: Boolean = false): String = {
val writer = new StringBuilderWriter()
try {
treeString(writer, verbose, addSuffix)
withSizeLimitedWriter(writer) { w =>
treeString(w, verbose, addSuffix)
}
writer.toString
} finally {
writer.close()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.spark.sql.catalyst.util

import java.io.Writer

class WriterSizeException(val attemptedSize: Long, val charLimit: Long) extends Exception(
s"Attempted to write $attemptedSize characters to a writer that is limited to $charLimit")

/**
* This class is used to control the size of generated writers. Guarantees that the total number
* of characters written will be less than the specified size.
*
* Checks size before writing and throws a WriterSizeException if the total size would count the
* limit.
*/
class SizeLimitedWriter(underlying: Writer, charLimit: Long) extends Writer {

var charsWritten: Long = 0

override def write(cbuf: Array[Char], off: Int, len: Int): Unit = {
val newLength = charsWritten + Math.min(cbuf.length - off, len)
if (newLength > charLimit) {
throw new WriterSizeException(newLength, charLimit)
}
charsWritten = newLength
underlying.write(cbuf, off, len)
}

override def flush(): Unit = underlying.flush()

override def close(): Unit = underlying.close()
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,26 @@ package object util extends Logging {
/** Shorthand for calling truncatedString() without start or end strings. */
def truncatedString[T](seq: Seq[T], sep: String): String = truncatedString(seq, "", sep, "")

/** Whether we have warned about plan string truncation yet. */
private val planSizeWarningPrinted = new AtomicBoolean(false)

def withSizeLimitedWriter[T](writer: Writer)(f: (Writer) => T): Option[T] = {
try {
val limited = new SizeLimitedWriter(writer, SQLConf.get.maxPlanStringLength)
Some(f(limited))
}
catch {
case e: WriterSizeException =>
writer.write("...")
if (planSizeWarningPrinted.compareAndSet(false, true)) {
logWarning(
"Truncated the string representation of a plan since it was too long. This " +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is possible I would print out the size of the plan. So, an user could know how much he/she should bump the SQL config.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be possible.

s"behavior can be adjusted by setting '${SQLConf.MAX_PLAN_STRING_LENGTH.key}'.")
}
None
}
}

/* FIX ME
implicit class debugLogging(a: Any) {
def debugLogging() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,12 @@ object SQLConf {
""" "... N more fields" placeholder.""")
.intConf
.createWithDefault(25)

val MAX_PLAN_STRING_LENGTH = buildConf("spark.sql.debug.maxPlanLength")
.doc("Maximum number of characters to output for a plan in debug output. If the plan is " +
"longer, it will end with a ... and further output will be truncated.")
.longConf
.createWithDefault(8192)
}

/**
Expand Down Expand Up @@ -2030,6 +2036,8 @@ class SQLConf extends Serializable with Logging {

def maxToStringFields: Int = getConf(SQLConf.MAX_TO_STRING_FIELDS)

def maxPlanStringLength: Long = getConf(SQLConf.MAX_PLAN_STRING_LENGTH)

/** ********************** SQLConf functionality methods ************ */

/** Set Spark SQL configuration properties. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ import java.math.BigInteger
import java.util.UUID

import scala.collection.mutable.ArrayBuffer

import org.json4s.JsonAST._
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods
import org.json4s.jackson.JsonMethods._

import org.apache.spark.SparkFunSuite
import org.apache.spark.sql.catalyst.{FunctionIdentifier, InternalRow, TableIdentifier}
import org.apache.spark.sql.catalyst.catalog._
Expand All @@ -36,6 +34,7 @@ import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
import org.apache.spark.sql.catalyst.plans.{LeftOuter, NaturalJoin}
import org.apache.spark.sql.catalyst.plans.logical.{LeafNode, Union}
import org.apache.spark.sql.catalyst.plans.physical.{IdentityBroadcastMode, RoundRobinPartitioning, SinglePartition}
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.types._
import org.apache.spark.storage.StorageLevel

Expand Down Expand Up @@ -595,4 +594,14 @@ class TreeNodeSuite extends SparkFunSuite {
val expected = Coalesce(Stream(Literal(1), Literal(3)))
assert(result === expected)
}

test("toString() tree depth") {
val ds = (1 until 100).foldLeft(Literal("TestLiteral"): Expression) { case (treeNode, x) =>
Add(Literal(x), treeNode)
}

val planString = ds.treeString
assert(planString.endsWith("..."))
assert(planString.length <= SQLConf.get.maxPlanStringLength)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.spark.sql.catalyst.util

import org.apache.commons.io.output.StringBuilderWriter

import org.apache.spark.SparkFunSuite
import org.apache.spark.sql.catalyst.util.StringUtils._

class SizeLimitedWriterSuite extends SparkFunSuite {

test("normal writer under limit") {
val writer = new StringBuilderWriter()
val limited = new SizeLimitedWriter(writer, 100)
limited.write("test")
limited.write("test")

assert(writer.toString === "testtest")
}

test("filter pattern") {
val writer = new StringBuilderWriter()
val limited = new SizeLimitedWriter(writer, 5)
assertThrows[WriterSizeException] {
limited.write("test")
limited.write("test")
}
assert(writer.toString === "test")
}
}