Skip to content

Commit 06fd668

Browse files
author
Andrew Or
committed
Make closure cleaning idempotent
We need this for tests because we clean the same closure many times there. Outside of tests this is probably not important.
1 parent a4866e3 commit 06fd668

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

core/src/main/scala/org/apache/spark/util/ClosureCleaner.scala

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,13 @@ object ClosureCleaner extends Logging {
5858
private def getOuterClasses(obj: AnyRef): List[Class[_]] = {
5959
for (f <- obj.getClass.getDeclaredFields if f.getName == "$outer") {
6060
f.setAccessible(true)
61-
if (isClosure(f.getType)) {
62-
return f.getType :: getOuterClasses(f.get(obj))
63-
} else {
64-
return f.getType :: Nil // Stop at the first $outer that is not a closure
61+
val outer = f.get(obj)
62+
if (outer != null) {
63+
if (isClosure(f.getType)) {
64+
return f.getType :: getOuterClasses(f.get(obj))
65+
} else {
66+
return f.getType :: Nil // Stop at the first $outer that is not a closure
67+
}
6568
}
6669
}
6770
Nil
@@ -71,10 +74,13 @@ object ClosureCleaner extends Logging {
7174
private def getOuterObjects(obj: AnyRef): List[AnyRef] = {
7275
for (f <- obj.getClass.getDeclaredFields if f.getName == "$outer") {
7376
f.setAccessible(true)
74-
if (isClosure(f.getType)) {
75-
return f.get(obj) :: getOuterObjects(f.get(obj))
76-
} else {
77-
return f.get(obj) :: Nil // Stop at the first $outer that is not a closure
77+
val outer = f.get(obj)
78+
if (outer != null) {
79+
if (isClosure(f.getType)) {
80+
return f.get(obj) :: getOuterObjects(f.get(obj))
81+
} else {
82+
return f.get(obj) :: Nil // Stop at the first $outer that is not a closure
83+
}
7884
}
7985
}
8086
Nil
@@ -167,11 +173,15 @@ object ClosureCleaner extends Logging {
167173
func: AnyRef,
168174
checkSerializable: Boolean,
169175
cleanTransitively: Boolean,
170-
accessedFields: Map[Class[_], Set[String]]) {
176+
accessedFields: Map[Class[_], Set[String]]): Unit = {
171177

172178
// TODO: clean all inner closures first. This requires us to find the inner objects.
173179
// TODO: cache outerClasses / innerClasses / accessedFields
174180

181+
if (func == null) {
182+
return
183+
}
184+
175185
logDebug(s"+++ Cleaning closure $func (${func.getClass.getName}}) +++")
176186

177187
// A list of classes that represents closures enclosed in the given one

0 commit comments

Comments
 (0)