@@ -72,6 +72,8 @@ final class ShuffleExternalSorter extends MemoryConsumer {
7272 private final BlockManager blockManager ;
7373 private final TaskContext taskContext ;
7474 private final ShuffleWriteMetrics writeMetrics ;
75+ private long totalSpillBytes = 0L ;
76+ private long shuffleSpillThreshold = 0L ;
7577
7678 /**
7779 * Force this sorter to spill when there are this many elements in memory. The default value is
@@ -117,6 +119,7 @@ final class ShuffleExternalSorter extends MemoryConsumer {
117119 this .numPartitions = numPartitions ;
118120 // Use getSizeAsKb (not bytes) to maintain backwards compatibility if no units are provided
119121 this .fileBufferSizeBytes = (int ) conf .getSizeAsKb ("spark.shuffle.file.buffer" , "32k" ) * 1024 ;
122+ this .shuffleSpillThreshold = conf .getSizeAsBytes ("spark.shuffle.spill.limit" , "10g" );
120123 this .numElementsForSpillThreshold =
121124 conf .getLong ("spark.shuffle.spill.numElementsForceSpillThreshold" , 1024 * 1024 * 1024 );
122125 this .writeMetrics = writeMetrics ;
@@ -245,6 +248,10 @@ public long spill(long size, MemoryConsumer trigger) throws IOException {
245248 return 0L ;
246249 }
247250
251+ if (totalSpillBytes > shuffleSpillThreshold ) {
252+ throw new IOException ("Shuffle spill exceed " + shuffleSpillThreshold );
253+ }
254+
248255 logger .info ("Thread {} spilling sort data of {} to disk ({} {} so far)" ,
249256 Thread .currentThread ().getId (),
250257 Utils .bytesToString (getMemoryUsage ()),
@@ -258,6 +265,7 @@ public long spill(long size, MemoryConsumer trigger) throws IOException {
258265 // records. Otherwise, if the task is over allocated memory, then without freeing the memory
259266 // pages, we might not be able to get memory for the pointer array.
260267 taskContext .taskMetrics ().incMemoryBytesSpilled (spillSize );
268+ totalSpillBytes += spillSize ;
261269 return spillSize ;
262270 }
263271
0 commit comments