source: trunk/libtransmission/bandwidth.h @ 8254

Last change on this file since 8254 was 8254, checked in by charles, 13 years ago

(trunk) experimental support for tr_torrentSetPriority()

  • Property svn:keywords set to Date Rev Author Id
File size: 8.8 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: bandwidth.h 8254 2009-04-18 23:17:30Z charles $
11 */
12
13#ifndef __TRANSMISSION__
14#error only libtransmission should #include this header.
15#endif
16
17#ifndef TR_BANDWIDTH_H
18#define TR_BANDWIDTH_H
19
20#include "transmission.h"
21#include "ptrarray.h"
22#include "utils.h" /* tr_new(), tr_free() */
23
24struct tr_peerIo;
25
26/* these are PRIVATE IMPLEMENTATION details that should not be touched.
27 * it's included in the header for inlining and composition. */
28enum
29{
30    HISTORY_MSEC = 2000,
31    INTERVAL_MSEC = HISTORY_MSEC,
32    GRANULARITY_MSEC = 50,
33    HISTORY_SIZE = ( INTERVAL_MSEC / GRANULARITY_MSEC ),
34    MAGIC_NUMBER = 43143
35};
36
37/* these are PRIVATE IMPLEMENTATION details that should not be touched.
38 * it's included in the header for inlining and composition. */
39struct bratecontrol
40{
41    int newest;
42    struct { uint64_t date, size; } transfers[HISTORY_SIZE];
43};
44
45/* these are PRIVATE IMPLEMENTATION details that should not be touched.
46 * it's included in the header for inlining and composition. */
47struct tr_band
48{
49    tr_bool isLimited;
50    tr_bool honorParentLimits;
51    size_t bytesLeft;
52    double desiredSpeed;
53    struct bratecontrol raw;
54    struct bratecontrol piece;
55};
56
57/**
58 * Bandwidth is an object for measuring and constraining bandwidth speeds.
59 *
60 * Bandwidth objects can be "stacked" so that a peer can be made to obey
61 * multiple constraints (for example, obeying the global speed limit and a
62 * per-torrent speed limit).
63 *
64 * HIERARCHY
65 *
66 *   Transmission's bandwidth hierarchy is a tree.
67 *   At the top is the global bandwidth object owned by tr_session.
68 *   Its children are per-torrent bandwidth objects owned by tr_torrent.
69 *   Underneath those are per-peer bandwidth objects owned by tr_peer.
70 *
71 *   tr_session also owns a tr_handshake's bandwidths, so that the handshake
72 *   I/O can be counted in the global raw totals.  When the handshake is done,
73 *   the bandwidth's ownership passes to a tr_peer.
74 *
75 * MEASURING
76 *
77 *   When you ask a bandwidth object for its speed, it gives the speed of the
78 *   subtree underneath it as well.  So you can get Transmission's overall
79 *   speed by quering tr_session's bandwidth, per-torrent speeds by asking
80 *   tr_torrent's bandwidth, and per-peer speeds by asking tr_peer's bandwidth.
81 *
82 * CONSTRAINING
83 *
84 *   Call tr_bandwidthAllocate() periodically.  tr_bandwidth knows its current
85 *   speed and will decide how many bytes to make available over the
86 *   user-specified period to reach the user-specified desired speed.
87 *   If appropriate, it notifies its peer-ios that new bandwidth is available.
88 *
89 *   tr_bandwidthAllocate() operates on the tr_bandwidth subtree, so usually
90 *   you'll only need to invoke it for the top-level tr_session bandwidth.
91 *
92 *   The peer-ios all have a pointer to their associated tr_bandwidth object,
93 *   and call tr_bandwidthClamp() before performing I/O to see how much
94 *   bandwidth they can safely use.
95 */
96typedef struct tr_bandwidth
97{
98    /* these are PRIVATE IMPLEMENTATION details that should not be touched.
99     * it's included in the header for inlining and composition. */
100
101    struct tr_band band[2];
102    struct tr_bandwidth * parent;
103    tr_priority_t priority;
104    int magicNumber;
105    tr_session * session;
106    tr_ptrArray children; /* struct tr_bandwidth */
107    struct tr_peerIo * peer;
108}
109tr_bandwidth;
110
111
112/**
113***
114**/
115
116tr_bandwidth* tr_bandwidthConstruct( tr_bandwidth * bandwidth,
117                                     tr_session   * session,
118                                     tr_bandwidth * parent );
119
120/** @brief create a new tr_bandwidth object */
121static TR_INLINE tr_bandwidth* tr_bandwidthNew( tr_session * session, tr_bandwidth * parent )
122{
123    return tr_bandwidthConstruct( tr_new0( tr_bandwidth, 1 ), session, parent );
124}
125
126tr_bandwidth* tr_bandwidthDestruct( tr_bandwidth * bandwidth );
127
128/** @brief free a tr_bandwidth object */
129static TR_INLINE void tr_bandwidthFree( tr_bandwidth * bandwidth )
130{
131    tr_free( tr_bandwidthDestruct( bandwidth ) );
132}
133
134/** @brief test to see if the pointer refers to a live bandwidth object */
135static TR_INLINE tr_bool tr_isBandwidth( const tr_bandwidth  * b )
136{
137    return ( b != NULL ) && ( b->magicNumber == MAGIC_NUMBER );
138}
139
140/******
141*******
142******/
143
144/**
145 * @brief Set the desired speed (in KiB/s) for this bandwidth subtree.
146 * @see tr_bandwidthAllocate
147 * @see tr_bandwidthGetDesiredSpeed
148 */
149static TR_INLINE void tr_bandwidthSetDesiredSpeed( tr_bandwidth        * bandwidth,
150                                                tr_direction          dir,
151                                                double                desiredSpeed )
152{
153    bandwidth->band[dir].desiredSpeed = desiredSpeed;
154}
155
156/**
157 * @brief Get the desired speed (in KiB/s) for ths bandwidth subtree.
158 * @see tr_bandwidthSetDesiredSpeed
159 */
160static TR_INLINE double
161tr_bandwidthGetDesiredSpeed( const tr_bandwidth  * bandwidth,
162                             tr_direction          dir )
163{
164    return bandwidth->band[dir].desiredSpeed;
165}
166
167/**
168 * @brief Set whether or not this bandwidth should throttle its peer-io's speeds
169 */
170static TR_INLINE void tr_bandwidthSetLimited( tr_bandwidth        * bandwidth,
171                                              tr_direction          dir,
172                                              tr_bool               isLimited )
173{
174    bandwidth->band[dir].isLimited = isLimited;
175}
176
177/**
178 * @return nonzero if this bandwidth throttles its peer-ios speeds
179 */
180static TR_INLINE tr_bool tr_bandwidthIsLimited( const tr_bandwidth  * bandwidth,
181                                                tr_direction          dir )
182{
183    return bandwidth->band[dir].isLimited;
184}
185
186/**
187 * @brief allocate the next period_msec's worth of bandwidth for the peer-ios to consume
188 */
189void    tr_bandwidthAllocate          ( tr_bandwidth        * bandwidth,
190                                        tr_direction          direction,
191                                        int                   period_msec );
192
193/**
194 * @brief clamps byteCount down to a number that this bandwidth will allow to be consumed
195 */
196size_t  tr_bandwidthClamp             ( const tr_bandwidth  * bandwidth,
197                                        tr_direction          direction,
198                                        size_t                byteCount );
199
200/******
201*******
202******/
203
204/** @brief Get the raw total of bytes read or sent by this bandwidth subtree. */
205double tr_bandwidthGetRawSpeed( const tr_bandwidth  * bandwidth,
206                                const uint64_t        now,
207                                const tr_direction    direction );
208
209/** @brief Get the number of piece data bytes read or sent by this bandwidth subtree. */
210double tr_bandwidthGetPieceSpeed( const tr_bandwidth  * bandwidth,
211                                  const uint64_t        now,
212                                  const tr_direction    direction );
213
214/**
215 * @brief Notify the bandwidth object that some of its allocated bandwidth has been consumed.
216 * This is is usually invoked by the peer-io after a read or write.
217 */
218void    tr_bandwidthUsed              ( tr_bandwidth        * bandwidth,
219                                        tr_direction          direction,
220                                        size_t                byteCount,
221                                        tr_bool               isPieceData );
222
223/******
224*******
225******/
226
227void    tr_bandwidthSetParent         ( tr_bandwidth        * bandwidth,
228                                        tr_bandwidth        * parent );
229
230/**
231 * Almost all the time we do want to honor a parents' bandwidth cap, so that
232 * (for example) a peer is constrained by a per-torrent cap and the global cap.
233 * But when we set a torrent's speed mode to TR_SPEEDLIMIT_UNLIMITED, then
234 * in that particular case we want to ignore the global speed limit...
235 */
236static TR_INLINE void tr_bandwidthHonorParentLimits ( tr_bandwidth        * bandwidth,
237                                                      tr_direction          direction,
238                                                      tr_bool               isEnabled )
239{
240    assert( tr_isBandwidth( bandwidth ) );
241    assert( tr_isDirection( direction ) );
242
243    bandwidth->band[direction].honorParentLimits = isEnabled;
244}
245
246static TR_INLINE tr_bool tr_bandwidthAreParentLimitsHonored( tr_bandwidth  * bandwidth,
247                                                             tr_direction    direction )
248{
249    assert( tr_isBandwidth( bandwidth ) );
250    assert( tr_isDirection( direction ) );
251
252    return bandwidth->band[direction].honorParentLimits;
253}
254
255/******
256*******
257******/
258
259void tr_bandwidthSetPeer( tr_bandwidth        * bandwidth,
260                          struct tr_peerIo    * peerIo );
261
262#endif
Note: See TracBrowser for help on using the repository browser.