updated client_test to use post_torrent_updates()

This commit is contained in:
Arvid Norberg 2011-12-23 05:36:13 +00:00
parent 2877903e75
commit d7103ab5b0
4 changed files with 138 additions and 77 deletions

View File

@ -1,6 +1,6 @@
* deprecate set_ratio(), and per-peer rate limits
* add web seed support for torrents with pad files
* introduced a more scalable API for torrent status updates (post_torrent_updates())
* introduced a more scalable API for torrent status updates (post_torrent_updates()) and updated client_test to use it
* updated the API to add_torrent_params turning all bools into flags of a flags field
* added async_add_torrent() function to significantly improve performance when
adding many torrents

View File

@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#include <boost/bind.hpp>
#include <boost/unordered_set.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
@ -277,26 +278,41 @@ bool show_torrent(libtorrent::torrent_status const& st, int torrent_filter, int*
bool yes(libtorrent::torrent_status const&)
{ return true; }
bool compare_torrent(torrent_status const& lhs, torrent_status const& rhs)
{
if (lhs.queue_position != -1 && rhs.queue_position != -1)
{
// both are downloading, sort by queue pos
return lhs.queue_position < rhs.queue_position;
}
else if (lhs.queue_position == -1 && rhs.queue_position == -1)
{
// both are seeding, sort by seed-rank
return lhs.seed_rank > rhs.seed_rank;
}
return (lhs.queue_position == -1) < (rhs.queue_position == -1);
}
FILE* g_log_file = 0;
int active_torrent = 0;
bool compare_torrent(torrent_status const* lhs, torrent_status const* rhs)
{
if (lhs->queue_position != -1 && rhs->queue_position != -1)
{
// both are downloading, sort by queue pos
return lhs->queue_position < rhs->queue_position;
}
else if (lhs->queue_position == -1 && rhs->queue_position == -1)
{
// both are seeding, sort by seed-rank
return lhs->seed_rank > rhs->seed_rank;
}
return (lhs->queue_position == -1) < (rhs->queue_position == -1);
}
void update_filtered_torrents(boost::unordered_set<torrent_status>& all_handles
, std::vector<torrent_status const*>& filtered_handles, int* counters)
{
filtered_handles.clear();
memset(counters, 0, sizeof(int) * torrents_max);
for (boost::unordered_set<torrent_status>::iterator i = all_handles.begin()
, end(all_handles.end()); i != end; ++i)
{
if (!show_torrent(*i, torrent_filter, counters)) continue;
filtered_handles.push_back(&*i);
}
if (active_torrent >= int(filtered_handles.size())) active_torrent = filtered_handles.size() - 1;
std::sort(filtered_handles.begin(), filtered_handles.end(), &compare_torrent);
}
char const* esc(char const* code)
{
#ifdef ANSI_TERMINAL_COLORS
@ -785,13 +801,11 @@ void scan_dir(std::string const& dir_path
}
}
torrent_status const& get_active_torrent(std::vector<torrent_status> const& torrents)
torrent_status const& get_active_torrent(std::vector<torrent_status const*> const& filtered_handles)
{
if (active_torrent >= int(torrents.size())
if (active_torrent >= int(filtered_handles.size())
|| active_torrent < 0) active_torrent = 0;
std::vector<torrent_status>::const_iterator i = torrents.begin();
std::advance(i, active_torrent);
return *i;
return *filtered_handles[active_torrent];
}
void print_alert(libtorrent::alert const* a, std::string& str)
@ -835,8 +849,13 @@ int save_file(std::string const& filename, std::vector<char>& v)
return 0;
}
void handle_alert(libtorrent::session& ses, libtorrent::alert* a
, handles_t& files, std::set<libtorrent::torrent_handle> const& non_files)
// returns true if the alert was handled (and should not be printed to the log)
// returns false if the alert was not handled
bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
, handles_t& files, std::set<libtorrent::torrent_handle> const& non_files
, int* counters, boost::unordered_set<torrent_status>& all_handles
, std::vector<torrent_status const*>& filtered_handles
, bool& need_resort)
{
using namespace libtorrent;
@ -854,7 +873,7 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
char msg[256];
snprintf(msg, sizeof(msg), "ERROR. could not load certificate %s: %s\n", cert.c_str(), ec.message().c_str());
if (g_log_file) fprintf(g_log_file, "[%s] %s\n", time_now_string(), msg);
return;
return true;
}
stat_file(priv, &st, ec);
if (ec)
@ -862,7 +881,7 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
char msg[256];
snprintf(msg, sizeof(msg), "ERROR. could not load private key %s: %s\n", priv.c_str(), ec.message().c_str());
if (g_log_file) fprintf(g_log_file, "[%s] %s\n", time_now_string(), msg);
return;
return true;
}
char msg[256];
@ -897,6 +916,14 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
h.resolve_countries(true);
#endif
boost::unordered_set<torrent_status>::iterator j
= all_handles.insert(h.status()).first;
if (show_torrent(*j, torrent_filter, counters))
{
filtered_handles.push_back(&*j);
need_resort = true;
}
}
}
else if (torrent_finished_alert* p = alert_cast<torrent_finished_alert>(a))
@ -946,6 +973,21 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
h.save_resume_data();
++num_outstanding_resume_data;
}
else if (state_update_alert* p = alert_cast<state_update_alert>(a))
{
for (std::vector<torrent_status>::iterator i = p->status.begin();
i != p->status.end(); ++i)
{
boost::unordered_set<torrent_status>::iterator j = all_handles.find(*i);
// don't add new entries here, that's done in the handler
// for add_torrent_alert
if (j == all_handles.end()) continue;
((torrent_status&)*j) = *i;
}
return true;
}
return false;
}
void print_piece(libtorrent::partial_piece_info* pp
@ -1120,7 +1162,9 @@ int main(int argc, char* argv[])
// it was added through the directory monitor. It is used to
// be able to remove torrents that were added via the directory
// monitor when they're not in the directory anymore.
std::vector<torrent_status> handles;
boost::unordered_set<torrent_status> all_handles;
std::vector<torrent_status const*> filtered_handles;
handles_t files;
// torrents that were not added via the monitor dir
std::set<torrent_handle> non_files;
@ -1447,16 +1491,15 @@ int main(int argc, char* argv[])
while (loop_limit > 1 || loop_limit == 0)
{
++tick;
handles.clear();
memset(counters, 0, sizeof(counters));
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter, (int*)counters));
if (active_torrent >= int(handles.size())) active_torrent = handles.size() - 1;
else if (active_torrent >= 0)
ses.post_torrent_updates();
if (active_torrent >= int(filtered_handles.size())) active_torrent = filtered_handles.size() - 1;
if (active_torrent >= 0)
{
// ask for distributed copies for the selected torrent. Since this
// is a somewhat expensive operation, don't do it by default for
// all torrents
handles[active_torrent] = handles[active_torrent].handle.status(
torrent_status const& h = *filtered_handles[active_torrent];
h.handle.status(
torrent_handle::query_distributed_copies
| torrent_handle::query_pieces
| torrent_handle::query_verified_pieces);
@ -1467,7 +1510,7 @@ int main(int argc, char* argv[])
counters[torrents_feeds] = feeds.size();
std::sort(handles.begin(), handles.end(), &compare_torrent);
std::sort(filtered_handles.begin(), filtered_handles.end(), &compare_torrent);
if (loop_limit > 1) --loop_limit;
int c = 0;
@ -1497,11 +1540,7 @@ int main(int argc, char* argv[])
if (torrent_filter > 0)
{
--torrent_filter;
handles.clear();
memset(counters, 0, sizeof(counters));
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter, (int*)counters));
if (active_torrent >= int(handles.size())) active_torrent = handles.size() - 1;
std::sort(handles.begin(), handles.end(), &compare_torrent);
update_filtered_torrents(all_handles, filtered_handles, counters);
}
}
else if (c == 67)
@ -1510,11 +1549,7 @@ int main(int argc, char* argv[])
if (torrent_filter < torrents_max - 1)
{
++torrent_filter;
handles.clear();
memset(counters, 0, sizeof(counters));
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter, (int*)counters));
if (active_torrent >= int(handles.size())) active_torrent = handles.size() - 1;
std::sort(handles.begin(), handles.end(), &compare_torrent);
update_filtered_torrents(all_handles, filtered_handles, counters);
}
}
else if (c == 65)
@ -1527,7 +1562,8 @@ int main(int argc, char* argv[])
{
// arrow down
++active_torrent;
if (active_torrent >= int(handles.size())) active_torrent = handles.size() - 1;
if (active_torrent >= int(filtered_handles.size()))
active_torrent = filtered_handles.size() - 1;
}
}
@ -1567,7 +1603,7 @@ int main(int argc, char* argv[])
if (c == 'D')
{
torrent_handle h = get_active_torrent(handles).handle;
torrent_handle h = get_active_torrent(filtered_handles).handle;
if (h.is_valid())
{
printf("\n\nARE YOU SURE YOU WANT TO DELETE THE FILES FOR '%s'. THIS OPERATION CANNOT BE UNDONE. (y/N)"
@ -1592,39 +1628,39 @@ int main(int argc, char* argv[])
}
}
if (c == 'j' && !handles.empty())
if (c == 'j' && !filtered_handles.empty())
{
get_active_torrent(handles).handle.force_recheck();
get_active_torrent(filtered_handles).handle.force_recheck();
}
if (c == 'r' && !handles.empty())
if (c == 'r' && !filtered_handles.empty())
{
get_active_torrent(handles).handle.force_reannounce();
get_active_torrent(filtered_handles).handle.force_reannounce();
}
if (c == 's' && !handles.empty())
if (c == 's' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
ts.handle.set_sequential_download(!ts.sequential_download);
}
if (c == 'R')
{
// save resume data for all torrents
for (std::vector<torrent_status>::iterator i = handles.begin()
, end(handles.end()); i != end; ++i)
for (std::vector<torrent_status const*>::iterator i = filtered_handles.begin()
, end(filtered_handles.end()); i != end; ++i)
{
if (i->need_save_resume)
if ((*i)->need_save_resume)
{
i->handle.save_resume_data();
(*i)->handle.save_resume_data();
++num_outstanding_resume_data;
}
}
}
if (c == 'o' && !handles.empty())
if (c == 'o' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
int num_pieces = ts.num_pieces;
if (num_pieces > 300) num_pieces = 300;
for (int i = 0; i < num_pieces; ++i)
@ -1633,15 +1669,15 @@ int main(int argc, char* argv[])
}
}
if (c == 'v' && !handles.empty())
if (c == 'v' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
ts.handle.scrape_tracker();
}
if (c == 'p' && !handles.empty())
if (c == 'p' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
if (!ts.auto_managed && ts.paused)
{
ts.handle.auto_managed(true);
@ -1654,16 +1690,16 @@ int main(int argc, char* argv[])
}
// toggle force-start
if (c == 'k' && !handles.empty())
if (c == 'k' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
ts.handle.auto_managed(!ts.auto_managed);
if (ts.auto_managed && ts.paused) ts.handle.resume();
}
if (c == 'c' && !handles.empty())
if (c == 'c' && !filtered_handles.empty())
{
torrent_status const& ts = get_active_torrent(handles);
torrent_status const& ts = get_active_torrent(filtered_handles);
ts.handle.clear_error();
}
@ -1731,16 +1767,26 @@ int main(int argc, char* argv[])
for (std::deque<alert*>::iterator i = alerts.begin()
, end(alerts.end()); i != end; ++i)
{
std::string event_string;
::print_alert(*i, event_string);
bool need_resort = false;
TORRENT_TRY
{
::handle_alert(ses, *i, files, non_files);
if (!::handle_alert(ses, *i, files, non_files, counters
, all_handles, filtered_handles, need_resort))
{
// if we didn't handle the alert, print it to the log
std::string event_string;
print_alert(*i, event_string);
events.push_back(event_string);
if (events.size() >= 20) events.pop_front();
}
} TORRENT_CATCH(std::exception& e) {}
events.push_back(event_string);
if (events.size() >= 20) events.pop_front();
if (need_resort)
{
std::sort(filtered_handles.begin(), filtered_handles.end()
, &compare_torrent);
}
delete *i;
}
alerts.clear();
@ -1794,8 +1840,8 @@ int main(int argc, char* argv[])
}
}
for (std::vector<torrent_status>::iterator i = handles.begin();
i != handles.end(); ++torrent_index)
for (std::vector<torrent_status const*>::iterator i = filtered_handles.begin();
i != filtered_handles.end(); ++torrent_index)
{
if (lines_printed >= terminal_height - 15)
{
@ -1803,10 +1849,10 @@ int main(int argc, char* argv[])
break;
}
torrent_status& s = *i;
torrent_status const& s = **i;
if (!s.handle.is_valid())
{
i = handles.erase(i);
i = filtered_handles.erase(i);
continue;
}
else
@ -2037,7 +2083,7 @@ int main(int argc, char* argv[])
}
torrent_status const* st = 0;
if (!handles.empty()) st = &get_active_torrent(handles);
if (!filtered_handles.empty()) st = &get_active_torrent(filtered_handles);
if (st && st->handle.is_valid())
{
torrent_handle h = st->handle;

View File

@ -71,6 +71,8 @@ namespace libtorrent
struct peer_list_entry;
struct torrent_status;
std::size_t hash_value(torrent_status const& ts);
#ifndef BOOST_NO_EXCEPTIONS
// for compatibility with 0.14
typedef libtorrent_exception duplicate_torrent;
@ -155,6 +157,7 @@ namespace libtorrent
friend struct aux::session_impl;
friend struct feed;
friend class torrent;
friend std::size_t hash_value(torrent_handle const& th);
torrent_handle() {}
@ -496,6 +499,9 @@ namespace libtorrent
, listen_port(0)
{}
bool operator==(torrent_status const& st) const
{ return handle == st.handle; }
// handle to the torrent
torrent_handle handle;

View File

@ -899,5 +899,14 @@ namespace libtorrent
TORRENT_ASYNC_CALL1(reset_piece_deadline, index);
}
std::size_t hash_value(torrent_status const& ts)
{
return hash_value(ts.handle);
}
std::size_t hash_value(torrent_handle const& th)
{
return std::size_t(th.m_torrent.lock().get());
}
}