introduced pop_alerts() which pops the entire alert queue in a single call
This commit is contained in:
parent
a18f047311
commit
27c1bc632d
|
@ -1,3 +1,4 @@
|
|||
* introduced pop_alerts() which pops the entire alert queue in a single call
|
||||
* support saving metadata in resume file, enable it by default for magnet links
|
||||
* support for receiving multi announce messages for local peer discovery
|
||||
* added session::listen_no_system_port flag to prevent libtorrent from ever binding the listen socket to port 0
|
||||
|
|
|
@ -1013,18 +1013,36 @@ Changes the mask of which alerts to receive. By default only errors are reported
|
|||
|
||||
See alerts_ for mor information on the alert categories.
|
||||
|
||||
pop_alert() wait_for_alert()
|
||||
----------------------------
|
||||
pop_alerts() pop_alert() wait_for_alert()
|
||||
-----------------------------------------
|
||||
|
||||
::
|
||||
|
||||
std::auto_ptr<alert> pop_alert();
|
||||
void pop_alerts(std::deque<alert*>* alerts);
|
||||
alert const* wait_for_alert(time_duration max_wait);
|
||||
|
||||
``pop_alert()`` is used to ask the session if any errors or events has occurred. With
|
||||
`set_alert_mask()`_ you can filter which alerts to receive through ``pop_alert()``.
|
||||
For information about the alert categories, see alerts_.
|
||||
|
||||
``pop_alerts()`` pops all pending alerts in a single call. In high performance environments
|
||||
with a very high alert churn rate, this can save significant amount of time compared to
|
||||
popping alerts one at a time. Each call requires one round-trip to the network thread. If
|
||||
alerts are produced in a higher rate than they can be popped (when popped one at a time)
|
||||
it's easy to get stuck in an infinite loop, trying to drain the alert queue. Popping the entire
|
||||
queue at once avoids this problem.
|
||||
|
||||
However, the ``pop_alerts`` function comes with significantly more responsibility. You pass
|
||||
in an *empty* ``std::dequeue<alert*>`` to it. If it's not empty, all elements in it will
|
||||
be deleted and then cleared. All currently pending alerts are returned by being swapped
|
||||
into the passed in container. The responsibility of deleting the alerts is transferred
|
||||
to the caller. This means you need to call delete for each item in the returned dequeue.
|
||||
It's probably a good idea to delete the alerts as you handle them, to save one extra
|
||||
pass over the dequeue.
|
||||
|
||||
Alternatively, you can pass in the same container the next time you call ``pop_alerts``.
|
||||
|
||||
``wait_for_alert`` blocks until an alert is available, or for no more than ``max_wait``
|
||||
time. If ``wait_for_alert`` returns because of the time-out, and no alerts are available,
|
||||
it returns 0. If at least one alert was generated, a pointer to that alert is returned.
|
||||
|
|
|
@ -1468,21 +1468,22 @@ int main(int argc, char* argv[])
|
|||
#endif
|
||||
|
||||
// loop through the alert queue to see if anything has happened.
|
||||
std::auto_ptr<alert> a;
|
||||
a = ses.pop_alert();
|
||||
std::deque<alert*> alerts;
|
||||
ses.pop_alerts(&alerts);
|
||||
std::string now = time_now_string();
|
||||
while (a.get())
|
||||
for (std::deque<alert*>::iterator i = alerts.begin()
|
||||
, end(alerts.end()); i != end; ++i)
|
||||
{
|
||||
std::string event_string;
|
||||
|
||||
::print_alert(a.get(), event_string);
|
||||
::handle_alert(ses, a.get(), files, non_files);
|
||||
::print_alert(*i, event_string);
|
||||
::handle_alert(ses, *i, files, non_files);
|
||||
|
||||
events.push_back(event_string);
|
||||
if (events.size() >= 20) events.pop_front();
|
||||
|
||||
a = ses.pop_alert();
|
||||
delete *i;
|
||||
}
|
||||
alerts.clear();
|
||||
|
||||
session_status sess_stat = ses.status();
|
||||
|
||||
|
@ -1967,46 +1968,48 @@ int main(int argc, char* argv[])
|
|||
alert const* a = ses.wait_for_alert(seconds(10));
|
||||
if (a == 0) continue;
|
||||
|
||||
std::auto_ptr<alert> holder = ses.pop_alert();
|
||||
std::deque<alert*> alerts;
|
||||
ses.pop_alerts(&alerts);
|
||||
std::string now = time_now_string();
|
||||
for (std::deque<alert*>::iterator i = alerts.begin()
|
||||
, end(alerts.end()); i != end; ++i)
|
||||
{
|
||||
// make sure to delete each alert
|
||||
std::auto_ptr<alert> a(*i);
|
||||
|
||||
torrent_paused_alert const* tp = alert_cast<torrent_paused_alert>(a);
|
||||
if (tp)
|
||||
{
|
||||
++num_paused;
|
||||
printf("\rleft: %d failed: %d pause: %d "
|
||||
, num_resume_data, num_failed, num_paused);
|
||||
continue;
|
||||
}
|
||||
torrent_paused_alert const* tp = alert_cast<torrent_paused_alert>(*i);
|
||||
if (tp)
|
||||
{
|
||||
++num_paused;
|
||||
printf("\rleft: %d failed: %d pause: %d "
|
||||
, num_resume_data, num_failed, num_paused);
|
||||
continue;
|
||||
}
|
||||
|
||||
save_resume_data_alert const* rd = alert_cast<save_resume_data_alert>(a);
|
||||
/* if (!rd)
|
||||
{
|
||||
std::string log;
|
||||
::print_alert(a, log);
|
||||
printf("\n%s\n", log.c_str());
|
||||
}
|
||||
*/
|
||||
if (alert_cast<save_resume_data_failed_alert>(a))
|
||||
{
|
||||
++num_failed;
|
||||
save_resume_data_alert const* rd = alert_cast<save_resume_data_alert>(*i);
|
||||
if (alert_cast<save_resume_data_failed_alert>(*i))
|
||||
{
|
||||
++num_failed;
|
||||
--num_resume_data;
|
||||
printf("\rleft: %d failed: %d pause: %d "
|
||||
, num_resume_data, num_failed, num_paused);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rd) continue;
|
||||
--num_resume_data;
|
||||
printf("\rleft: %d failed: %d pause: %d "
|
||||
, num_resume_data, num_failed, num_paused);
|
||||
continue;
|
||||
|
||||
if (!rd->resume_data) continue;
|
||||
|
||||
torrent_handle h = rd->handle;
|
||||
std::vector<char> out;
|
||||
bencode(std::back_inserter(out), *rd->resume_data);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + to_hex(h.info_hash().to_string()) + ".resume"), out);
|
||||
}
|
||||
|
||||
if (!rd) continue;
|
||||
--num_resume_data;
|
||||
printf("\rleft: %d failed: %d pause: %d "
|
||||
, num_resume_data, num_failed, num_paused);
|
||||
|
||||
if (!rd->resume_data) continue;
|
||||
|
||||
torrent_handle h = rd->handle;
|
||||
std::vector<char> out;
|
||||
bencode(std::back_inserter(out), *rd->resume_data);
|
||||
save_file(combine_path(h.save_path(), ".resume/" + to_hex(h.info_hash().to_string()) + ".resume"), out);
|
||||
}
|
||||
|
||||
if (g_log_file) fclose(g_log_file);
|
||||
printf("\nsaving session state\n");
|
||||
{
|
||||
|
|
|
@ -134,6 +134,7 @@ namespace libtorrent {
|
|||
void post_alert(const alert& alert_);
|
||||
bool pending() const;
|
||||
std::auto_ptr<alert> get();
|
||||
void get_all(std::deque<alert*>* alerts);
|
||||
|
||||
template <class T>
|
||||
bool should_post() const
|
||||
|
|
|
@ -285,6 +285,7 @@ namespace libtorrent
|
|||
void set_alert_mask(int m);
|
||||
size_t set_alert_queue_size_limit(size_t queue_size_limit_);
|
||||
std::auto_ptr<alert> pop_alert();
|
||||
void pop_alerts(std::deque<alert*>* alerts);
|
||||
void set_alert_dispatch(boost::function<void(std::auto_ptr<alert>)> const&);
|
||||
void post_alert(const alert& alert_);
|
||||
|
||||
|
|
|
@ -430,7 +430,20 @@ namespace libtorrent
|
|||
int max_uploads() const TORRENT_DEPRECATED;
|
||||
#endif
|
||||
|
||||
// pop one alert from the alert queue, or do nothing
|
||||
// and return a NULL pointer if there are no alerts
|
||||
// in the queue
|
||||
std::auto_ptr<alert> pop_alert();
|
||||
|
||||
// pop all alerts in the alert queue and returns them
|
||||
// in the supplied dequeue 'alerts'. The passed in
|
||||
// queue must be empty when passed in.
|
||||
// the responsibility of individual alerts returned
|
||||
// in the dequeue is passed on to the caller of this function.
|
||||
// when you're done with reacting to the alerts, you need to
|
||||
// delete them all.
|
||||
void pop_alerts(std::deque<alert*>* alerts);
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
TORRENT_DEPRECATED_PREFIX
|
||||
void set_severity_level(alert::severity_t s) TORRENT_DEPRECATED;
|
||||
|
|
|
@ -446,6 +446,13 @@ namespace libtorrent {
|
|||
return std::auto_ptr<alert>(result);
|
||||
}
|
||||
|
||||
void alert_manager::get_all(std::deque<alert*>* alerts)
|
||||
{
|
||||
mutex::scoped_lock lock(m_mutex);
|
||||
if (m_alerts.empty()) return;
|
||||
m_alerts.swap(*alerts);
|
||||
}
|
||||
|
||||
bool alert_manager::pending() const
|
||||
{
|
||||
mutex::scoped_lock lock(m_mutex);
|
||||
|
|
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -978,6 +979,15 @@ namespace libtorrent
|
|||
return m_impl->pop_alert();
|
||||
}
|
||||
|
||||
void session::pop_alerts(std::deque<alert*>* alerts)
|
||||
{
|
||||
for (std::deque<alert*>::iterator i = alerts->begin()
|
||||
, end(alerts->end()); i != end; ++i)
|
||||
delete *i;
|
||||
alerts->clear();
|
||||
m_impl->pop_alerts(alerts);
|
||||
}
|
||||
|
||||
alert const* session::wait_for_alert(time_duration max_wait)
|
||||
{
|
||||
return m_impl->wait_for_alert(max_wait);
|
||||
|
|
|
@ -4766,12 +4766,14 @@ namespace aux {
|
|||
|
||||
std::auto_ptr<alert> session_impl::pop_alert()
|
||||
{
|
||||
// too expensive
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
return m_alerts.get();
|
||||
}
|
||||
|
||||
void session_impl::pop_alerts(std::deque<alert*>* alerts)
|
||||
{
|
||||
m_alerts.get_all(alerts);
|
||||
}
|
||||
|
||||
alert const* session_impl::wait_for_alert(time_duration max_wait)
|
||||
{
|
||||
return m_alerts.wait_for_alert(max_wait);
|
||||
|
|
|
@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <deque>
|
||||
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
|
@ -80,24 +81,24 @@ bool print_alerts(libtorrent::session& ses, char const* name
|
|||
TEST_CHECK(!handles.empty() || allow_no_torrents);
|
||||
torrent_handle h;
|
||||
if (!handles.empty()) h = handles[0];
|
||||
std::auto_ptr<alert> a;
|
||||
a = ses.pop_alert();
|
||||
while (a.get())
|
||||
std::deque<alert*> alerts;
|
||||
ses.pop_alerts(&alerts);
|
||||
for (std::deque<alert*>::iterator i = alerts.begin(); i != alerts.end(); ++i)
|
||||
{
|
||||
if (predicate && predicate(a.get())) ret = true;
|
||||
if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(a.get()))
|
||||
if (predicate && predicate(*i)) ret = true;
|
||||
if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(*i))
|
||||
{
|
||||
fprintf(stderr, "%s(%s): %s\n", name, print_endpoint(p->ip).c_str(), p->message().c_str());
|
||||
}
|
||||
else if (a->message() != "block downloading"
|
||||
&& a->message() != "block finished"
|
||||
&& a->message() != "piece finished")
|
||||
else if ((*i)->message() != "block downloading"
|
||||
&& (*i)->message() != "block finished"
|
||||
&& (*i)->message() != "piece finished")
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", name, a->message().c_str());
|
||||
fprintf(stderr, "%s: %s\n", name, (*i)->message().c_str());
|
||||
}
|
||||
TEST_CHECK(alert_cast<fastresume_rejected_alert>(a.get()) == 0 || allow_failed_fastresume);
|
||||
TEST_CHECK(alert_cast<fastresume_rejected_alert>(*i) == 0 || allow_failed_fastresume);
|
||||
|
||||
peer_error_alert* pea = alert_cast<peer_error_alert>(a.get());
|
||||
peer_error_alert* pea = alert_cast<peer_error_alert>(*i);
|
||||
TEST_CHECK(pea == 0
|
||||
|| (!handles.empty() && h.status().is_seeding)
|
||||
|| pea->error.message() == "connecting to peer"
|
||||
|
@ -109,7 +110,7 @@ bool print_alerts(libtorrent::session& ses, char const* name
|
|||
|| (allow_disconnects && pea->error.message() == "Broken pipe")
|
||||
|| (allow_disconnects && pea->error.message() == "Connection reset by peer")
|
||||
|| (allow_disconnects && pea->error.message() == "End of file."));
|
||||
a = ses.pop_alert();
|
||||
delete *i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue