Skip to content

Commit

Permalink
Merge pull request arvidn#299 from arvidn/fix-torrent-invariants
Browse files Browse the repository at this point in the history
torrent invariant failure
  • Loading branch information
arvidn committed Nov 28, 2015
2 parents 359fc56 + 2c3d7ee commit 578349e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 55 deletions.
3 changes: 1 addition & 2 deletions include/libtorrent/performance_counters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 9 additions & 1 deletion simulation/swarm_suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion simulation/swarm_suite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions simulation/test_swarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ TORRENT_TEST(explicit_cache)
simulate_swarm(suggest_read_cache | explicit_cache);
}

TORRENT_TEST(shutdown)
{
simulate_swarm(early_shutdown);
}

54 changes: 41 additions & 13 deletions src/session_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -2932,17 +2938,39 @@ namespace aux {
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;

// we have to keep ticking the utp socket manager
// 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
}

Expand Down Expand Up @@ -2980,12 +3008,6 @@ namespace aux {
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;
Expand Down Expand Up @@ -3604,6 +3626,8 @@ namespace aux {
t->log_to_all_peers("auto manager starting (inactive) torrent");
#endif
t->set_allow_peers(true);
t->update_gauge();
t->update_want_peers();
continue;
}

Expand All @@ -3620,6 +3644,8 @@ namespace aux {
t->log_to_all_peers("auto manager starting torrent");
#endif
t->set_allow_peers(true);
t->update_gauge();
t->update_want_peers();
continue;
}

Expand All @@ -3632,6 +3658,8 @@ namespace aux {
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();
}
}

Expand Down
78 changes: 40 additions & 38 deletions src/torrent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -9787,6 +9788,7 @@ namespace libtorrent
&& graceful == false)
{
m_graceful_pause_mode = graceful;
update_gauge();
do_pause();
}
return;
Expand Down

0 comments on commit 578349e

Please sign in to comment.