PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 1ms 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
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "throttle.h"
  3. #include "mordor/assert.h"
  4. #include "mordor/log.h"
  5. #include "mordor/sleep.h"
  6. #include "mordor/timer.h"
  7. namespace Mordor {
  8. static Logger::ptr g_log = Log::lookup("mordor:streams:throttle");
  9. size_t
  10. ThrottleStream::read(Buffer &b, size_t len)
  11. {
  12. MORDOR_ASSERT(len != 0);
  13. unsigned int throttle = m_dg();
  14. if (throttle == 0 || throttle == ~0u) {
  15. if (m_read > 0){
  16. m_read = 0;
  17. MORDOR_LOG_DEBUG(g_log) << this << " no longer throttling on read";
  18. }
  19. MORDOR_LOG_DEBUG(g_log) << this << " read " << len << "B unthrottled ";
  20. return parent()->read(b, len);
  21. }
  22. unsigned long long now = TimerManager::now();
  23. if (m_read == 0) {
  24. MORDOR_LOG_DEBUG(g_log) << this << " starting throttling on read " << throttle << "bps";
  25. } else {
  26. unsigned long long minTime = 1000000ull * (m_read * 8) / throttle;
  27. unsigned long long actualTime = (now - m_readTimestamp);
  28. MORDOR_LOG_DEBUG(g_log) << this << " read " << m_read << "B throttle "
  29. << throttle << "bps now " << now << "us last " << m_readTimestamp
  30. << "us min" << minTime << " us actual " << actualTime << "us";
  31. if (actualTime < minTime) {
  32. unsigned long long sleepTime = minTime - actualTime;
  33. // Never sleep for longer than a tenth of a second
  34. sleepTime = (std::min)(100000ull, sleepTime);
  35. if (m_timerManager)
  36. sleep(*m_timerManager, sleepTime);
  37. else
  38. sleep(sleepTime);
  39. now = TimerManager::now();
  40. }
  41. }
  42. // Aim for no more than a tenth of a second's worth of data
  43. len = std::min<size_t>(throttle / 8 / 10, len);
  44. if (len == 0)
  45. len = 1;
  46. m_readTimestamp = now;
  47. return m_read = parent()->read(b, len);
  48. }
  49. size_t
  50. ThrottleStream::write(const Buffer &b, size_t len)
  51. {
  52. MORDOR_ASSERT(len != 0);
  53. unsigned int throttle = m_dg();
  54. if (throttle == 0 || throttle == ~0u) {
  55. if (m_written > 0){
  56. m_written = 0;
  57. MORDOR_LOG_DEBUG(g_log) << this << " no longer throttling";
  58. }
  59. MORDOR_LOG_DEBUG(g_log) << this << " write " << len << "B unthrottled ";
  60. m_writeTimestamp = TimerManager::now();
  61. return parent()->write(b, len);
  62. }
  63. unsigned long long now = TimerManager::now();
  64. if (m_written == 0) {
  65. MORDOR_LOG_DEBUG(g_log) << this << " starting throttling " << throttle << "bps";
  66. } else {
  67. unsigned long long minTime = 1000000ull * (m_written * 8) / throttle;
  68. unsigned long long actualTime = (now - m_writeTimestamp);
  69. MORDOR_LOG_DEBUG(g_log) << this << " write " << m_written << "B throttle "
  70. << throttle << "bps now " << now << "us last " << m_writeTimestamp
  71. << "us min " << minTime << "us actual " << actualTime << "us";
  72. if (actualTime < minTime) {
  73. unsigned long long sleepTime = minTime - actualTime;
  74. // Never sleep for longer than a tenth of a second
  75. sleepTime = (std::min)(100000ull, sleepTime);
  76. if (m_timerManager)
  77. sleep(*m_timerManager, sleepTime);
  78. else
  79. sleep(sleepTime);
  80. now = TimerManager::now();
  81. }
  82. }
  83. // Aim for no more than a tenth of a second's worth of data
  84. len = std::min<size_t>(throttle / 8 / 10, len);
  85. if (len == 0)
  86. len = 1;
  87. // 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.
  88. m_writeTimestamp = now;
  89. return m_written = parent()->write(b, len);
  90. }
  91. }