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
* rate limited DHT send socket
* tracker connections are now also subject to IP filtering

View File

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

View File

@ -2376,7 +2376,8 @@ It contains the following fields::
downloading,
finished,
seeding,
allocating
allocating,
checking_resume_data
};
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
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 |
| |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[] =
{"checking (q)", "checking", "dl metadata"
, "downloading", "finished", "seeding", "allocating"};
, "downloading", "finished", "seeding", "allocating", "checking (r)"};
int main(int ac, char* av[])
{

View File

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

View File

@ -1875,10 +1875,10 @@ namespace aux {
void session_impl::check_torrent(boost::shared_ptr<torrent> const& t)
{
if (m_abort) return;
TORRENT_ASSERT(!t->is_paused() || t->is_auto_managed());
TORRENT_ASSERT(t->state() == torrent_status::checking_files
|| t->state() == torrent_status::queued_for_checking);
TORRENT_ASSERT(t->should_check_files());
TORRENT_ASSERT(t->state() != torrent_status::checking_files);
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()
, m_queued_for_checking.end(), t) == m_queued_for_checking.end());
m_queued_for_checking.push_back(t);
@ -1900,17 +1900,21 @@ namespace aux {
void session_impl::done_checking(boost::shared_ptr<torrent> const& t)
{
INVARIANT_CHECK;
if (m_queued_for_checking.empty()) return;
check_queue_t::iterator next_check = m_queued_for_checking.begin();
check_queue_t::iterator done = m_queued_for_checking.end();
for (check_queue_t::iterator i = m_queued_for_checking.begin()
, end(m_queued_for_checking.end()); i != end; ++i)
{
TORRENT_ASSERT(*i == t || (*i)->should_check_files());
if (*i == t) done = i;
if (next_check == done || (*next_check)->queue_position() > (*i)->queue_position())
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);
}
@ -2631,6 +2635,13 @@ namespace aux {
#ifndef NDEBUG
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;
int total_downloaders = 0;
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_save_path(complete(save_path))
, m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking)
, m_state(torrent_status::checking_resume_data)
, m_settings(ses.settings())
, m_storage_constructor(sc)
, m_progress(0.f)
@ -250,7 +250,7 @@ namespace libtorrent
, m_net_interface(net_interface.address(), 0)
, m_save_path(complete(save_path))
, m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking)
, m_state(torrent_status::checking_resume_data)
, m_settings(ses.settings())
, m_storage_constructor(sc)
, m_progress(0.f)
@ -472,7 +472,7 @@ namespace libtorrent
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
, 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)
{
@ -552,6 +552,7 @@ namespace libtorrent
}
m_error = j.str;
pause();
set_state(torrent_status::queued_for_checking);
std::vector<char>().swap(m_resume_data);
lazy_entry().swap(m_resume_entry);
@ -680,7 +681,8 @@ namespace libtorrent
{
// either the fastresume data was rejected or there are
// 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());
}
@ -690,10 +692,21 @@ namespace libtorrent
void torrent::force_recheck()
{
if (m_state == torrent_status::checking_files
|| m_state == torrent_status::queued_for_checking)
// if the torrent is already queued to check its files
// don't do anything
if (should_check_files()
|| m_state == torrent_status::checking_resume_data)
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();
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));
// assume that we don't have anything
m_files_checked = false;
set_state(torrent_status::queued_for_checking);
set_state(torrent_status::checking_resume_data);
if (m_auto_managed)
set_queue_position((std::numeric_limits<int>::max)());
@ -744,6 +757,7 @@ namespace libtorrent
void torrent::start_checking()
{
TORRENT_ASSERT(should_check_files());
set_state(torrent_status::checking_files);
m_storage->async_check_files(bind(
@ -773,7 +787,11 @@ namespace libtorrent
}
m_error = j.str;
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;
}
@ -1636,7 +1654,10 @@ namespace libtorrent
}
if (m_state == torrent_status::checking_files)
{
m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
}
m_owning_storage = 0;
m_host_resolver.cancel();
@ -3065,7 +3086,8 @@ namespace libtorrent
m_has_incoming = true;
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())
{
p->disconnect("torrent is not ready to accept peers");
@ -3133,8 +3155,9 @@ namespace libtorrent
{
return int(m_connections.size()) < m_max_connections
&& !is_paused()
&& m_state != torrent_status::checking_files
&& (m_state != torrent_status::queued_for_checking
&& ((m_state != torrent_status::checking_files
&& m_state != torrent_status::checking_resume_data
&& m_state != torrent_status::queued_for_checking)
|| !valid_metadata())
&& m_policy.num_connect_candidates() > 0
&& !m_abort;
@ -3600,6 +3623,9 @@ namespace libtorrent
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 there are torrents waiting to be checked
@ -3891,9 +3917,12 @@ namespace libtorrent
void torrent::clear_error()
{
if (m_error.empty()) return;
bool checking_files = should_check_files();
if (m_ses.m_auto_manage_time_scaler > 2)
m_ses.m_auto_manage_time_scaler = 2;
m_error.clear();
if (!checking_files && should_check_files())
m_ses.check_torrent(shared_from_this());
}
void torrent::auto_managed(bool a)
@ -3914,6 +3943,7 @@ namespace libtorrent
// stop checking
m_storage->abort_disk_io();
m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
}
}
@ -3994,7 +4024,8 @@ namespace libtorrent
TORRENT_ASSERT(m_storage);
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>())
{
@ -4011,7 +4042,8 @@ namespace libtorrent
{
return (m_state == torrent_status::checking_files
|| 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
@ -4033,6 +4065,7 @@ namespace libtorrent
// stop checking
m_storage->abort_disk_io();
m_ses.done_checking(shared_from_this());
set_state(torrent_status::queued_for_checking);
}
}