]>
git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - www/pages/torrent/client/RateLimiter.py
1 # Written by Bram Cohen
2 # see LICENSE.txt for license information
4 from traceback
import print_exc
5 from binascii
import b2a_hex
6 from clock
import clock
7 from CurrentRateMeasure
import Measure
8 from cStringIO
import StringIO
19 sum = lambda a
: reduce(lambda x
,y
: x
+y
, a
, 0)
23 MAX_RATE_PERIOD
= 20.0
29 PING_DELAY
= 5 # cycles 'til first upward adjustment
30 PING_DELAY_NEXT
= 2 # 'til next
36 SLOTS_FACTOR
= 1.66/1000
39 def __init__(self
, sched
, unitsize
, slotsfunc
= lambda x
: 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
49 def set_upload_rate(self
, rate
):
50 # rate = -1 # test automatic
54 self
.autoadjust
= True
58 self
.slots
= SLOTS_STARTING
59 self
.slotsfunc(self
.slots
)
61 self
.autoadjust
= False
64 self
.upload_rate
= rate
* 1000
65 self
.lasttime
= clock()
68 def queue(self
, conn
):
69 assert conn
.next_upload
is None
72 conn
.next_upload
= conn
75 conn
.next_upload
= self
.last
.next_upload
76 self
.last
.next_upload
= conn
79 def try_send(self
, check_time
= False):
81 self
.bytes_sent
-= (t
- self
.lasttime
) * self
.upload_rate
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():
93 cur
.next_upload
= None
96 self
.last
.next_upload
= cur
.next_upload
97 cur
.next_upload
= None
98 cur
= self
.last
.next_upload
101 cur
= cur
.next_upload
103 self
.sched(self
.try_send
, self
.bytes_sent
/ self
.upload_rate
)
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
)
110 def ping(self
, delay
):
113 if not self
.autoadjust
:
115 self
.pings
.append(delay
> PING_BOUNDARY
)
116 if len(self
.pings
) < PING_SAMPLES
+PING_DISCARDS
:
120 pings
= sum(self
.pings
[PING_DISCARDS
:])
122 if pings
>= PING_THRESHHOLD
: # assume flooded
123 if self
.upload_rate
== MAX_RATE
:
124 self
.upload_rate
= self
.measure
.get_rate()*ADJUST_DOWN
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
)
132 print 'adjust down to '+str(self
.upload_rate
)
133 self
.lasttime
= clock()
135 self
.autoadjustup
= UP_DELAY_FIRST
137 if self
.upload_rate
== MAX_RATE
:
139 self
.autoadjustup
-= 1
140 if self
.autoadjustup
:
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
)
146 print 'adjust up to '+str(self
.upload_rate
)
147 self
.lasttime
= clock()
149 self
.autoadjustup
= UP_DELAY_NEXT