Documentation
¶
Overview ¶
Package choker implements the BitTorrent choking algorithm (BEP 3).
Purpose ¶
The choking algorithm controls which peers we upload data to. Uploading to everyone simultaneously would saturate our upload bandwidth without improving our download rate. By being selective, we implement tit-for-tat: we prefer peers who upload to us, which incentivises mutual cooperation.
Algorithm overview ¶
Every RechokePeriod (10 s) the choker selects [Slots]−1 peers to receive regular unchoke slots and one additional peer for the optimistic unchoke slot.
Regular slot selection:
- Leecher mode: rank interested peers by bytes downloaded FROM them in the last measurement window (descending). Top [Slots]−1 win regular slots.
- Seeder mode: rank interested peers by bytes uploaded TO them (descending).
- Snubbed peers (no data received for SnubTimeout seconds) are excluded from regular slots regardless of mode.
Optimistic unchoke (rotated every OptimisticPeriod = 30 s):
- One slot is always reserved for a randomly selected choked-but-interested peer, giving them a chance to demonstrate they are a good upload partner.
- Newly connected peers (< NewPeerWindow) are given 3× the selection probability to accelerate swarm discovery.
Integration ¶
The caller provides two callbacks in Config:
- GetPeers returns the current snapshot of all peer stats. Called every tick.
- SetChoked applies a choke or unchoke wire message to a specific peer. This is called outside the choker's internal mutex.
Call New to start the background ticker goroutine, and [Stop] when the torrent session ends. [Trigger] forces an immediate rechoke cycle (useful when a peer connects or disconnects).
Index ¶
Constants ¶
const ( // DefaultSlots is the default number of unchoke slots (regular + optimistic). DefaultSlots = 4 // RechokePeriod is how often the regular unchoke set is recomputed. RechokePeriod = 10 * time.Second // OptimisticPeriod is how often the optimistic unchoke slot is rotated. OptimisticPeriod = 30 * time.Second // SnubTimeout is how long a peer can be silent (no piece data received) // before the choker marks it snubbed and excludes it from regular slots. SnubTimeout = 60 * time.Second // NewPeerWindow is the age threshold for 3× optimistic-unchoke weighting. // Peers connected more recently than this are preferred for discovery. NewPeerWindow = 3 * time.Minute )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Choker ¶
type Choker struct {
// contains filtered or unexported fields
}
Choker implements the BEP 3 choking algorithm.
func New ¶
New creates a Choker and starts the background rechoke goroutine. Call Choker.Stop when the torrent session ends to release resources.
func (*Choker) SetSeeder ¶
SetSeeder switches between leecher ranking (by download rate) and seeder ranking (by upload rate). Triggers an immediate rechoke.
func (*Choker) Stop ¶
func (c *Choker) Stop()
Stop shuts down the background goroutine. Safe to call multiple times.
type Config ¶
type Config struct {
// Slots is the total number of unchoke slots (regular + 1 optimistic).
// 0 falls back to [DefaultSlots].
Slots int
// IsSeeder indicates we have 100% of the torrent's pieces. Switches the
// ranking metric from download rate to upload rate.
IsSeeder bool
// GetPeers is called each rechoke cycle to obtain the current peer stats.
// It must be non-nil.
GetPeers func() []PeerStats
// SetChoked is called to apply a choke (true) or unchoke (false) decision
// to a peer. Called outside the choker's internal mutex.
// It must be non-nil.
SetChoked func(id PeerID, choked bool)
}
Config holds constructor parameters for New.
type PeerID ¶
type PeerID string
PeerID uniquely identifies a peer connection. In practice this is the remote address string ("1.2.3.4:6881") or peer_id.
type PeerStats ¶
type PeerStats struct {
ID PeerID
// Interested is true if the peer has sent us an Interested message and not
// yet a NotInterested message.
Interested bool
// BytesDownloadedFrom is the bytes received from this peer in the current
// measurement window (~20 s recommended). Used in leecher mode ranking.
BytesDownloadedFrom int64
// BytesUploadedTo is the bytes sent to this peer in the current measurement
// window. Used in seeder mode ranking.
BytesUploadedTo int64
// LastReceived is the wall time of the most recent piece block received from
// this peer. Zero if no data has ever been received. Used for snub detection.
LastReceived time.Time
// ConnectedAt is when the TCP connection to this peer was established.
// Used to give newly connected peers a 3× optimistic-unchoke weight.
ConnectedAt time.Time
}
PeerStats is a snapshot of the metrics the choker needs for one peer. The peer connection layer is responsible for updating these values before each GetPeers call.