solved issue with pausing checking torrents. Introduced a new state, checkin_resume_data, which a torrent is in while waiting for the disk io thread to verify the resume data, but before it has been determined wheter it should be queued for checking or not

This commit is contained in:
Arvid Norberg 2008-11-19 00:46:48 +00:00
parent 78abf8a340
commit 723aba6c24
7 changed files with 79 additions and 22 deletions

View File

@ -1,4 +1,9 @@
* torrents that are checking can now be paused, which will
pause the checking
* introduced another torrent state, checking_resume_data, which
the torrent is in when it's first added, and is comparing
the files on disk with the resume data
* DHT bandwidth usage optimizations * DHT bandwidth usage optimizations
* rate limited DHT send socket * rate limited DHT send socket
* tracker connections are now also subject to IP filtering * tracker connections are now also subject to IP filtering

View File

@ -283,7 +283,8 @@ def main():
if s.state != lt.torrent_status.seeding: if s.state != lt.torrent_status.seeding:
state_str = ['queued', 'checking', 'downloading metadata', \ state_str = ['queued', 'checking', 'downloading metadata', \
'downloading', 'finished', 'seeding', 'allocating'] 'downloading', 'finished', 'seeding', \
'allocating', 'checking fastresume']
out += state_str[s.state] + ' ' out += state_str[s.state] + ' '
out += '%5.4f%% ' % (s.progress*100) out += '%5.4f%% ' % (s.progress*100)

View File

@ -2376,7 +2376,8 @@ It contains the following fields::
downloading, downloading,
finished, finished,
seeding, seeding,
allocating allocating,
checking_resume_data
}; };
state_t state; state_t state;
@ -2453,6 +2454,11 @@ It contains the following fields::
torrent's current task. It may be checking files or downloading. The torrent's torrent's current task. It may be checking files or downloading. The torrent's
current task is in the ``state`` member, it will be one of the following: current task is in the ``state`` member, it will be one of the following:
+--------------------------+----------------------------------------------------------+
|``checking_resume_data`` |The torrent is currently checking the fastresume data and |
| |comparing it to the files on disk. This is typically |
| |completed in a fraction of a second, but if you add a |
| |large number of torrents at once, they will queue up. |
+--------------------------+----------------------------------------------------------+ +--------------------------+----------------------------------------------------------+
|``queued_for_checking`` |The torrent is in the queue for being checked. But there | |``queued_for_checking`` |The torrent is in the queue for being checked. But there |
| |currently is another torrent that are being checked. | | |currently is another torrent that are being checked. |

View File

@ -667,7 +667,7 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
static char const* state_str[] = static char const* state_str[] =
{"checking (q)", "checking", "dl metadata" {"checking (q)", "checking", "dl metadata"
, "downloading", "finished", "seeding", "allocating"}; , "downloading", "finished", "seeding", "allocating", "checking (r)"};
int main(int ac, char* av[]) int main(int ac, char* av[])
{ {

View File

@ -81,7 +81,7 @@ namespace libtorrent
struct TORRENT_EXPORT torrent_status struct TORRENT_EXPORT torrent_status
{ {
torrent_status() torrent_status()
: state(queued_for_checking) : state(checking_resume_data)
, paused(false) , paused(false)
, progress(0.f) , progress(0.f)
, total_download(0) , total_download(0)
@ -130,7 +130,8 @@ namespace libtorrent
downloading, downloading,
finished, finished,
seeding, seeding,
allocating allocating,
checking_resume_data
}; };
state_t state; state_t state;

View File

@ -1875,10 +1875,10 @@ namespace aux {
void session_impl::check_torrent(boost::shared_ptr<torrent> const& t) void session_impl::check_torrent(boost::shared_ptr<torrent> const& t)
{ {
if (m_abort) return; if (m_abort) return;
TORRENT_ASSERT(!t->is_paused() || t->is_auto_managed()); TORRENT_ASSERT(t->should_check_files());
TORRENT_ASSERT(t->state() == torrent_status::checking_files TORRENT_ASSERT(t->state() != torrent_status::checking_files);
|| t->state() == torrent_status::queued_for_checking);
if (m_queued_for_checking.empty()) t->start_checking(); if (m_queued_for_checking.empty()) t->start_checking();
else t->set_state(torrent_status::queued_for_checking);
TORRENT_ASSERT(std::find(m_queued_for_checking.begin() TORRENT_ASSERT(std::find(m_queued_for_checking.begin()
, m_queued_for_checking.end(), t) == m_queued_for_checking.end()); , m_queued_for_checking.end(), t) == m_queued_for_checking.end());
m_queued_for_checking.push_back(t); m_queued_for_checking.push_back(t);
@ -1900,17 +1900,21 @@ namespace aux {
void session_impl::done_checking(boost::shared_ptr<torrent> const& t) void session_impl::done_checking(boost::shared_ptr<torrent> const& t)
{ {
INVARIANT_CHECK;
if (m_queued_for_checking.empty()) return; if (m_queued_for_checking.empty()) return;
check_queue_t::iterator next_check = m_queued_for_checking.begin(); check_queue_t::iterator next_check = m_queued_for_checking.begin();
check_queue_t::iterator done = m_queued_for_checking.end(); check_queue_t::iterator done = m_queued_for_checking.end();
for (check_queue_t::iterator i = m_queued_for_checking.begin() for (check_queue_t::iterator i = m_queued_for_checking.begin()
, end(m_queued_for_checking.end()); i != end; ++i) , end(m_queued_for_checking.end()); i != end; ++i)
{ {
TORRENT_ASSERT(*i == t || (*i)->should_check_files());
if (*i == t) done = i; if (*i == t) done = i;
if (next_check == done || (*next_check)->queue_position() > (*i)->queue_position()) if (next_check == done || (*next_check)->queue_position() > (*i)->queue_position())
next_check = i; next_check = i;
} }
if (next_check != done) (*next_check)->start_checking(); // only start a new one if we removed the one that is checking
if (next_check != done && t->state() == torrent_status::checking_files) (*next_check)->start_checking();
m_queued_for_checking.erase(done); m_queued_for_checking.erase(done);
} }
@ -2631,6 +2635,13 @@ namespace aux {
#ifndef NDEBUG #ifndef NDEBUG
void session_impl::check_invariant() const void session_impl::check_invariant() const
{ {
int num_checking = std::count_if(m_queued_for_checking.begin()
, m_queued_for_checking.end(), boost::bind(&torrent::state, _1)
== torrent_status::checking_files);
// the queue is either empty, or it has exactly one checking torrent in it
TORRENT_ASSERT(m_queued_for_checking.empty() || num_checking == 1);
std::set<int> unique; std::set<int> unique;
int total_downloaders = 0; int total_downloaders = 0;
for (torrent_map::const_iterator i = m_torrents.begin() for (torrent_map::const_iterator i = m_torrents.begin()

View File

@ -170,7 +170,7 @@ namespace libtorrent
, m_net_interface(net_interface.address(), 0) , m_net_interface(net_interface.address(), 0)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , m_state(torrent_status::checking_resume_data)
, m_settings(ses.settings()) , m_settings(ses.settings())
, m_storage_constructor(sc) , m_storage_constructor(sc)
, m_progress(0.f) , m_progress(0.f)
@ -250,7 +250,7 @@ namespace libtorrent
, m_net_interface(net_interface.address(), 0) , m_net_interface(net_interface.address(), 0)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , m_state(torrent_status::checking_resume_data)
, m_settings(ses.settings()) , m_settings(ses.settings())
, m_storage_constructor(sc) , m_storage_constructor(sc)
, m_progress(0.f) , m_progress(0.f)
@ -472,7 +472,7 @@ namespace libtorrent
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
, m_web_seeds.begin())); , m_web_seeds.begin()));
set_state(torrent_status::queued_for_checking); set_state(torrent_status::checking_resume_data);
if (m_resume_entry.type() == lazy_entry::dict_t) if (m_resume_entry.type() == lazy_entry::dict_t)
{ {
@ -552,6 +552,7 @@ namespace libtorrent
} }
m_error = j.str; m_error = j.str;
pause(); pause();
set_state(torrent_status::queued_for_checking);
std::vector<char>().swap(m_resume_data); std::vector<char>().swap(m_resume_data);
lazy_entry().swap(m_resume_entry); lazy_entry().swap(m_resume_entry);
@ -680,7 +681,8 @@ namespace libtorrent
{ {
// either the fastresume data was rejected or there are // either the fastresume data was rejected or there are
// some files // some files
if (!is_torrent_paused() || is_auto_managed()) set_state(torrent_status::queued_for_checking);
if (should_check_files())
m_ses.check_torrent(shared_from_this()); m_ses.check_torrent(shared_from_this());
} }
@ -690,10 +692,21 @@ namespace libtorrent
void torrent::force_recheck() void torrent::force_recheck()
{ {
if (m_state == torrent_status::checking_files // if the torrent is already queued to check its files
|| m_state == torrent_status::queued_for_checking) // don't do anything
if (should_check_files()
|| m_state == torrent_status::checking_resume_data)
return; return;
if ((is_paused() && !m_auto_managed))
{
// set the queued for checking state, so that it's
// checked as soon as it's resumed or made auto managed
set_state(torrent_status::queued_for_checking);
return;
}
if (!m_error.empty()) m_error.clear();
disconnect_all(); disconnect_all();
m_owning_storage->async_release_files(); m_owning_storage->async_release_files();
@ -706,7 +719,7 @@ namespace libtorrent
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size)); , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
// assume that we don't have anything // assume that we don't have anything
m_files_checked = false; m_files_checked = false;
set_state(torrent_status::queued_for_checking); set_state(torrent_status::checking_resume_data);
if (m_auto_managed) if (m_auto_managed)
set_queue_position((std::numeric_limits<int>::max)()); set_queue_position((std::numeric_limits<int>::max)());
@ -744,6 +757,7 @@ namespace libtorrent
void torrent::start_checking() void torrent::start_checking()
{ {
TORRENT_ASSERT(should_check_files());
set_state(torrent_status::checking_files); set_state(torrent_status::checking_files);
m_storage->async_check_files(bind( m_storage->async_check_files(bind(
@ -773,7 +787,11 @@ namespace libtorrent
} }
m_error = j.str; m_error = j.str;
pause(); pause();
if (!m_abort) m_ses.done_checking(shared_from_this()); if (!m_abort)
{
m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
}
return; return;
} }
@ -1636,7 +1654,10 @@ namespace libtorrent
} }
if (m_state == torrent_status::checking_files) if (m_state == torrent_status::checking_files)
{
m_ses.done_checking(shared_from_this()); m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
}
m_owning_storage = 0; m_owning_storage = 0;
m_host_resolver.cancel(); m_host_resolver.cancel();
@ -3065,7 +3086,8 @@ namespace libtorrent
m_has_incoming = true; m_has_incoming = true;
if ((m_state == torrent_status::queued_for_checking if ((m_state == torrent_status::queued_for_checking
|| m_state == torrent_status::checking_files) || m_state == torrent_status::checking_files
|| m_state == torrent_status::checking_resume_data)
&& valid_metadata()) && valid_metadata())
{ {
p->disconnect("torrent is not ready to accept peers"); p->disconnect("torrent is not ready to accept peers");
@ -3133,8 +3155,9 @@ namespace libtorrent
{ {
return int(m_connections.size()) < m_max_connections return int(m_connections.size()) < m_max_connections
&& !is_paused() && !is_paused()
&& m_state != torrent_status::checking_files && ((m_state != torrent_status::checking_files
&& (m_state != torrent_status::queued_for_checking && m_state != torrent_status::checking_resume_data
&& m_state != torrent_status::queued_for_checking)
|| !valid_metadata()) || !valid_metadata())
&& m_policy.num_connect_candidates() > 0 && m_policy.num_connect_candidates() > 0
&& !m_abort; && !m_abort;
@ -3600,6 +3623,9 @@ namespace libtorrent
if (is_paused()) TORRENT_ASSERT(num_peers() == 0); if (is_paused()) TORRENT_ASSERT(num_peers() == 0);
if (!should_check_files())
TORRENT_ASSERT(m_state != torrent_status::checking_files);
if (!m_ses.m_queued_for_checking.empty()) if (!m_ses.m_queued_for_checking.empty())
{ {
// if there are torrents waiting to be checked // if there are torrents waiting to be checked
@ -3891,9 +3917,12 @@ namespace libtorrent
void torrent::clear_error() void torrent::clear_error()
{ {
if (m_error.empty()) return; if (m_error.empty()) return;
bool checking_files = should_check_files();
if (m_ses.m_auto_manage_time_scaler > 2) if (m_ses.m_auto_manage_time_scaler > 2)
m_ses.m_auto_manage_time_scaler = 2; m_ses.m_auto_manage_time_scaler = 2;
m_error.clear(); m_error.clear();
if (!checking_files && should_check_files())
m_ses.check_torrent(shared_from_this());
} }
void torrent::auto_managed(bool a) void torrent::auto_managed(bool a)
@ -3914,6 +3943,7 @@ namespace libtorrent
// stop checking // stop checking
m_storage->abort_disk_io(); m_storage->abort_disk_io();
m_ses.done_checking(shared_from_this()); m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
} }
} }
@ -3994,7 +4024,8 @@ namespace libtorrent
TORRENT_ASSERT(m_storage); TORRENT_ASSERT(m_storage);
if (m_state == torrent_status::queued_for_checking if (m_state == torrent_status::queued_for_checking
|| m_state == torrent_status::checking_files) || m_state == torrent_status::checking_files
|| m_state == torrent_status::checking_resume_data)
{ {
if (alerts().should_post<save_resume_data_failed_alert>()) if (alerts().should_post<save_resume_data_failed_alert>())
{ {
@ -4011,7 +4042,8 @@ namespace libtorrent
{ {
return (m_state == torrent_status::checking_files return (m_state == torrent_status::checking_files
|| m_state == torrent_status::queued_for_checking) || m_state == torrent_status::queued_for_checking)
&& (!is_paused() || m_auto_managed); && (!is_paused() || m_auto_managed)
&& m_error.empty();
} }
bool torrent::is_paused() const bool torrent::is_paused() const
@ -4033,6 +4065,7 @@ namespace libtorrent
// stop checking // stop checking
m_storage->abort_disk_io(); m_storage->abort_disk_io();
m_ses.done_checking(shared_from_this()); m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
} }
} }