@@ -22,12 +22,20 @@ import scala.annotation.tailrec
2222import java .io .OutputStream
2323import java .util .concurrent .TimeUnit ._
2424
25+ import org .apache .spark .Logging
26+
27+
2528private [streaming]
26- class RateLimitedOutputStream (out : OutputStream , bytesPerSec : Int ) extends OutputStream {
27- val SYNC_INTERVAL = NANOSECONDS .convert(10 , SECONDS )
28- val CHUNK_SIZE = 8192
29- var lastSyncTime = System .nanoTime
30- var bytesWrittenSinceSync : Long = 0
29+ class RateLimitedOutputStream (out : OutputStream , desiredBytesPerSec : Int )
30+ extends OutputStream
31+ with Logging {
32+
33+ require(desiredBytesPerSec > 0 )
34+
35+ private val SYNC_INTERVAL = NANOSECONDS .convert(10 , SECONDS )
36+ private val CHUNK_SIZE = 8192
37+ private var lastSyncTime = System .nanoTime
38+ private var bytesWrittenSinceSync = 0L
3139
3240 override def write (b : Int ) {
3341 waitToWrite(1 )
@@ -59,9 +67,9 @@ class RateLimitedOutputStream(out: OutputStream, bytesPerSec: Int) extends Outpu
5967 @ tailrec
6068 private def waitToWrite (numBytes : Int ) {
6169 val now = System .nanoTime
62- val elapsedSecs = SECONDS .convert( math.max(now - lastSyncTime, 1 ), NANOSECONDS )
63- val rate = bytesWrittenSinceSync.toDouble / elapsedSecs
64- if (rate < bytesPerSec ) {
70+ val elapsedNanosecs = math.max(now - lastSyncTime, 1 )
71+ val rate = bytesWrittenSinceSync.toDouble * 1000000000 / elapsedNanosecs
72+ if (rate < desiredBytesPerSec ) {
6573 // It's okay to write; just update some variables and return
6674 bytesWrittenSinceSync += numBytes
6775 if (now > lastSyncTime + SYNC_INTERVAL ) {
@@ -71,13 +79,14 @@ class RateLimitedOutputStream(out: OutputStream, bytesPerSec: Int) extends Outpu
7179 }
7280 } else {
7381 // Calculate how much time we should sleep to bring ourselves to the desired rate.
74- // Based on throttler in Kafka
75- // scalastyle:off
76- // (https://github.com/kafka-dev/kafka/blob/master/core/src/main/scala/kafka/utils/Throttler.scala)
77- // scalastyle:on
78- val sleepTime = MILLISECONDS .convert((bytesWrittenSinceSync / bytesPerSec - elapsedSecs),
79- SECONDS )
80- if (sleepTime > 0 ) Thread .sleep(sleepTime)
82+ val targetTimeInMillis = bytesWrittenSinceSync * 1000 / desiredBytesPerSec
83+ val elapsedTimeInMillis = elapsedNanosecs / 1000000
84+ val sleepTimeInMillis = targetTimeInMillis - elapsedTimeInMillis
85+ if (sleepTimeInMillis > 0 ) {
86+ logTrace(" Natural rate is " + rate + " per second but desired rate is " +
87+ desiredBytesPerSec + " , sleeping for " + sleepTimeInMillis + " ms to compensate." )
88+ Thread .sleep(sleepTimeInMillis)
89+ }
8190 waitToWrite(numBytes)
8291 }
8392 }
0 commit comments