]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blame - www/pages/torrent/client/RateLimiter.py
Change Color of Menuitem CeBIT.
[people/shoehn/ipfire.org.git] / www / pages / torrent / client / RateLimiter.py
CommitLineData
879aa787
MT
1# Written by Bram Cohen
2# see LICENSE.txt for license information
3
4from traceback import print_exc
5from binascii import b2a_hex
6from clock import clock
7from CurrentRateMeasure import Measure
8from cStringIO import StringIO
9from math import sqrt
10
11try:
12 True
13except:
14 True = 1
15 False = 0
16try:
17 sum([1])
18except:
19 sum = lambda a: reduce(lambda x,y: x+y, a, 0)
20
21DEBUG = False
22
23MAX_RATE_PERIOD = 20.0
24MAX_RATE = 10e10
25PING_BOUNDARY = 1.2
26PING_SAMPLES = 7
27PING_DISCARDS = 1
28PING_THRESHHOLD = 5
29PING_DELAY = 5 # cycles 'til first upward adjustment
30PING_DELAY_NEXT = 2 # 'til next
31ADJUST_UP = 1.05
32ADJUST_DOWN = 0.95
33UP_DELAY_FIRST = 5
34UP_DELAY_NEXT = 2
35SLOTS_STARTING = 6
36SLOTS_FACTOR = 1.66/1000
37
38class RateLimiter:
39 def __init__(self, sched, unitsize, slotsfunc = lambda x: None):
40 self.sched = sched
41 self.last = None
42 self.unitsize = unitsize
43 self.slotsfunc = slotsfunc
44 self.measure = Measure(MAX_RATE_PERIOD)
45 self.autoadjust = False
46 self.upload_rate = MAX_RATE * 1000
47 self.slots = SLOTS_STARTING # garbage if not automatic
48
49 def set_upload_rate(self, rate):
50 # rate = -1 # test automatic
51 if rate < 0:
52 if self.autoadjust:
53 return
54 self.autoadjust = True
55 self.autoadjustup = 0
56 self.pings = []
57 rate = MAX_RATE
58 self.slots = SLOTS_STARTING
59 self.slotsfunc(self.slots)
60 else:
61 self.autoadjust = False
62 if not rate:
63 rate = MAX_RATE
64 self.upload_rate = rate * 1000
65 self.lasttime = clock()
66 self.bytes_sent = 0
67
68 def queue(self, conn):
69 assert conn.next_upload is None
70 if self.last is None:
71 self.last = conn
72 conn.next_upload = conn
73 self.try_send(True)
74 else:
75 conn.next_upload = self.last.next_upload
76 self.last.next_upload = conn
77 self.last = conn
78
79 def try_send(self, check_time = False):
80 t = clock()
81 self.bytes_sent -= (t - self.lasttime) * self.upload_rate
82 self.lasttime = t
83 if check_time:
84 self.bytes_sent = max(self.bytes_sent, 0)
85 cur = self.last.next_upload
86 while self.bytes_sent <= 0:
87 bytes = cur.send_partial(self.unitsize)
88 self.bytes_sent += bytes
89 self.measure.update_rate(bytes)
90 if bytes == 0 or cur.backlogged():
91 if self.last is cur:
92 self.last = None
93 cur.next_upload = None
94 break
95 else:
96 self.last.next_upload = cur.next_upload
97 cur.next_upload = None
98 cur = self.last.next_upload
99 else:
100 self.last = cur
101 cur = cur.next_upload
102 else:
103 self.sched(self.try_send, self.bytes_sent / self.upload_rate)
104
105 def adjust_sent(self, bytes):
106 self.bytes_sent = min(self.bytes_sent+bytes, self.upload_rate*3)
107 self.measure.update_rate(bytes)
108
109
110 def ping(self, delay):
111 if DEBUG:
112 print delay
113 if not self.autoadjust:
114 return
115 self.pings.append(delay > PING_BOUNDARY)
116 if len(self.pings) < PING_SAMPLES+PING_DISCARDS:
117 return
118 if DEBUG:
119 print 'cycle'
120 pings = sum(self.pings[PING_DISCARDS:])
121 del self.pings[:]
122 if pings >= PING_THRESHHOLD: # assume flooded
123 if self.upload_rate == MAX_RATE:
124 self.upload_rate = self.measure.get_rate()*ADJUST_DOWN
125 else:
126 self.upload_rate = min(self.upload_rate,
127 self.measure.get_rate()*1.1)
128 self.upload_rate = max(int(self.upload_rate*ADJUST_DOWN),2)
129 self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR))
130 self.slotsfunc(self.slots)
131 if DEBUG:
132 print 'adjust down to '+str(self.upload_rate)
133 self.lasttime = clock()
134 self.bytes_sent = 0
135 self.autoadjustup = UP_DELAY_FIRST
136 else: # not flooded
137 if self.upload_rate == MAX_RATE:
138 return
139 self.autoadjustup -= 1
140 if self.autoadjustup:
141 return
142 self.upload_rate = int(self.upload_rate*ADJUST_UP)
143 self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR))
144 self.slotsfunc(self.slots)
145 if DEBUG:
146 print 'adjust up to '+str(self.upload_rate)
147 self.lasttime = clock()
148 self.bytes_sent = 0
149 self.autoadjustup = UP_DELAY_NEXT
150
151
152
153