i2psnark: Bandwidth limiter improvements
- New BandwidthLimiter class implemented at 3 levels: Peer, PeerCoordinator, and total
- Use SyntheticREDQueue (SRQ) for accurate and responsive total bandwidth estimates
- Track request size and inbound bandwidth
- Implement request throttling and inbound bandwidth limits
- Don't unchoke peers when over outbound bandwidth limit
- Don't choke peers so aggressively in PeerCheckerTask
- Use low-level received chunk data size for accurate inbound bandwidth calculation
- Implement low-level send-piece throttling
- Track chunks directly in PartialPiece via a BitField, not indirectly via the outstandingRequests queue, to handle "holes" and not lose chunks when returned to the PeerCoordinator
- Add down bandwidth limit to config UI
- Bandwidth tracking refactoring all over
This completely redesigns bandwidth limiting. Upload bandwidth limiting is changed to use SyntheticREDQueue for smoother internal bandwidth estimation and choking/unchoking behavior
Download bandwidth limiting is implemented for the first time to prevent snark from overwhelming the router and disrupting other tunnels. Download bandwidth estimation is done with two SyntheticREDQueues, one for requests and one for received chunks. These estimates are similar but separated temporally by RTT. Requests are limited if either the request or download estimate is over the limit.
The new BandwidthLimiter interface is implemented at three levels. Each level reports to the higher level for aggregation. Limiting is done only at the top level.
- Total, by BandwidthManager, using SyntheticREDQueues
- Per-torrent, by PeerCoordinator, using 40s buckets as before
- Per-peer, by Peer, using 40s buckets as before
Received bandwidth is changed to be tracked per-read, not per-chunk, for greatly improved accuracy, in PartialPiece. Outgoing requests and piece throttling is redesigned to hold the pending requests and pieces directly in the outbound queue, see PeerConnectionOut. We no longer simply choke the peer when over the upload limit. Request queue for each peer can be individually limited (maxPipeline).
PartialPiece now tracks received chunks with a Bitfield, to prevent out-of-order chunks from being lost after being choked, for greater efficiency.
PeerCoordinator is responsible for adjusting request queue limits for each peer. It also sets a timer after being throttled, so that it pokes peers t rerequest after being unthrottled.
The bandwidths reported on the UI are unchanged; they continue to use the 40s bucket value, as the internal SRQ value is too volatile. Down bandwidth limit form is added to the config UI. The three SRQ states are added to the debug UI.
TODO: WebPeer throttling may need additional work and testing