PageRenderTime 93ms CodeModel.GetById 50ms app.highlight 14ms RepoModel.GetById 26ms app.codeStats 0ms

/mordor/streams/throttle.cpp

http://github.com/mozy/mordor
C++ | 99 lines | 85 code | 8 blank | 6 comment | 26 complexity | b88ee6f53ee6828404a2299b77cef8b5 MD5 | raw file
 1// Copyright (c) 2009 - Mozy, Inc.
 2
 3#include "throttle.h"
 4
 5#include "mordor/assert.h"
 6#include "mordor/log.h"
 7#include "mordor/sleep.h"
 8#include "mordor/timer.h"
 9
10namespace Mordor {
11
12static Logger::ptr g_log = Log::lookup("mordor:streams:throttle");
13
14size_t
15ThrottleStream::read(Buffer &b, size_t len)
16{
17    MORDOR_ASSERT(len != 0);
18    unsigned int throttle = m_dg();
19    if (throttle == 0 || throttle == ~0u) {
20        if (m_read > 0){
21            m_read = 0;
22            MORDOR_LOG_DEBUG(g_log) << this << " no longer throttling on read";
23        }
24        MORDOR_LOG_DEBUG(g_log) << this << " read " << len << "B unthrottled ";
25        return parent()->read(b, len);
26    }
27    unsigned long long now = TimerManager::now();
28    if (m_read == 0) {
29        MORDOR_LOG_DEBUG(g_log) << this << " starting throttling on read " << throttle << "bps";
30    } else {
31        unsigned long long minTime = 1000000ull * (m_read * 8) / throttle;
32        unsigned long long actualTime = (now - m_readTimestamp);
33
34        MORDOR_LOG_DEBUG(g_log) << this << " read " << m_read << "B throttle "
35            << throttle << "bps now " << now << "us last " << m_readTimestamp
36            << "us min" << minTime << " us actual " << actualTime << "us";
37        if (actualTime < minTime) {
38            unsigned long long sleepTime = minTime - actualTime;
39            // Never sleep for longer than a tenth of a second
40            sleepTime = (std::min)(100000ull, sleepTime);
41            if (m_timerManager)
42                sleep(*m_timerManager, sleepTime);
43            else
44                sleep(sleepTime);
45            now = TimerManager::now();
46        }
47    }
48    // Aim for no more than a tenth of a second's worth of data
49    len = std::min<size_t>(throttle / 8 / 10, len);
50    if (len == 0)
51        len = 1;
52    m_readTimestamp = now;
53    return m_read = parent()->read(b, len);
54}
55
56size_t
57ThrottleStream::write(const Buffer &b, size_t len)
58{
59    MORDOR_ASSERT(len != 0);
60    unsigned int throttle = m_dg();
61    if (throttle == 0 || throttle == ~0u) {
62        if (m_written > 0){
63            m_written = 0;
64            MORDOR_LOG_DEBUG(g_log) << this << " no longer throttling";
65        }
66        MORDOR_LOG_DEBUG(g_log) << this << " write " << len << "B unthrottled ";
67        m_writeTimestamp = TimerManager::now();
68        return parent()->write(b, len);
69    }
70    unsigned long long now = TimerManager::now();
71    if (m_written == 0) {
72        MORDOR_LOG_DEBUG(g_log) << this << " starting throttling " << throttle << "bps";
73    } else {
74        unsigned long long minTime = 1000000ull * (m_written * 8) / throttle;
75        unsigned long long actualTime = (now - m_writeTimestamp);
76        MORDOR_LOG_DEBUG(g_log) << this << " write " << m_written << "B throttle "
77            << throttle << "bps now " << now << "us last " << m_writeTimestamp
78            << "us min " << minTime << "us actual " << actualTime << "us";
79        if (actualTime < minTime) {
80            unsigned long long sleepTime = minTime - actualTime;
81            // Never sleep for longer than a tenth of a second
82            sleepTime = (std::min)(100000ull, sleepTime);
83            if (m_timerManager)
84                sleep(*m_timerManager, sleepTime);
85            else
86                sleep(sleepTime);
87            now = TimerManager::now();
88        }
89    }
90    // Aim for no more than a tenth of a second's worth of data
91    len = std::min<size_t>(throttle / 8 / 10, len);
92    if (len == 0)
93        len = 1;
94    // set timestamp to now. This needs to include the sleep time above - with multiple connections per host, we may be doing context switching when we sleep.
95    m_writeTimestamp = now;
96    return m_written = parent()->write(b, len);
97}
98
99}