Merge pull request #299 from arvidn/fix-torrent-invariants
torrent invariant failure
This commit is contained in:
commit
578349e1d2
|
@ -319,8 +319,7 @@ namespace libtorrent
|
|||
{
|
||||
num_checking_torrents = num_stats_counters,
|
||||
num_stopped_torrents,
|
||||
// upload_only means finished
|
||||
num_upload_only_torrents,
|
||||
num_upload_only_torrents, // upload_only means finished
|
||||
num_downloading_torrents,
|
||||
num_seeding_torrents,
|
||||
num_queued_seeding_torrents,
|
||||
|
|
|
@ -53,9 +53,17 @@ struct test_swarm_config : swarm_config
|
|||
, m_resumed_once(false)
|
||||
{}
|
||||
|
||||
virtual bool tick(int t) override
|
||||
{
|
||||
return (m_flags & early_shutdown) ? t >= 1 : t > 200;
|
||||
}
|
||||
|
||||
virtual void on_exit(std::vector<torrent_handle> const& torrents) override
|
||||
{
|
||||
swarm_config::on_exit(torrents);
|
||||
if ((m_flags & early_shutdown) == 0)
|
||||
{
|
||||
swarm_config::on_exit(torrents);
|
||||
}
|
||||
|
||||
// if we stopped and started again, we loose some time and need a bit
|
||||
// more slack for completion
|
||||
|
|
|
@ -44,7 +44,8 @@ enum test_flags_t
|
|||
stop_start_download = 128,
|
||||
stop_start_seed = 256,
|
||||
graceful_pause = 1024,
|
||||
add_extra_peers = 2048
|
||||
add_extra_peers = 2048,
|
||||
early_shutdown = 4096
|
||||
};
|
||||
|
||||
void EXPORT simulate_swarm(int flags = 0);
|
||||
|
|
|
@ -80,3 +80,8 @@ TORRENT_TEST(explicit_cache)
|
|||
simulate_swarm(suggest_read_cache | explicit_cache);
|
||||
}
|
||||
|
||||
TORRENT_TEST(shutdown)
|
||||
{
|
||||
simulate_swarm(early_shutdown);
|
||||
}
|
||||
|
||||
|
|
|
@ -1123,11 +1123,17 @@ namespace aux {
|
|||
m_ssl_udp_socket.close();
|
||||
#endif
|
||||
|
||||
m_undead_peers.clear();
|
||||
|
||||
// give all the sockets an opportunity to actually have their handlers
|
||||
// called and cancelled before we continue the shutdown
|
||||
m_io_service.post(boost::bind(&session_impl::abort_stage2, this));
|
||||
// we need to give all the sockets an opportunity to actually have their handlers
|
||||
// called and cancelled before we continue the shutdown. This is a bit
|
||||
// complicated, if there are no "undead" peers, it's safe tor resume the
|
||||
// shutdown, but if there are, we have to wait for them to be cleared out
|
||||
// first. In session_impl::on_tick() we check them periodically. If we're
|
||||
// shutting down and we remove the last one, we'll initiate
|
||||
// shutdown_stage2 from there.
|
||||
if (m_undead_peers.empty())
|
||||
{
|
||||
m_io_service.post(boost::bind(&session_impl::abort_stage2, this));
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::abort_stage2()
|
||||
|
@ -2932,6 +2938,25 @@ retry:
|
|||
aux::update_time_now();
|
||||
time_point now = aux::time_now();
|
||||
|
||||
// remove undead peers that only have this list as their reference keeping them alive
|
||||
if (!m_undead_peers.empty())
|
||||
{
|
||||
std::vector<boost::shared_ptr<peer_connection> >::iterator remove_it
|
||||
= std::remove_if(m_undead_peers.begin(), m_undead_peers.end()
|
||||
, boost::bind(&boost::shared_ptr<peer_connection>::unique, _1));
|
||||
m_undead_peers.erase(remove_it, m_undead_peers.end());
|
||||
if (m_undead_peers.empty())
|
||||
{
|
||||
// we just removed our last "undead" peer (i.e. a peer connection
|
||||
// that had some external reference to it). It's now safe to
|
||||
// shut-down
|
||||
if (m_abort)
|
||||
{
|
||||
m_io_service.post(boost::bind(&session_impl::abort_stage2, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// too expensive
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
|
@ -2939,10 +2964,13 @@ retry:
|
|||
// until they're all closed
|
||||
if (m_abort)
|
||||
{
|
||||
if (m_utp_socket_manager.num_sockets() == 0)
|
||||
if (m_utp_socket_manager.num_sockets() == 0
|
||||
&& m_undead_peers.empty())
|
||||
return;
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
fprintf(stderr, "uTP sockets left: %d\n", m_utp_socket_manager.num_sockets());
|
||||
fprintf(stderr, "uTP sockets left: %d undead-peers left: %d\n"
|
||||
, m_utp_socket_manager.num_sockets()
|
||||
, int(m_undead_peers.size()));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2980,12 +3008,6 @@ retry:
|
|||
update_dht_announce_interval();
|
||||
#endif
|
||||
|
||||
// remove undead peers that only have this list as their reference keeping them alive
|
||||
std::vector<boost::shared_ptr<peer_connection> >::iterator remove_it
|
||||
= std::remove_if(m_undead_peers.begin(), m_undead_peers.end()
|
||||
, boost::bind(&boost::shared_ptr<peer_connection>::unique, _1));
|
||||
m_undead_peers.erase(remove_it, m_undead_peers.end());
|
||||
|
||||
int tick_interval_ms = int(total_milliseconds(now - m_last_second_tick));
|
||||
m_last_second_tick = now;
|
||||
m_tick_residual += tick_interval_ms - 1000;
|
||||
|
@ -3604,6 +3626,8 @@ retry:
|
|||
t->log_to_all_peers("auto manager starting (inactive) torrent");
|
||||
#endif
|
||||
t->set_allow_peers(true);
|
||||
t->update_gauge();
|
||||
t->update_want_peers();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3620,6 +3644,8 @@ retry:
|
|||
t->log_to_all_peers("auto manager starting torrent");
|
||||
#endif
|
||||
t->set_allow_peers(true);
|
||||
t->update_gauge();
|
||||
t->update_want_peers();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3632,6 +3658,8 @@ retry:
|
|||
t->set_announce_to_dht(false);
|
||||
t->set_announce_to_trackers(false);
|
||||
t->set_announce_to_lsd(false);
|
||||
t->update_gauge();
|
||||
t->update_want_peers();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -516,44 +516,6 @@ namespace libtorrent
|
|||
}
|
||||
#else // if 0
|
||||
|
||||
int torrent::current_stats_state() const
|
||||
{
|
||||
if (m_abort) return counters::num_checking_torrents + no_gauge_state;
|
||||
|
||||
if (has_error()) return counters::num_error_torrents;
|
||||
if (!m_allow_peers || m_graceful_pause_mode)
|
||||
{
|
||||
if (!is_auto_managed()) return counters::num_stopped_torrents;
|
||||
if (is_seed()) return counters::num_queued_seeding_torrents;
|
||||
return counters::num_queued_download_torrents;
|
||||
}
|
||||
if (state() == torrent_status::checking_files
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
|| state() == torrent_status::queued_for_checking
|
||||
#endif
|
||||
)
|
||||
return counters::num_checking_torrents;
|
||||
else if (is_seed()) return counters::num_seeding_torrents;
|
||||
else if (is_upload_only()) return counters::num_upload_only_torrents;
|
||||
return counters::num_downloading_torrents;
|
||||
}
|
||||
|
||||
void torrent::update_gauge()
|
||||
{
|
||||
int new_gauge_state = current_stats_state() - counters::num_checking_torrents;
|
||||
TORRENT_ASSERT(new_gauge_state >= 0);
|
||||
TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
|
||||
|
||||
if (new_gauge_state == m_current_gauge_state) return;
|
||||
|
||||
if (m_current_gauge_state != no_gauge_state)
|
||||
inc_stats_counter(m_current_gauge_state + counters::num_checking_torrents, -1);
|
||||
if (new_gauge_state != no_gauge_state)
|
||||
inc_stats_counter(new_gauge_state + counters::num_checking_torrents, 1);
|
||||
|
||||
m_current_gauge_state = new_gauge_state;
|
||||
}
|
||||
|
||||
void torrent::on_torrent_download(error_code const& ec
|
||||
, http_parser const& parser, char const* data, int size)
|
||||
{
|
||||
|
@ -663,6 +625,45 @@ namespace libtorrent
|
|||
|
||||
#endif // if 0
|
||||
|
||||
int torrent::current_stats_state() const
|
||||
{
|
||||
if (m_abort) return counters::num_checking_torrents + no_gauge_state;
|
||||
|
||||
if (has_error()) return counters::num_error_torrents;
|
||||
if (!m_allow_peers || m_graceful_pause_mode)
|
||||
{
|
||||
if (!is_auto_managed()) return counters::num_stopped_torrents;
|
||||
if (is_seed()) return counters::num_queued_seeding_torrents;
|
||||
return counters::num_queued_download_torrents;
|
||||
}
|
||||
if (state() == torrent_status::checking_files
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
|| state() == torrent_status::queued_for_checking
|
||||
#endif
|
||||
)
|
||||
return counters::num_checking_torrents;
|
||||
else if (is_seed()) return counters::num_seeding_torrents;
|
||||
else if (is_upload_only()) return counters::num_upload_only_torrents;
|
||||
return counters::num_downloading_torrents;
|
||||
}
|
||||
|
||||
void torrent::update_gauge()
|
||||
{
|
||||
int new_gauge_state = current_stats_state() - counters::num_checking_torrents;
|
||||
TORRENT_ASSERT(new_gauge_state >= 0);
|
||||
TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
|
||||
|
||||
if (new_gauge_state == m_current_gauge_state) return;
|
||||
|
||||
if (m_current_gauge_state != no_gauge_state)
|
||||
inc_stats_counter(m_current_gauge_state + counters::num_checking_torrents, -1);
|
||||
if (new_gauge_state != no_gauge_state)
|
||||
inc_stats_counter(new_gauge_state + counters::num_checking_torrents, 1);
|
||||
|
||||
m_current_gauge_state = new_gauge_state;
|
||||
}
|
||||
|
||||
|
||||
void torrent::leave_seed_mode(bool skip_checking)
|
||||
{
|
||||
if (!m_seed_mode) return;
|
||||
|
@ -9787,6 +9788,7 @@ namespace libtorrent
|
|||
&& graceful == false)
|
||||
{
|
||||
m_graceful_pause_mode = graceful;
|
||||
update_gauge();
|
||||
do_pause();
|
||||
}
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue