diff --git a/docs/manual.html b/docs/manual.html index 597827a3e..b2b432f40 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -662,6 +662,7 @@ struct torrent_status }; state_t state; + bool paused; float progress; boost::posix_time::time_duration next_announce; boost::posix_time::time_duration announce_interval; @@ -717,6 +718,7 @@ is a pure seeder. +

paused is set to true if the torrent is paused and false otherwise.

next_announce is the time until the torrent will announce itself to the tracker. And announce_interval is the time the tracker want us to wait until we announce ourself again the next time.

diff --git a/docs/manual.rst b/docs/manual.rst index 3de747af2..89d5f3bc0 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -675,6 +675,7 @@ It contains the following fields:: }; state_t state; + bool paused; float progress; boost::posix_time::time_duration next_announce; boost::posix_time::time_duration announce_interval; @@ -725,6 +726,8 @@ current task is in the ``state`` member, it will be one of the following: | | | +--------------------------+----------------------------------------------------------+ +``paused`` is set to true if the torrent is paused and false otherwise. + ``next_announce`` is the time until the torrent will announce itself to the tracker. And ``announce_interval`` is the time the tracker want us to wait until we announce ourself again the next time. diff --git a/include/libtorrent/allocate_resources.hpp b/include/libtorrent/allocate_resources.hpp index c8b474493..c30492a62 100644 --- a/include/libtorrent/allocate_resources.hpp +++ b/include/libtorrent/allocate_resources.hpp @@ -33,24 +33,17 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED #define TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED -#include -#include +#include +#include + +#include + +#include "libtorrent/resource_request.hpp" namespace libtorrent { - 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; - }; + class socket; + class peer_connection; // Function to allocate a limited resource fairly among many consumers. // It takes into account the current use, and the consumer's desired use. @@ -59,9 +52,11 @@ namespace libtorrent // If resources = std::numeric_limits::max() it means there is an infinite // supply of resources (so everyone can get what they want). - - void allocate_resources(int resources, - std::vector & requests); + void allocate_resources( + int resources + , std::map, boost::shared_ptr >& connections + , resource_request peer_connection::* res); + } diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index ca69940be..940195bf7 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -178,8 +178,12 @@ namespace libtorrent int send_quota_left() const; resource_request* upload_bandwidth_quota(); - // ?? TODO: document - void update_send_quota_left(); + // This is called for every peer right after the upload + // bandwidth has been distributed among them + // It will reset the used bandwidth to 0 and + // possibly add or remove the peer's socket + // from the socket monitor + void reset_upload_quota(); // free upload. size_type total_free_upload() const; @@ -242,6 +246,9 @@ namespace libtorrent void send_extensions(); void send_chat_message(const std::string& msg); + // how much bandwidth we're using, how much we want, + // and how much we are allowed to use. + resource_request m_upload_bandwidth_quota; private: @@ -331,14 +338,10 @@ namespace libtorrent // peer's socket from the writability monitor list. selector& m_selector; boost::shared_ptr m_socket; - - // how much bandwidth we're using, how much we want, - // and how much we are allowed to use. - resource_request m_upload_bandwidth_quota; // upload bandwidth used this second. // Must not exceed m_upload_bandwidth_quota.given. - int m_upload_bandwidth_quota_used; +// int m_upload_bandwidth_quota_used; // this is the torrent this connection is // associated with. If the connection is an diff --git a/include/libtorrent/resource_request.hpp b/include/libtorrent/resource_request.hpp new file mode 100755 index 000000000..774968f57 --- /dev/null +++ b/include/libtorrent/resource_request.hpp @@ -0,0 +1,52 @@ +/* + +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_RESOURCE_REQUEST_HPP_INCLUDED +#define TORRENT_RESOURCE_REQUEST_HPP_INCLUDED + +namespace libtorrent +{ + 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; + }; +} + + +#endif diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 3a85dd9a0..bdac8ada6 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -74,6 +74,7 @@ namespace libtorrent { torrent_status() : state(queued_for_checking) + , paused(false) , progress(0.f) , total_download(0) , total_upload(0) diff --git a/src/allocate_resources.cpp b/src/allocate_resources.cpp index 42019779b..29dcc1ff2 100644 --- a/src/allocate_resources.cpp +++ b/src/allocate_resources.cpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2003, Magnus Jonsson +Copyright (c) 2003, Magnus Jonsson, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -32,9 +32,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/allocate_resources.hpp" #include "libtorrent/size_type.hpp" +#include "libtorrent/peer_connection.hpp" + #include #include #include +#include #if defined(_MSC_VER) && _MSC_VER < 1300 #define for if (false) {} else for @@ -46,89 +49,61 @@ namespace libtorrent { int saturated_add(int a, int b) { - assert(a>=0); - assert(b>=0); + assert(a >= 0); + assert(b >= 0); + assert(std::numeric_limits::max() + std::numeric_limits::max() < 0); - int sum=a+b; - if(sum<0) - sum=std::numeric_limits::max(); + int sum = a + b; + if(sum < 0) + sum = std::numeric_limits::max(); - assert(sum>=a && sum>=b); + 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; - } - - // 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) + int give(resource_request& r, int num_resources) { - assert(r); assert(num_resources >= 0); - assert(r->given <= r->wanted); + assert(r.given <= r.wanted); - int accepted = std::min(num_resources, r->wanted - r->given); + int accepted = std::min(num_resources, r.wanted - r.given); assert(accepted >= 0); - r->given += accepted; - assert(r->given <= r->wanted); + r.given += accepted; + assert(r.given <= r.wanted); return accepted; } - // sum of requests' "wanted" field. - int total_wanted(std::vector & requests) - { - int total_wanted=0; - - for(int i=0;i<(int)requests.size();i++) - { - total_wanted= - saturated_add(total_wanted,requests[i]->wanted); - - if(total_wanted == std::numeric_limits::max()) - break; - } - - assert(total_wanted>=0); - return total_wanted; - } - #ifndef NDEBUG + template class allocate_resources_contract_check { - - int resources; - std::vector & requests; + int m_resources; + It m_start; + It m_end; + resource_request T::* m_res; public: - allocate_resources_contract_check( - int resources_ - , std::vector& requests_) - : resources(resources_) - , requests(requests_) + int resources + , It start + , It end + , resource_request T::* res) + : m_resources(resources) + , m_start(start) + , m_end(end) + , m_res(res) { - assert(resources >= 0); - for (int i = 0; i < (int)requests.size(); ++i) + assert(m_resources >= 0); + for (It i = m_start, end(m_end); i != end; ++i) { - assert(requests[i]->used >= 0); - assert(requests[i]->wanted >= 0); - assert(requests[i]->given >= 0); + assert(((*i).*m_res).used >= 0); + assert(((*i).*m_res).wanted >= 0); + assert(((*i).*m_res).given >= 0); } } @@ -136,212 +111,127 @@ namespace libtorrent { int sum_given = 0; int sum_wanted = 0; - for (int i = 0; i < (int)requests.size(); ++i) + for (It i = m_start, end(m_end); i != end; ++i) { - assert(requests[i]->used >= 0); - assert(requests[i]->wanted >= 0); - assert(requests[i]->given >= 0); - assert(requests[i]->given <= requests[i]->wanted); + assert(((*i).*m_res).wanted >= 0); + assert(((*i).*m_res).given >= 0); + assert(((*i).*m_res).given <= ((*i).*m_res).wanted); - sum_given = saturated_add(sum_given, requests[i]->given); - sum_wanted = saturated_add(sum_wanted, requests[i]->wanted); + sum_given = saturated_add(sum_given, ((*i).*m_res).given); + sum_wanted = saturated_add(sum_wanted, ((*i).*m_res).wanted); } - assert(sum_given == std::min(resources,sum_wanted)); + assert(sum_given == std::min(m_resources, sum_wanted)); } }; #endif - } // namespace unnamed - void allocate_resources(int resources, - std::vector& requests) - { -#ifndef NDEBUG - allocate_resources_contract_check contract_check(resources,requests); -#endif + template + void allocate_resources_impl( + int resources + , It start + , It end + , resource_request T::* res) + { + #ifndef NDEBUG + allocate_resources_contract_check contract_check( + resources + , start + , end + , res); + #endif + + if(resources == std::numeric_limits::max()) + { + // No competition for resources. + // Just give everyone what they want. + for (It i = start; i != end; ++i) + { + ((*i).*res).given = ((*i).*res).wanted; + } + return; + } - if(resources == std::numeric_limits::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; + int total_wanted = 0; + for (It i = start; i != end; ++i) + { + ((*i).*res).given = 0; + total_wanted = saturated_add(total_wanted, ((*i).*res).wanted); + } - if (resources == 0) - return; - - int resources_to_distribute = - std::min( - resources, - total_wanted(requests)); - - if (resources_to_distribute == 0) + if (resources == 0 || total_wanted == 0) return; + int resources_to_distribute = std::min(resources, total_wanted); assert(resources_to_distribute > 0); - while(resources_to_distribute > 0) + while (resources_to_distribute > 0) { -#if 0 - int num_active=0; - for(int i = 0;i < (int)requests.size();++i) + size_type total_used = 0; + size_type max_used = 0; + for (It i = start; i != end; ++i) { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - num_active++; + resource_request& r = (*i).*res; + if(r.given == r.wanted) continue; + + assert(r.given < r.wanted); + + max_used = std::max(max_used, (size_type)r.used + 1); + total_used += (size_type)r.used + 1; } - int max_give=resources_to_distribute/num_active; - max_give=std::max(max_give,1); - - for(int i = 0;i < (int)requests.size() && resources_to_distribute;++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; + size_type kNumer = resources_to_distribute; + size_type kDenom = total_used; - int toGive = 1+std::min(max_give-1,r->used); - resources_to_distribute-=give(r,toGive); - } -#elif 0 - size_type total_used=0; - size_type max_used=0; - for(int i = 0;i < (int)requests.size();++i) + if (kNumer * max_used <= kDenom) { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - assert(r->given < r->wanted); - - max_used = std::max(max_used, (size_type)r->used + 1); - total_used += (size_type)r->used + 1; + kNumer = 1; + kDenom = max_used; } - size_type kNumer=resources_to_distribute; - size_type kDenom=total_used; - + for (It i = start; i != end && resources_to_distribute > 0; ++i) { - size_type numer=1; - size_type denom=max_used; + resource_request& r = (*i).*res; + if(r.given == r.wanted) continue; - if(numer*kDenom >= kNumer*denom) - { - kNumer=numer; - kDenom=denom; - } - } + assert(r.given < r.wanted); - for(int i = 0;i < (int)requests.size();++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - assert(r->given < r->wanted); - - size_type numer = r->wanted - r->given; - size_type denom = (size_type)r->used + 1; - - if(numer*kDenom <= kNumer*denom) - { - kNumer=numer; - kDenom=denom; - } - } - - for(int i = 0;i < (int)requests.size() && resources_to_distribute;++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - assert(r->given < r->wanted); - - size_type used = (size_type)r->used + 1; - size_type toGive = (used * kNumer) / kDenom; - if(toGive>std::numeric_limits::max()) - toGive=std::numeric_limits::max(); - resources_to_distribute-=give(r,(int)toGive); - } -#else - size_type total_used=0; - size_type max_used=0; - for(int i = 0;i < (int)requests.size();++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - assert(r->given < r->wanted); - - 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; - - if(kNumer*max_used <= kDenom) - { - kNumer=1; - kDenom=max_used; - } -/* - if(kNumer > kDenom) - { - kNumer=1; - kDenom=1; - } -*/ - for(int i = 0;i < (int)requests.size() && resources_to_distribute;++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - assert(r->given < r->wanted); - - size_type used = (size_type)r->used + 1; + size_type used = (size_type)r.used + 1; size_type toGive = used * kNumer / kDenom; - if(toGive>std::numeric_limits::max()) - toGive=std::numeric_limits::max(); - resources_to_distribute-=give(r,(int)toGive); + if(toGive > std::numeric_limits::max()) + toGive = std::numeric_limits::max(); + resources_to_distribute -= give(r, (int)toGive); } -/* - while(resources_to_distribute != 0) - { - int num_active=0; - for(int i = 0;i < (int)requests.size();++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - num_active++; - } - int max_give=resources_to_distribute/num_active; - max_give=std::max(max_give,1); - - for(int i = 0;i < (int)requests.size() && resources_to_distribute;++i) - { - resource_request *r=requests[i]; - if(r->given == r->wanted) - continue; - - int toGive = 1+std::min(max_give-1,r->used); - resources_to_distribute-=give(r,toGive); - } - } -*/ -#endif assert(resources_to_distribute >= 0); } - assert(resources_to_distribute == 0); - } + + peer_connection& pick_peer( + std::pair, boost::shared_ptr > const& p) + { + return *p.second; + } + + } // namespace anonymous + + + void allocate_resources( + int resources + , std::map, boost::shared_ptr >& c + , resource_request peer_connection::* res) + { + typedef std::map, boost::shared_ptr >::iterator orig_iter; + typedef std::pair, boost::shared_ptr > in_param; + typedef boost::transform_iterator new_iter; + + allocate_resources_impl( + resources + , new_iter(c.begin(), &pick_peer) + , new_iter(c.end(), &pick_peer) + , res); } -} + +} // namespace libtorrent diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index b80621ba2..48458cbdd 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -107,7 +107,7 @@ namespace libtorrent , m_disconnecting(false) , m_became_uninterested(boost::posix_time::second_clock::local_time()) , m_became_uninteresting(boost::posix_time::second_clock::local_time()) - , m_upload_bandwidth_quota_used(0) +// , m_upload_bandwidth_quota_used(0) { INVARIANT_CHECK; @@ -170,7 +170,7 @@ namespace libtorrent , m_disconnecting(false) , m_became_uninterested(boost::posix_time::second_clock::local_time()) , m_became_uninteresting(boost::posix_time::second_clock::local_time()) - , m_upload_bandwidth_quota_used(0) +// , m_upload_bandwidth_quota_used(0) { INVARIANT_CHECK; @@ -272,12 +272,12 @@ namespace libtorrent int peer_connection::send_quota_left() const { - return m_upload_bandwidth_quota.given - m_upload_bandwidth_quota_used; + return m_upload_bandwidth_quota.given - m_upload_bandwidth_quota.used; } - void peer_connection::update_send_quota_left() + void peer_connection::reset_upload_quota() { - m_upload_bandwidth_quota_used=0; + m_upload_bandwidth_quota.used = 0; send_buffer_updated(); } @@ -286,7 +286,6 @@ namespace libtorrent return &m_upload_bandwidth_quota; } - void peer_connection::send_handshake() { INVARIANT_CHECK; @@ -1303,9 +1302,9 @@ namespace libtorrent INVARIANT_CHECK; m_statistics.second_tick(); - m_upload_bandwidth_quota.used=(int)ceil(statistics().upload_rate()); + m_upload_bandwidth_quota.used = (int)ceil(statistics().upload_rate()); -// update_send_quota_left(); + send_buffer_updated(); // If the client sends more data // we send it data faster, otherwise, slower. @@ -1678,7 +1677,7 @@ namespace libtorrent // we want to send data return ((!m_requests.empty() && !m_choked) || !m_send_buffer.empty()) - && send_quota_left()>0; + && send_quota_left() > 0; } // -------------------------- @@ -1757,7 +1756,7 @@ namespace libtorrent m_announce_queue.clear(); } - assert(m_upload_bandwidth_quota_used < m_upload_bandwidth_quota.given); + assert(m_upload_bandwidth_quota.used <= m_upload_bandwidth_quota.given); // send the actual buffer if (!m_send_buffer.empty()) @@ -1774,7 +1773,7 @@ namespace libtorrent if (sent > 0) { - m_upload_bandwidth_quota_used += sent; + m_upload_bandwidth_quota.used += sent; // manage the payload markers int amount_payload = 0; diff --git a/src/session.cpp b/src/session.cpp index e590f93f8..3f3d02871 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -67,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/invariant_check.hpp" #include "libtorrent/file.hpp" #include "libtorrent/allocate_resources.hpp" +#include "libtorrent/peer_connection.hpp" #if defined(_MSC_VER) && _MSC_VER < 1300 namespace std @@ -78,6 +79,7 @@ namespace std namespace { +/* int saturated_add(int a, int b) { assert(a>=0); @@ -90,13 +92,14 @@ namespace assert(sum>=a && sum>=b); 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::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) @@ -122,6 +125,7 @@ namespace p->update_send_quota_left(); } } +*/ /* void control_number_of_connections( int connections_limit, @@ -530,12 +534,12 @@ namespace libtorrent { namespace detail boost::shared_ptr c( new peer_connection(*this, m_selector, s)); - if (m_upload_rate != -1) +/* if (m_upload_rate != -1) { c->upload_bandwidth_quota()->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); @@ -704,12 +708,17 @@ namespace libtorrent { namespace detail // distribute the maximum upload rate among the peers - control_upload_rates( - m_upload_rate == -1 + allocate_resources(m_upload_rate == -1 ? std::numeric_limits::max() : m_upload_rate - , m_connections); + , m_connections + , &peer_connection::m_upload_bandwidth_quota); + for (detail::session_impl::connection_map::iterator c = m_connections.begin(); + c != m_connections.end(); ++c) + { + c->second->reset_upload_quota(); + } m_tracker_manager.tick(); } @@ -1000,8 +1009,9 @@ namespace libtorrent i != m_impl.m_connections.end();) { i->second->upload_bandwidth_quota()->given = std::numeric_limits::max(); - i->second->update_send_quota_left(); +// i->second->update_send_quota_left(); } + } std::auto_ptr session::pop_alert()