Skip to content

[SPARK-25986][Build] Add rules to ban throw Errors in application code #22989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -39,7 +39,9 @@ public static int getSize(Object object, long offset) {
case 8:
return (int)Platform.getLong(object, offset);
default:
// checkstyle.off: RegexpSinglelineJava
throw new AssertionError("Illegal UAO_SIZE");
Copy link
Contributor

Choose a reason for hiding this comment

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

shall we throw IllegalStateException here?

Copy link
Member

Choose a reason for hiding this comment

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

I think these are ok as AssertionError because they shouldn't be able to happen in any JVM state

Copy link
Contributor

Choose a reason for hiding this comment

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

yea, that's exactly the use case of IllegalStateException, which can also pass the style check here.

Copy link
Member

Choose a reason for hiding this comment

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

It would be OK too. This is just picking nits now but I thought AssertionError was still better. ISE is about application state. Errors are about JVM state.

// checkstyle.on: RegexpSinglelineJava
}
}

Expand All @@ -52,7 +54,9 @@ public static void putSize(Object object, long offset, int value) {
Platform.putLong(object, offset, value);
break;
default:
// checkstyle.off: RegexpSinglelineJava
throw new AssertionError("Illegal UAO_SIZE");
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

// checkstyle.on: RegexpSinglelineJava
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ private void throwOom(final MemoryBlock page, final long required) {
taskMemoryManager.freePage(page, this);
}
taskMemoryManager.showMemoryUsage();
// checkstyle.off: RegexpSinglelineJava
throw new SparkOutOfMemoryError("Unable to acquire " + required + " bytes of memory, got " +
got);
// checkstyle.on: RegexpSinglelineJava
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,10 @@ public long acquireExecutionMemory(long required, MemoryConsumer consumer) {
throw new RuntimeException(e.getMessage());
} catch (IOException e) {
logger.error("error while calling spill() on " + c, e);
// checkstyle.off: RegexpSinglelineJava
throw new SparkOutOfMemoryError("error while calling spill() on " + c + " : "
+ e.getMessage());
// checkstyle.on: RegexpSinglelineJava
}
}
}
Expand All @@ -215,8 +217,10 @@ public long acquireExecutionMemory(long required, MemoryConsumer consumer) {
throw new RuntimeException(e.getMessage());
} catch (IOException e) {
logger.error("error while calling spill() on " + consumer, e);
// checkstyle.off: RegexpSinglelineJava
throw new SparkOutOfMemoryError("error while calling spill() on " + consumer + " : "
+ e.getMessage());
// checkstyle.on: RegexpSinglelineJava
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ public boolean hasSpaceForAnotherRecord() {

public void expandPointerArray(LongArray newArray) {
if (newArray.size() < array.size()) {
// checkstyle.off: RegexpSinglelineJava
throw new SparkOutOfMemoryError("Not enough memory to grow pointer array");
// checkstyle.on: RegexpSinglelineJava
}
Platform.copyMemory(
array.getBaseObject(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ trait RandomSampler[T, U] extends Pseudorandom with Cloneable with Serializable

/** return a copy of the RandomSampler object */
override def clone: RandomSampler[T, U] =
throw new NotImplementedError("clone() is not implemented.")
throw new UnsupportedOperationException("clone() is not implemented.")
}

private[spark]
Expand Down
2 changes: 2 additions & 0 deletions core/src/test/scala/org/apache/spark/FailureSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,9 @@ class FailureSuite extends SparkFunSuite with LocalSparkContext {
sc = new SparkContext("local[1,2]", "test")
intercept[SparkException] {
sc.parallelize(1 to 2).foreach { i =>
// scalastyle:off throwerror
throw new LinkageError()
// scalastyle:on throwerror
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,9 @@ class FetchFailureHidingRDD(
} catch {
case t: Throwable =>
if (throwOOM) {
// scalastyle:off throwerror
throw new OutOfMemoryError("OOM while handling another exception")
// scalastyle:on throwerror
} else if (interrupt) {
// make sure our test is setup correctly
assert(TaskContext.get().asInstanceOf[TaskContextImpl].fetchFailed.isDefined)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ class TaskResultGetterSuite extends SparkFunSuite with BeforeAndAfter with Local

private class UndeserializableException extends Exception {
private def readObject(in: ObjectInputStream): Unit = {
// scalastyle:off throwerror
throw new NoClassDefFoundError()
// scalastyle:on throwerror
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ class BlockManagerSuite extends SparkFunSuite with Matchers with BeforeAndAfterE
"list1",
StorageLevel.MEMORY_ONLY,
ClassTag.Any,
() => throw new AssertionError("attempted to compute locally")).isLeft)
() => fail("attempted to compute locally")).isLeft)
}

test("in-memory LRU storage") {
Expand Down
13 changes: 9 additions & 4 deletions dev/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@
If you wish to turn off checking for a section of code, you can put a comment in the source
before and after the section, with the following syntax:

// checkstyle:off no.XXX (such as checkstyle.off: NoFinalizer)
// checkstyle.off: XXX (such as checkstyle.off: NoFinalizer)
... // stuff that breaks the styles
// checkstyle:on
// checkstyle.on: XXX (such as checkstyle.on: NoFinalizer)
-->
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="checkstyle.off\: ([\w\|]+)"/>
<property name="onCommentFormat" value="checkstyle.on\: ([\w\|]+)"/>
<property name="offCommentFormat" value="checkstyle\.off\: ([\w\|]+)"/>
<property name="onCommentFormat" value="checkstyle\.on\: ([\w\|]+)"/>
<property name="checkFormat" value="$1"/>
</module>
<module name="OuterTypeFilename"/>
Expand Down Expand Up @@ -180,5 +180,10 @@
<module name="UnusedImports"/>
<module name="RedundantImport"/>
<module name="RedundantModifier"/>
<module name="RegexpSinglelineJava">
<property name="format" value="throw new \w+Error\("/>
<property name="message" value="Avoid throwing error in application code."/>
Copy link
Member

Choose a reason for hiding this comment

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

What application code means here?

Copy link
Member Author

Choose a reason for hiding this comment

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

application code against JVM here, as Error subclasses generally represent internal JVM errors.

</module>

</module>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object KafkaUtils extends Logging {
): RDD[ConsumerRecord[K, V]] = {
val preferredHosts = locationStrategy match {
case PreferBrokers =>
throw new AssertionError(
throw new IllegalArgumentException(
"If you want to prefer brokers, you must provide a mapping using PreferFixed " +
"A single KafkaRDD does not have a driver consumer and cannot look up brokers for you.")
case PreferConsistent => ju.Collections.emptyMap[TopicPartition, String]()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ sealed trait Vector extends Serializable {
*/
@Since("2.0.0")
def copy: Vector = {
throw new NotImplementedError(s"copy is not implemented for ${this.getClass}.")
throw new UnsupportedOperationException(s"copy is not implemented for ${this.getClass}.")
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class NaiveBayes @Since("1.5.0") (
requireZeroOneBernoulliValues
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: ${$(modelType)}.")
throw new IllegalArgumentException(s"Invalid modelType: ${$(modelType)}.")
}
}

Expand Down Expand Up @@ -196,7 +196,7 @@ class NaiveBayes @Since("1.5.0") (
case Bernoulli => math.log(n + 2.0 * lambda)
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: ${$(modelType)}.")
throw new IllegalArgumentException(s"Invalid modelType: ${$(modelType)}.")
}
var j = 0
while (j < numFeatures) {
Expand Down Expand Up @@ -295,7 +295,7 @@ class NaiveBayesModel private[ml] (
(Option(thetaMinusNegTheta), Option(negTheta.multiply(ones)))
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: ${$(modelType)}.")
throw new IllegalArgumentException(s"Invalid modelType: ${$(modelType)}.")
}

@Since("1.6.0")
Expand Down Expand Up @@ -329,7 +329,7 @@ class NaiveBayesModel private[ml] (
bernoulliCalculation(features)
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: ${$(modelType)}.")
throw new IllegalArgumentException(s"Invalid modelType: ${$(modelType)}.")
}
}

Expand Down
4 changes: 2 additions & 2 deletions mllib/src/main/scala/org/apache/spark/ml/param/params.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Param[T](val parent: String, val name: String, val doc: String, val isVali
case m: Matrix =>
JsonMatrixConverter.toJson(m)
case _ =>
throw new NotImplementedError(
throw new UnsupportedOperationException(
"The default jsonEncode only supports string, vector and matrix. " +
s"${this.getClass.getName} must override jsonEncode for ${value.getClass.getName}.")
}
Expand Down Expand Up @@ -151,7 +151,7 @@ private[ml] object Param {
}

case _ =>
throw new NotImplementedError(
throw new UnsupportedOperationException(
"The default jsonDecode only supports string, vector and matrix. " +
s"${this.getClass.getName} must override jsonDecode to support its value type.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ private[ml] object ValidatorParams {
"value" -> compact(render(JString(relativePath))),
"isJson" -> compact(render(JBool(false))))
case _: MLWritable =>
throw new NotImplementedError("ValidatorParams.saveImpl does not handle parameters " +
"of type: MLWritable that are not DefaultParamsWritable")
throw new UnsupportedOperationException("ValidatorParams.saveImpl does not handle" +
" parameters of type: MLWritable that are not DefaultParamsWritable")
case _ =>
Map("parent" -> p.parent, "name" -> p.name, "value" -> p.jsonEncode(v),
"isJson" -> compact(render(JBool(true))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class NaiveBayesModel private[spark] (
(Option(thetaMinusNegTheta), Option(negTheta.multiply(ones)))
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: $modelType.")
throw new IllegalArgumentException(s"Invalid modelType: $modelType.")
}

@Since("1.0.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ sealed trait Vector extends Serializable {
*/
@Since("1.1.0")
def copy: Vector = {
throw new NotImplementedError(s"copy is not implemented for ${this.getClass}.")
throw new UnsupportedOperationException(s"copy is not implemented for ${this.getClass}.")
}

/**
Expand Down
6 changes: 3 additions & 3 deletions mllib/src/test/scala/org/apache/spark/ml/PredictorSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object PredictorSuite {
}

override def copy(extra: ParamMap): MockPredictor =
throw new NotImplementedError()
throw new UnsupportedOperationException()
}

class MockPredictionModel(override val uid: String)
Expand All @@ -82,9 +82,9 @@ object PredictorSuite {
def this() = this(Identifiable.randomUID("mockpredictormodel"))

override def predict(features: Vector): Double =
throw new NotImplementedError()
throw new UnsupportedOperationException()

override def copy(extra: ParamMap): MockPredictionModel =
throw new NotImplementedError()
throw new UnsupportedOperationException()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ object ClassifierSuite {

def this() = this(Identifiable.randomUID("mockclassifier"))

override def copy(extra: ParamMap): MockClassifier = throw new NotImplementedError()
override def copy(extra: ParamMap): MockClassifier = throw new UnsupportedOperationException()

override def train(dataset: Dataset[_]): MockClassificationModel =
throw new NotImplementedError()
throw new UnsupportedOperationException()

// Make methods public
override def extractLabeledPoints(dataset: Dataset[_], numClasses: Int): RDD[LabeledPoint] =
Expand All @@ -133,11 +133,12 @@ object ClassifierSuite {

def this() = this(Identifiable.randomUID("mockclassificationmodel"))

protected def predictRaw(features: Vector): Vector = throw new NotImplementedError()
protected def predictRaw(features: Vector): Vector = throw new UnsupportedOperationException()

override def copy(extra: ParamMap): MockClassificationModel = throw new NotImplementedError()
override def copy(extra: ParamMap): MockClassificationModel =
throw new UnsupportedOperationException()

override def numClasses: Int = throw new NotImplementedError()
override def numClasses: Int = throw new UnsupportedOperationException()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class NaiveBayesSuite extends MLTest with DefaultReadWriteTest {
case Bernoulli =>
expectedBernoulliProbabilities(model, features)
case _ =>
throw new UnknownError(s"Invalid modelType: $modelType.")
throw new IllegalArgumentException(s"Invalid modelType: $modelType.")
}
assert(probability ~== expected relTol 1.0e-10)
}
Expand Down Expand Up @@ -378,7 +378,7 @@ object NaiveBayesSuite {
counts.toArray.sortBy(_._1).map(_._2)
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: $modelType.")
throw new IllegalArgumentException(s"Invalid modelType: $modelType.")
}

LabeledPoint(y, Vectors.dense(xi))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ class OneVsRestSuite extends MLTest with DefaultReadWriteTest {
assert(lrModel1.coefficients ~== lrModel2.coefficients relTol 1E-3)
assert(lrModel1.intercept ~== lrModel2.intercept relTol 1E-3)
case other =>
throw new AssertionError(s"Loaded OneVsRestModel expected model of type" +
s" LogisticRegressionModel but found ${other.getClass.getName}")
fail("Loaded OneVsRestModel expected model of type LogisticRegressionModel " +
s"but found ${other.getClass.getName}")
}
}

Expand Down Expand Up @@ -247,8 +247,8 @@ class OneVsRestSuite extends MLTest with DefaultReadWriteTest {
assert(lr.getMaxIter === lr2.getMaxIter)
assert(lr.getRegParam === lr2.getRegParam)
case other =>
throw new AssertionError(s"Loaded OneVsRest expected classifier of type" +
s" LogisticRegression but found ${other.getClass.getName}")
fail("Loaded OneVsRest expected classifier of type LogisticRegression" +
s" but found ${other.getClass.getName}")
}
}

Expand All @@ -267,8 +267,8 @@ class OneVsRestSuite extends MLTest with DefaultReadWriteTest {
assert(classifier.getMaxIter === lr2.getMaxIter)
assert(classifier.getRegParam === lr2.getRegParam)
case other =>
throw new AssertionError(s"Loaded OneVsRestModel expected classifier of type" +
s" LogisticRegression but found ${other.getClass.getName}")
fail("Loaded OneVsRestModel expected classifier of type LogisticRegression" +
s" but found ${other.getClass.getName}")
}

assert(model.labelMetadata === model2.labelMetadata)
Expand All @@ -278,8 +278,8 @@ class OneVsRestSuite extends MLTest with DefaultReadWriteTest {
assert(lrModel1.coefficients === lrModel2.coefficients)
assert(lrModel1.intercept === lrModel2.intercept)
case other =>
throw new AssertionError(s"Loaded OneVsRestModel expected model of type" +
s" LogisticRegressionModel but found ${other.getClass.getName}")
fail(s"Loaded OneVsRestModel expected model of type LogisticRegressionModel" +
s" but found ${other.getClass.getName}")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ class VectorIndexerSuite extends MLTest with DefaultReadWriteTest with Logging {
points.zip(rows.map(_(0))).foreach {
case (orig: SparseVector, indexed: SparseVector) =>
assert(orig.indices.length == indexed.indices.length)
case _ => throw new UnknownError("Unit test has a bug in it.") // should never happen
case _ =>
// should never happen
fail("Unit test has a bug in it.")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,9 @@ class RandomForestSuite extends SparkFunSuite with MLlibTestSparkContext {
case n: InternalNode => n.split match {
case s: CategoricalSplit =>
assert(s.leftCategories === Array(1.0))
case _ => throw new AssertionError("model.rootNode.split was not a CategoricalSplit")
case _ => fail("model.rootNode.split was not a CategoricalSplit")
}
case _ => throw new AssertionError("model.rootNode was not an InternalNode")
case _ => fail("model.rootNode was not an InternalNode")
}
}

Expand All @@ -444,7 +444,7 @@ class RandomForestSuite extends SparkFunSuite with MLlibTestSparkContext {
assert(n.leftChild.isInstanceOf[InternalNode])
assert(n.rightChild.isInstanceOf[InternalNode])
Array(n.leftChild.asInstanceOf[InternalNode], n.rightChild.asInstanceOf[InternalNode])
case _ => throw new AssertionError("rootNode was not an InternalNode")
case _ => fail("rootNode was not an InternalNode")
}

// Single group second level tree construction.
Expand Down
Loading