add API to query whether alerts have been dropped or not

This commit is contained in:
arvidn 2017-11-10 22:50:31 +01:00 committed by Arvid Norberg
parent 254f813626
commit 1c278cc697
9 changed files with 86 additions and 16 deletions

View File

@ -1,3 +1,4 @@
* add API to query whether alerts have been dropped or not
* add flags()/set_flags()/unset_flags() to torrent_handle, deprecate individual functions
* added alert for block being sent to the send buffer
* drop support for windows compilers without std::wstring

View File

@ -228,11 +228,11 @@ namespace libtorrent {
// }
// }
// }
virtual int type() const = 0;
virtual int type() const noexcept = 0;
// returns a string literal describing the type of the alert. It does
// not include any information that might be bundled with the alert.
virtual char const* what() const = 0;
virtual char const* what() const noexcept = 0;
// generate a string describing the alert and the information bundled
// with it. This is mainly intended for debug and development use. It is not suitable
@ -242,7 +242,7 @@ namespace libtorrent {
virtual std::string message() const = 0;
// returns a bitmask specifying which categories this alert belong to.
virtual alert_category_t category() const = 0;
virtual alert_category_t category() const noexcept = 0;
#ifndef TORRENT_NO_DEPRECATE

View File

@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/heterogeneous_queue.hpp"
#include "libtorrent/stack_allocator.hpp"
#include "libtorrent/alert_types.hpp" // for num_alert_types
#include <functional>
#include <list>
@ -44,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <bitset>
namespace libtorrent {
@ -51,6 +53,10 @@ namespace libtorrent {
struct plugin;
#endif
// this bitset is used to indicate which alert types have been dropped since
// last queried.
using dropped_alerts_t = std::bitset<num_alert_types>;
class TORRENT_EXTRA_EXPORT alert_manager
{
public:
@ -58,8 +64,10 @@ namespace libtorrent {
, alert_category_t alert_mask = alert::error_notification);
~alert_manager();
dropped_alerts_t dropped_alerts();
template <class T, typename... Args>
void emplace_alert(Args&&... args)
void emplace_alert(Args&&... args) try
{
std::unique_lock<std::mutex> lock(m_mutex);
@ -69,12 +77,8 @@ namespace libtorrent {
if (m_alerts[m_generation].size() >= m_queue_size_limit
* (1 + T::priority))
{
// if (T::priority > 0)
// {
// TODO: there should be a way for the client to detect that an
// alert was dropped. Maybe add a flag to each m_alerts
// generation
// }
// record that we dropped an alert of this type
m_dropped.set(T::alert_type);
return;
}
@ -83,6 +87,12 @@ namespace libtorrent {
maybe_notify(&alert, lock);
}
catch (std::bad_alloc const&)
{
// record that we dropped an alert of this type
std::unique_lock<std::mutex> lock(m_mutex);
m_dropped.set(T::alert_type);
}
bool pending() const;
void get_all(std::vector<alert*>& alerts);
@ -105,12 +115,12 @@ namespace libtorrent {
m_alert_mask = m;
}
alert_category_t alert_mask() const
alert_category_t alert_mask() const noexcept
{
return m_alert_mask;
}
int alert_queue_size_limit() const { return m_queue_size_limit; }
int alert_queue_size_limit() const noexcept { return m_queue_size_limit; }
int set_alert_queue_size_limit(int queue_size_limit_);
void set_notify_function(std::function<void()> const& fun);
@ -133,6 +143,12 @@ namespace libtorrent {
std::atomic<alert_category_t> m_alert_mask;
int m_queue_size_limit;
// a bitfield where each bit represents an alert type. Every time we drop
// an alert (because the queue is full or of some other error) we set the
// corresponding bit in this mask, to communicate to the client that it
// may have missed an update.
dropped_alerts_t m_dropped;
// this function (if set) is called whenever the number of alerts in
// the alert queue goes from 0 to 1. The client is expected to wake up
// its main message loop for it to poll for alerts (using get_alerts()).

View File

@ -161,9 +161,9 @@ namespace libtorrent {
name(name&&) noexcept = default; \
static const int priority = prio; \
static const int alert_type = seq; \
virtual int type() const override { return alert_type; } \
virtual alert_category_t category() const override { return static_category; } \
virtual char const* what() const override { return #name; }
virtual int type() const noexcept override { return alert_type; } \
virtual alert_category_t category() const noexcept override { return static_category; } \
virtual char const* what() const noexcept override { return #name; }
#define TORRENT_DEFINE_ALERT(name, seq) \
TORRENT_DEFINE_ALERT_IMPL(name, seq, 0)

View File

@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/io_service.hpp"
#include "libtorrent/session_types.hpp"
#include "libtorrent/portmap.hpp" // for portmap_protocol
#include "libtorrent/alert_manager.hpp" // for dropped_alerts_t
#include "libtorrent/kademlia/dht_storage.hpp"
#include "libtorrent/kademlia/dht_settings.hpp"
@ -934,9 +935,22 @@ namespace libtorrent {
// retrieval of alerts should not be done in the callback. In fact, the
// callback should not block. It should not perform any expensive work.
// It really should just notify the main application thread.
//
// The ``dropped_alerts()`` function returns a ``std::bitfield``
// representing which types of alerts have been dropped. Dropped meaning
// that the alert failed to be delivered to the client. The most common
// cause of such failure is that the internal alert queue grew too big
// (controlled by alert_queue_size). This call also clears the internal
// bitfield, so the bitfield starts recording dropped alerts from this
// point forward only.
//
// The type of an alert is returned by the polymorphic function
// ``alert::type()`` but can also be queries from a concrete type via
// ``T::alert_type``, as a static constant.
void pop_alerts(std::vector<alert*>* alerts);
alert* wait_for_alert(time_duration max_wait);
void set_alert_notify(std::function<void()> const& fun);
dropped_alerts_t dropped_alerts();
#ifndef TORRENT_NO_DEPRECATE
#include "libtorrent/aux_/disable_warnings_push.hpp"

View File

@ -1442,7 +1442,11 @@ namespace libtorrent {
// ``alert_queue_size`` is the maximum number of alerts queued up
// internally. If alerts are not popped, the queue will eventually
// fill up to this level.
// fill up to this level. Once the alert queue is full, additional
// alerts will be dropped, and not delievered to the client. Once the
// client drains the queue, new alerts may be delivered again. In order
// to know that alerts have been dropped, see
// session_handle::dropped_alerts().
alert_queue_size,
// ``max_metadata_size`` is the maximum allowed size (in bytes) to be

View File

@ -146,4 +146,12 @@ namespace libtorrent {
std::swap(m_queue_size_limit, queue_size_limit_);
return queue_size_limit_;
}
dropped_alerts_t alert_manager::dropped_alerts()
{
std::unique_lock<std::mutex> lock(m_mutex);
dropped_alerts_t const ret = m_dropped;
m_dropped.reset();
return ret;
}
}

View File

@ -1130,6 +1130,13 @@ namespace {
s->alerts().set_notify_function(fun);
}
dropped_alerts_t session_handle::dropped_alerts()
{
std::shared_ptr<session_impl> s = m_impl.lock();
if (!s) aux::throw_ex<system_error>(errors::invalid_session_handle);
return s->alerts().dropped_alerts();
}
#ifndef TORRENT_NO_DEPRECATE
void session_handle::set_severity_level(alert::severity_t s)
{

View File

@ -248,3 +248,23 @@ TORRENT_TEST(alert_mask)
TEST_CHECK(!mgr.should_post<torrent_paused_alert>());
}
TORRENT_TEST(dropped_alerts)
{
alert_manager mgr(1, alert::all_categories);
// nothing has dropped yet
TEST_CHECK(mgr.dropped_alerts().none());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// still nothing, there's space for one alert
TEST_CHECK(mgr.dropped_alerts().none());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// that last alert got dropped though, since it would have brought the queue
// size to 2
auto const d = mgr.dropped_alerts();
TEST_CHECK(d.count() == 1);
TEST_CHECK(d.test(torrent_finished_alert::alert_type));
// it should have been cleared now though
TEST_CHECK(mgr.dropped_alerts().none());
}