source: trunk/libtransmission/bandwidth.h @ 12918

Last change on this file since 12918 was 12509, checked in by jordan, 10 years ago

(trunk libT) add a unique key to each tr_bandwidth object, so that when sorting them arbitrarily we can use that key rather than their pointer address. Apparently comparing pointers that aren't allocated in the same array is undefined behavior.

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