Modernize bandwidth.cc: Moved functions inside struct (#1895)

* Modernize bandwidth.cc: Move functions inside struct

* Modernize bandwidth.cc: Review notes - remove extraneous checks, move small functions into .H file, etc

* Modernize bandwidth.cc: Construction and destruction is now via C++ new/delete

* Modernize bandwidth.cc: Rename used() to notifyBandwidthConsumed()

* Modernize bandwidth.cc: Children is now unordered_set

* Modernize bandwidth.cc: Allocation functions for peer bandwidth are now using std::vector instead of ptrArrays

* Modernize bandwidth.cc: Code formatting

* Modernize bandwidth.cc: Private fields after public; Minor review notes

* Modernize bandwidth.cc: Ungroup enums into constants; Docs minor update

* Modernize bitfield.cc: Docs comments changes; Using constexpr instead of const

Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
Dmytro Lytovchenko
2021-10-09 14:52:09 +02:00
committed by GitHub
parent 1ba64684f9
commit c287b82c00
11 changed files with 326 additions and 390 deletions

View File

@@ -23,7 +23,7 @@
****
***/
static unsigned int getSpeed_Bps(struct bratecontrol const* r, unsigned int interval_msec, uint64_t now)
unsigned int tr_bandwidth::getSpeed_Bps(struct bratecontrol const* r, unsigned int interval_msec, uint64_t now)
{
if (now == 0)
{
@@ -34,7 +34,7 @@ static unsigned int getSpeed_Bps(struct bratecontrol const* r, unsigned int inte
{
uint64_t bytes = 0;
uint64_t const cutoff = now - interval_msec;
struct bratecontrol* rvolatile = (struct bratecontrol*)r;
auto* rvolatile = (struct bratecontrol*)r;
for (int i = r->newest; r->transfers[i].date > cutoff;)
{
@@ -58,7 +58,7 @@ static unsigned int getSpeed_Bps(struct bratecontrol const* r, unsigned int inte
return r->cache_val;
}
static void bytesUsed(uint64_t const now, struct bratecontrol* r, size_t size)
void tr_bandwidth::notifyBandwidthConsumedBytes(uint64_t const now, struct bratecontrol* r, size_t size)
{
if (r->transfers[r->newest].date + GRANULARITY_MSEC >= now)
{
@@ -79,69 +79,43 @@ static void bytesUsed(uint64_t const now, struct bratecontrol* r, size_t size)
r->cache_time = 0;
}
/******
*******
*******
******/
/***
****
***/
static int compareBandwidth(void const* va, void const* vb)
tr_bandwidth::tr_bandwidth(tr_bandwidth* newParent)
: band{}
, parent{ nullptr }
, children{}
, peer{ nullptr }
{
auto const* a = static_cast<tr_bandwidth const*>(va);
auto const* b = static_cast<tr_bandwidth const*>(vb);
return a->uniqueKey - b->uniqueKey;
this->children = {};
this->band[TR_UP].honorParentLimits = true;
this->band[TR_DOWN].honorParentLimits = true;
this->setParent(newParent);
}
/***
****
***/
void tr_bandwidthConstruct(tr_bandwidth* b, tr_bandwidth* parent)
void tr_bandwidth::setParent(tr_bandwidth* newParent)
{
static unsigned int uniqueKey = 0;
TR_ASSERT(this != newParent);
b->children = {};
b->magicNumber = BANDWIDTH_MAGIC_NUMBER;
b->uniqueKey = uniqueKey++;
b->band[TR_UP].honorParentLimits = true;
b->band[TR_DOWN].honorParentLimits = true;
tr_bandwidthSetParent(b, parent);
}
void tr_bandwidthDestruct(tr_bandwidth* b)
{
TR_ASSERT(tr_isBandwidth(b));
tr_bandwidthSetParent(b, nullptr);
tr_ptrArrayDestruct(&b->children, nullptr);
memset(b, ~0, sizeof(tr_bandwidth));
}
/***
****
***/
void tr_bandwidthSetParent(tr_bandwidth* b, tr_bandwidth* parent)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(b != parent);
if (b->parent != nullptr)
if (this->parent != nullptr)
{
TR_ASSERT(tr_isBandwidth(b->parent));
tr_ptrArrayRemoveSortedPointer(&b->parent->children, b, compareBandwidth);
b->parent = nullptr;
this->parent->children.erase(this);
this->parent = nullptr;
}
if (parent != nullptr)
if (newParent != nullptr)
{
TR_ASSERT(tr_isBandwidth(parent));
TR_ASSERT(parent->parent != b);
TR_ASSERT(newParent->parent != this);
TR_ASSERT(newParent->children.find(this) == newParent->children.end()); // does not exist
TR_ASSERT(tr_ptrArrayFindSorted(&parent->children, b, compareBandwidth) == nullptr);
tr_ptrArrayInsertSorted(&parent->children, b, compareBandwidth);
TR_ASSERT(tr_ptrArrayFindSorted(&parent->children, b, compareBandwidth) == b);
b->parent = parent;
newParent->children.insert(this);
this->parent = newParent;
}
}
@@ -149,54 +123,46 @@ void tr_bandwidthSetParent(tr_bandwidth* b, tr_bandwidth* parent)
****
***/
static void allocateBandwidth(
tr_bandwidth* b,
void tr_bandwidth::allocateBandwidth(
tr_priority_t parent_priority,
tr_direction dir,
unsigned int period_msec,
tr_ptrArray* peer_pool)
std::vector<tr_peerIo*>& peer_pool)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(tr_isDirection(dir));
tr_priority_t const priority = std::max(parent_priority, b->priority);
tr_priority_t const priority_ = std::max(parent_priority, this->priority);
/* set the available bandwidth */
if (b->band[dir].isLimited)
if (this->band[dir].isLimited)
{
uint64_t const nextPulseSpeed = b->band[dir].desiredSpeed_Bps;
b->band[dir].bytesLeft = nextPulseSpeed * period_msec / 1000U;
uint64_t const nextPulseSpeed = this->band[dir].desiredSpeed_Bps;
this->band[dir].bytesLeft = nextPulseSpeed * period_msec / 1000U;
}
/* add this bandwidth's peer, if any, to the peer pool */
if (b->peer != nullptr)
if (this->peer != nullptr)
{
b->peer->priority = priority;
tr_ptrArrayAppend(peer_pool, b->peer);
this->peer->priority = priority_;
peer_pool.push_back(this->peer);
}
/* traverse & repeat for the subtree */
struct tr_bandwidth** children = (struct tr_bandwidth**)tr_ptrArrayBase(&b->children);
struct tr_bandwidth** const end = children + tr_ptrArraySize(&b->children);
for (; children != end; ++children)
// traverse & repeat for the subtree
for (auto child : this->children)
{
allocateBandwidth(*children, priority, dir, period_msec, peer_pool);
child->allocateBandwidth(priority_, dir, period_msec, peer_pool);
}
}
static void phaseOne(tr_ptrArray const* peerArray, tr_direction dir)
void tr_bandwidth::phaseOne(std::vector<tr_peerIo*>& peerArray, tr_direction dir)
{
int n;
int peerCount = tr_ptrArraySize(peerArray);
struct tr_peerIo** peers = (struct tr_peerIo**)tr_ptrArrayBase(peerArray);
/* First phase of IO. Tries to distribute bandwidth fairly to keep faster
* peers from starving the others. Loop through the peers, giving each a
* small chunk of bandwidth. Keep looping until we run out of bandwidth
* and/or peers that can use it */
n = peerCount;
dbgmsg("%d peers to go round-robin for %s", n, dir == TR_UP ? "upload" : "download");
dbgmsg("%lu peers to go round-robin for %s", peerArray.size(), dir == TR_UP ? "upload" : "download");
size_t n = peerArray.size();
while (n > 0)
{
int const i = tr_rand_int_weak(n); /* pick a peer at random */
@@ -206,56 +172,48 @@ static void phaseOne(tr_ptrArray const* peerArray, tr_direction dir)
* out in a timely manner. */
size_t const increment = 3000;
int const bytesUsed = tr_peerIoFlush(peers[i], dir, increment);
int const bytesUsed = tr_peerIoFlush(peerArray[i], dir, increment);
dbgmsg("peer #%d of %d used %d bytes in this pass", i, n, bytesUsed);
dbgmsg("peer #%d of %zu used %d bytes in this pass", i, n, bytesUsed);
if (bytesUsed != (int)increment)
{
/* peer is done writing for now; move it to the end of the list */
tr_peerIo* pio = peers[i];
peers[i] = peers[n - 1];
peers[n - 1] = pio;
std::swap(peerArray[i], peerArray[n - 1]);
--n;
}
}
}
void tr_bandwidthAllocate(tr_bandwidth* b, tr_direction dir, unsigned int period_msec)
void tr_bandwidth::allocate(tr_direction dir, unsigned int period_msec)
{
int peerCount;
auto tmp = tr_ptrArray{};
auto low = tr_ptrArray{};
auto high = tr_ptrArray{};
auto normal = tr_ptrArray{};
struct tr_peerIo** peers;
std::vector<tr_peerIo*> tmp;
std::vector<tr_peerIo*> low;
std::vector<tr_peerIo*> normal;
std::vector<tr_peerIo*> high;
/* allocateBandwidth () is a helper function with two purposes:
* 1. allocate bandwidth to b and its subtree
* 2. accumulate an array of all the peerIos from b and its subtree. */
allocateBandwidth(b, TR_PRI_LOW, dir, period_msec, &tmp);
peers = (struct tr_peerIo**)tr_ptrArrayBase(&tmp);
peerCount = tr_ptrArraySize(&tmp);
this->allocateBandwidth(TR_PRI_LOW, dir, period_msec, tmp);
for (int i = 0; i < peerCount; ++i)
for (auto io : tmp)
{
tr_peerIo* io = peers[i];
tr_peerIoRef(io);
tr_peerIoFlushOutgoingProtocolMsgs(io);
switch (io->priority)
{
case TR_PRI_HIGH:
tr_ptrArrayAppend(&high, io);
high.push_back(io);
[[fallthrough]];
case TR_PRI_NORMAL:
tr_ptrArrayAppend(&normal, io);
normal.push_back(io);
[[fallthrough]];
default:
tr_ptrArrayAppend(&low, io);
low.push_back(io);
}
}
@@ -263,153 +221,113 @@ void tr_bandwidthAllocate(tr_bandwidth* b, tr_direction dir, unsigned int period
* peers from starving the others. Loop through the peers, giving each a
* small chunk of bandwidth. Keep looping until we run out of bandwidth
* and/or peers that can use it */
phaseOne(&high, dir);
phaseOne(&normal, dir);
phaseOne(&low, dir);
phaseOne(high, dir);
phaseOne(normal, dir);
phaseOne(low, dir);
/* Second phase of IO. To help us scale in high bandwidth situations,
* enable on-demand IO for peers with bandwidth left to burn.
* This on-demand IO is enabled until (1) the peer runs out of bandwidth,
* or (2) the next tr_bandwidthAllocate () call, when we start over again. */
for (int i = 0; i < peerCount; ++i)
* or (2) the next tr_bandwidth::allocate () call, when we start over again. */
for (auto io : tmp)
{
tr_peerIoSetEnabled(peers[i], dir, tr_peerIoHasBandwidthLeft(peers[i], dir));
tr_peerIoSetEnabled(io, dir, tr_peerIoHasBandwidthLeft(io, dir));
}
for (int i = 0; i < peerCount; ++i)
for (auto io : tmp)
{
tr_peerIoUnref(peers[i]);
tr_peerIoUnref(io);
}
/* cleanup */
tr_ptrArrayDestruct(&normal, nullptr);
tr_ptrArrayDestruct(&high, nullptr);
tr_ptrArrayDestruct(&low, nullptr);
tr_ptrArrayDestruct(&tmp, nullptr);
}
void tr_bandwidthSetPeer(tr_bandwidth* b, tr_peerIo* peer)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(peer == nullptr || tr_isPeerIo(peer));
b->peer = peer;
}
/***
****
***/
static unsigned int bandwidthClamp(tr_bandwidth const* b, uint64_t now, tr_direction dir, unsigned int byteCount)
unsigned int tr_bandwidth::clamp(uint64_t now, tr_direction dir, unsigned int byteCount) const
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(tr_isDirection(dir));
if (b != nullptr)
if (this->band[dir].isLimited)
{
if (b->band[dir].isLimited)
byteCount = std::min(byteCount, this->band[dir].bytesLeft);
/* if we're getting close to exceeding the speed limit,
* clamp down harder on the bytes available */
if (byteCount > 0)
{
byteCount = std::min(byteCount, b->band[dir].bytesLeft);
double current;
double desired;
double r;
/* if we're getting close to exceeding the speed limit,
* clamp down harder on the bytes available */
if (byteCount > 0)
if (now == 0)
{
double current;
double desired;
double r;
now = tr_time_msec();
}
if (now == 0)
{
now = tr_time_msec();
}
current = this->getRawSpeed_Bps(now, TR_DOWN);
desired = this->getDesiredSpeed_Bps(TR_DOWN);
r = desired >= 1 ? current / desired : 0;
current = tr_bandwidthGetRawSpeed_Bps(b, now, TR_DOWN);
desired = tr_bandwidthGetDesiredSpeed_Bps(b, TR_DOWN);
r = desired >= 1 ? current / desired : 0;
if (r > 1.0)
{
byteCount = 0;
}
else if (r > 0.9)
{
byteCount *= 0.8;
}
else if (r > 0.8)
{
byteCount *= 0.9;
}
if (r > 1.0)
{
byteCount = 0;
}
else if (r > 0.9)
{
byteCount = static_cast<unsigned int>(byteCount * 0.8);
}
else if (r > 0.8)
{
byteCount = static_cast<unsigned int>(byteCount * 0.9);
}
}
}
if (b->parent != nullptr && b->band[dir].honorParentLimits && byteCount > 0)
{
byteCount = bandwidthClamp(b->parent, now, dir, byteCount);
}
if (this->parent != nullptr && this->band[dir].honorParentLimits && byteCount > 0)
{
byteCount = this->parent->clamp(now, dir, byteCount);
}
return byteCount;
}
unsigned int tr_bandwidthClamp(tr_bandwidth const* b, tr_direction dir, unsigned int byteCount)
void tr_bandwidth::notifyBandwidthConsumed(tr_direction dir, size_t byteCount, bool isPieceData, uint64_t now)
{
return bandwidthClamp(b, 0, dir, byteCount);
}
unsigned int tr_bandwidthGetRawSpeed_Bps(tr_bandwidth const* b, uint64_t const now, tr_direction const dir)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(tr_isDirection(dir));
return getSpeed_Bps(&b->band[dir].raw, HISTORY_MSEC, now);
}
struct tr_band* band_ = &this->band[dir];
unsigned int tr_bandwidthGetPieceSpeed_Bps(tr_bandwidth const* b, uint64_t const now, tr_direction const dir)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(tr_isDirection(dir));
return getSpeed_Bps(&b->band[dir].piece, HISTORY_MSEC, now);
}
void tr_bandwidthUsed(tr_bandwidth* b, tr_direction dir, size_t byteCount, bool isPieceData, uint64_t now)
{
TR_ASSERT(tr_isBandwidth(b));
TR_ASSERT(tr_isDirection(dir));
struct tr_band* band = &b->band[dir];
if (band->isLimited && isPieceData)
if (band_->isLimited && isPieceData)
{
band->bytesLeft -= std::min(size_t{ band->bytesLeft }, byteCount);
band_->bytesLeft -= std::min(size_t{ band_->bytesLeft }, byteCount);
}
#ifdef DEBUG_DIRECTION
if (dir == DEBUG_DIRECTION && band->isLimited)
if (dir == DEBUG_DIRECTION && band_->isLimited)
{
fprintf(
stderr,
"%p consumed %5zu bytes of %5s data... was %6zu, now %6zu left\n",
b,
this,
byteCount,
isPieceData ? "piece" : "raw",
oldBytesLeft,
band->bytesLeft);
band_->bytesLeft);
}
#endif
bytesUsed(now, &band->raw, byteCount);
notifyBandwidthConsumedBytes(now, &band_->raw, byteCount);
if (isPieceData)
{
bytesUsed(now, &band->piece, byteCount);
notifyBandwidthConsumedBytes(now, &band_->piece, byteCount);
}
if (b->parent != nullptr)
if (this->parent != nullptr)
{
tr_bandwidthUsed(b->parent, dir, byteCount, isPieceData, now);
this->parent->notifyBandwidthConsumed(dir, byteCount, isPieceData, now);
}
}

View File

@@ -12,8 +12,10 @@
#error only libtransmission should #include this header.
#endif
#include <array>
#include <unordered_set>
#include "transmission.h"
#include "ptrarray.h"
#include "tr-assert.h"
#include "utils.h" /* tr_new(), tr_free() */
@@ -26,14 +28,10 @@ struct tr_peerIo;
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
* it's included in the header for inlining and composition. */
enum
{
HISTORY_MSEC = 2000U,
INTERVAL_MSEC = HISTORY_MSEC,
GRANULARITY_MSEC = 200,
HISTORY_SIZE = (INTERVAL_MSEC / GRANULARITY_MSEC),
BANDWIDTH_MAGIC_NUMBER = 43143
};
constexpr size_t HISTORY_MSEC = 2000U;
constexpr size_t INTERVAL_MSEC = HISTORY_MSEC;
constexpr size_t GRANULARITY_MSEC = 200;
constexpr size_t HISTORY_SIZE = (INTERVAL_MSEC / GRANULARITY_MSEC);
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
* it's included in the header for inlining and composition. */
@@ -88,149 +86,170 @@ struct tr_band
*
* CONSTRAINING
*
* Call tr_bandwidthAllocate() periodically. tr_bandwidth knows its current
* Call tr_bandwidth::allocate() periodically. tr_bandwidth knows its current
* speed and will decide how many bytes to make available over the
* user-specified period to reach the user-specified desired speed.
* If appropriate, it notifies its peer-ios that new bandwidth is available.
*
* tr_bandwidthAllocate() operates on the tr_bandwidth subtree, so usually
* tr_bandwidth::allocate() operates on the tr_bandwidth subtree, so usually
* you'll only need to invoke it for the top-level tr_session bandwidth.
*
* The peer-ios all have a pointer to their associated tr_bandwidth object,
* and call tr_bandwidthClamp() before performing I/O to see how much
* and call tr_bandwidth::clamp() before performing I/O to see how much
* bandwidth they can safely use.
*/
struct tr_bandwidth
{
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
* it's included in the header for inlining and composition. */
public:
explicit tr_bandwidth(tr_bandwidth* newParent);
struct tr_band band[2];
tr_bandwidth()
: tr_bandwidth(nullptr)
{
}
~tr_bandwidth()
{
this->setParent(nullptr);
}
/**
* @brief Sets new peer, nullptr is allowed.
*/
void setPeer(tr_peerIo* newPeer)
{
this->peer = newPeer;
}
/**
* @brief Notify the bandwidth object that some of its allocated bandwidth has been consumed.
* This is is usually invoked by the peer-io after a read or write.
*/
void notifyBandwidthConsumed(tr_direction dir, size_t byteCount, bool isPieceData, uint64_t now);
/**
* @brief allocate the next period_msec's worth of bandwidth for the peer-ios to consume
*/
void allocate(tr_direction dir, unsigned int period_msec);
void setParent(tr_bandwidth* newParent);
[[nodiscard]] tr_priority_t getPriority() const
{
return this->priority;
}
void setPriority(tr_priority_t prio)
{
this->priority = prio;
}
/**
* @brief clamps byteCount down to a number that this bandwidth will allow to be consumed
*/
[[nodiscard]] unsigned int clamp(tr_direction dir, unsigned int byteCount) const
{
return this->clamp(0, dir, byteCount);
}
/** @brief Get the raw total of bytes read or sent by this bandwidth subtree. */
[[nodiscard]] unsigned int getRawSpeed_Bps(uint64_t const now, tr_direction const dir) const
{
TR_ASSERT(tr_isDirection(dir));
return getSpeed_Bps(&this->band[dir].raw, HISTORY_MSEC, now);
}
/** @brief Get the number of piece data bytes read or sent by this bandwidth subtree. */
[[nodiscard]] unsigned int getPieceSpeed_Bps(uint64_t const now, tr_direction const dir) const
{
TR_ASSERT(tr_isDirection(dir));
return getSpeed_Bps(&this->band[dir].piece, HISTORY_MSEC, now);
}
/**
* @brief Set the desired speed for this bandwidth subtree.
* @see tr_bandwidth::allocate
* @see tr_bandwidth::getDesiredSpeed
*/
constexpr bool setDesiredSpeed_Bps(tr_direction dir, unsigned int desiredSpeed)
{
unsigned int* value = &this->band[dir].desiredSpeed_Bps;
bool const didChange = desiredSpeed != *value;
*value = desiredSpeed;
return didChange;
}
/**
* @brief Get the desired speed for the bandwidth subtree.
* @see tr_bandwidth::setDesiredSpeed
*/
[[nodiscard]] constexpr double getDesiredSpeed_Bps(tr_direction dir) const
{
return this->band[dir].desiredSpeed_Bps;
}
/**
* @brief Set whether or not this bandwidth should throttle its peer-io's speeds
*/
constexpr bool setLimited(tr_direction dir, bool isLimited)
{
bool* value = &this->band[dir].isLimited;
bool const didChange = isLimited != *value;
*value = isLimited;
return didChange;
}
/**
* @return nonzero if this bandwidth throttles its peer-ios speeds
*/
[[nodiscard]] constexpr bool isLimited(tr_direction dir) const
{
return this->band[dir].isLimited;
}
/**
* Almost all the time we do want to honor a parents' bandwidth cap, so that
* (for example) a peer is constrained by a per-torrent cap and the global cap.
* But when we set a torrent's speed mode to TR_SPEEDLIMIT_UNLIMITED, then
* in that particular case we want to ignore the global speed limit...
*/
constexpr bool honorParentLimits(tr_direction direction, bool isEnabled)
{
bool* value = &this->band[direction].honorParentLimits;
bool const didChange = isEnabled != *value;
*value = isEnabled;
return didChange;
}
[[nodiscard]] constexpr bool areParentLimitsHonored(tr_direction direction) const
{
TR_ASSERT(tr_isDirection(direction));
return this->band[direction].honorParentLimits;
}
private:
static unsigned int getSpeed_Bps(struct bratecontrol const* r, unsigned int interval_msec, uint64_t now);
static void notifyBandwidthConsumedBytes(uint64_t now, struct bratecontrol* r, size_t size);
[[nodiscard]] unsigned int clamp(uint64_t now, tr_direction dir, unsigned int byteCount) const;
static void phaseOne(std::vector<tr_peerIo*>& peerArray, tr_direction dir);
void allocateBandwidth(
tr_priority_t parent_priority,
tr_direction dir,
unsigned int period_msec,
std::vector<tr_peerIo*>& peer_pool);
tr_priority_t priority = 0;
std::array<struct tr_band, 2> band;
struct tr_bandwidth* parent;
tr_priority_t priority;
int magicNumber;
unsigned int uniqueKey;
tr_ptrArray children; /* struct tr_bandwidth */
std::unordered_set<tr_bandwidth*> children;
struct tr_peerIo* peer;
};
/**
***
**/
void tr_bandwidthConstruct(tr_bandwidth* bandwidth, tr_bandwidth* parent);
void tr_bandwidthDestruct(tr_bandwidth* bandwidth);
/** @brief test to see if the pointer refers to a live bandwidth object */
constexpr bool tr_isBandwidth(tr_bandwidth const* b)
{
return b != nullptr && b->magicNumber == BANDWIDTH_MAGIC_NUMBER;
}
/******
*******
******/
/**
* @brief Set the desired speed for this bandwidth subtree.
* @see tr_bandwidthAllocate
* @see tr_bandwidthGetDesiredSpeed
*/
constexpr bool tr_bandwidthSetDesiredSpeed_Bps(tr_bandwidth* bandwidth, tr_direction dir, unsigned int desiredSpeed)
{
unsigned int* value = &bandwidth->band[dir].desiredSpeed_Bps;
bool const didChange = desiredSpeed != *value;
*value = desiredSpeed;
return didChange;
}
/**
* @brief Get the desired speed for the bandwidth subtree.
* @see tr_bandwidthSetDesiredSpeed
*/
constexpr double tr_bandwidthGetDesiredSpeed_Bps(tr_bandwidth const* bandwidth, tr_direction dir)
{
return bandwidth->band[dir].desiredSpeed_Bps;
}
/**
* @brief Set whether or not this bandwidth should throttle its peer-io's speeds
*/
constexpr bool tr_bandwidthSetLimited(tr_bandwidth* bandwidth, tr_direction dir, bool isLimited)
{
bool* value = &bandwidth->band[dir].isLimited;
bool const didChange = isLimited != *value;
*value = isLimited;
return didChange;
}
/**
* @return nonzero if this bandwidth throttles its peer-ios speeds
*/
constexpr bool tr_bandwidthIsLimited(tr_bandwidth const* bandwidth, tr_direction dir)
{
return bandwidth->band[dir].isLimited;
}
/**
* @brief allocate the next period_msec's worth of bandwidth for the peer-ios to consume
*/
void tr_bandwidthAllocate(tr_bandwidth* bandwidth, tr_direction direction, unsigned int period_msec);
/**
* @brief clamps byteCount down to a number that this bandwidth will allow to be consumed
*/
unsigned int tr_bandwidthClamp(tr_bandwidth const* bandwidth, tr_direction direction, unsigned int byteCount);
/******
*******
******/
/** @brief Get the raw total of bytes read or sent by this bandwidth subtree. */
unsigned int tr_bandwidthGetRawSpeed_Bps(tr_bandwidth const* bandwidth, uint64_t const now, tr_direction const direction);
/** @brief Get the number of piece data bytes read or sent by this bandwidth subtree. */
unsigned int tr_bandwidthGetPieceSpeed_Bps(tr_bandwidth const* bandwidth, uint64_t const now, tr_direction const direction);
/**
* @brief Notify the bandwidth object that some of its allocated bandwidth has been consumed.
* This is is usually invoked by the peer-io after a read or write.
*/
void tr_bandwidthUsed(tr_bandwidth* bandwidth, tr_direction direction, size_t byteCount, bool isPieceData, uint64_t now);
/******
*******
******/
void tr_bandwidthSetParent(tr_bandwidth* bandwidth, tr_bandwidth* parent);
/**
* Almost all the time we do want to honor a parents' bandwidth cap, so that
* (for example) a peer is constrained by a per-torrent cap and the global cap.
* But when we set a torrent's speed mode to TR_SPEEDLIMIT_UNLIMITED, then
* in that particular case we want to ignore the global speed limit...
*/
constexpr bool tr_bandwidthHonorParentLimits(tr_bandwidth* bandwidth, tr_direction direction, bool isEnabled)
{
bool* value = &bandwidth->band[direction].honorParentLimits;
bool const didChange = isEnabled != *value;
*value = isEnabled;
return didChange;
}
constexpr bool tr_bandwidthAreParentLimitsHonored(tr_bandwidth const* bandwidth, tr_direction direction)
{
TR_ASSERT(tr_isBandwidth(bandwidth));
TR_ASSERT(tr_isDirection(direction));
return bandwidth->band[direction].honorParentLimits;
}
/******
*******
******/
void tr_bandwidthSetPeer(tr_bandwidth* bandwidth, struct tr_peerIo* peerIo);
/* @} */

View File

@@ -164,11 +164,11 @@ static void didWriteWrapper(tr_peerIo* io, unsigned int bytes_transferred)
unsigned int const overhead = io->socket.type == TR_PEER_SOCKET_TYPE_TCP ? guessPacketOverhead(payload) : 0;
uint64_t const now = tr_time_msec();
tr_bandwidthUsed(&io->bandwidth, TR_UP, payload, next->isPieceData, now);
io->bandwidth->notifyBandwidthConsumed(TR_UP, payload, next->isPieceData, now);
if (overhead > 0)
{
tr_bandwidthUsed(&io->bandwidth, TR_UP, overhead, false, now);
io->bandwidth->notifyBandwidthConsumed(TR_UP, overhead, false, now);
}
if (io->didWrite != nullptr)
@@ -220,18 +220,18 @@ static void canReadWrapper(tr_peerIo* io)
{
if (piece != 0)
{
tr_bandwidthUsed(&io->bandwidth, TR_DOWN, piece, true, now);
io->bandwidth->notifyBandwidthConsumed(TR_DOWN, piece, true, now);
}
if (used != piece)
{
tr_bandwidthUsed(&io->bandwidth, TR_DOWN, used - piece, false, now);
io->bandwidth->notifyBandwidthConsumed(TR_DOWN, used - piece, false, now);
}
}
if (overhead > 0)
{
tr_bandwidthUsed(&io->bandwidth, TR_UP, overhead, false, now);
io->bandwidth->notifyBandwidthConsumed(TR_UP, overhead, false, now);
}
switch (ret)
@@ -285,7 +285,7 @@ static void event_read_cb(evutil_socket_t fd, short event, void* vio)
curlen = evbuffer_get_length(io->inbuf);
howmuch = curlen >= max ? 0 : max - curlen;
howmuch = tr_bandwidthClamp(&io->bandwidth, TR_DOWN, howmuch);
howmuch = io->bandwidth->clamp(TR_DOWN, howmuch);
dbgmsg(io, "libevent says this peer is ready to read");
@@ -378,7 +378,7 @@ static void event_write_cb(evutil_socket_t fd, short event, void* vio)
/* Write as much as possible, since the socket is non-blocking, write() will
* return if it can't write any more data without blocking */
howmuch = tr_bandwidthClamp(&io->bandwidth, dir, evbuffer_get_length(io->outbuf));
howmuch = io->bandwidth->clamp(dir, evbuffer_get_length(io->outbuf));
/* if we don't have any bandwidth left, stop writing */
if (howmuch < 1)
@@ -496,7 +496,7 @@ static size_t utp_get_rb_size(void* vio)
TR_ASSERT(tr_isPeerIo(io));
size_t bytes = tr_bandwidthClamp(&io->bandwidth, TR_DOWN, UTP_READ_BUFFER_SIZE);
size_t bytes = io->bandwidth->clamp(TR_DOWN, UTP_READ_BUFFER_SIZE);
dbgmsg(io, "utp_get_rb_size is saying it's ready to read %zu bytes", bytes);
return UTP_READ_BUFFER_SIZE - bytes;
@@ -577,7 +577,7 @@ static void utp_on_overhead(void* vio, bool send, size_t count, int type)
dbgmsg(io, "utp_on_overhead -- count is %zu", count);
tr_bandwidthUsed(&io->bandwidth, send ? TR_UP : TR_DOWN, count, false, tr_time_msec());
io->bandwidth->notifyBandwidthConsumed(send ? TR_UP : TR_DOWN, count, false, tr_time_msec());
}
static auto utp_function_table = UTPFunctionTable{
@@ -680,8 +680,8 @@ static tr_peerIo* tr_peerIoNew(
io->timeCreated = tr_time();
io->inbuf = evbuffer_new();
io->outbuf = evbuffer_new();
tr_bandwidthConstruct(&io->bandwidth, parent);
tr_bandwidthSetPeer(&io->bandwidth, io);
io->bandwidth = new tr_bandwidth(parent);
io->bandwidth->setPeer(io);
dbgmsg(io, "bandwidth is %p; its parent is %p", (void*)&io->bandwidth, (void*)parent);
switch (socket.type)
@@ -921,7 +921,7 @@ static void io_dtor(void* vio)
dbgmsg(io, "in tr_peerIo destructor");
event_disable(io, EV_READ | EV_WRITE);
tr_bandwidthDestruct(&io->bandwidth);
delete io->bandwidth;
evbuffer_free(io->outbuf);
evbuffer_free(io->inbuf);
io_close_socket(io);
@@ -1094,7 +1094,7 @@ static unsigned int getDesiredOutputBufferSize(tr_peerIo const* io, uint64_t now
* being large enough to hold the next 20 seconds' worth of input,
* or a few blocks, whichever is bigger.
* It's okay to tweak this as needed */
unsigned int const currentSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps(&io->bandwidth, now, TR_UP);
unsigned int const currentSpeed_Bps = io->bandwidth->getPieceSpeed_Bps(now, TR_UP);
unsigned int const period = 15U; /* arbitrary */
/* the 3 is arbitrary; the .5 is to leave room for messages */
static auto const ceiling = (unsigned int)(MAX_BLOCK_SIZE * 3.5);
@@ -1316,7 +1316,7 @@ static int tr_peerIoTryRead(tr_peerIo* io, size_t howmuch)
{
int res = 0;
if ((howmuch = tr_bandwidthClamp(&io->bandwidth, TR_DOWN, howmuch)) != 0)
if ((howmuch = io->bandwidth->clamp(TR_DOWN, howmuch)) != 0)
{
switch (io->socket.type)
{
@@ -1389,7 +1389,7 @@ static int tr_peerIoTryWrite(tr_peerIo* io, size_t howmuch)
howmuch = old_len;
}
if ((howmuch = tr_bandwidthClamp(&io->bandwidth, TR_UP, howmuch)) != 0)
if ((howmuch = io->bandwidth->clamp(TR_UP, howmuch)) != 0)
{
switch (io->socket.type)
{
@@ -1454,7 +1454,7 @@ int tr_peerIoFlush(tr_peerIo* io, tr_direction dir, size_t limit)
bytesUsed = tr_peerIoTryWrite(io, limit);
}
dbgmsg(io, "flushing peer-io, direction %d, limit %zu, bytesUsed %d", (int)dir, limit, bytesUsed);
dbgmsg(io, "flushing peer-io, direction %d, limit %zu, notifyBandwidthConsumedBytes %d", (int)dir, limit, bytesUsed);
return bytesUsed;
}

View File

@@ -91,7 +91,9 @@ struct tr_peerIo
tr_net_error_cb gotError;
void* userData;
struct tr_bandwidth bandwidth;
// Changed to non-owning pointer temporarily till tr_peerIo becomes C++-constructible and destructible
// TODO: change tr_bandwidth* to owning pointer to the bandwidth, or remove * and own the value
struct tr_bandwidth* bandwidth;
tr_crypto crypto;
struct evbuffer* inbuf;
@@ -134,8 +136,7 @@ void tr_peerIoUnrefImpl(char const* file, int line, tr_peerIo* io);
constexpr bool tr_isPeerIo(tr_peerIo const* io)
{
return io != nullptr && io->magicNumber == PEER_IO_MAGIC_NUMBER && io->refCount >= 0 && tr_isBandwidth(&io->bandwidth) &&
tr_address_is_valid(&io->addr);
return io != nullptr && io->magicNumber == PEER_IO_MAGIC_NUMBER && io->refCount >= 0 && tr_address_is_valid(&io->addr);
}
/**
@@ -302,19 +303,19 @@ static inline void tr_peerIoSetParent(tr_peerIo* io, struct tr_bandwidth* parent
{
TR_ASSERT(tr_isPeerIo(io));
tr_bandwidthSetParent(&io->bandwidth, parent);
io->bandwidth->setParent(parent);
}
void tr_peerIoBandwidthUsed(tr_peerIo* io, tr_direction direction, size_t byteCount, int isPieceData);
static inline bool tr_peerIoHasBandwidthLeft(tr_peerIo const* io, tr_direction dir)
{
return tr_bandwidthClamp(&io->bandwidth, dir, 1024) > 0;
return io->bandwidth->clamp(dir, 1024) > 0;
}
static inline unsigned int tr_peerIoGetPieceSpeed_Bps(tr_peerIo const* io, uint64_t now, tr_direction dir)
{
return tr_bandwidthGetPieceSpeed_Bps(&io->bandwidth, now, dir);
return io->bandwidth->getPieceSpeed_Bps(now, dir);
}
/**

View File

@@ -2054,7 +2054,7 @@ static bool myHandshakeDoneCB(
/* this steals its refcount too, which is balanced by our unref in peerDelete() */
tr_peerIo* stolen = tr_handshakeStealIO(handshake);
tr_peerIoSetParent(stolen, &s->tor->bandwidth);
tr_peerIoSetParent(stolen, s->tor->bandwidth);
createBitTorrentPeer(s->tor, stolen, atom, client);
success = true;
@@ -2116,7 +2116,7 @@ void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address* addr, tr_port port,
tr_peerIo* io;
tr_handshake* handshake;
io = tr_peerIoNewIncoming(session, &session->bandwidth, addr, port, socket);
io = tr_peerIoNewIncoming(session, session->bandwidth, addr, port, socket);
handshake = tr_handshakeNew(io, session->encryptionMode, myHandshakeDoneCB, manager);
@@ -3185,14 +3185,14 @@ static int getRate(tr_torrent const* tor, struct peer_atom* atom, uint64_t now)
static inline bool isBandwidthMaxedOut(tr_bandwidth const* b, uint64_t const now_msec, tr_direction dir)
{
if (!tr_bandwidthIsLimited(b, dir))
if (!b->isLimited(dir))
{
return false;
}
else
{
unsigned int const got = tr_bandwidthGetPieceSpeed_Bps(b, now_msec, dir);
unsigned int const want = tr_bandwidthGetDesiredSpeed_Bps(b, dir);
unsigned int const got = b->getPieceSpeed_Bps(now_msec, dir);
unsigned int const want = b->getDesiredSpeed_Bps(dir);
return got >= want;
}
}
@@ -3206,7 +3206,7 @@ static void rechokeUploads(tr_swarm* s, uint64_t const now)
struct ChokeData* choke = tr_new0(struct ChokeData, peerCount);
tr_session const* session = s->manager->session;
bool const chokeAll = !tr_torrentIsPieceTransferAllowed(s->tor, TR_CLIENT_TO_PEER);
bool const isMaxedOut = isBandwidthMaxedOut(&s->tor->bandwidth, now, TR_UP);
bool const isMaxedOut = isBandwidthMaxedOut(s->tor->bandwidth, now, TR_UP);
/* an optimistic unchoke peer's "optimistic"
* state lasts for N calls to rechokeUploads(). */
@@ -3805,8 +3805,8 @@ static void bandwidthPulse(evutil_socket_t fd, short what, void* vmgr)
pumpAllPeers(mgr);
/* allocate bandwidth to the peers */
tr_bandwidthAllocate(&session->bandwidth, TR_UP, BANDWIDTH_PERIOD_MSEC);
tr_bandwidthAllocate(&session->bandwidth, TR_DOWN, BANDWIDTH_PERIOD_MSEC);
session->bandwidth->allocate(TR_UP, BANDWIDTH_PERIOD_MSEC);
session->bandwidth->allocate(TR_DOWN, BANDWIDTH_PERIOD_MSEC);
/* torrent upkeep */
for (auto* tor : session->torrents)
@@ -4213,7 +4213,7 @@ static struct peer_candidate* getPeerCandidates(tr_session* session, int* candid
}
/* if we've already got enough speed in this torrent... */
if (seeding && isBandwidthMaxedOut(&tor->bandwidth, now_msec, TR_UP))
if (seeding && isBandwidthMaxedOut(tor->bandwidth, now_msec, TR_UP))
{
continue;
}
@@ -4268,7 +4268,7 @@ static void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, struct peer_atom* a
io = tr_peerIoNewOutgoing(
mgr->session,
&mgr->session->bandwidth,
mgr->session->bandwidth,
&atom->addr,
atom->port,
s->tor->info.hash,

View File

@@ -636,7 +636,7 @@ tr_session* tr_sessionInit(char const* configDir, bool messageQueuingEnabled, tr
session->cache = tr_cacheNew(1024 * 1024 * 2);
session->magicNumber = SESSION_MAGIC_NUMBER;
session->session_id = tr_session_id_new();
tr_bandwidthConstruct(&session->bandwidth, nullptr);
session->bandwidth = new tr_bandwidth(nullptr);
tr_variantInitList(&session->removedTorrents, 0);
/* nice to start logging at the very beginning */
@@ -1494,9 +1494,9 @@ static void updateBandwidth(tr_session* session, tr_direction dir)
bool const isLimited = tr_sessionGetActiveSpeedLimit_Bps(session, dir, &limit_Bps);
bool const zeroCase = isLimited && limit_Bps == 0;
tr_bandwidthSetLimited(&session->bandwidth, dir, isLimited && !zeroCase);
session->bandwidth->setLimited(dir, isLimited && !zeroCase);
tr_bandwidthSetDesiredSpeed_Bps(&session->bandwidth, dir, limit_Bps);
session->bandwidth->setDesiredSpeed_Bps(dir, limit_Bps);
}
enum
@@ -1891,12 +1891,12 @@ bool tr_sessionGetDeleteSource(tr_session const* session)
unsigned int tr_sessionGetPieceSpeed_Bps(tr_session const* session, tr_direction dir)
{
return tr_isSession(session) ? tr_bandwidthGetPieceSpeed_Bps(&session->bandwidth, 0, dir) : 0;
return tr_isSession(session) ? session->bandwidth->getPieceSpeed_Bps(0, dir) : 0;
}
static unsigned int tr_sessionGetRawSpeed_Bps(tr_session const* session, tr_direction dir)
{
return tr_isSession(session) ? tr_bandwidthGetRawSpeed_Bps(&session->bandwidth, 0, dir) : 0;
return tr_isSession(session) ? session->bandwidth->getRawSpeed_Bps(0, dir) : 0;
}
double tr_sessionGetRawSpeed_KBps(tr_session const* session, tr_direction dir)
@@ -2112,7 +2112,7 @@ void tr_sessionClose(tr_session* session)
/* free the session memory */
tr_variantFree(&session->removedTorrents);
tr_bandwidthDestruct(&session->bandwidth);
delete session->bandwidth;
tr_bitfieldDestruct(&session->turtle.minutes);
tr_session_id_free(session->session_id);
tr_lockFree(session->lock);

View File

@@ -240,7 +240,9 @@ struct tr_session
struct event* saveTimer;
/* monitors the "global pool" speeds */
struct tr_bandwidth bandwidth;
// Changed to non-owning pointer temporarily till tr_session becomes C++-constructible and destructible
// TODO: change tr_bandwidth* to owning pointer to the bandwidth, or remove * and own the value
struct tr_bandwidth* bandwidth;
float desiredRatio;

View File

@@ -196,7 +196,7 @@ void tr_torrentSetSpeedLimit_Bps(tr_torrent* tor, tr_direction dir, unsigned int
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tr_isDirection(dir));
if (tr_bandwidthSetDesiredSpeed_Bps(&tor->bandwidth, dir, Bps))
if (tor->bandwidth->setDesiredSpeed_Bps(dir, Bps))
{
tr_torrentSetDirty(tor);
}
@@ -212,7 +212,7 @@ unsigned int tr_torrentGetSpeedLimit_Bps(tr_torrent const* tor, tr_direction dir
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tr_isDirection(dir));
return tr_bandwidthGetDesiredSpeed_Bps(&tor->bandwidth, dir);
return tor->bandwidth->getDesiredSpeed_Bps(dir);
}
unsigned int tr_torrentGetSpeedLimit_KBps(tr_torrent const* tor, tr_direction dir)
@@ -228,7 +228,7 @@ void tr_torrentUseSpeedLimit(tr_torrent* tor, tr_direction dir, bool do_use)
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tr_isDirection(dir));
if (tr_bandwidthSetLimited(&tor->bandwidth, dir, do_use))
if (tor->bandwidth->setLimited(dir, do_use))
{
tr_torrentSetDirty(tor);
}
@@ -238,19 +238,14 @@ bool tr_torrentUsesSpeedLimit(tr_torrent const* tor, tr_direction dir)
{
TR_ASSERT(tr_isTorrent(tor));
return tr_bandwidthIsLimited(&tor->bandwidth, dir);
return tor->bandwidth->isLimited(dir);
}
void tr_torrentUseSessionLimits(tr_torrent* tor, bool doUse)
{
TR_ASSERT(tr_isTorrent(tor));
bool changed;
changed = tr_bandwidthHonorParentLimits(&tor->bandwidth, TR_UP, doUse);
changed |= tr_bandwidthHonorParentLimits(&tor->bandwidth, TR_DOWN, doUse);
if (changed)
if (tor->bandwidth->honorParentLimits(TR_UP, doUse) || tor->bandwidth->honorParentLimits(TR_DOWN, doUse))
{
tr_torrentSetDirty(tor);
}
@@ -260,7 +255,7 @@ bool tr_torrentUsesSessionLimits(tr_torrent const* tor)
{
TR_ASSERT(tr_isTorrent(tor));
return tr_bandwidthAreParentLimitsHonored(&tor->bandwidth, TR_UP);
return tor->bandwidth->areParentLimitsHonored(TR_UP);
}
/***
@@ -886,9 +881,9 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tor->incompleteDir = tr_strdup(dir);
}
tr_bandwidthConstruct(&tor->bandwidth, &session->bandwidth);
tor->bandwidth = new tr_bandwidth(session->bandwidth);
tor->bandwidth.priority = tr_ctorGetBandwidthPriority(ctor);
tor->bandwidth->setPriority(tr_ctorGetBandwidthPriority(ctor));
tor->error = TR_STAT_OK;
tor->finishedSeedingByIdle = false;
@@ -1301,10 +1296,10 @@ tr_stat const* tr_torrentStat(tr_torrent* tor)
s->peersFrom[i] = swarm_stats.peerFromCount[i];
}
s->rawUploadSpeed_KBps = toSpeedKBps(tr_bandwidthGetRawSpeed_Bps(&tor->bandwidth, now, TR_UP));
s->rawDownloadSpeed_KBps = toSpeedKBps(tr_bandwidthGetRawSpeed_Bps(&tor->bandwidth, now, TR_DOWN));
pieceUploadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps(&tor->bandwidth, now, TR_UP);
pieceDownloadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps(&tor->bandwidth, now, TR_DOWN);
s->rawUploadSpeed_KBps = toSpeedKBps(tor->bandwidth->getRawSpeed_Bps(now, TR_UP));
s->rawDownloadSpeed_KBps = toSpeedKBps(tor->bandwidth->getRawSpeed_Bps(now, TR_DOWN));
pieceUploadSpeed_Bps = tor->bandwidth->getPieceSpeed_Bps(now, TR_UP);
pieceDownloadSpeed_Bps = tor->bandwidth->getPieceSpeed_Bps(now, TR_DOWN);
s->pieceUploadSpeed_KBps = toSpeedKBps(pieceUploadSpeed_Bps);
s->pieceDownloadSpeed_KBps = toSpeedKBps(pieceDownloadSpeed_Bps);
@@ -1638,7 +1633,7 @@ static void freeTorrent(tr_torrent* tor)
TR_ASSERT(queueIsSequenced(session));
tr_bandwidthDestruct(&tor->bandwidth);
delete tor->bandwidth;
tr_metainfoFree(inf);
delete tor;
@@ -2444,7 +2439,7 @@ tr_priority_t tr_torrentGetPriority(tr_torrent const* tor)
{
TR_ASSERT(tr_isTorrent(tor));
return tor->bandwidth.priority;
return tor->bandwidth->getPriority();
}
void tr_torrentSetPriority(tr_torrent* tor, tr_priority_t priority)
@@ -2452,9 +2447,9 @@ void tr_torrentSetPriority(tr_torrent* tor, tr_priority_t priority)
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tr_isPriority(priority));
if (tor->bandwidth.priority != priority)
if (tor->bandwidth->getPriority() != priority)
{
tor->bandwidth.priority = priority;
tor->bandwidth->setPriority(priority);
tr_torrentSetDirty(tor);
}

View File

@@ -257,7 +257,9 @@ struct tr_torrent
int uniqueId;
struct tr_bandwidth bandwidth;
// Changed to non-owning pointer temporarily till tr_torrent becomes C++-constructible and destructible
// TODO: change tr_bandwidth* to owning pointer to the bandwidth, or remove * and own the value
struct tr_bandwidth* bandwidth;
struct tr_swarm* swarm;

View File

@@ -115,7 +115,7 @@ static size_t writeFunc(void* ptr, size_t size, size_t nmemb, void* vtask)
{
tr_torrent const* const tor = tr_torrentFindFromId(task->session, task->torrentId);
if (tor != nullptr && tr_bandwidthClamp(&tor->bandwidth, TR_DOWN, nmemb) == 0)
if (tor != nullptr && tor->bandwidth->clamp(TR_DOWN, nmemb) == 0)
{
task->session->web->paused_easy_handles.insert(task->curl_easy);
return CURL_WRITEFUNC_PAUSE;

View File

@@ -64,6 +64,7 @@ public:
, base_url{ url }
, callback{ callback_in }
, callback_data{ callback_data_in }
, bandwidth(tor->bandwidth)
{
// init parent bits
tr_bitfieldSetHasAll(&have);
@@ -71,7 +72,6 @@ public:
file_urls.resize(tr_torrentInfo(tor)->fileCount);
tr_bandwidthConstruct(&bandwidth, &tor->bandwidth);
timer = evtimer_new(session->event_base, webseed_timer_func, this);
tr_timerAddMsec(timer, TR_IDLE_TIMER_MSEC);
}
@@ -83,7 +83,6 @@ public:
tasks.clear();
event_free(timer);
tr_bandwidthDestruct(&bandwidth);
}
bool is_transferring_pieces(uint64_t now, tr_direction direction, unsigned int* setme_Bps) const override
@@ -94,7 +93,7 @@ public:
if (direction == TR_DOWN)
{
is_active = !std::empty(tasks);
Bps = tr_bandwidthGetPieceSpeed_Bps(&bandwidth, now, direction);
Bps = bandwidth.getPieceSpeed_Bps(now, direction);
}
if (setme_Bps != nullptr)
@@ -110,7 +109,7 @@ public:
tr_peer_callback const callback;
void* const callback_data;
tr_bandwidth bandwidth = {};
tr_bandwidth bandwidth;
std::set<tr_webseed_task*> tasks;
struct event* timer = nullptr;
int consecutive_failures = 0;
@@ -288,7 +287,7 @@ static void on_content_changed(struct evbuffer* buf, struct evbuffer_cb_info con
uint32_t len;
struct tr_webseed* w = task->webseed;
tr_bandwidthUsed(&w->bandwidth, TR_DOWN, n_added, true, tr_time_msec());
w->bandwidth.notifyBandwidthConsumed(TR_DOWN, n_added, true, tr_time_msec());
fire_client_got_piece_data(w, n_added);
len = evbuffer_get_length(buf);