introduced a more scalable API for torrent status updates (post_torrent_updates())

This commit is contained in:
Arvid Norberg 2011-11-15 02:34:00 +00:00
parent b0271e993c
commit c4232065d8
14 changed files with 260 additions and 46 deletions

View File

@ -1,3 +1,4 @@
* introduced a more scalable API for torrent status updates (post_torrent_updates())
* 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

@ -394,7 +394,8 @@ async_add_torrent() add_torrent()
flag_paused = 0x020,
flag_auto_managed = 0x040.
flag_duplicate_is_error = 0x080,
flag_merge_resume_trackers = 0x100
flag_merge_resume_trackers = 0x100,
flag_update_subscribe = 0x200
};
int version;
@ -524,7 +525,8 @@ and how it's added. These are the flags::
flag_paused = 0x020,
flag_auto_managed = 0x040.
flag_duplicate_is_error = 0x080,
flag_merge_resume_trackers = 0x100
flag_merge_resume_trackers = 0x100,
flag_update_subscribe = 0x200
}
``flag_apply_ip_filter`` determines if the IP filter should apply to this torrent or not. By
@ -535,6 +537,9 @@ an auto-update torrent for instance.
``flag_merge_resume_trackers`` defaults to off and specifies whether tracker URLs loaded from
resume data should be added to the trackers in the torrent or replace the trackers.
``flag_update_subscribe`` is on by default and means that this torrent will be part of state
updates when calling `post_torrent_updates()`_.
``flag_paused`` specifies whether or not the torrent is to be started in a paused
state. I.e. it won't connect to the tracker or any of the peers until it's
resumed. This is typically a good way of avoiding race conditions when setting
@ -637,6 +642,11 @@ get_torrent_status() refresh_torrent_status()
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags = 0) const;
.. note::
these calls are potentially expensive and won't scale well
with lots of torrents. If you're concerned about performance, consider
using ``post_torrent_updates()`` instead.
``get_torrent_status`` returns a vector of the ``torrent_status`` for every
torrent which satisfies ``pred``, which is a predicate function which determines
if a torrent should be included in the returned set or not. Returning true means
@ -656,6 +666,21 @@ if you have a lot of torrents.
Any ``torrent_status`` object whose ``handle`` member is not referring to a
valid torrent are ignored.
post_torrent_updates()
----------------------
::
void post_torrent_updates();
This functions instructs the session to post the state_update_alert_, containing
the status of all torrents whose state changed since the last time this function
was called.
Only torrents who has the state subscription flag set will be included. This flag
is on by default. See ``add_torrent_params`` under `async_add_torrent() add_torrent()`_.
load_asnum_db() load_country_db() as_for_ip()
---------------------------------------------
@ -7430,6 +7455,28 @@ as:
``ip`` is the IP address and port the connection came from.
state_update_alert
------------------
This alert is only posted when requested by the user, by calling `post_torrent_updates()`_
on the session. It contains the torrent status of all torrents that changed
since last time this message was posted. Its category is ``status_notification``, but
it's not subject to filtering, since it's only manually posted anyway.
::
struct state_update_alert: alert
{
// ...
std::vector<torrent_status> status;
};
``status`` contains the torrent status of all torrents that changed since last time
this message was posted. Note that you can map a torrent status to a specific torrent
via its ``handle`` member. The receiving end is suggested to have all torrents sorted
by the ``torrent_handle`` or hashed by it, for efficient updates.
alert dispatcher
================

View File

@ -57,7 +57,7 @@ namespace libtorrent
, userdata(0)
, file_priorities(0)
#ifndef TORRENT_NO_DEPRECATE
, flags(flag_ignore_flags)
, flags(flag_ignore_flags | default_flags)
, seed_mode(false)
, override_resume_data(false)
, upload_mode(false)
@ -68,26 +68,30 @@ namespace libtorrent
, duplicate_is_error(false)
, merge_resume_trackers(false)
#else
, flags(flag_apply_ip_filter | flag_paused | flag_auto_managed)
, flags(default_flags)
#endif
{
#ifndef TORRENT_NO_DEPRECATE
if (flags == flag_ignore_flags)
{
flags = 0;
if (seed_mode) flags |= flag_seed_mode;
if (override_resume_data) flags |= flag_override_resume_data;
if (upload_mode) flags |= flag_upload_mode;
if (share_mode) flags |= flag_share_mode;
if (apply_ip_filter) flags |= flag_apply_ip_filter;
if (paused) flags |= flag_paused;
if (auto_managed) flags |= flag_auto_managed;
if (duplicate_is_error) flags |= flag_duplicate_is_error;
if (merge_resume_trackers) flags |= flag_merge_resume_trackers;
}
#endif
}
#ifndef TORRENT_NO_DEPRECATE
void update_flags() const
{
if (flags != (flag_ignore_flags | default_flags)) return;
boost::uint64_t& f = const_cast<boost::uint64_t&>(flags);
f = flag_update_subscribe;
if (seed_mode) f |= flag_seed_mode;
if (override_resume_data) f |= flag_override_resume_data;
if (upload_mode) f |= flag_upload_mode;
if (share_mode) f |= flag_share_mode;
if (apply_ip_filter) f |= flag_apply_ip_filter;
if (paused) f |= flag_paused;
if (auto_managed) f |= flag_auto_managed;
if (duplicate_is_error) f |= flag_duplicate_is_error;
if (merge_resume_trackers) f |= flag_merge_resume_trackers;
}
#endif
enum flags_t
{
flag_seed_mode = 0x001,
@ -98,8 +102,10 @@ namespace libtorrent
flag_paused = 0x020,
flag_auto_managed = 0x040,
flag_duplicate_is_error = 0x080,
flag_merge_resume_trackers = 0x100
flag_merge_resume_trackers = 0x100,
flag_update_subscribe = 0x200,
default_flags = flag_update_subscribe | flag_auto_managed | flag_paused | flag_apply_ip_filter
#ifndef TORRENT_NO_DEPRECATE
, flag_ignore_flags = 0x80000000
#endif

View File

@ -133,6 +133,7 @@ namespace libtorrent {
~alert_manager();
void post_alert(const alert& alert_);
void post_alert_ptr(alert* alert_);
bool pending() const;
std::auto_ptr<alert> get();
void get_all(std::deque<alert*>* alerts);
@ -165,6 +166,8 @@ namespace libtorrent {
#endif
private:
void post_impl(std::auto_ptr<alert>& alert_);
std::deque<alert*> m_alerts;
mutable mutex m_mutex;
// event m_condition;

View File

@ -1312,6 +1312,16 @@ namespace libtorrent
error_code error;
};
struct TORRENT_EXPORT state_update_alert : alert
{
TORRENT_DEFINE_ALERT(state_update_alert);
const static int static_category = alert::status_notification;
virtual std::string message() const;
virtual bool discardable() const { return false; }
std::vector<torrent_status> status;
};
}

View File

@ -326,6 +326,7 @@ namespace libtorrent
, boost::uint32_t flags) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags) const;
void post_torrent_updates();
std::vector<torrent_handle> get_torrents() const;
@ -1062,6 +1063,10 @@ namespace libtorrent
std::vector<boost::shared_ptr<feed> > m_feeds;
// this is the set of (subscribed) torrents that have changed
// their states since the last time the user requested updates.
std::vector<boost::weak_ptr<torrent> > m_state_updates;
// the main working thread
boost::scoped_ptr<thread> m_thread;

View File

@ -184,6 +184,7 @@ namespace libtorrent
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags = 0) const;
void post_torrent_updates();
// returns a list of all torrents in this session
std::vector<torrent_handle> get_torrents() const;

View File

@ -304,6 +304,10 @@ namespace libtorrent
void status(torrent_status* st, boost::uint32_t flags);
// this torrent changed state, if the user is subscribing to
// it, add it to the m_state_updates list in session_impl
void state_updated();
void file_progress(std::vector<size_type>& fp, int flags = 0) const;
void use_interface(std::string net_interface);
@ -325,6 +329,7 @@ namespace libtorrent
if (prio > 255) prio = 255;
else if (prio < 0) prio = 0;
m_priority = prio;
state_updated();
}
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
@ -839,6 +844,9 @@ namespace libtorrent
void queue_torrent_check();
void dequeue_torrent_check();
void clear_in_state_update()
{ m_in_state_updates = false; }
#ifdef TORRENT_USE_OPENSSL
void set_ssl_cert(std::string const& certificate
, std::string const& private_key
@ -1322,7 +1330,7 @@ namespace libtorrent
// these are the flags sent in on a call to save_resume_data
// we need to save them to check them in write_resume_data
boost::uint8_t m_save_resume_flags;
boost::uint8_t m_save_resume_flags;
// set to true when this torrent has been paused but
// is waiting to finish all current download requests
@ -1359,6 +1367,16 @@ namespace libtorrent
// paused it's removed and when it's started again, it's
// re-added
bool m_in_encrypted_list:1;
// state subscription. If set, a pointer to this torrent
// will be added to the m_state_updates set in session_impl
// whenever this torrent's state changes (any state).
bool m_state_subscription:1;
// in state_updates list. When adding a torrent to the
// session_impl's m_state_update list, this bit is set
// to never add the same torrent twice
bool m_in_state_updates:1;
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
public:

View File

@ -403,22 +403,20 @@ namespace libtorrent {
dispatcher(*alert_);
}
void alert_manager::post_alert(const alert& alert_)
void alert_manager::post_alert_ptr(alert* alert_)
{
std::auto_ptr<alert> a(alert_);
mutex::scoped_lock lock(m_mutex);
if (m_dispatch)
{
TORRENT_ASSERT(m_alerts.empty());
TORRENT_TRY {
m_dispatch(std::auto_ptr<alert>(alert_.clone()));
} TORRENT_CATCH(std::exception&) {}
}
else if (m_alerts.size() < m_queue_size_limit || !alert_.discardable())
{
m_alerts.push_back(alert_.clone().release());
}
post_impl(a);
}
void alert_manager::post_alert(const alert& alert_)
{
std::auto_ptr<alert> a(alert_.clone());
mutex::scoped_lock lock(m_mutex);
post_impl(a);
#ifndef TORRENT_DISABLE_EXTENSIONS
lock.unlock();
@ -433,6 +431,21 @@ namespace libtorrent {
#endif
}
void alert_manager::post_impl(std::auto_ptr<alert>& alert_)
{
if (m_dispatch)
{
TORRENT_ASSERT(m_alerts.empty());
TORRENT_TRY {
m_dispatch(alert_);
} TORRENT_CATCH(std::exception&) {}
}
else if (m_alerts.size() < m_queue_size_limit || !alert_->discardable())
{
m_alerts.push_back(alert_.release());
}
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void alert_manager::add_extension(boost::shared_ptr<plugin> ext)
@ -601,5 +614,12 @@ namespace libtorrent {
return msg;
}
std::string state_update_alert::message() const
{
char msg[600];
snprintf(msg, sizeof(msg), "state updates for %d torrents", int(status.size()));
return msg;
}
} // namespace libtorrent

View File

@ -2139,11 +2139,15 @@ namespace libtorrent
TORRENT_ASSERT(m_outstanding_bytes >= bytes);
m_outstanding_bytes -= bytes;
if (m_outstanding_bytes < 0) m_outstanding_bytes = 0;
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
boost::shared_ptr<torrent> t = associated_torrent().lock();
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
TORRENT_ASSERT(m_received_in_piece + bytes <= t->block_size());
m_received_in_piece += bytes;
#endif
// progress of this torrent increased
t->state_updated();
#if !defined TORRENT_DISABLE_INVARIANT_CHECKS && defined TORRENT_DEBUG
check_invariant();
#endif

View File

@ -939,6 +939,7 @@ namespace libtorrent
// this cannot be a connect candidate anymore, since i->connection is set
TORRENT_ASSERT(!is_connect_candidate(*i, m_finished));
TORRENT_ASSERT(has_connection(&c));
m_torrent->state_updated();
return true;
}
@ -1091,6 +1092,8 @@ namespace libtorrent
if (is_connect_candidate(*p, m_finished))
++m_num_connect_candidates;
m_torrent->state_updated();
return true;
}
@ -1195,6 +1198,7 @@ namespace libtorrent
p = *iter;
update_peer(p, src, flags, tcp::endpoint(), destination);
}
m_torrent->state_updated();
return p;
}
#endif // TORRENT_USE_I2P

View File

@ -567,6 +567,11 @@ namespace libtorrent
TORRENT_SYNC_CALL2(refresh_torrent_status, ret, flags);
}
void session::post_torrent_updates()
{
TORRENT_ASYNC_CALL(post_torrent_updates);
}
std::vector<torrent_handle> session::get_torrents() const
{
TORRENT_SYNC_CALL_RET(std::vector<torrent_handle>, get_torrents);

View File

@ -4342,6 +4342,25 @@ namespace aux {
t->status(&*i, flags);
}
}
void session_impl::post_torrent_updates()
{
std::auto_ptr<state_update_alert> alert(new state_update_alert());
alert->status.reserve(m_state_updates.size());
for (std::vector<boost::weak_ptr<torrent> >::iterator i = m_state_updates.begin()
, end(m_state_updates.end()); i != end; ++i)
{
boost::shared_ptr<torrent> t = i->lock();
if (!t) continue;
alert->status.push_back(torrent_status());
t->clear_in_state_update();
t->status(&alert->status.back(), 0xffffffff);
}
m_state_updates.clear();
m_alerts.post_alert_ptr(alert.release());
}
std::vector<torrent_handle> session_impl::get_torrents() const
{
@ -4378,6 +4397,10 @@ namespace aux {
{
TORRENT_ASSERT(!params.save_path.empty());
#ifndef TORRENT_NO_DEPRECATE
params.update_flags();
#endif
if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0)
{
ec = errors::no_files_in_torrent;

View File

@ -427,6 +427,8 @@ namespace libtorrent
, m_apply_ip_filter(p.flags & add_torrent_params::flag_apply_ip_filter)
, m_merge_resume_trackers(p.flags & add_torrent_params::flag_merge_resume_trackers)
, m_in_encrypted_list(false)
, m_state_subscription(p.flags & add_torrent_params::flag_update_subscribe)
, m_in_state_updates(false)
{
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
m_resume_data_loaded = false;
@ -700,6 +702,8 @@ namespace libtorrent
get_handle()));
}
state_updated();
set_state(torrent_status::downloading);
m_override_resume_data = true;
@ -855,6 +859,7 @@ namespace libtorrent
}
m_apply_ip_filter = b;
m_policy.ip_filter_updated();
state_updated();
}
#ifndef TORRENT_DISABLE_DHT
@ -1001,6 +1006,7 @@ namespace libtorrent
m_upload_mode = b;
state_updated();
send_upload_only();
if (m_upload_mode)
@ -2471,16 +2477,21 @@ ctx->set_verify_callback(verify_function, ec);
INVARIANT_CHECK;
TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
if (complete >= 0) m_complete = complete;
if (incomplete >= 0) m_incomplete = incomplete;
if (downloaders >= 0) m_downloaders = downloaders;
if (m_ses.m_alerts.should_post<scrape_reply_alert>())
{
m_ses.m_alerts.post_alert(scrape_reply_alert(
get_handle(), m_incomplete, m_complete, req.url));
}
}
if ((complete >= 0 && m_complete != complete)
|| (incomplete >= 0 && m_incomplete != incomplete)
|| (downloaders >= 0 && m_downloaders != downloaders))
state_updated();
if (complete >= 0) m_complete = complete;
if (incomplete >= 0) m_incomplete = incomplete;
if (downloaders >= 0) m_downloaders = downloaders;
if (m_ses.m_alerts.should_post<scrape_reply_alert>())
{
m_ses.m_alerts.post_alert(scrape_reply_alert(
get_handle(), m_incomplete, m_complete, req.url));
}
}
void torrent::tracker_response(
tracker_request const& r
@ -2673,6 +2684,8 @@ ctx->set_verify_callback(verify_function, ec);
++m_ses.m_boost_connections;
}
}
state_updated();
}
ptime torrent::next_announce() const
@ -3061,6 +3074,8 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(!m_picker->have_piece(index));
state_updated();
// even though the piece passed the hash-check
// it might still have failed being written to disk
// if so, piece_picker::write_failed() has been
@ -3176,6 +3191,7 @@ ctx->set_verify_callback(verify_function, ec);
, index));
}
state_updated();
m_need_save_resume_data = true;
remove_time_critical_piece(index, true);
@ -3593,6 +3609,7 @@ ctx->set_verify_callback(verify_function, ec);
write_resume_data(*j.resume_data);
alerts().post_alert(save_resume_data_alert(j.resume_data
, get_handle()));
state_updated();
}
}
@ -3828,6 +3845,8 @@ ctx->set_verify_callback(verify_function, ec);
update_peer_interest(was_finished);
remove_time_critical_pieces(pieces);
}
state_updated();
}
void torrent::piece_priorities(std::vector<int>* pieces) const
@ -4178,6 +4197,7 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_num_uploads > 0);
if (!c.send_choke()) return false;
--m_num_uploads;
state_updated();
return true;
}
@ -4194,6 +4214,7 @@ ctx->set_verify_callback(verify_function, ec);
if (m_num_uploads >= m_max_uploads && !optimistic) return false;
if (!c.send_unchoke()) return false;
++m_num_uploads;
state_updated();
return true;
}
@ -5288,7 +5309,6 @@ ctx->set_verify_callback(verify_function, ec);
file_priority.clear();
for (int i = 0, end(m_file_priority.size()); i < end; ++i)
file_priority.push_back(m_file_priority[i]);
}
void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
@ -5846,6 +5866,8 @@ ctx->set_verify_callback(verify_function, ec);
send_upload_only();
state_updated();
m_completed_time = time(0);
// disconnect all seeds
@ -6294,7 +6316,10 @@ ctx->set_verify_callback(verify_function, ec);
void torrent::set_sequential_download(bool sd)
{
TORRENT_ASSERT(m_ses.is_network_thread());
if (m_sequential_download == sd) return;
m_sequential_download = sd;
state_updated();
}
void torrent::queue_up()
@ -6317,6 +6342,8 @@ ctx->set_verify_callback(verify_function, ec);
if (is_finished() && p != -1) return;
if (p == m_sequence_number) return;
state_updated();
session_impl::torrent_map& torrents = m_ses.m_torrents;
if (p >= 0 && m_sequence_number == -1)
{
@ -6386,6 +6413,7 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_ses.is_network_thread());
TORRENT_ASSERT(limit >= -1);
if (limit <= 0) limit = (std::numeric_limits<int>::max)();
if (m_max_uploads != limit) state_updated();
m_max_uploads = limit;
}
@ -6394,6 +6422,7 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_ses.is_network_thread());
TORRENT_ASSERT(limit >= -1);
if (limit <= 0) limit = (std::numeric_limits<int>::max)();
if (m_max_connections != limit) state_updated();
m_max_connections = limit;
if (num_peers() > int(m_max_connections))
@ -6446,6 +6475,8 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_ses.is_network_thread());
TORRENT_ASSERT(limit >= -1);
if (limit <= 0) limit = 0;
if (m_bandwidth_channel[peer_connection::upload_channel].throttle() != limit)
state_updated();
m_bandwidth_channel[peer_connection::upload_channel].throttle(limit);
}
@ -6462,6 +6493,8 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_ses.is_network_thread());
TORRENT_ASSERT(limit >= -1);
if (limit <= 0) limit = 0;
if (m_bandwidth_channel[peer_connection::download_channel].throttle() != limit)
state_updated();
m_bandwidth_channel[peer_connection::download_channel].throttle(limit);
}
@ -6502,6 +6535,8 @@ ctx->set_verify_callback(verify_function, ec);
m_error = error_code();
m_error_file.clear();
state_updated();
// if we haven't downloaded the metadata from m_url, try again
if (!m_url.empty() && !m_torrent_file->is_valid())
{
@ -6541,6 +6576,8 @@ ctx->set_verify_callback(verify_function, ec);
dequeue_torrent_check();
set_state(torrent_status::queued_for_checking);
}
state_updated();
}
void torrent::auto_managed(bool a)
@ -6552,6 +6589,8 @@ ctx->set_verify_callback(verify_function, ec);
bool checking_files = should_check_files();
m_auto_managed = a;
state_updated();
// we need to save this new state as well
m_need_save_resume_data = true;
@ -6665,6 +6704,7 @@ ctx->set_verify_callback(verify_function, ec);
m_need_save_resume_data = false;
m_last_saved_resume = time(0);
m_save_resume_flags = boost::uint8_t(flags);
state_updated();
TORRENT_ASSERT(m_storage);
if (m_state == torrent_status::queued_for_checking
@ -6734,6 +6774,7 @@ ctx->set_verify_callback(verify_function, ec);
// we need to save this new state
m_need_save_resume_data = true;
state_updated();
bool prev_graceful = m_graceful_pause_mode;
m_graceful_pause_mode = graceful;
@ -6765,6 +6806,8 @@ ctx->set_verify_callback(verify_function, ec);
}
#endif
state_updated();
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
log_to_all_peers("PAUSING TORRENT");
#endif
@ -6926,6 +6969,8 @@ ctx->set_verify_callback(verify_function, ec);
if (alerts().should_post<torrent_resumed_alert>())
alerts().post_alert(torrent_resumed_alert(get_handle()));
state_updated();
m_started = time_now();
clear_error();
start_announcing();
@ -7155,6 +7200,9 @@ ctx->set_verify_callback(verify_function, ec);
// let the stats fade out to 0
accumulator += m_stat;
m_stat.second_tick(tick_interval_ms);
// if the rate is 0, there's no update because of network transfers
if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0)
state_updated();
return;
}
@ -7250,6 +7298,10 @@ ctx->set_verify_callback(verify_function, ec);
m_total_uploaded += m_stat.last_payload_uploaded();
m_total_downloaded += m_stat.last_payload_downloaded();
m_stat.second_tick(tick_interval_ms);
// if the rate is 0, there's no update because of network transfers
if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0)
state_updated();
}
void torrent::recalc_share_mode()
@ -7697,6 +7749,8 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_ses.is_network_thread());
peer_id id(0);
m_policy.add_peer(adr, id, source, 0);
state_updated();
}
void torrent::async_verify_piece(int piece_index, boost::function<void(int)> const& f)
@ -7944,6 +7998,8 @@ ctx->set_verify_callback(verify_function, ec);
m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s, (torrent_status::state_t)m_state));
m_state = s;
state_updated();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
@ -7969,6 +8025,17 @@ ctx->set_verify_callback(verify_function, ec);
}
#endif
void torrent::state_updated()
{
// we're either not subscribing to this torrent, or
// it has already been updated this round, no need to
// add it to the list twice
if (!m_state_subscription || m_in_state_updates) return;
m_ses.m_state_updates.push_back(shared_from_this());
m_in_state_updates = true;
}
void torrent::status(torrent_status* st, boost::uint32_t flags)
{
INVARIANT_CHECK;