1
0

KRateLimiter.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. # The contents of this file are subject to the BitTorrent Open Source License
  2. # Version 1.1 (the License). You may not copy or use this file, in either
  3. # source code or executable form, except in compliance with the License. You
  4. # may obtain a copy of the License at http://www.bittorrent.com/license/.
  5. #
  6. # Software distributed under the License is distributed on an AS IS basis,
  7. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. # for the specific language governing rights and limitations under the
  9. # License.
  10. from BTL.platform import bttime as time
  11. from BitTorrent.CurrentRateMeasure import Measure
  12. from const import *
  13. from random import randrange, shuffle
  14. from traceback import print_exc
  15. class KRateLimiter:
  16. # special rate limiter that drops entries that have been sitting in the queue for longer than self.age seconds
  17. # by default we toss anything that has less than 5 seconds to live
  18. def __init__(self, transport, rate, call_later, rlcount, rate_period, age=(KRPC_TIMEOUT - 5)):
  19. self.q = []
  20. self.transport = transport
  21. self.rate = rate
  22. self.curr = 0
  23. self.running = False
  24. self.age = age
  25. self.last = 0
  26. self.call_later = call_later
  27. self.rlcount = rlcount
  28. self.measure = Measure(rate_period)
  29. self.sent=self.dropped=0
  30. if self.rate == 0:
  31. self.rate = 1e10
  32. def sendto(self, s, i, addr):
  33. self.q.append((time(), (s, i, addr)))
  34. if not self.running:
  35. self.run(check=True)
  36. def run(self, check=False):
  37. t = time()
  38. self.expire(t)
  39. self.curr -= (t - self.last) * self.rate
  40. self.last = t
  41. if check:
  42. self.curr = max(self.curr, 0 - self.rate)
  43. shuffle(self.q)
  44. while self.q and self.curr <= 0:
  45. x, tup = self.q.pop()
  46. size = len(tup[0])
  47. self.curr += size
  48. try:
  49. self.transport.sendto(*tup)
  50. self.sent+=1
  51. self.rlcount(size)
  52. self.measure.update_rate(size)
  53. except:
  54. if tup[2][1] != 0:
  55. print ">>> sendto exception", tup
  56. print_exc()
  57. self.q.sort()
  58. if self.q or self.curr > 0:
  59. self.running = True
  60. # sleep for at least a half second
  61. self.call_later(max(self.curr / self.rate, 0.5), self.run)
  62. else:
  63. self.running = False
  64. def expire(self, t=time()):
  65. if self.q:
  66. expire_time = t - self.age
  67. while self.q and self.q[0][0] < expire_time:
  68. self.q.pop(0)
  69. self.dropped+=1