xxx-bwrate-algs.txt 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # The following two algorithms
  2. # Algorithm 1
  3. # TODO: Burst and Relay/Regular differentiation
  4. BwRate = Bandwidth Rate in Bytes Per Second
  5. GlobalWriteBucket = 0
  6. GlobalReadBucket = 0
  7. Epoch = Token Fill Rate in seconds: suggest 50ms=.050
  8. SecondCounter = 0
  9. MinWriteBytes = Minimum amount bytes per write
  10. Every Epoch Seconds:
  11. UseMinWriteBytes = MinWriteBytes
  12. WriteCnt = 0
  13. ReadCnt = 0
  14. BytesRead = 0
  15. For Each Open OR Conn with pending write data:
  16. WriteCnt++
  17. For Each Open OR Conn:
  18. ReadCnt++
  19. BytesToRead = (BwRate*Epoch + GlobalReadBucket)/ReadCnt
  20. BytesToWrite = (BwRate*Epoch + GlobalWriteBucket)/WriteCnt
  21. if BwRate/WriteCnt < MinWriteBytes:
  22. # If we aren't likely to accumulate enough bytes in a second to
  23. # send a whole cell for our connections, send partials
  24. Log(NOTICE, "Too many ORCons to write full blocks. Sending short packets.")
  25. UseMinWriteBytes = 1
  26. # Other option: We could switch to plan 2 here
  27. # Service each writable ORConn. If there are any partial writes,
  28. # return remaining bytes from this epoch to the global pool
  29. For Each Open OR Conn with pending write data:
  30. ORConn->write_bucket += BytesToWrite
  31. if ORConn->write_bucket > UseMinWriteBytes:
  32. w = write(ORConn, MIN(len(ORConn->write_data), ORConn->write_bucket))
  33. # possible that w < ORConn->write_data here due to TCP pushback.
  34. # We should restore the rest of the write_bucket to the global
  35. # buffer
  36. GlobalWriteBucket += (ORConn->write_bucket - w)
  37. ORConn->write_bucket = 0
  38. For Each Open OR Conn:
  39. r = read_nonblock(ORConn, BytesToRead)
  40. BytesRead += r
  41. SecondCounter += Epoch
  42. if SecondCounter < 1:
  43. # Save unused bytes from this epoch to be used later in the second
  44. GlobalReadBucket += (BwRate*Epoch - BytesRead)
  45. else:
  46. SecondCounter = 0
  47. GlobalReadBucket = 0
  48. GlobalWriteBucket = 0
  49. For Each ORConn:
  50. ORConn->write_bucket = 0
  51. # Alternate plan for Writing fairly. Reads would still be covered
  52. # by plan 1 as there is no additional network overhead for short reads,
  53. # so we don't need to try to avoid them.
  54. #
  55. # I think this is actually pretty similar to what we do now, but
  56. # with the addition that the bytes accumulate up to the second mark
  57. # and we try to keep track of our position in the write list here
  58. # (unless libevent is doing that for us already and I just don't see it)
  59. #
  60. # TODO: Burst and Relay/Regular differentiation
  61. # XXX: The inability to send single cells will cause us to block
  62. # on EXTEND cells for low-bandwidth node pairs..
  63. BwRate = Bandwidth Rate in Bytes Per Second
  64. WriteBytes = Bytes per write
  65. Epoch = MAX(MIN(WriteBytes/BwRate, .333s), .050s)
  66. SecondCounter = 0
  67. GlobalWriteBucket = 0
  68. # New connections are inserted at Head-1 (the 'tail' of this circular list)
  69. # This is not 100% fifo for all node data, but it is the best we can do
  70. # without insane amounts of additional queueing complexity.
  71. WriteConnList = List of Open OR Conns with pending write data > WriteBytes
  72. WriteConnHead = 0
  73. Every Epoch Seconds:
  74. GlobalWriteBucket += BwRate*Epoch
  75. WriteListEnd = WriteConnHead
  76. do
  77. ORCONN = WriteConnList[WriteConnHead]
  78. w = write(ORConn, WriteBytes)
  79. GlobalWriteBucket -= w
  80. WriteConnHead += 1
  81. while GlobalWriteBucket > 0 and WriteConnHead != WriteListEnd
  82. SecondCounter += Epoch
  83. if SecondCounter >= 1:
  84. SecondCounter = 0
  85. GlobalWriteBucket = 0