diff options
author | Chris Wilson <chris+github@qwirx.com> | 2011-01-12 00:11:53 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2011-01-12 00:11:53 +0000 |
commit | 8ee2327add953c8282807c988dcaef7a2d03a7f1 (patch) | |
tree | c97d2b6c91b4c7d3c4d4d4c720ae3d0599b505df /lib/common/RateLimitingStream.cpp | |
parent | bc6ccea0d973ce4a0eb370191c3bbcd22d6cb45b (diff) |
Add an implementation of a stream wrapper that limits reading rate, to
control bandwidth usage.
Diffstat (limited to 'lib/common/RateLimitingStream.cpp')
-rw-r--r-- | lib/common/RateLimitingStream.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/lib/common/RateLimitingStream.cpp b/lib/common/RateLimitingStream.cpp new file mode 100644 index 00000000..67a97e6b --- /dev/null +++ b/lib/common/RateLimitingStream.cpp @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: RateLimitingStream.cpp +// Purpose: Rate-limiting write-only wrapper around IOStreams +// Created: 2011/01/11 +// +// -------------------------------------------------------------------------- + +#include "Box.h" +#include "RateLimitingStream.h" +#include "CommonException.h" + +#include <string.h> + +#include "MemLeakFindOn.h" + +// -------------------------------------------------------------------------- +// +// Function +// Name: RateLimitingStream::RateLimitingStream(const char *, int, int) +// Purpose: Constructor, set up buffer +// Created: 2011/01/11 +// +// -------------------------------------------------------------------------- +RateLimitingStream::RateLimitingStream(IOStream& rSink, size_t targetBytesPerSecond) +: mrSink(rSink), mStartTime(GetCurrentBoxTime()), mTotalBytesRead(0), + mTargetBytesPerSecond(targetBytesPerSecond) +{ } + +// -------------------------------------------------------------------------- +// +// Function +// Name: RateLimitingStream::Read(void *pBuffer, int NBytes, +// int Timeout) +// Purpose: Reads bytes to the underlying stream at no more than +// a fixed rate +// Created: 2011/01/11 +// +// -------------------------------------------------------------------------- +int RateLimitingStream::Read(void *pBuffer, int NBytes, int Timeout) +{ + if(NBytes > 0 && (size_t)NBytes > mTargetBytesPerSecond) + { + // Limit to one second's worth of data for performance + BOX_TRACE("Reducing read size from " << NBytes << " to " << + mTargetBytesPerSecond << " to smooth upload rate"); + NBytes = mTargetBytesPerSecond; + } + + int bytesReadThisTime = mrSink.Read(pBuffer, NBytes, Timeout); + + // How many bytes we will have written after this write finishes? + mTotalBytesRead += bytesReadThisTime; + + // When should it be completed by? + box_time_t desiredFinishTime = mStartTime + + SecondsToBoxTime(mTotalBytesRead / mTargetBytesPerSecond); + + // How long do we have to wait? + box_time_t currentTime = GetCurrentBoxTime(); + int64_t waitTime = desiredFinishTime - currentTime; + + // How are we doing so far? (for logging only) + box_time_t currentDuration = currentTime - mStartTime; + uint64_t effectiveRateSoFar = (mTotalBytesRead * MICRO_SEC_IN_SEC_LL) + / currentDuration; + + if(waitTime > 0) + { + BOX_TRACE("Current rate " << effectiveRateSoFar << + " higher than desired rate " << mTargetBytesPerSecond << + ", sleeping for " << BoxTimeToMilliSeconds(waitTime) << + " ms"); + ShortSleep(waitTime, false); + } + else + { + BOX_TRACE("Current rate " << effectiveRateSoFar << + " lower than desired rate " << mTargetBytesPerSecond << + ", sending immediately (would have sent " << + (BoxTimeToMilliSeconds(-waitTime)) << " ms ago)"); + } + + return bytesReadThisTime; +} + |