forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
9a2fc89eae
commit
4cb125a694
|
@ -242,7 +242,7 @@ int main(int argc, char* argv[])
|
|||
std::vector<torrent_handle> handles;
|
||||
session ses(std::make_pair(6881, 6889));
|
||||
|
||||
// ses.set_upload_rate_limit(30 * 1024);
|
||||
ses.set_upload_rate_limit(40 * 1024);
|
||||
ses.set_http_settings(settings);
|
||||
ses.set_severity_level(alert::debug);
|
||||
|
||||
|
@ -384,16 +384,16 @@ int main(int argc, char* argv[])
|
|||
i != peers.end();
|
||||
++i)
|
||||
{
|
||||
out << "d: " << add_suffix(i->down_speed) << "/s "
|
||||
out << "d:" << add_suffix(i->down_speed) << "/s "
|
||||
<< "(" << add_suffix(i->total_download) << ") "
|
||||
<< "u: " << add_suffix(i->up_speed) << "/s "
|
||||
<< "u:" << add_suffix(i->up_speed) << "/s "
|
||||
<< "(" << add_suffix(i->total_upload) << ") "
|
||||
<< "ul:" << add_suffix(i->upload_limit) << "/s "
|
||||
// << "uc:" << add_suffix(i->upload_ceiling) << "/s "
|
||||
// << "df: " << ratio(i->total_download, i->total_upload) << " "
|
||||
// << "q: " << i->download_queue_length << " "
|
||||
<< "r: " << i->upload_queue_length << " "
|
||||
<< "f: "
|
||||
// << "df:" << ratio(i->total_download, i->total_upload) << " "
|
||||
<< "q:" << i->download_queue_length << " "
|
||||
<< "r:" << i->upload_queue_length << " "
|
||||
<< "f:"
|
||||
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::remote_interested)?"i":"_")
|
||||
|
|
|
@ -38,52 +38,26 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
struct resource_consumer;
|
||||
struct resource_request {
|
||||
resource_request() : used(0), wanted(0), given(0) { }
|
||||
|
||||
// I'm right now actively using:
|
||||
int used;
|
||||
|
||||
// I would like to use this much:
|
||||
int wanted;
|
||||
|
||||
// Reply: Okay, you're allowed to use this much (a compromise):
|
||||
int given;
|
||||
};
|
||||
|
||||
// Function to allocate a limited resource fairly among many consumers.
|
||||
// It takes into account the current use, and the consumer's desired use.
|
||||
// Should be invoked periodically to allow it adjust to the situation.
|
||||
// Should be invoked periodically to allow it adjust to the situation (make
|
||||
// sure "used" is updated between calls!).
|
||||
|
||||
void allocate_resources(int resources,
|
||||
std::vector<resource_consumer> & consumers);
|
||||
|
||||
// information needed by allocate_resources about each client.
|
||||
struct resource_consumer
|
||||
{
|
||||
resource_consumer(
|
||||
boost::any who, // who is this info about?
|
||||
int desired_use, // the max that the consumer is willing/able to use
|
||||
int current_use // how many resources does it use right now?
|
||||
);
|
||||
|
||||
// who/what is this info about?
|
||||
boost::any const &who() const { return m_who; }
|
||||
|
||||
// after the allocation process, this is the resulting
|
||||
// number of resources that this consumer is allowed to
|
||||
// use up. If it's currently using up more resources it
|
||||
// must free up resources accordingly.
|
||||
int allowed_use() const { return m_allowed_use; };
|
||||
|
||||
// how many resources does it use right now?
|
||||
int current_use() const { return m_current_use; }
|
||||
|
||||
// how many resources does it desire to use?
|
||||
// - the max that the consumer is willing/able to use
|
||||
int desired_use() const { return m_desired_use; }
|
||||
|
||||
// give allowance to use num_resources more resources
|
||||
// than currently allowed. returns how many the consumer
|
||||
// accepts. used internally by allocate_resources.
|
||||
int give(int num_resources);
|
||||
|
||||
private:
|
||||
boost::any m_who;
|
||||
int m_current_use;
|
||||
int m_desired_use;
|
||||
int m_allowed_use;
|
||||
};
|
||||
std::vector<resource_request *> & requests);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include "allocate_resources.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
|
@ -205,13 +206,7 @@ namespace libtorrent
|
|||
bool is_disconnecting() const
|
||||
{ return m_disconnecting; }
|
||||
|
||||
// sets the number of bytes this peer
|
||||
// is allowed to send until it should
|
||||
// stop sending. When it stops sending
|
||||
// it will simply wait for another call
|
||||
// to second_tick() where it will get
|
||||
// more send quota.
|
||||
void set_send_quota(int num_bytes);
|
||||
resource_request upload_bandwidth;
|
||||
|
||||
// returns the send quota this peer has
|
||||
// left until will stop sending.
|
||||
|
@ -219,15 +214,17 @@ namespace libtorrent
|
|||
// quota is unlimited.
|
||||
int send_quota_left() const { return m_send_quota_left; }
|
||||
|
||||
void update_send_quota_left() {
|
||||
m_send_quota_left = upload_bandwidth.given;
|
||||
if (m_send_quota_left > 0) send_buffer_updated();
|
||||
}
|
||||
|
||||
size_type total_free_upload() const
|
||||
{ return m_free_upload; }
|
||||
|
||||
void add_free_upload(size_type free_upload)
|
||||
{ m_free_upload += free_upload; }
|
||||
|
||||
// returns the send quota assigned to this
|
||||
// peer.
|
||||
int send_quota() const { return m_send_quota; }
|
||||
|
||||
void received_valid_data()
|
||||
{
|
||||
|
@ -244,9 +241,6 @@ namespace libtorrent
|
|||
int trust_points() const
|
||||
{ return m_trust_points; }
|
||||
|
||||
int send_quota_limit() const
|
||||
{ return m_send_quota_limit; }
|
||||
|
||||
size_type share_diff() const;
|
||||
|
||||
bool support_extensions() const
|
||||
|
@ -481,16 +475,8 @@ namespace libtorrent
|
|||
// more quota. if it is set to -1, the peer
|
||||
// will ignore the qouta and send at maximum
|
||||
// speed
|
||||
int m_send_quota;
|
||||
int m_send_quota_left;
|
||||
|
||||
// this is the maximum send quota we should give
|
||||
// this peer given the current download rate
|
||||
// and the current share ratio with this peer.
|
||||
// this limit will maintain a 1:1 share ratio.
|
||||
// -1 means no limit
|
||||
int m_send_quota_limit;
|
||||
|
||||
// for every valid piece we receive where this
|
||||
// peer was one of the participants, we increase
|
||||
// this value. For every invalid piece we receive
|
||||
|
|
|
@ -36,39 +36,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/limits.hpp>
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
resource_consumer::resource_consumer(boost::any who, int desired_use, int current_use)
|
||||
: m_who(who)
|
||||
, m_desired_use(desired_use)
|
||||
, m_current_use(current_use)
|
||||
, m_allowed_use(0)
|
||||
{
|
||||
assert(desired_use>=0);
|
||||
assert(current_use>=0);
|
||||
}
|
||||
|
||||
int resource_consumer::give(int num_resources)
|
||||
{
|
||||
assert(num_resources>0);
|
||||
|
||||
int accepted_resources=std::min(num_resources, m_desired_use-m_allowed_use);
|
||||
assert(accepted_resources>=0);
|
||||
|
||||
m_allowed_use+=accepted_resources;
|
||||
assert(m_allowed_use<=m_desired_use);
|
||||
|
||||
return accepted_resources;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool by_desired_use(
|
||||
const resource_consumer &a,
|
||||
const resource_consumer &b)
|
||||
{
|
||||
return a.desired_use() < b.desired_use();
|
||||
}
|
||||
|
||||
int saturated_add(int a, int b)
|
||||
{
|
||||
assert(a>=0);
|
||||
|
@ -92,78 +61,133 @@ namespace libtorrent {
|
|||
return result;
|
||||
}
|
||||
|
||||
int total_demand(std::vector<resource_consumer> & consumers)
|
||||
{
|
||||
int total_demand=0;
|
||||
|
||||
for(int i=0;i<(int)consumers.size();i++)
|
||||
// for use with std::sort
|
||||
bool by_used(const resource_request *a, const resource_request *b)
|
||||
{ return a->used < b->used; }
|
||||
|
||||
// give num_resources to r,
|
||||
// return how how many were actually accepted.
|
||||
int give(resource_request *r, int num_resources)
|
||||
{
|
||||
assert(r);
|
||||
assert(num_resources > 0);
|
||||
assert(r->given <= r->wanted);
|
||||
|
||||
int accepted=std::min(num_resources, r->wanted - r->given);
|
||||
assert(accepted >= 0);
|
||||
|
||||
r->given += accepted;
|
||||
assert(r->given <= r->wanted);
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
int total_wanted(std::vector<resource_request *> & requests)
|
||||
{
|
||||
int total_wanted=0;
|
||||
|
||||
for(int i=0;i<(int)requests.size();i++)
|
||||
{
|
||||
total_demand=saturated_add(total_demand, consumers[i].desired_use());
|
||||
if(total_demand == std::numeric_limits<int>::max())
|
||||
total_wanted=
|
||||
saturated_add(total_wanted,requests[i]->wanted);
|
||||
|
||||
if(total_wanted == std::numeric_limits<int>::max())
|
||||
break;
|
||||
}
|
||||
|
||||
assert(total_demand>=0);
|
||||
return total_demand;
|
||||
assert(total_wanted>=0);
|
||||
return total_wanted;
|
||||
}
|
||||
}
|
||||
|
||||
void allocate_resources(int resources,
|
||||
std::vector<resource_consumer> & consumers)
|
||||
#ifndef NDEBUG
|
||||
class allocate_resources_contract_check
|
||||
{
|
||||
assert(resources>=0);
|
||||
|
||||
// no competition for resources?
|
||||
if(resources==std::numeric_limits<int>::max())
|
||||
int resources;
|
||||
std::vector<resource_request *> & requests;
|
||||
public:
|
||||
allocate_resources_contract_check(int resources_,std::vector<resource_request *> & requests_)
|
||||
: resources(resources_)
|
||||
, requests(requests_)
|
||||
{
|
||||
for(int i=0;i<(int)consumers.size();i++)
|
||||
consumers[i].give(std::numeric_limits<int>::max());
|
||||
assert(resources >= 0);
|
||||
for(int i=0;i<(int)requests.size();i++)
|
||||
{
|
||||
assert(requests[i]->used >= 0);
|
||||
assert(requests[i]->wanted >= 0);
|
||||
assert(requests[i]->given >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
~allocate_resources_contract_check()
|
||||
{
|
||||
int sum_given = 0;
|
||||
int sum_wanted = 0;
|
||||
for(int i=0;i<(int)requests.size();i++)
|
||||
{
|
||||
assert(requests[i]->used >= 0);
|
||||
assert(requests[i]->wanted >= 0);
|
||||
assert(requests[i]->given >= 0);
|
||||
assert(requests[i]->given <= requests[i]->wanted);
|
||||
|
||||
sum_given = saturated_add(sum_given, requests[i]->given);
|
||||
sum_wanted = saturated_add(sum_wanted, requests[i]->wanted);
|
||||
}
|
||||
assert(sum_given == std::min(resources,sum_wanted));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
void allocate_resources(int resources,
|
||||
std::vector<resource_request *> & requests)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
allocate_resources_contract_check
|
||||
contract_check(resources,requests);
|
||||
#endif
|
||||
|
||||
if(resources == std::numeric_limits<int>::max())
|
||||
{
|
||||
// No competition for resources.
|
||||
// Just give everyone what they want.
|
||||
for(int i=0;i<(int)requests.size();i++)
|
||||
requests[i]->given = requests[i]->wanted;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resources are scarce
|
||||
|
||||
for(int i=0;i < (int)requests.size();i++)
|
||||
requests[i]->given = 0;
|
||||
|
||||
if(resources == 0)
|
||||
return;
|
||||
|
||||
int resources_to_distribute =
|
||||
std::min(
|
||||
resources,
|
||||
total_demand(consumers));
|
||||
total_wanted(requests));
|
||||
|
||||
if (resources_to_distribute != 0)
|
||||
{
|
||||
assert(resources_to_distribute>0);
|
||||
if (resources_to_distribute == 0)
|
||||
return;
|
||||
|
||||
assert(resources_to_distribute>0);
|
||||
|
||||
std::random_shuffle(consumers.begin(),consumers.end());
|
||||
std::sort(consumers.begin(),consumers.end(),by_desired_use);
|
||||
std::random_shuffle(requests.begin(),requests.end());
|
||||
std::sort(requests.begin(),requests.end(),by_used);
|
||||
|
||||
while(resources_to_distribute > 0)
|
||||
for(int i = 0; i < (int)consumers.size() && resources_to_distribute>0; i++)
|
||||
resources_to_distribute -=
|
||||
consumers[i].give(
|
||||
std::min(
|
||||
round_up_division(
|
||||
(int)resources_to_distribute,
|
||||
(int)consumers.size()),
|
||||
std::min(
|
||||
consumers[i].current_use()*2+1, // allow for fast growth
|
||||
consumers[i].desired_use())));
|
||||
}
|
||||
while(resources_to_distribute > 0)
|
||||
for(int i = 0; i < (int)requests.size() && resources_to_distribute>0; i++)
|
||||
resources_to_distribute -=
|
||||
give(
|
||||
requests[i],
|
||||
std::min(
|
||||
requests[i]->used+1,
|
||||
round_up_division(
|
||||
(int)resources_to_distribute,
|
||||
(int)requests.size()-i)));
|
||||
assert(resources_to_distribute == 0);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
int sum_given = 0;
|
||||
int sum_desired = 0;
|
||||
for (std::vector<resource_consumer>::iterator i = consumers.begin();
|
||||
i != consumers.end();
|
||||
++i)
|
||||
{
|
||||
assert(i->allowed_use() <= i->desired_use());
|
||||
|
||||
sum_given = saturated_add(sum_given, i->allowed_use());
|
||||
sum_desired = saturated_add(sum_desired, i->desired_use());
|
||||
}
|
||||
assert(sum_given == std::min(resources,sum_desired));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -122,7 +122,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
m_send_buffer += request;
|
||||
/*
|
||||
|
||||
m_send_buffer += "?info_hash=";
|
||||
m_send_buffer += escape_string(
|
||||
reinterpret_cast<const char*>(req.info_hash.begin()), 20);
|
||||
|
@ -153,7 +153,7 @@ namespace libtorrent
|
|||
// extension that tells the tracker that
|
||||
// we don't need any peer_id's in the response
|
||||
m_send_buffer += "&no_peer_id=1";
|
||||
*/
|
||||
|
||||
m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n"
|
||||
"User-Agent: ";
|
||||
m_send_buffer += m_settings.user_agent;
|
||||
|
|
|
@ -100,9 +100,7 @@ namespace libtorrent
|
|||
, m_supports_extensions(false)
|
||||
, m_num_pieces(0)
|
||||
, m_free_upload(0)
|
||||
, m_send_quota(100)
|
||||
, m_send_quota_left(100)
|
||||
, m_send_quota_limit(100)
|
||||
, m_send_quota_left(0)
|
||||
, m_trust_points(0)
|
||||
, m_num_invalid_requests(0)
|
||||
, m_last_piece(boost::posix_time::second_clock::local_time())
|
||||
|
@ -164,9 +162,7 @@ namespace libtorrent
|
|||
, m_supports_extensions(false)
|
||||
, m_num_pieces(0)
|
||||
, m_free_upload(0)
|
||||
, m_send_quota(100)
|
||||
, m_send_quota_left(100)
|
||||
, m_send_quota_limit(100)
|
||||
, m_send_quota_left(0)
|
||||
, m_trust_points(0)
|
||||
, m_num_invalid_requests(0)
|
||||
, m_last_piece(boost::posix_time::second_clock::local_time())
|
||||
|
@ -208,23 +204,6 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void peer_connection::set_send_quota(int num_bytes)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(num_bytes >= 0 || num_bytes == -1);
|
||||
|
||||
if (num_bytes > m_send_quota_limit
|
||||
&& m_send_quota_limit != -1)
|
||||
num_bytes = m_send_quota_limit;
|
||||
|
||||
assert(num_bytes <= m_send_quota_limit || m_send_quota_limit == -1);
|
||||
|
||||
m_send_quota = num_bytes;
|
||||
m_send_quota_left = num_bytes;
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
void peer_connection::send_handshake()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -1246,9 +1225,9 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
m_statistics.second_tick();
|
||||
m_send_quota_left = m_send_quota;
|
||||
if (m_send_quota > 0) send_buffer_updated();
|
||||
|
||||
update_send_quota_left();
|
||||
|
||||
// If the client sends more data
|
||||
// we send it data faster, otherwise, slower.
|
||||
// It will also depend on how much data the
|
||||
|
@ -1256,16 +1235,47 @@ namespace libtorrent
|
|||
// maintain the share ratio given by m_ratio
|
||||
// with all peers.
|
||||
|
||||
size_type diff = share_diff();
|
||||
|
||||
enum { block_limit=2 }; // how many blocks difference is considered unfair
|
||||
|
||||
if (diff > block_limit*m_torrent->block_size() || m_torrent->is_seed())
|
||||
if (m_torrent->is_seed() || is_choked() || m_torrent->ratio()==0.0f)
|
||||
{
|
||||
// if we have downloaded more than one piece more
|
||||
// than we have uploaded OR if we are a seed
|
||||
// have an unlimited upload rate
|
||||
m_send_quota_limit = -1;
|
||||
upload_bandwidth.wanted = std::numeric_limits<int>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
double bias = 0x20000 + m_free_upload;
|
||||
|
||||
double break_even_time = 10;
|
||||
double have_uploaded = (double)m_statistics.total_payload_upload();
|
||||
double have_downloaded = (double)m_statistics.total_payload_download();
|
||||
double download_speed = m_statistics.download_rate();
|
||||
|
||||
double soon_downloaded =
|
||||
have_downloaded+download_speed * 2 * break_even_time;
|
||||
|
||||
double upload_speed_limit = (soon_downloaded*m_torrent->ratio()
|
||||
- have_uploaded + bias) / break_even_time;
|
||||
upload_speed_limit=std::max(upload_speed_limit,1.0);
|
||||
upload_speed_limit=std::min(upload_speed_limit,
|
||||
(double)std::numeric_limits<int>::max());
|
||||
|
||||
upload_bandwidth.wanted = (int) upload_speed_limit;
|
||||
}
|
||||
|
||||
/*
|
||||
size_type diff = share_diff();
|
||||
|
||||
enum { block_limit=2 }; // how many blocks difference is considered unfair
|
||||
|
||||
// if the peer has been choked, send tha current piece
|
||||
// as fast as possible
|
||||
if (diff > block_limit*m_torrent->block_size() || m_torrent->is_seed() || is_choked())
|
||||
{
|
||||
// if we have downloaded more than one piece more
|
||||
// than we have uploaded OR if we are a seed
|
||||
// have an unlimited upload rate
|
||||
upload_bandwidth.wanted = std::numeric_limits<int>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1284,15 +1294,12 @@ namespace libtorrent
|
|||
{
|
||||
bias = -static_cast<int>(m_statistics.download_rate() * ratio) / 2;
|
||||
}
|
||||
m_send_quota_limit = static_cast<int>(m_statistics.download_rate()) + bias;
|
||||
upload_bandwidth.wanted = static_cast<int>(m_statistics.download_rate()) + bias;
|
||||
|
||||
// the maximum send_quota given our download rate from this peer
|
||||
if (m_send_quota_limit < 256) m_send_quota_limit = 256;
|
||||
|
||||
// if the peer has been choked, send tha current piece
|
||||
// as fast as possible
|
||||
if (is_choked()) m_send_quota_limit = -1;
|
||||
if (upload_bandwidth.wanted < 256) upload_bandwidth.wanted = 256;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
|
|
269
src/session.cpp
269
src/session.cpp
|
@ -91,6 +91,12 @@ namespace
|
|||
return sum;
|
||||
}
|
||||
|
||||
// adjusts the upload rates of every peer connection
|
||||
// to make sure the sum of all send quotas equals
|
||||
// the given upload_limit. An upload limit of
|
||||
// std::numeric_limits<int>::max() means unlimited upload
|
||||
// rate, but the rates of each peer has to be set anyway,
|
||||
// since it depends on the download rate from the peer.
|
||||
void control_upload_rates(
|
||||
int upload_limit,
|
||||
libtorrent::detail::session_impl::connection_map connections)
|
||||
|
@ -98,56 +104,29 @@ namespace
|
|||
assert(upload_limit >= 0);
|
||||
|
||||
using namespace libtorrent;
|
||||
std::vector<resource_consumer> peers;
|
||||
std::vector<resource_request *> requests;
|
||||
|
||||
for (detail::session_impl::connection_map::iterator c = connections.begin();
|
||||
c != connections.end(); ++c)
|
||||
{
|
||||
boost::shared_ptr<peer_connection> p = c->second;
|
||||
int estimated_upload_capacity=
|
||||
p->has_data() ? (int)ceil(p->statistics().upload_rate()) // std::max(10,(int)ceil(p->statistics().upload_rate()*1.1f))
|
||||
: 1;
|
||||
|
||||
int limit=p->send_quota_limit();
|
||||
if(limit==-1)
|
||||
limit=std::numeric_limits<int>::max();
|
||||
|
||||
peers.push_back(resource_consumer(p,limit,estimated_upload_capacity));
|
||||
p->upload_bandwidth.used =
|
||||
p->has_data() ? (int)ceil(p->statistics().upload_rate())
|
||||
: 0;
|
||||
|
||||
requests.push_back(&p->upload_bandwidth);
|
||||
}
|
||||
|
||||
allocate_resources(upload_limit, peers);
|
||||
allocate_resources(upload_limit, requests);
|
||||
|
||||
for (std::vector<resource_consumer>::iterator r=peers.begin();
|
||||
r!=peers.end(); ++r)
|
||||
for (detail::session_impl::connection_map::iterator c = connections.begin();
|
||||
c != connections.end(); ++c)
|
||||
{
|
||||
boost::any_cast<boost::shared_ptr<peer_connection> >
|
||||
(r->who())->set_send_quota(r->allowed_use());
|
||||
boost::shared_ptr<peer_connection> p = c->second;
|
||||
p->update_send_quota_left();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
int sum_quota = 0;
|
||||
int sum_quota_limit = 0;
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
|
||||
int quota=p.send_quota();
|
||||
int quota_limit=p.send_quota_limit();
|
||||
if(quota==-1)
|
||||
quota=std::numeric_limits<int>::max();
|
||||
if(quota_limit==-1)
|
||||
quota_limit=std::numeric_limits<int>::max();
|
||||
|
||||
sum_quota = saturated_add(sum_quota,quota);
|
||||
sum_quota_limit = saturated_add(sum_quota_limit,quota_limit);
|
||||
}
|
||||
assert(sum_quota == std::min(upload_limit,sum_quota_limit));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
void control_number_of_connections(
|
||||
int connections_limit,
|
||||
libtorrent::detail::session_impl::torrent_map hash_list)
|
||||
|
@ -180,197 +159,6 @@ namespace
|
|||
// (r->who())->set_send_quota(r->allowed_use());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// This struct is used by control_upload_rates() below. It keeps
|
||||
// track how much bandwidth has been allocated to each connection
|
||||
// and other relevant information to assist in the allocation process.
|
||||
struct connection_info
|
||||
{
|
||||
libtorrent::peer_connection* p; // which peer_connection this info refers to
|
||||
int allocated_quota; // bandwidth allocated to this peer connection
|
||||
int quota_limit; // bandwidth limit
|
||||
int estimated_upload_capacity; // estimated channel bandwidth
|
||||
|
||||
bool operator < (const connection_info &other) const
|
||||
{
|
||||
return estimated_upload_capacity < other.estimated_upload_capacity;
|
||||
}
|
||||
|
||||
int give(int amount)
|
||||
{
|
||||
|
||||
// if amount > 0, try to add amount to the allocated quota.
|
||||
// if amount < 0, try to subtract abs(amount) from the allocated quota
|
||||
//
|
||||
// Quota will not go above quota_limit or below 0. This means that
|
||||
// not all the amount given or taken may be accepted.
|
||||
//
|
||||
// return value: how much quota was actually added (or subtracted if negative).
|
||||
|
||||
int old_quota=allocated_quota;
|
||||
allocated_quota+=amount;
|
||||
if(quota_limit!=-1)
|
||||
allocated_quota=std::min(allocated_quota,quota_limit);
|
||||
allocated_quota=std::max(0,allocated_quota);
|
||||
return allocated_quota-old_quota;
|
||||
}
|
||||
};
|
||||
|
||||
// adjusts the upload rates of every peer connection
|
||||
// to make sure the sum of all send quotas equals
|
||||
// the given upload_limit. An upload limit of -1 means
|
||||
// unlimited upload rate, but the rates of each peer
|
||||
// has to be set anyway, since it depends on the download
|
||||
// rate from the peer.
|
||||
void control_upload_rates(
|
||||
int upload_limit
|
||||
, libtorrent::detail::session_impl::connection_map connections)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
||||
assert(upload_limit > 0 || upload_limit == -1);
|
||||
|
||||
if (connections.empty()) return;
|
||||
|
||||
|
||||
if (upload_limit == -1)
|
||||
{
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
// there's no limit, set the quota to max
|
||||
// allowed
|
||||
peer_connection& p = *i->second;
|
||||
p.set_send_quota(p.send_quota_limit());
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's an upload limit, so we need to distribute the available
|
||||
// upload bandwidth among the peer_connections fairly, but not
|
||||
// wastefully.
|
||||
|
||||
// For each peer_connection, keep some local data about their
|
||||
// quota limit and estimated upload capacity, and how much quota
|
||||
// has been allocated to them.
|
||||
|
||||
std::vector<connection_info> peer_info;
|
||||
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
connection_info pi;
|
||||
|
||||
pi.p = &p;
|
||||
pi.allocated_quota = 0; // we haven't given it any bandwith yet
|
||||
pi.quota_limit = p.send_quota_limit();
|
||||
|
||||
pi.estimated_upload_capacity=
|
||||
p.has_data() ? std::max(10,(int)ceil(p.statistics().upload_rate()*1.1f))
|
||||
// If there's no data to send, upload capacity is practically 0.
|
||||
// Here we set it to 1 though, because otherwise it will not be able
|
||||
// to accept any quota at all, which may upset quota_limit balances.
|
||||
: 1;
|
||||
|
||||
peer_info.push_back(pi);
|
||||
}
|
||||
|
||||
// Sum all peer_connections' quota limit to get the total quota limit.
|
||||
|
||||
int sum_total_of_quota_limits=0;
|
||||
for (int i = 0; i < (int)peer_info.size(); ++i)
|
||||
{
|
||||
int quota_limit = peer_info[i].quota_limit;
|
||||
if (quota_limit == -1)
|
||||
{
|
||||
// quota_limit=-1 means infinite, so
|
||||
// sum_total_of_quota_limits will be infinite too...
|
||||
sum_total_of_quota_limits = std::numeric_limits<int>::max();
|
||||
break;
|
||||
}
|
||||
sum_total_of_quota_limits += quota_limit;
|
||||
}
|
||||
|
||||
// This is how much total bandwidth that can be distributed.
|
||||
int quota_left_to_distribute = std::min(upload_limit,sum_total_of_quota_limits);
|
||||
|
||||
|
||||
// Sort w.r.t. channel capacitiy, lowest channel capacity first.
|
||||
// Makes it easy to traverse the list in sorted order.
|
||||
std::sort(peer_info.begin(),peer_info.end());
|
||||
|
||||
|
||||
// Distribute quota until there's nothing more to distribute
|
||||
|
||||
while (quota_left_to_distribute != 0)
|
||||
{
|
||||
assert(quota_left_to_distribute > 0);
|
||||
|
||||
for (int i = 0; i < (int)peer_info.size(); ++i)
|
||||
{
|
||||
// Traverse the peer list from slowest connection to fastest.
|
||||
|
||||
// In each step, share bandwidth equally between this peer_connection
|
||||
// and the following faster peer_connections.
|
||||
//
|
||||
// Rounds upwards to avoid trying to give 0 bandwidth to someone
|
||||
// (may get caught in an endless loop otherwise)
|
||||
|
||||
int num_peers_left_to_share_quota = (int)peer_info.size() - i;
|
||||
int try_to_give_to_this_peer
|
||||
= (quota_left_to_distribute + num_peers_left_to_share_quota - 1)
|
||||
/ num_peers_left_to_share_quota;
|
||||
|
||||
// But do not allocate more than the estimated upload capacity.
|
||||
try_to_give_to_this_peer = std::min(
|
||||
peer_info[i].estimated_upload_capacity
|
||||
, try_to_give_to_this_peer);
|
||||
|
||||
// Also, when the peer is given quota, it will
|
||||
// not accept more than it's quota_limit.
|
||||
int quota_actually_given_to_peer
|
||||
= peer_info[i].give(try_to_give_to_this_peer);
|
||||
|
||||
quota_left_to_distribute -= quota_actually_given_to_peer;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, inform the peers of how much quota they get.
|
||||
|
||||
for(int i = 0; i < (int)peer_info.size(); ++i)
|
||||
peer_info[i].p->set_send_quota(peer_info[i].allocated_quota);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
int sum_quota = 0;
|
||||
int sum_quota_limit = 0;
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
sum_quota += p.send_quota();
|
||||
|
||||
if(p.send_quota_limit() == -1)
|
||||
{
|
||||
sum_quota_limit=std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
if(sum_quota_limit!=std::numeric_limits<int>::max())
|
||||
{
|
||||
sum_quota_limit += p.send_quota_limit();
|
||||
}
|
||||
}
|
||||
assert(sum_quota == std::min(upload_limit,sum_quota_limit));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -590,8 +378,7 @@ namespace libtorrent
|
|||
++i)
|
||||
{
|
||||
i->second->abort();
|
||||
m_tracker_manager.queue_request(
|
||||
i->second->generate_tracker_request(m_listen_port));
|
||||
m_tracker_manager.queue_request(i->second->generate_tracker_request(m_listen_port));
|
||||
}
|
||||
m_connections.clear();
|
||||
m_torrents.clear();
|
||||
|
@ -680,9 +467,9 @@ namespace libtorrent
|
|||
if (*i == listener)
|
||||
{
|
||||
boost::shared_ptr<libtorrent::socket> s = (*i)->accept();
|
||||
s->set_blocking(false);
|
||||
if (s)
|
||||
{
|
||||
s->set_blocking(false);
|
||||
// we got a connection request!
|
||||
m_incoming_connection = true;
|
||||
#ifndef NDEBUG
|
||||
|
@ -693,7 +480,11 @@ namespace libtorrent
|
|||
boost::shared_ptr<peer_connection> c(
|
||||
new peer_connection(*this, m_selector, s));
|
||||
|
||||
if (m_upload_rate != -1) c->set_send_quota(0);
|
||||
if (m_upload_rate != -1) {
|
||||
c->upload_bandwidth.given=0;
|
||||
c->update_send_quota_left();
|
||||
}
|
||||
|
||||
m_connections.insert(std::make_pair(s, c));
|
||||
m_selector.monitor_readability(s);
|
||||
m_selector.monitor_errors(s);
|
||||
|
@ -845,9 +636,8 @@ namespace libtorrent
|
|||
else if (i->second->should_request())
|
||||
{
|
||||
m_tracker_manager.queue_request(
|
||||
i->second->generate_tracker_request(m_listen_port)
|
||||
, boost::get_pointer(i->second)
|
||||
, i->second->tracker_password());
|
||||
i->second->generate_tracker_request(m_listen_port),
|
||||
boost::get_pointer(i->second));
|
||||
}
|
||||
|
||||
i->second->second_tick();
|
||||
|
@ -933,7 +723,7 @@ namespace libtorrent
|
|||
"peer_connection::has_data() != is_writability_monitored()\n";
|
||||
error_log << "peer_connection::has_data() " << p->has_data() << "\n";
|
||||
error_log << "peer_connection::send_quota_left " << p->send_quota_left() << "\n";
|
||||
error_log << "peer_connection::send_quota " << p->send_quota() << "\n";
|
||||
error_log << "peer_connection::upload_bandwidth.given " << p->upload_bandwidth.given << "\n";
|
||||
error_log << "peer_connection::get_peer_id " << p->get_peer_id() << "\n";
|
||||
error_log << "place: " << place << "\n";
|
||||
error_log.flush();
|
||||
|
@ -1101,7 +891,8 @@ namespace libtorrent
|
|||
= m_impl.m_connections.begin();
|
||||
i != m_impl.m_connections.end();)
|
||||
{
|
||||
i->second->set_send_quota(-1);
|
||||
i->second->upload_bandwidth.given=std::numeric_limits<int>::max();
|
||||
i->second->update_send_quota_left();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ namespace libtorrent
|
|||
|
||||
slot_lock lock(*m_pimpl, slot);
|
||||
|
||||
size_type start = slot * m_pimpl->info.piece_length() + offset;
|
||||
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
|
@ -376,7 +376,7 @@ namespace libtorrent
|
|||
|
||||
slot_lock lock(*m_pimpl, slot);
|
||||
|
||||
size_type start = slot * m_pimpl->info.piece_length() + offset;
|
||||
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
|
|
|
@ -537,8 +537,6 @@ namespace libtorrent
|
|||
, this
|
||||
, s));
|
||||
|
||||
if (m_ses.m_upload_rate != -1) c->set_send_quota(0);
|
||||
|
||||
detail::session_impl::connection_map::iterator p =
|
||||
m_ses.m_connections.insert(std::make_pair(s, c)).first;
|
||||
|
||||
|
|
|
@ -459,8 +459,8 @@ namespace libtorrent
|
|||
p.total_download = statistics.total_payload_download();
|
||||
p.total_upload = statistics.total_payload_upload();
|
||||
|
||||
p.upload_limit = peer->send_quota();
|
||||
p.upload_ceiling = peer->send_quota_limit();
|
||||
p.upload_limit = peer->upload_bandwidth.given;
|
||||
p.upload_ceiling = peer->upload_bandwidth.wanted;
|
||||
|
||||
p.load_balancing = peer->total_free_upload();
|
||||
|
||||
|
|
Loading…
Reference in New Issue