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 268