From 71e1fd4407712ba6c99a8bc3bab4f86c96ba8cf1 Mon Sep 17 00:00:00 2001 From: Magnus Jonsson Date: Tue, 17 Feb 2004 00:18:29 +0000 Subject: [PATCH] *** empty log message *** --- include/libtorrent/allocate_resources.hpp | 90 ++++++++++++ include/libtorrent/policy.hpp | 2 + include/libtorrent/session.hpp | 3 +- src/allocate_resources.cpp | 169 ++++++++++++++++++++++ src/session.cpp | 41 +++++- 5 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 include/libtorrent/allocate_resources.hpp create mode 100644 src/allocate_resources.cpp diff --git a/include/libtorrent/allocate_resources.hpp b/include/libtorrent/allocate_resources.hpp new file mode 100644 index 000000000..0ba39abf8 --- /dev/null +++ b/include/libtorrent/allocate_resources.hpp @@ -0,0 +1,90 @@ +/* + +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 +#include + +namespace libtorrent +{ + struct resource_consumer; + + + // 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. + + void allocate_resources(int resources, + std::vector & 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; + }; +} + + +#endif diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp index 1037070bd..3bf55ddd8 100755 --- a/include/libtorrent/policy.hpp +++ b/include/libtorrent/policy.hpp @@ -103,6 +103,7 @@ namespace libtorrent void not_interested(peer_connection& c); void set_max_uploads(int num_unchoked); + int get_max_uploads() const { return m_max_uploads; } /* A limit on the number of sockets opened, for use on systems where a @@ -110,6 +111,7 @@ namespace libtorrent which has a buggy tcp-stack. */ void set_max_connections(int num_connected); + int get_max_connections() const { return m_max_connections; } #ifndef NDEBUG bool has_connection(const peer_connection* p); diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 60584cb35..3a9efebf2 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -155,6 +155,7 @@ namespace libtorrent { friend class invariant_access; typedef std::map, boost::shared_ptr > connection_map; + typedef std::map > torrent_map; session_impl( std::pair listen_port_range @@ -169,7 +170,7 @@ namespace libtorrent const peer_id& get_peer_id() const { return m_peer_id; } tracker_manager m_tracker_manager; - std::map > m_torrents; + torrent_map m_torrents; // this maps sockets to their peer_connection // object. It is the complete list of all connected diff --git a/src/allocate_resources.cpp b/src/allocate_resources.cpp new file mode 100644 index 000000000..fd1034c2b --- /dev/null +++ b/src/allocate_resources.cpp @@ -0,0 +1,169 @@ +/* + +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. + +*/ + +#include "libtorrent/allocate_resources.hpp" +#include +#include +#include + +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); + assert(b>=0); + + int sum=a+b; + if(sum<0) + sum=std::numeric_limits::max(); + + assert(sum>=a && sum>=b); + return sum; + } + + int round_up_division(int numer, int denom) + { + assert(numer>0); + assert(denom>0); + int result=(numer+denom-1)/denom; + assert(result>0); + assert(result<=numer); + return result; + } + + int total_demand(std::vector & consumers) + { + int total_demand=0; + + for(int i=0;i<(int)consumers.size();i++) + { + total_demand=saturated_add(total_demand, consumers[i].desired_use()); + if(total_demand == std::numeric_limits::max()) + break; + } + + assert(total_demand>=0); + return total_demand; + } + } + + void allocate_resources(int resources, + std::vector & consumers) + { + assert(resources>=0); + + // no competition for resources? + if(resources==std::numeric_limits::max()) + { + for(int i=0;i<(int)consumers.size();i++) + consumers[i].give(std::numeric_limits::max()); + } + else + { + int resources_to_distribute = + std::min( + resources, + total_demand(consumers)); + + if (resources_to_distribute != 0) + { + assert(resources_to_distribute>0); + + std::random_shuffle(consumers.begin(),consumers.end()); + std::sort(consumers.begin(),consumers.end(),by_desired_use); + + 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()))); + } + assert(resources_to_distribute == 0); + } + +#ifndef NDEBUG + { + int sum_given = 0; + int sum_desired = 0; + for (std::vector::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 + } + +} \ No newline at end of file diff --git a/src/session.cpp b/src/session.cpp index a12732954..172cee6f3 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -92,13 +92,13 @@ namespace } void control_upload_rates( - int upload_limit - , libtorrent::detail::session_impl::connection_map connections) + int upload_limit, + libtorrent::detail::session_impl::connection_map connections) { + assert(upload_limit >= 0); + using namespace libtorrent; std::vector peers; - - assert(upload_limit >= 0); for (detail::session_impl::connection_map::iterator c = connections.begin(); c != connections.end(); ++c) @@ -148,6 +148,39 @@ namespace } #endif } + void control_number_of_connections( + int connections_limit, + libtorrent::detail::session_impl::torrent_map hash_list) + { + assert(connections_limit >= 0); + + using namespace libtorrent; + std::vector torrents; + + for (detail::session_impl::torrent_map::iterator c = hash_list.begin(); + c != hash_list.end(); ++c) + { + boost::shared_ptr t = c->second; + + int estimated_capacity=t->num_peers()+1; + int limit =t->get_policy().get_max_connections(); + if(limit==-1) + limit=std::numeric_limits::max(); + + torrents.push_back(resource_consumer(t,limit,estimated_capacity)); + } + + allocate_resources(connections_limit, torrents); + + for (std::vector::iterator r=torrents.begin(); + r!=torrents.end(); ++r) + { + // TODO: inform torrent of how many connections it's allowed. +// boost::any_cast > +// (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