From 13b2590c0b3e635c6b1f73122375939f3026694e Mon Sep 17 00:00:00 2001 From: Magnus Jonsson Date: Tue, 24 Feb 2004 19:23:37 +0000 Subject: [PATCH] *** empty log message *** --- examples/client_test.cpp | 26 +- include/libtorrent/allocate_resources.hpp | 3 + include/libtorrent/peer_connection.hpp | 21 +- src/allocate_resources.cpp | 107 ++++++-- src/peer_connection.cpp | 25 +- src/session.cpp | 281 +++------------------- src/torrent_handle.cpp | 23 +- 7 files changed, 164 insertions(+), 322 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index c51da53da..915894ede 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -378,7 +378,7 @@ int main(int argc, char* argv[]) out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n"; out << "tracker: " << s.current_tracker << "\n"; - out << "___________________________________\n"; +// out << "___________________________________\n"; for (std::vector::iterator i = peers.begin(); i != peers.end(); @@ -389,17 +389,17 @@ int main(int argc, char* argv[]) << "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 " + << "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:" - << static_cast((i->flags & peer_info::interesting)?"I":"_") - << static_cast((i->flags & peer_info::choked)?"C":"_") - << static_cast((i->flags & peer_info::remote_interested)?"i":"_") - << static_cast((i->flags & peer_info::remote_choked)?"c":"_") - << static_cast((i->flags & peer_info::supports_extensions)?"e":"_") - << static_cast((i->flags & peer_info::local_connection)?"l":"r") +// << "q:" << i->download_queue_length << " " +// << "r:" << i->upload_queue_length << " " +// << "f:" +// << static_cast((i->flags & peer_info::interesting)?"I":"_") +// << static_cast((i->flags & peer_info::choked)?"C":"_") +// << static_cast((i->flags & peer_info::remote_interested)?"i":"_") +// << static_cast((i->flags & peer_info::remote_choked)?"c":"_") +// << static_cast((i->flags & peer_info::supports_extensions)?"e":"_") +// << static_cast((i->flags & peer_info::local_connection)?"l":"r") << "\n"; /* if (i->downloading_piece_index >= 0) @@ -415,7 +415,7 @@ int main(int argc, char* argv[]) } */ } - +/* out << "___________________________________\n"; i->get_download_queue(queue); @@ -436,7 +436,7 @@ int main(int argc, char* argv[]) } out << "___________________________________\n"; - +*/ } for (std::deque::iterator i = events.begin(); diff --git a/include/libtorrent/allocate_resources.hpp b/include/libtorrent/allocate_resources.hpp index a285d102a..389c09a73 100644 --- a/include/libtorrent/allocate_resources.hpp +++ b/include/libtorrent/allocate_resources.hpp @@ -55,6 +55,9 @@ namespace libtorrent // 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::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); diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 063c96c3f..5ec8ac597 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -212,12 +212,12 @@ namespace libtorrent // left until will stop sending. // if the send_quota is -1, it means the // quota is unlimited. - int send_quota_left() const { return m_send_quota_left; } + int send_quota_left() const { return upload_bandwidth.given-upload_bandwidth.used; } void update_send_quota_left() { - m_send_quota_left = upload_bandwidth.given; - if (m_send_quota_left > 0) send_buffer_updated(); + upload_bandwidth.used=0; + send_buffer_updated(); } size_type total_free_upload() const @@ -465,19 +465,6 @@ namespace libtorrent // that we give the free upload, to keep the balance. size_type m_free_upload; - // this is used to limit upload bandwidth. - // it is reset to the allowed number of - // bytes to send frequently. Every time - // thie peer send some data, - // m_send_quota_left variable will be decreased - // so it can limit the number of bytes next - // time it sends data. when it reaches zero - // the client will stop send data and await - // more quota. if it is set to -1, the peer - // will ignore the qouta and send at maximum - // speed - int m_send_quota_left; - // for every valid piece we receive where this // peer was one of the participants, we increase // this value. For every invalid piece we receive @@ -536,7 +523,7 @@ namespace libtorrent return; } - assert(m_send_quota_left > 0 || m_send_quota_left == -1); + assert(upload_bandwidth.used < upload_bandwidth.given); assert(has_data()); if (!m_added_to_selector) { diff --git a/src/allocate_resources.cpp b/src/allocate_resources.cpp index cca105fe0..6206723ee 100644 --- a/src/allocate_resources.cpp +++ b/src/allocate_resources.cpp @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/allocate_resources.hpp" +#include "libtorrent/size_type.hpp" #include #include #include @@ -51,7 +52,7 @@ namespace libtorrent assert(sum>=a && sum>=b); return sum; } - +/* int round_up_division(int numer, int denom) { assert(numer>0); @@ -66,13 +67,13 @@ namespace libtorrent // 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(num_resources >= 0); assert(r->given <= r->wanted); int accepted = std::min(num_resources, r->wanted - r->given); @@ -84,6 +85,7 @@ namespace libtorrent return accepted; } + // sum of requests' "wanted" field. int total_wanted(std::vector & requests) { int total_wanted=0; @@ -154,7 +156,7 @@ namespace libtorrent allocate_resources_contract_check contract_check(resources,requests); #endif - + if(resources == std::numeric_limits::max()) { // No competition for resources. @@ -181,27 +183,94 @@ namespace libtorrent return; assert(resources_to_distribute > 0); - - 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)requests.size() && resources_to_distribute > 0; - ++i) +#if 1 + int num_active=0; + for(int i = 0;i < (int)requests.size();++i) { - resources_to_distribute -= - give( - requests[i], - std::min( - requests[i]->used+1, - round_up_division( - (int)resources_to_distribute, - (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); + } +#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; + + { + size_type numer=1; + size_type denom=max_used; + + if(numer*kDenom >= kNumer*denom) + { + kNumer=numer; + kDenom=denom; + } + } + + 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); + } +#endif + assert(resources_to_distribute >= 0); } assert(resources_to_distribute == 0); + } } -} +} \ No newline at end of file diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index a42f14b55..f105d8dde 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -100,7 +100,6 @@ namespace libtorrent , m_supports_extensions(false) , m_num_pieces(0) , m_free_upload(0) - , m_send_quota_left(0) , m_trust_points(0) , m_num_invalid_requests(0) , m_last_piece(boost::posix_time::second_clock::local_time()) @@ -162,7 +161,6 @@ namespace libtorrent , m_supports_extensions(false) , m_num_pieces(0) , m_free_upload(0) - , m_send_quota_left(0) , m_trust_points(0) , m_num_invalid_requests(0) , m_last_piece(boost::posix_time::second_clock::local_time()) @@ -1226,7 +1224,7 @@ namespace libtorrent m_statistics.second_tick(); - update_send_quota_left(); +// update_send_quota_left(); // If the client sends more data // we send it data faster, otherwise, slower. @@ -1240,7 +1238,10 @@ namespace libtorrent // 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::max(); +// if(!m_send_buffer.empty() || (!m_requests.empty() && !is_choked())) + upload_bandwidth.wanted = std::numeric_limits::max(); +// else +// upload_bandwidth.wanted = 0; } else { @@ -1566,7 +1567,7 @@ namespace libtorrent // we want to send data return ((!m_requests.empty() && !m_choked) || !m_send_buffer.empty()) - && m_send_quota_left != 0; + && upload_bandwidth.used < upload_bandwidth.given; } // -------------------------- @@ -1645,17 +1646,15 @@ namespace libtorrent m_announce_queue.clear(); } - assert(m_send_quota_left != 0); + assert(upload_bandwidth.used < upload_bandwidth.given); // send the actual buffer if (!m_send_buffer.empty()) { int amount_to_send = (int)m_send_buffer.size(); - assert(m_send_quota_left != 0); - if (m_send_quota_left > 0) - amount_to_send = std::min(m_send_quota_left, amount_to_send); - + assert(upload_bandwidth.used < upload_bandwidth.given); + amount_to_send = std::min(upload_bandwidth.given-upload_bandwidth.used, amount_to_send); // we have data that's scheduled for sending int sent = m_socket->send( @@ -1664,11 +1663,7 @@ namespace libtorrent if (sent > 0) { - if (m_send_quota_left != -1) - { - assert(m_send_quota_left >= sent); - m_send_quota_left -= sent; - } + upload_bandwidth.used += sent; // manage the payload markers int amount_payload = 0; diff --git a/src/session.cpp b/src/session.cpp index 95ce583ac..332873bfc 100755 --- a/src/session.cpp +++ b/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::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 peers; + std::vector requests; for (detail::session_impl::connection_map::iterator c = connections.begin(); c != connections.end(); ++c) { boost::shared_ptr 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::max(); - - peers.push_back(resource_consumer(p,limit,estimated_upload_capacity)); + p->upload_bandwidth.used = (int) ((p->statistics().upload_rate()+p->upload_bandwidth.used) / 2); +// p->has_data() ? (int) (p->upload_bandwidth.given - p->send_quota_left()) //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::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 > - (r->who())->set_send_quota(r->allowed_use()); + boost::shared_ptr 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::max(); - if(quota_limit==-1) - quota_limit=std::numeric_limits::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 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::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::max(); - } - - if(sum_quota_limit!=std::numeric_limits::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 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,12 @@ namespace libtorrent boost::shared_ptr 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); @@ -824,7 +616,6 @@ namespace libtorrent // check each torrent for abortion or // tracker updates - assert(m_disconnect_peer.empty()); for (std::map >::iterator i = m_torrents.begin(); i != m_torrents.end();) @@ -834,9 +625,6 @@ namespace libtorrent m_tracker_manager.queue_request( i->second->generate_tracker_request(m_listen_port)); i->second->disconnect_all(); - // make sure all connection are closed - // before the torrent is removed - purge_connections(); #ifndef NDEBUG sha1_hash i_hash = i->second->torrent_file().info_hash(); #endif @@ -850,8 +638,7 @@ namespace libtorrent { m_tracker_manager.queue_request( i->second->generate_tracker_request(m_listen_port) - , boost::get_pointer(i->second) - , i->second->tracker_password()); + , boost::get_pointer(i->second)); } i->second->second_tick(); @@ -861,10 +648,11 @@ namespace libtorrent // distribute the maximum upload rate among the peers - control_upload_rates(m_upload_rate == -1 - ? std::numeric_limits::max() - : m_upload_rate - ,m_connections); + control_upload_rates( + m_upload_rate == -1 + ? std::numeric_limits::max() + : m_upload_rate + , m_connections); m_tracker_manager.tick(); @@ -937,7 +725,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(); @@ -1105,7 +893,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::max(); + i->second->update_send_quota_left(); } } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index e27328ba1..297f2c673 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -192,22 +192,14 @@ namespace libtorrent { boost::mutex::scoped_lock l(m_ses->m_mutex); torrent* t = m_ses->find_torrent(m_info_hash); - if (t != 0) - { - t->set_tracker_login(name, password); - return; - } + if (t != 0) t->set_tracker_login(name, password); } if (m_chk) { boost::mutex::scoped_lock l(m_chk->m_mutex); detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) - { - d->torrent_ptr->set_tracker_login(name, password); - return; - } + if (d != 0) d->torrent_ptr->set_tracker_login(name, password); } throw invalid_handle(); @@ -467,8 +459,15 @@ 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(); + if (peer->upload_bandwidth.given == std::numeric_limits::max()) + p.upload_limit = -1; + else + p.upload_limit = peer->upload_bandwidth.given; + + if (peer->upload_bandwidth.wanted == std::numeric_limits::max()) + p.upload_ceiling = -1; + else + p.upload_ceiling = peer->upload_bandwidth.wanted; p.load_balancing = peer->total_free_upload();