This repository has been archived on 2024-05-09. You can view files and clone it, but cannot push or open issues/pull-requests.
ipodderx-core/khashmir/KRateLimiter.py

76 lines
2.7 KiB
Python

# The contents of this file are subject to the BitTorrent Open Source License
# Version 1.1 (the License). You may not copy or use this file, in either
# source code or executable form, except in compliance with the License. You
# may obtain a copy of the License at http://www.bittorrent.com/license/.
#
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
from BitTorrent.platform import bttime as time
from BitTorrent.CurrentRateMeasure import Measure
from const import *
from random import randrange, shuffle
from traceback import print_exc
class KRateLimiter:
# special rate limiter that drops entries that have been sitting in the queue for longer than self.age seconds
# by default we toss anything that has less than 5 seconds to live
def __init__(self, transport, rate, call_later, rlcount, rate_period, age=(KRPC_TIMEOUT - 5)):
self.q = []
self.transport = transport
self.rate = rate
self.curr = 0
self.running = False
self.age = age
self.last = 0
self.call_later = call_later
self.rlcount = rlcount
self.measure = Measure(rate_period)
self.sent=self.dropped=0
if self.rate == 0:
self.rate = 1e10
def sendto(self, s, i, addr):
self.q.append((time(), (s, i, addr)))
if not self.running:
self.run(check=True)
def run(self, check=False):
t = time()
self.expire(t)
self.curr -= (t - self.last) * self.rate
self.last = t
if check:
self.curr = max(self.curr, 0 - self.rate)
shuffle(self.q)
while self.q and self.curr <= 0:
x, tup = self.q.pop()
size = len(tup[0])
self.curr += size
try:
self.transport.sendto(*tup)
self.sent+=1
self.rlcount(size)
self.measure.update_rate(size)
except:
if tup[2][1] != 0:
print ">>> sendto exception", tup
print_exc()
self.q.sort()
if self.q or self.curr > 0:
self.running = True
# sleep for at least a half second
self.call_later(self.run, max(self.curr / self.rate, 0.5))
else:
self.running = False
def expire(self, t=time()):
if self.q:
expire_time = t - self.age
while self.q and self.q[0][0] < expire_time:
self.q.pop(0)
self.dropped+=1