123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- # 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
|