mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 14:23:30 +01:00
107 lines
3.3 KiB
Plaintext
107 lines
3.3 KiB
Plaintext
|
# The following two algorithms
|
||
|
|
||
|
|
||
|
# Algorithm 1
|
||
|
# TODO: Burst and Relay/Regular differentiation
|
||
|
|
||
|
BwRate = Bandwidth Rate in Bytes Per Second
|
||
|
GlobalWriteBucket = 0
|
||
|
GlobalReadBucket = 0
|
||
|
Epoch = Token Fill Rate in seconds: suggest 50ms=.050
|
||
|
SecondCounter = 0
|
||
|
MinWriteBytes = Minimum amount bytes per write
|
||
|
|
||
|
Every Epoch Seconds:
|
||
|
UseMinWriteBytes = MinWriteBytes
|
||
|
WriteCnt = 0
|
||
|
ReadCnt = 0
|
||
|
BytesRead = 0
|
||
|
|
||
|
For Each Open OR Conn with pending write data:
|
||
|
WriteCnt++
|
||
|
For Each Open OR Conn:
|
||
|
ReadCnt++
|
||
|
|
||
|
BytesToRead = (BwRate*Epoch + GlobalReadBucket)/ReadCnt
|
||
|
BytesToWrite = (BwRate*Epoch + GlobalWriteBucket)/WriteCnt
|
||
|
|
||
|
if BwRate/WriteCnt < MinWriteBytes:
|
||
|
# If we aren't likely to accumulate enough bytes in a second to
|
||
|
# send a whole cell for our connections, send partials
|
||
|
Log(NOTICE, "Too many ORCons to write full blocks. Sending short packets.")
|
||
|
UseMinWriteBytes = 1
|
||
|
# Other option: We could switch to plan 2 here
|
||
|
|
||
|
# Service each writable ORConn. If there are any partial writes,
|
||
|
# return remaining bytes from this epoch to the global pool
|
||
|
For Each Open OR Conn with pending write data:
|
||
|
ORConn->write_bucket += BytesToWrite
|
||
|
if ORConn->write_bucket > UseMinWriteBytes:
|
||
|
w = write(ORConn, MIN(len(ORConn->write_data), ORConn->write_bucket))
|
||
|
# possible that w < ORConn->write_data here due to TCP pushback.
|
||
|
# We should restore the rest of the write_bucket to the global
|
||
|
# buffer
|
||
|
GlobalWriteBucket += (ORConn->write_bucket - w)
|
||
|
ORConn->write_bucket = 0
|
||
|
|
||
|
For Each Open OR Conn:
|
||
|
r = read_nonblock(ORConn, BytesToRead)
|
||
|
BytesRead += r
|
||
|
|
||
|
SecondCounter += Epoch
|
||
|
if SecondCounter < 1:
|
||
|
# Save unused bytes from this epoch to be used later in the second
|
||
|
GlobalReadBucket += (BwRate*Epoch - BytesRead)
|
||
|
else:
|
||
|
SecondCounter = 0
|
||
|
GlobalReadBucket = 0
|
||
|
GlobalWriteBucket = 0
|
||
|
For Each ORConn:
|
||
|
ORConn->write_bucket = 0
|
||
|
|
||
|
|
||
|
|
||
|
# Alternate plan for Writing fairly. Reads would still be covered
|
||
|
# by plan 1 as there is no additional network overhead for short reads,
|
||
|
# so we don't need to try to avoid them.
|
||
|
#
|
||
|
# I think this is actually pretty similar to what we do now, but
|
||
|
# with the addition that the bytes accumulate up to the second mark
|
||
|
# and we try to keep track of our position in the write list here
|
||
|
# (unless libevent is doing that for us already and I just don't see it)
|
||
|
#
|
||
|
# TODO: Burst and Relay/Regular differentiation
|
||
|
|
||
|
# XXX: The inability to send single cells will cause us to block
|
||
|
# on EXTEND cells for low-bandwidth node pairs..
|
||
|
BwRate = Bandwidth Rate in Bytes Per Second
|
||
|
WriteBytes = Bytes per write
|
||
|
Epoch = MAX(MIN(WriteBytes/BwRate, .333s), .050s)
|
||
|
|
||
|
SecondCounter = 0
|
||
|
GlobalWriteBucket = 0
|
||
|
|
||
|
# New connections are inserted at Head-1 (the 'tail' of this circular list)
|
||
|
# This is not 100% fifo for all node data, but it is the best we can do
|
||
|
# without insane amounts of additional queueing complexity.
|
||
|
WriteConnList = List of Open OR Conns with pending write data > WriteBytes
|
||
|
WriteConnHead = 0
|
||
|
|
||
|
Every Epoch Seconds:
|
||
|
GlobalWriteBucket += BwRate*Epoch
|
||
|
WriteListEnd = WriteConnHead
|
||
|
|
||
|
do
|
||
|
ORCONN = WriteConnList[WriteConnHead]
|
||
|
w = write(ORConn, WriteBytes)
|
||
|
GlobalWriteBucket -= w
|
||
|
WriteConnHead += 1
|
||
|
while GlobalWriteBucket > 0 and WriteConnHead != WriteListEnd
|
||
|
|
||
|
SecondCounter += Epoch
|
||
|
if SecondCounter >= 1:
|
||
|
SecondCounter = 0
|
||
|
GlobalWriteBucket = 0
|
||
|
|
||
|
|