removed allocate_resources. switched to a global unchoker and connection distribution

This commit is contained in:
Arvid Norberg 2007-08-16 12:41:46 +00:00
parent b62bb7944f
commit 4ac1ac8a1f
20 changed files with 350 additions and 1028 deletions

View File

@ -171,7 +171,6 @@ lib wsock32 : : <name>wsock32 ;
lib ws2_32 : : <name>ws2_32 ;
SOURCES =
allocate_resources
alert
connection_queue
entry

View File

@ -1,78 +0,0 @@
/*
Copyright (c) 2003, Magnus Jonsson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/session.hpp"
namespace libtorrent
{
class peer_connection;
class torrent;
int saturated_add(int a, int b);
// 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 (make
// sure "used" is updated between calls!).
// If resources = std::numeric_limits<int>::max() it means there is an infinite
// supply of resources (so everyone can get what they want).
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& torrents
, resource_request torrent::* res);
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& connections
, resource_request peer_connection::* res);
// Used for global limits.
void allocate_resources(
int resources
, std::vector<session*>& _sessions
, resource_request session::* res);
}
#endif

View File

@ -1,328 +0,0 @@
/*
Copyright (c) 2003, Magnus Jonsson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/size_type.hpp"
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
namespace libtorrent
{
int saturated_add(int a, int b);
namespace aux
{
// give num_resources to r,
// return how how many were actually accepted.
inline int give(resource_request& r, int num_resources)
{
assert(num_resources >= 0);
assert(r.given <= r.max);
int accepted = (std::min)(num_resources, r.max - r.given);
assert(accepted >= 0);
r.given += accepted;
assert(r.given <= r.max);
return accepted;
}
inline int div_round_up(int numerator, int denominator)
{
return (numerator + denominator - 1) / denominator;
}
#ifndef NDEBUG
template<class It, class T>
class allocate_resources_contract_check
{
int m_resources;
It m_start;
It m_end;
resource_request T::* m_res;
public:
allocate_resources_contract_check(
int resources
, It start
, It end
, resource_request T::* res)
: m_resources(resources)
, m_start(start)
, m_end(end)
, m_res(res)
{
assert(m_resources >= 0);
for (It i = m_start, end(m_end); i != end; ++i)
{
assert(((*i).*m_res).max >= 0);
assert(((*i).*m_res).given >= 0);
}
}
~allocate_resources_contract_check()
{
int sum_given = 0;
int sum_max = 0;
int sum_min = 0;
for (It i = m_start, end(m_end); i != end; ++i)
{
assert(((*i).*m_res).max >= 0);
assert(((*i).*m_res).min >= 0);
assert(((*i).*m_res).max >= ((*i).*m_res).min);
assert(((*i).*m_res).given >= 0);
assert(((*i).*m_res).given <= ((*i).*m_res).max);
sum_given = saturated_add(sum_given, ((*i).*m_res).given);
sum_max = saturated_add(sum_max, ((*i).*m_res).max);
sum_min = saturated_add(sum_min, ((*i).*m_res).min);
}
if (sum_given != (std::min)(std::max(m_resources, sum_min), sum_max))
{
std::cerr << sum_given << " " << m_resources << " " << sum_min << " " << sum_max << std::endl;
assert(false);
}
}
};
#endif
template<class It, class T>
void allocate_resources_impl(
int resources
, It start
, It end
, resource_request T::* res)
{
assert(resources >= 0);
#ifndef NDEBUG
allocate_resources_contract_check<It, T> contract_check(
resources
, start
, end
, res);
#endif
for (It i = start; i != end; ++i)
{
resource_request& r = (*i).*res;
r.leftovers = (std::max)(r.used - r.given, 0);
}
if (resources == resource_request::inf)
{
// No competition for resources.
// Just give everyone what they want.
for (It i = start; i != end; ++i)
{
((*i).*res).given = ((*i).*res).max;
}
return;
}
// Resources are scarce
int sum_max = 0;
int sum_min = 0;
// the number of consumer that saturated their
// quota last time slice
int num_saturated = 0;
// the total resources that those saturated their
// quota used. This is used to calculate the mean
// of the saturating consumers, in order to
// balance their quotas for the next time slice.
size_type saturated_sum = 0;
for (It i = start; i != end; ++i)
{
resource_request& r = (*i).*res;
sum_max = saturated_add(sum_max, r.max);
assert(r.min < resource_request::inf);
assert(r.min >= 0);
assert(r.min <= r.max);
sum_min += r.min;
// a consumer that uses 95% or more of its assigned
// quota is considered saturating
size_type used = r.used;
if (r.given == 0) continue;
if (used * 20 / r.given >= 19)
{
++num_saturated;
saturated_sum += r.given;
}
}
if (sum_max <= resources)
{
// it turns out that there's no competition for resources
// after all.
for (It i = start; i != end; ++i)
{
((*i).*res).given = ((*i).*res).max;
}
return;
}
if (sum_min >= resources)
{
// the amount of resources is smaller than
// the minimum resources to distribute, so
// give everyone the minimum
for (It i = start; i != end; ++i)
{
((*i).*res).given = ((*i).*res).min;
}
return;
}
// now, the "used" field will be used as a target value.
// the algorithm following this loop will then scale the
// used values to fit the available resources and store
// the scaled values as given. So, the ratios of the
// used values will be maintained.
for (It i = start; i != end; ++i)
{
resource_request& r = (*i).*res;
int target;
size_type used = r.used;
if (r.given > 0 && used * 20 / r.given >= 19)
{
assert(num_saturated > 0);
target = div_round_up(saturated_sum, num_saturated);
target += div_round_up(target, 10);
}
else
{
target = r.used;
}
if (target > r.max) target = r.max;
else if (target < r.min) target = r.min;
// move 12.5% towards the the target value
r.used = r.given + div_round_up(target - r.given, 8);
r.given = r.min;
}
resources = (std::max)(resources, sum_min);
int resources_to_distribute = (std::min)(resources, sum_max) - sum_min;
assert(resources_to_distribute >= 0);
#ifndef NDEBUG
int prev_resources_to_distribute = resources_to_distribute;
#endif
while (resources_to_distribute > 0)
{
// in order to scale, we need to calculate the sum of
// all the used values.
size_type total_used = 0;
size_type max_used = 0;
for (It i = start; i != end; ++i)
{
resource_request& r = (*i).*res;
if (r.given == r.max) continue;
assert(r.given < r.max);
max_used = (std::max)(max_used, (size_type)r.used + 1);
total_used += (size_type)r.used + 1;
}
size_type kNumer = resources_to_distribute;
size_type kDenom = total_used;
assert(kNumer >= 0);
assert(kDenom >= 0);
assert(kNumer <= (std::numeric_limits<int>::max)());
if (kNumer * max_used <= kDenom)
{
kNumer = 1;
kDenom = max_used;
assert(kDenom >= 0);
}
for (It i = start; i != end && resources_to_distribute > 0; ++i)
{
resource_request& r = (*i).*res;
if (r.given == r.max) continue;
assert(r.given < r.max);
size_type used = (size_type)r.used + 1;
if (used < 1) used = 1;
size_type to_give = used * kNumer / kDenom;
if (to_give > resources_to_distribute)
to_give = resources_to_distribute;
assert(to_give >= 0);
assert(to_give <= resources_to_distribute);
#ifndef NDEBUG
int tmp = resources_to_distribute;
#endif
resources_to_distribute -= give(r, (int)to_give);
assert(resources_to_distribute <= tmp);
assert(resources_to_distribute >= 0);
}
assert(resources_to_distribute >= 0);
assert(resources_to_distribute < prev_resources_to_distribute);
#ifndef NDEBUG
prev_resources_to_distribute = resources_to_distribute;
#endif
}
assert(resources_to_distribute == 0);
}
} // namespace libtorrent::aux
}
#endif

View File

@ -273,8 +273,18 @@ namespace libtorrent
void set_max_connections(int limit);
void set_max_uploads(int limit);
int num_uploads() const;
int num_connections() const;
int max_connections() const { return m_max_connections; }
int max_uploads() const { return m_max_uploads; }
int num_uploads() const { return m_num_unchoked; }
int num_connections() const
{ return m_connections.size(); }
void unchoke_peer(peer_connection& c)
{
c.send_unchoke();
++m_num_unchoked;
}
session_status status() const;
void set_peer_id(peer_id const& id);
@ -417,6 +427,28 @@ namespace libtorrent
int m_max_uploads;
int m_max_connections;
// the number of unchoked peers
int m_num_unchoked;
// this is initialized to the unchoke_interval
// session_setting and decreased every second.
// when it reaches zero, it is reset to the
// unchoke_interval and the unchoke set is
// recomputed.
int m_unchoke_time_scaler;
// works like unchoke_time_scaler but it
// is only decresed when the unchoke set
// is recomputed, and when it reaches zero,
// the optimistic unchoke is moved to another peer.
int m_optimistic_unchoke_time_scaler;
// works like unchoke_time_scaler. Each time
// it reaches 0, and all the connections are
// used, the worst connection will be disconnected
// from the torrent with the most peers
int m_disconnect_time_scaler;
// statistics gathered from all torrents.
stat m_stat;

View File

@ -65,7 +65,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"

View File

@ -64,7 +64,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"
@ -213,7 +212,7 @@ namespace libtorrent
void add_stat(size_type downloaded, size_type uploaded);
// is called once every second by the main loop
void second_tick(float tick_interval);
void second_tick(float tick_interval) throw();
boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; }

View File

@ -155,6 +155,13 @@ namespace libtorrent
// this is true if the peer is a seed
bool seed;
// true if this peer currently is unchoked
// because of an optimistic unchoke.
// when the optimistic unchoke is moved to
// another peer, this peer will be choked
// if this is true
bool optimistically_unchoked;
// the time when this peer was optimistically unchoked
// the last time.
libtorrent::ptime last_optimistically_unchoked;
@ -203,25 +210,18 @@ namespace libtorrent
peer_connection* connection;
};
int num_peers() const
{
return m_peers.size();
}
int num_peers() const { return m_peers.size(); }
int num_uploads() const
{
return m_num_unchoked;
}
typedef std::list<peer>::iterator iterator;
typedef std::list<peer>::const_iterator const_iterator;
iterator begin_peer() { return m_peers.begin(); }
iterator end_peer() { return m_peers.end(); }
bool connect_one_peer();
bool disconnect_one_peer();
private:
/*
bool unchoke_one_peer();
void choke_one_peer();
iterator find_choke_candidate();
@ -233,8 +233,7 @@ namespace libtorrent
void seed_choke_one_peer();
iterator find_seed_choke_candidate();
iterator find_seed_unchoke_candidate();
bool disconnect_one_peer();
*/
iterator find_disconnect_candidate();
iterator find_connect_candidate();
@ -242,10 +241,6 @@ namespace libtorrent
torrent* m_torrent;
// the number of unchoked peers
// at any given time
int m_num_unchoked;
// free download we have got that hasn't
// been distributed yet.
size_type m_available_free_upload;
@ -253,7 +248,7 @@ namespace libtorrent
// if there is a connection limit,
// we disconnect one peer every minute in hope of
// establishing a connection with a better peer
ptime m_last_optimistic_disconnect;
// ptime m_last_optimistic_disconnect;
};
}

View File

@ -1,99 +0,0 @@
/*
Copyright (c) 2003, Magnus Jonsson, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_RESOURCE_REQUEST_HPP_INCLUDED
#define TORRENT_RESOURCE_REQUEST_HPP_INCLUDED
#include <boost/integer_traits.hpp>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include "libtorrent/config.hpp"
namespace libtorrent
{
struct TORRENT_EXPORT resource_request
{
resource_request()
: used(0)
, min(0)
, max(0)
, given(0)
, leftovers(0)
{}
resource_request(int used_, int min_, int max_, int given_)
: used(used_)
, min(min_)
, max(max_)
, given(given_)
, leftovers(0)
{}
int left() const
{
assert(given <= max);
assert(given >= min);
assert(used >= 0);
return (std::max)(given - used, 0);
}
void reset() { used = leftovers; leftovers = 0; }
static const int inf = boost::integer_traits<int>::const_max;
// right now I'm actively using this amount
int used;
// given cannot be smaller than min
// and not greater than max.
int min;
int max;
// Reply: Okay, you're allowed to use this amount (a compromise):
int given;
// this is the amount of resources that exceeded the
// given limit. When the used field is reset (after resources
// have been distributed), it is reset to this number.
int leftovers;
};
}
#endif

View File

@ -61,7 +61,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/version.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/resource_request.hpp"
#include "libtorrent/storage.hpp"
#ifdef _MSC_VER
@ -266,12 +265,6 @@ namespace libtorrent
void stop_natpmp();
void stop_upnp();
// Resource management used for global limits.
resource_request m_ul_bandwidth_quota;
resource_request m_dl_bandwidth_quota;
resource_request m_uploads_quota;
resource_request m_connections_quota;
private:
// just a way to initialize boost.filesystem

View File

@ -105,7 +105,8 @@ namespace libtorrent
, send_redundant_have(false)
, lazy_bitfields(true)
, inactivity_timeout(600)
, unchoke_interval(20)
, unchoke_interval(15)
, optimistic_unchoke_multiplier(4)
, num_want(200)
, initial_picker_threshold(4)
, allowed_fast_set_size(10)
@ -242,6 +243,10 @@ namespace libtorrent
// the number of seconds between chokes/unchokes
int unchoke_interval;
// the number of unchoke intervals between
// optimistic unchokes
int optimistic_unchoke_multiplier;
// if this is set, this IP will be reported do the
// tracker in the ip= parameter.
address announce_ip;

View File

@ -62,7 +62,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/resource_request.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/escape_string.hpp"
@ -154,10 +153,6 @@ namespace libtorrent
bool verify_resume_data(entry& rd, std::string& error)
{ assert(m_storage); return m_storage->verify_resume_data(rd, error); }
// is called every second by session. This will
// caclulate the upload/download and number
// of connections this torrent needs. And prepare
// it for being used by allocate_resources.
void second_tick(stat& accumulator, float tick_interval);
// debug purpose only
@ -516,11 +511,6 @@ namespace libtorrent
// --------------------------------------------
// RESOURCE MANAGEMENT
void distribute_resources(float tick_interval);
resource_request m_uploads_quota;
resource_request m_connections_quota;
void set_peer_upload_limit(tcp::endpoint ip, int limit);
void set_peer_download_limit(tcp::endpoint ip, int limit);
@ -530,7 +520,9 @@ namespace libtorrent
int download_limit() const;
void set_max_uploads(int limit);
int max_uploads() const { return m_max_uploads; }
void set_max_connections(int limit);
int max_connections() const { return m_max_connections; }
void move_storage(fs::path const& save_path);
// unless this returns true, new connections must wait
@ -705,9 +697,9 @@ namespace libtorrent
// determine the timeout until next try.
int m_failed_trackers;
// this is a counter that is increased every
// second, and when it reaches 10, the policy::pulse()
// is called and the time scaler is reset to 0.
// this is a counter that is decreased every
// second, and when it reaches 0, the policy::pulse()
// is called and the time scaler is reset to 10.
int m_time_scaler;
// the bitmask that says which pieces we have
@ -774,6 +766,12 @@ namespace libtorrent
session_settings const& m_settings;
storage_constructor_type m_storage_constructor;
// the maximum number of uploads for this torrent
int m_max_uploads;
// the maximum number of connections for this torrent
int m_max_connections;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;

View File

@ -65,7 +65,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"

View File

@ -1,225 +0,0 @@
/*
Copyright (c) 2006, Magnus Jonsson, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
//The Standard Library defines the two template functions std::min()
//and std::max() in the <algorithm> header. In general, you should
//use these template functions for calculating the min and max values
//of a pair. Unfortunately, Visual C++ does not define these function
// templates. This is because the names min and max clash with
//the traditional min and max macros defined in <windows.h>.
//As a workaround, Visual C++ defines two alternative templates with
//identical functionality called _cpp_min() and _cpp_max(). You can
//use them instead of std::min() and std::max().To disable the
//generation of the min and max macros in Visual C++, #define
//NOMINMAX before #including <windows.h>.
#include "libtorrent/pch.hpp"
#ifdef _WIN32
//support boost1.32.0(2004-11-19 18:47)
//now all libs can be compiled and linked with static module
#define NOMINMAX
#endif
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/aux_/allocate_resources_impl.hpp"
#include <cassert>
#include <algorithm>
#include <boost/limits.hpp>
#if defined(_MSC_VER) && _MSC_VER < 1310
#define for if (false) {} else for
#else
#include <boost/iterator/transform_iterator.hpp>
#endif
namespace libtorrent
{
int saturated_add(int a, int b)
{
assert(a >= 0);
assert(b >= 0);
assert(a <= resource_request::inf);
assert(b <= resource_request::inf);
assert(resource_request::inf + resource_request::inf < 0);
unsigned int sum = unsigned(a) + unsigned(b);
if (sum > unsigned(resource_request::inf))
sum = resource_request::inf;
assert(sum >= unsigned(a) && sum >= unsigned(b));
return int(sum);
}
#if defined(_MSC_VER) && _MSC_VER < 1310
namespace detail
{
struct iterator_wrapper
{
typedef std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator orig_iter;
orig_iter iter;
iterator_wrapper(orig_iter i): iter(i) {}
void operator++() { ++iter; }
torrent& operator*() { return *(iter->second); }
bool operator==(const iterator_wrapper& i) const
{ return iter == i.iter; }
bool operator!=(const iterator_wrapper& i) const
{ return iter != i.iter; }
};
struct iterator_wrapper2
{
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
orig_iter iter;
iterator_wrapper2(orig_iter i): iter(i) {}
void operator++() { ++iter; }
peer_connection& operator*() { return *(iter->second); }
bool operator==(const iterator_wrapper2& i) const
{ return iter == i.iter; }
bool operator!=(const iterator_wrapper2& i) const
{ return iter != i.iter; }
};
}
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& c
, resource_request torrent::* res)
{
aux::allocate_resources_impl(
resources
, detail::iterator_wrapper(c.begin())
, detail::iterator_wrapper(c.end())
, res);
}
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& c
, resource_request peer_connection::* res)
{
aux::allocate_resources_impl(
resources
, detail::iterator_wrapper2(c.begin())
, detail::iterator_wrapper2(c.end())
, res);
}
#else
namespace aux
{
peer_connection& pick_peer(
std::pair<boost::shared_ptr<stream_socket>
, boost::intrusive_ptr<peer_connection> > const& p)
{
return *p.second;
}
peer_connection& pick_peer2(
std::pair<tcp::endpoint, peer_connection*> const& p)
{
return *p.second;
}
torrent& deref(std::pair<sha1_hash, boost::shared_ptr<torrent> > const& p)
{
return *p.second;
}
session& deref(session* p)
{
return *p;
}
}
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& c
, resource_request torrent::* res)
{
typedef std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator orig_iter;
typedef std::pair<sha1_hash, boost::shared_ptr<torrent> > in_param;
typedef boost::transform_iterator<torrent& (*)(in_param const&), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(c.begin(), &aux::deref)
, new_iter(c.end(), &aux::deref)
, res);
}
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& c
, resource_request peer_connection::* res)
{
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
typedef std::pair<tcp::endpoint, peer_connection*> in_param;
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(c.begin(), &aux::pick_peer2)
, new_iter(c.end(), &aux::pick_peer2)
, res);
}
void allocate_resources(
int resources
, std::vector<session*>& _sessions
, resource_request session::* res)
{
typedef std::vector<session*>::iterator orig_iter;
typedef session* in_param;
typedef boost::transform_iterator<session& (*)(in_param), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(_sessions.begin(), &aux::deref)
, new_iter(_sessions.end(), &aux::deref)
, res);
}
#endif
} // namespace libtorrent

View File

@ -109,8 +109,8 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_connection_ticket(-1)
@ -185,8 +185,8 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_remote_bytes_dled(0)
@ -526,30 +526,18 @@ namespace libtorrent
&& p.start + p.length <= t->torrent_file().piece_size(p.piece)
&& (p.start % t->block_size() == 0);
}
struct disconnect_torrent
{
disconnect_torrent(boost::weak_ptr<torrent>& t): m_t(&t) {}
~disconnect_torrent() { if (m_t) m_t->reset(); }
void cancel() { m_t = 0; }
private:
boost::weak_ptr<torrent>* m_t;
};
void peer_connection::attach_to_torrent(sha1_hash const& ih)
{
INVARIANT_CHECK;
assert(!m_disconnecting);
m_torrent = m_ses.find_torrent(ih);
assert(m_torrent.expired());
boost::weak_ptr<torrent> wpt = m_ses.find_torrent(ih);
boost::shared_ptr<torrent> t = m_torrent.lock();
if (t && t->is_aborted())
{
m_torrent.reset();
t.reset();
}
if (!t)
{
@ -560,7 +548,6 @@ namespace libtorrent
throw std::runtime_error("got info-hash that is not in our session");
}
disconnect_torrent disconnect(m_torrent);
if (t->is_paused())
{
// paused torrents will not accept
@ -571,21 +558,27 @@ namespace libtorrent
throw std::runtime_error("connection rejected by paused torrent");
}
assert(m_torrent.expired());
// check to make sure we don't have another connection with the same
// info_hash and peer_id. If we do. close this connection.
t->attach_peer(this);
m_torrent = wpt;
assert(!m_torrent.expired());
// if the torrent isn't ready to accept
// connections yet, we'll have to wait with
// our initialization
if (t->ready_for_connections()) init();
assert(!m_torrent.expired());
// assume the other end has no pieces
// if we don't have valid metadata yet,
// leave the vector unallocated
assert(m_num_pieces == 0);
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
disconnect.cancel();
assert(!m_torrent.expired());
}
// message handlers
@ -1543,7 +1536,7 @@ namespace libtorrent
// if the peer has the piece and we want
// to download it, request it
if (m_have_piece.size() > index
if (int(m_have_piece.size()) > index
&& m_have_piece[index]
&& t->has_picker()
&& t->picker().piece_priority(index) > 0)
@ -1900,7 +1893,7 @@ namespace libtorrent
void peer_connection::set_upload_limit(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = resource_request::inf;
if (limit == -1) limit = std::numeric_limits<int>::max();
if (limit < 10) limit = 10;
m_upload_limit = limit;
m_bandwidth_limit[upload_channel].throttle(m_upload_limit);
@ -1909,7 +1902,7 @@ namespace libtorrent
void peer_connection::set_download_limit(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = resource_request::inf;
if (limit == -1) limit = std::numeric_limits<int>::max();
if (limit < 10) limit = 10;
m_download_limit = limit;
m_bandwidth_limit[download_channel].throttle(m_download_limit);
@ -2044,10 +2037,13 @@ namespace libtorrent
if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size);
}
void peer_connection::second_tick(float tick_interval)
void peer_connection::second_tick(float tick_interval) throw()
{
INVARIANT_CHECK;
try
{
ptime now(time_now());
boost::shared_ptr<torrent> t = m_torrent.lock();
@ -2186,43 +2182,14 @@ namespace libtorrent
}
fill_send_buffer();
/*
size_type diff = share_diff();
enum { block_limit = 2 }; // how many blocks difference is considered unfair
// if the peer has been choked, send the 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
m_ul_bandwidth_quota.wanted = std::numeric_limits<int>::max();
}
else
catch (std::exception& e)
{
float ratio = m_torrent->ratio();
// if we have downloaded too much, response with an
// upload rate of 10 kB/s more than we dowlload
// if we have uploaded too much, send with a rate of
// 10 kB/s less than we receive
int bias = 0;
if (diff > -block_limit*m_torrent->block_size())
{
bias = static_cast<int>(m_statistics.download_rate() * ratio) / 2;
if (bias < 10*1024) bias = 10*1024;
}
else
{
bias = -static_cast<int>(m_statistics.download_rate() * ratio) / 2;
}
m_ul_bandwidth_quota.wanted = static_cast<int>(m_statistics.download_rate()) + bias;
// the maximum send_quota given our download rate from this peer
if (m_ul_bandwidth_quota.wanted < 256) m_ul_bandwidth_quota.wanted = 256;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << e.what() << "\n";
#endif
m_ses.connection_failed(m_socket, remote(), e.what());
}
*/
}
void peer_connection::fill_send_buffer()

View File

@ -331,9 +331,8 @@ namespace libtorrent
policy::policy(torrent* t)
: m_torrent(t)
, m_num_unchoked(0)
, m_available_free_upload(0)
, m_last_optimistic_disconnect(min_time())
// , m_last_optimistic_disconnect(min_time())
{ assert(t); }
// disconnects and removes all peers that are now filtered
@ -375,7 +374,7 @@ namespace libtorrent
m_peers.erase(i++);
}
}
/*
// finds the peer that has the worst download rate
// and returns it. May return 0 if all peers are
// choked.
@ -457,7 +456,7 @@ namespace libtorrent
}
return unchoke_peer;
}
*/
policy::iterator policy::find_disconnect_candidate()
{
INVARIANT_CHECK;
@ -542,7 +541,7 @@ namespace libtorrent
return candidate;
}
/*
policy::iterator policy::find_seed_choke_candidate()
{
INVARIANT_CHECK;
@ -648,7 +647,7 @@ namespace libtorrent
--m_num_unchoked;
}
}
*/
void policy::pulse()
{
INVARIANT_CHECK;
@ -680,7 +679,7 @@ namespace libtorrent
// -------------------------------------
// maintain the number of connections
// -------------------------------------
/*
// count the number of connected peers except for peers
// that are currently in the process of disconnecting
int num_connected_peers = 0;
@ -692,10 +691,9 @@ namespace libtorrent
++num_connected_peers;
}
if (m_torrent->m_connections_quota.given != std::numeric_limits<int>::max())
if (m_torrent->max_connections() != std::numeric_limits<int>::max())
{
int max_connections = m_torrent->m_connections_quota.given;
int max_connections = m_torrent->max_connections();
if (num_connected_peers >= max_connections)
{
@ -723,7 +721,7 @@ namespace libtorrent
--num_connected_peers;
}
}
*/
// ------------------------
// upload shift
// ------------------------
@ -754,7 +752,7 @@ namespace libtorrent
, m_torrent->end()
, m_available_free_upload);
}
/*
// ------------------------
// seed choking policy
// ------------------------
@ -870,6 +868,7 @@ namespace libtorrent
while (m_num_unchoked < m_torrent->m_uploads_quota.given
&& unchoke_one_peer());
}
*/
}
int policy::count_choked() const
@ -902,7 +901,8 @@ namespace libtorrent
// override at a time
assert(c.remote() == c.get_socket()->remote_endpoint());
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
if (m_torrent->num_peers() >= m_torrent->max_connections()
&& m_torrent->session().num_connections() >= m_torrent->session().max_connections()
&& c.remote().address() != m_torrent->current_tracker().address())
{
throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
@ -984,7 +984,7 @@ namespace libtorrent
i->connection = &c;
assert(i->connection);
i->connected = time_now();
m_last_optimistic_disconnect = time_now();
// m_last_optimistic_disconnect = time_now();
}
void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid
@ -1172,14 +1172,38 @@ namespace libtorrent
// In that case we don't care if people are leeching, they
// can't pay for their downloads anyway.
if (c.is_choked()
&& m_num_unchoked < m_torrent->m_uploads_quota.given
&& m_torrent->session().num_uploads() < m_torrent->session().max_uploads()
&& (m_torrent->ratio() == 0
|| c.share_diff() >= -free_upload_amount
|| m_torrent->is_seed()))
{
c.send_unchoke();
++m_num_unchoked;
m_torrent->session().unchoke_peer(c);
}
#if defined(TORRENT_VERBOSE_LOGGING)
else if (c.is_choked())
{
std::string reason;
if (m_torrent->session().num_uploads() >= m_torrent->session().max_uploads())
{
reason = "the number of uploads ("
+ boost::lexical_cast<std::string>(m_torrent->session().num_uploads())
+ ") is more than or equal to the limit ("
+ boost::lexical_cast<std::string>(m_torrent->session().max_uploads())
+ ")";
}
else
{
reason = "the share ratio ("
+ boost::lexical_cast<std::string>(c.share_diff())
+ ") is <= free_upload_amount ("
+ boost::lexical_cast<std::string>(int(free_upload_amount))
+ ") and we are not seeding and the ratio ("
+ boost::lexical_cast<std::string>(m_torrent->ratio())
+ ")is non-zero";
}
(*c.m_logger) << time_now_string() << " DID NOT UNCHOKE [ " << reason << " ]\n";
}
#endif
}
// called when a peer is no longer interested in us
@ -1211,7 +1235,7 @@ namespace libtorrent
}
*/
}
/*
bool policy::unchoke_one_peer()
{
INVARIANT_CHECK;
@ -1240,7 +1264,7 @@ namespace libtorrent
p->connection->send_choke();
--m_num_unchoked;
}
*/
bool policy::connect_one_peer()
{
INVARIANT_CHECK;
@ -1256,7 +1280,7 @@ namespace libtorrent
try
{
p->connected = m_last_optimistic_disconnect = time_now();
p->connected = time_now();
p->connection = m_torrent->connect_to_peer(&*p);
if (p->connection == 0) return false;
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
@ -1296,6 +1320,7 @@ namespace libtorrent
// assert(c.is_disconnecting());
bool unchoked = false;
#warning extract policy::peer pointer from c
iterator i = std::find_if(
m_peers.begin()
, m_peers.end()
@ -1305,6 +1330,7 @@ namespace libtorrent
if (i == m_peers.end()) return;
assert(i->connection == &c);
i->connection = 0;
i->optimistically_unchoked = false;
i->connected = time_now();
if (!c.is_choked() && !m_torrent->is_aborted())
@ -1330,15 +1356,15 @@ namespace libtorrent
i->prev_amount_download += c.statistics().total_payload_download();
i->prev_amount_upload += c.statistics().total_payload_upload();
if (unchoked)
{
// if (unchoked)
// {
// if the peer that is diconnecting is unchoked
// then unchoke another peer in order to maintain
// the total number of unchoked peers
--m_num_unchoked;
if (m_torrent->is_seed()) seed_unchoke_one_peer();
else unchoke_one_peer();
}
// --m_num_unchoked;
// if (m_torrent->is_seed()) seed_unchoke_one_peer();
// else unchoke_one_peer();
// }
}
catch (std::exception& e)
{
@ -1376,7 +1402,6 @@ namespace libtorrent
void policy::check_invariant() const
{
if (m_torrent->is_aborted()) return;
int actual_unchoked = 0;
int connected_peers = 0;
int total_connections = 0;
@ -1405,10 +1430,7 @@ namespace libtorrent
++nonempty_connections;
if (!p.connection->is_disconnecting())
++connected_peers;
if (!p.connection->is_choked()) ++actual_unchoked;
}
// assert(actual_unchoked <= m_torrent->m_uploads_quota.given);
assert(actual_unchoked == m_num_unchoked);
int num_torrent_peers = 0;
for (torrent::const_peer_iterator i = m_torrent->begin();
@ -1475,6 +1497,7 @@ namespace libtorrent
, failcount(0)
, hashfails(0)
, seed(false)
, optimistically_unchoked(false)
, last_optimistically_unchoked(min_time())
, connected(min_time())
, trust_points(0)

View File

@ -68,7 +68,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/socket.hpp"

View File

@ -68,7 +68,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/socket.hpp"
@ -505,8 +504,12 @@ namespace detail
, m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
, m_external_listen_port(0)
, m_abort(false)
, m_max_uploads(-1)
, m_max_connections(-1)
, m_max_uploads(8)
, m_max_connections(200)
, m_num_unchoked(0)
, m_unchoke_time_scaler(0)
, m_optimistic_unchoke_time_scaler(0)
, m_disconnect_time_scaler(0)
, m_incoming_connection(false)
, m_last_tick(time_now())
#ifndef TORRENT_DISABLE_DHT
@ -821,7 +824,10 @@ namespace detail
assert(p->is_disconnecting());
connection_map::iterator i = m_connections.find(p->get_socket());
if (i != m_connections.end())
{
if (!i->second->is_choked()) --m_num_unchoked;
m_connections.erase(i);
}
}
void session_impl::set_peer_id(peer_id const& id)
@ -901,7 +907,9 @@ namespace detail
// round robin fashion, so that every torrent is
// equallt likely to connect to a peer
if (!m_torrents.empty() && m_half_open.free_slots())
if (!m_torrents.empty()
&& m_half_open.free_slots()
&& num_connections() < m_max_connections)
{
// this is the maximum number of connections we will
// attempt this tick
@ -918,11 +926,13 @@ namespace detail
{
torrent& t = *i->second;
if (t.want_more_peers())
{
if (t.try_connect_peer())
{
--max_connections;
steps_since_last_connect = 0;
}
}
++m_next_connect_torrent;
++steps_since_last_connect;
++i;
@ -976,18 +986,7 @@ namespace detail
continue;
}
try
{
c.keep_alive();
}
catch (std::exception& exc)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*c.m_logger) << "**ERROR**: " << exc.what() << "\n";
#endif
c.set_failed();
c.disconnect();
}
c.keep_alive();
}
// check each torrent for tracker updates
@ -1019,30 +1018,148 @@ namespace detail
}
m_stat.second_tick(tick_interval);
// distribute the maximum upload rate among the torrents
assert(m_max_uploads >= -1);
assert(m_max_connections >= -1);
allocate_resources(m_max_uploads == -1
? std::numeric_limits<int>::max()
: m_max_uploads
, m_torrents
, &torrent::m_uploads_quota);
allocate_resources(m_max_connections == -1
? std::numeric_limits<int>::max()
: m_max_connections
, m_torrents
, &torrent::m_connections_quota);
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
= m_torrents.begin(); i != m_torrents.end(); ++i)
// --------------------------------------------------------------
// unchoke set and optimistic unchoke calculations
// --------------------------------------------------------------
m_unchoke_time_scaler--;
if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
{
#ifndef NDEBUG
i->second->check_invariant();
#endif
i->second->distribute_resources(tick_interval);
m_unchoke_time_scaler = settings().unchoke_interval;
std::vector<peer_connection*> peers;
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->second.get();
torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct()
|| !p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
|| (p->share_diff() < -free_upload_amount
&& t && !t->is_seed()))
{
if (!i->second->is_choked())
i->second->send_choke();
continue;
}
peers.push_back(i->second.get());
}
// sort the peers that are eligible for unchoke by download rate and secondary
// by total upload. The reason for this is, if all torrents are being seeded,
// the download rate will be 0, and the peers we have sent the least to should
// be unchoked
std::sort(peers.begin(), peers.end()
, bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _1))
< bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _2)));
std::stable_sort(peers.begin(), peers.end()
, bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _1))
> bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _2)));
// reserve one upload slot for optimistic unchokes
int unchoke_set_size = m_max_uploads - 1;
m_num_unchoked = 0;
// go through all the peers and unchoke the first ones and choke
// all the other ones.
for (std::vector<peer_connection*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_connection* p = *i;
assert(p);
if (unchoke_set_size > 0)
{
if (p->is_choked()) p->send_unchoke();
assert(p->peer_info_struct());
if (p->peer_info_struct()->optimistically_unchoked)
{
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
p->peer_info_struct()->optimistically_unchoked = false;
}
--unchoke_set_size;
++m_num_unchoked;
}
else
{
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
p->send_choke();
}
}
m_optimistic_unchoke_time_scaler--;
if (m_optimistic_unchoke_time_scaler <= 0)
{
m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_multiplier;
// find the peer that has been waiting the longest to be optimistically
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
ptime last_unchoke = max_time();
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->second.get();
assert(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
if (pi->optimistically_unchoked)
{
assert(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
{
if (current_optimistic_unchoke != m_connections.end())
{
current_optimistic_unchoke->second->send_choke();
current_optimistic_unchoke->second->peer_info_struct()->optimistically_unchoked = false;
}
optimistic_unchoke_candidate->second->send_unchoke();
optimistic_unchoke_candidate->second->peer_info_struct()->optimistically_unchoked = true;
}
if (optimistic_unchoke_candidate != m_connections.end())
++m_num_unchoked;
}
}
// --------------------------------------------------------------
// disconnect peers when we have too many
// --------------------------------------------------------------
--m_disconnect_time_scaler;
if (m_disconnect_time_scaler <= 0)
{
m_disconnect_time_scaler = 60;
// every 60 seconds, disconnect the worst peer
// if we have reached the connection limit
if (num_connections() >= max_connections() && !m_torrents.empty())
{
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
, bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1)));
assert(i != m_torrents.end());
i->second->get_policy().disconnect_one_peer();
}
}
}
catch (std::exception& exc)
@ -1866,24 +1983,6 @@ namespace detail
m_bandwidth_manager[peer_connection::upload_channel]->throttle(bytes_per_second);
}
int session_impl::num_uploads() const
{
int uploads = 0;
mutex_t::scoped_lock l(m_mutex);
for (torrent_map::const_iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; i++)
{
uploads += i->second->get_policy().num_uploads();
}
return uploads;
}
int session_impl::num_connections() const
{
mutex_t::scoped_lock l(m_mutex);
return m_connections.size();
}
std::auto_ptr<alert> session_impl::pop_alert()
{
mutex_t::scoped_lock l(m_mutex);
@ -1978,17 +2077,25 @@ namespace detail
void session_impl::check_invariant(const char *place)
{
assert(place);
int unchokes = 0;
int num_optimistic = 0;
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
assert(i->second);
boost::shared_ptr<torrent> t = i->second->associated_torrent().lock();
if (!i->second->is_choked()) ++unchokes;
if (i->second->peer_info_struct()
&& i->second->peer_info_struct()->optimistically_unchoked)
++num_optimistic;
if (t)
{
assert(t->get_policy().has_connection(boost::get_pointer(i->second)));
}
}
assert(num_optimistic == 0 || num_optimistic == 1);
assert(m_num_unchoked == unchokes);
}
#endif

View File

@ -199,18 +199,12 @@ namespace libtorrent
, m_connections_initialized(true)
, m_settings(s)
, m_storage_constructor(sc)
, m_max_uploads(std::numeric_limits<int>::max())
, m_max_connections(std::numeric_limits<int>::max())
{
#ifndef NDEBUG
m_initial_done = 0;
#endif
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
// distributes resources, i.e. on average in 0.5 seconds
m_connections_quota.given = 100;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
m_policy.reset(new policy(this));
}
@ -277,13 +271,6 @@ namespace libtorrent
if (name) m_name.reset(new std::string(name));
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
// distributes resources, i.e. on average in 0.5 seconds
m_connections_quota.given = 100;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
if (tracker_url)
{
m_trackers.push_back(announce_entry(tracker_url));
@ -329,6 +316,14 @@ namespace libtorrent
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** DESTRUCTING TORRENT\n";
}
#endif
assert(m_abort);
if (!m_connections.empty())
disconnect_all();
@ -1020,6 +1015,15 @@ namespace libtorrent
m_event = tracker_request::stopped;
// disconnect all peers and close all
// files belonging to the torrents
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** ABORTING TORRENT\n";
}
#endif
disconnect_all();
if (m_owning_storage.get()) m_storage->async_release_files();
m_owning_storage = 0;
@ -1890,7 +1894,7 @@ namespace libtorrent
void torrent::attach_peer(peer_connection* p)
{
INVARIANT_CHECK;
// INVARIANT_CHECK;
assert(p != 0);
assert(!p->is_local());
@ -1955,7 +1959,7 @@ namespace libtorrent
bool torrent::want_more_peers() const
{
return int(m_connections.size()) < m_connections_quota.given
return int(m_connections.size()) < m_max_connections
&& m_ses.m_half_open.free_slots()
&& !m_paused;
}
@ -2425,15 +2429,15 @@ namespace libtorrent
void torrent::set_max_uploads(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = std::numeric_limits<int>::max();
m_uploads_quota.max = std::max(m_uploads_quota.min, limit);
if (limit < 0) limit = std::numeric_limits<int>::max();
m_max_uploads = limit;
}
void torrent::set_max_connections(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = std::numeric_limits<int>::max();
m_connections_quota.max = std::max(m_connections_quota.min, limit);
if (limit < -1) limit = std::numeric_limits<int>::max();
m_max_connections = limit;
}
void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
@ -2496,6 +2500,14 @@ namespace libtorrent
}
#endif
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** PAUSING TORRENT\n";
}
#endif
disconnect_all();
m_paused = true;
// tell the tracker that we stopped
@ -2528,10 +2540,6 @@ namespace libtorrent
#endif
m_paused = false;
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
// tell the tracker that we're back
m_event = tracker_request::started;
@ -2545,10 +2553,6 @@ namespace libtorrent
{
INVARIANT_CHECK;
m_connections_quota.used = (int)m_connections.size();
m_uploads_quota.used = m_policy->num_uploads();
m_uploads_quota.max = (int)m_connections.size();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
@ -2561,10 +2565,6 @@ namespace libtorrent
{
// let the stats fade out to 0
m_stat.second_tick(tick_interval);
m_connections_quota.min = 0;
m_connections_quota.max = 0;
m_uploads_quota.min = 0;
m_uploads_quota.max = 0;
return;
}
@ -2623,6 +2623,13 @@ namespace libtorrent
}
accumulator += m_stat;
m_stat.second_tick(tick_interval);
m_time_scaler--;
if (m_time_scaler <= 0)
{
m_time_scaler = 10;
m_policy->pulse();
}
}
bool torrent::try_connect_peer()
@ -2631,18 +2638,6 @@ namespace libtorrent
return m_policy->connect_one_peer();
}
void torrent::distribute_resources(float tick_interval)
{
INVARIANT_CHECK;
m_time_scaler--;
if (m_time_scaler <= 0)
{
m_time_scaler = settings().unchoke_interval;
m_policy->pulse();
}
}
void torrent::async_verify_piece(int piece_index, boost::function<void(bool)> const& f)
{
INVARIANT_CHECK;
@ -2764,10 +2759,10 @@ namespace libtorrent
= m_trackers[m_last_working_tracker].url;
}
st.num_uploads = m_uploads_quota.used;
st.uploads_limit = m_uploads_quota.given;
st.num_connections = m_connections_quota.used;
st.connections_limit = m_connections_quota.given;
st.num_uploads = -1;
st.uploads_limit = m_max_uploads;
st.num_connections = int(m_connections.size());
st.connections_limit = m_max_connections;
// if we don't have any metadata, stop here
if (!valid_metadata())

View File

@ -32,7 +32,6 @@ test-suite libtorrent :
[ run test_hasher.cpp ]
[ run test_metadata_extension.cpp ]
[ run test_swarm.cpp ]
[ run test_allocate_resources.cpp ]
[ run test_web_seed.cpp ]
[ run test_bandwidth_limiter.cpp ]
;

View File

@ -1,57 +0,0 @@
#include "libtorrent/aux_/allocate_resources_impl.hpp"
#include <boost/utility.hpp>
#include "test.hpp"
using namespace libtorrent;
struct resource_entry
{
resource_entry(resource_request r_): r(r_) {}
resource_request r;
};
void fill_client_vector(std::vector<resource_entry>& v)
{
v.push_back(resource_request(5000, 20, 20000, 10000));
v.push_back(resource_request(9000, 20, 20000, 10000));
v.push_back(resource_request(8000, 20, 20000, 10000));
v.push_back(resource_request(7000, 20, 20000, 10000));
v.push_back(resource_request(5000, 20, 20000, 10000));
v.push_back(resource_request(8000, 20, 20000, 10000));
}
void check_client_vec(std::vector<resource_entry> const& v, int resources)
{
int sum = 0;
int min_sum = 0;
for (std::vector<resource_entry>::const_iterator i = v.begin()
, end(v.end()); i != end; ++i)
{
TEST_CHECK(i->r.given >= i->r.min);
TEST_CHECK(i->r.given <= i->r.max);
sum += i->r.given;
min_sum += i->r.min;
}
TEST_CHECK(sum <= (std::max)(resources, min_sum));
}
int test_main()
{
using namespace libtorrent;
std::vector<resource_entry> clients;
fill_client_vector(clients);
using aux::allocate_resources_impl;
allocate_resources_impl(20, clients.begin(), clients.end(), &resource_entry::r);
check_client_vec(clients, 20);
fill_client_vector(clients);
allocate_resources_impl(20000, clients.begin(), clients.end(), &resource_entry::r);
check_client_vec(clients, 20000);
return 0;
}