deliver notification of alerts being dropped via alerts_dropped_alert

This commit is contained in:
arvidn 2018-05-26 13:40:49 +02:00 committed by Arvid Norberg
parent f9b43f3511
commit c56f6abf72
10 changed files with 142 additions and 47 deletions

View File

@ -1,10 +1,10 @@
* deliver notification of alerts being dropped via alerts_dropped_alert
* deprecated alert::progress_notification alert category, split into
finer grained categories
* update plugin interface functions for improved type-safety
* implemented support magnet URI extension, select specific file indices
for download, BEP53
* make tracker keys multi-homed. remove set_key() function on session.
* 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

@ -54,10 +54,6 @@ 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:
@ -69,8 +65,6 @@ namespace libtorrent {
~alert_manager();
dropped_alerts_t dropped_alerts();
template <class T, typename... Args>
void emplace_alert(Args&&... args) try
{
@ -145,7 +139,7 @@ namespace libtorrent {
// 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;
std::bitset<num_alert_types> 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

View File

@ -59,6 +59,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/shared_array.hpp>
#include "libtorrent/aux_/disable_warnings_pop.hpp"
#include <bitset>
#if TORRENT_ABI_VERSION == 1
#define PROGRESS_NOTIFICATION | alert::progress_notification
#else
@ -72,8 +74,14 @@ namespace libtorrent {
TORRENT_DEPRECATED_EXPORT char const* operation_name(int op);
#endif
// internal
TORRENT_EXTRA_EXPORT char const* alert_name(int alert_type);
// user defined alerts should use IDs greater than this
static const int user_alert_id = 10000;
constexpr int user_alert_id = 10000;
// this constant represents "max_alert_index" + 1
constexpr int num_alert_types = 96;
enum alert_priority
{
@ -190,7 +198,7 @@ TORRENT_VERSION_NAMESPACE_2
static const int alert_type = seq; \
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; }
virtual char const* what() const noexcept override { return alert_name(alert_type); }
#define TORRENT_DEFINE_ALERT(name, seq) \
TORRENT_DEFINE_ALERT_IMPL(name, seq, alert_priority_normal)
@ -1848,7 +1856,7 @@ TORRENT_VERSION_NAMESPACE_2
};
// This alert is posted whenever a tracker responds with a ``trackerid``.
// The tracker ID is like a cookie. The libtorrent will store the tracker ID
// The tracker ID is like a cookie. libtorrent will store the tracker ID
// for this tracker and repeat it in subsequent announces.
struct TORRENT_EXPORT trackerid_alert final : tracker_alert
{
@ -2839,6 +2847,25 @@ TORRENT_VERSION_NAMESPACE_2
piece_index_t const piece_index;
};
// this alert is posted to indicate to the client that some alerts were
// 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).
struct TORRENT_EXPORT alerts_dropped_alert final : alert
{
explicit alerts_dropped_alert(aux::stack_allocator& alloc
, std::bitset<num_alert_types> const&);
TORRENT_DEFINE_ALERT_PRIO(alerts_dropped_alert, 95, alert_priority_critical + 1)
static constexpr alert_category_t static_category = alert::error_notification;
std::string message() const override;
// a bitmask indicating which alerts were dropped. Each bit represents the
// alert type ID, where bit 0 represents whether any alert of type 0 has
// been dropped, and so on.
std::bitset<num_alert_types> dropped_alerts;
};
TORRENT_VERSION_NAMESPACE_2_END
#undef TORRENT_DEFINE_ALERT_IMPL
@ -2846,7 +2873,6 @@ TORRENT_VERSION_NAMESPACE_2_END
#undef TORRENT_DEFINE_ALERT_PRIO
#undef PROGRESS_NOTIFICATION
constexpr int num_alert_types = 95; // this constant represents "max_alert_index" + 1
}
#endif

View File

@ -46,7 +46,6 @@ 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"
@ -933,21 +932,12 @@ namespace libtorrent {
// 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();
#if TORRENT_ABI_VERSION == 1
#include "libtorrent/aux_/disable_warnings_push.hpp"

View File

@ -2540,6 +2540,83 @@ namespace {
return ret;
}
alerts_dropped_alert::alerts_dropped_alert(aux::stack_allocator&
, std::bitset<num_alert_types> const& dropped)
: dropped_alerts(dropped)
{}
char const* alert_name(int const alert_type)
{
static std::array<char const*, num_alert_types> const names = {{
#if TORRENT_ABI_VERSION == 1
"torrent", "peer", "tracker", "torrent_added",
#else
"", "", "", "",
#endif
"torrent_removed", "read_piece", "file_completed",
"file_renamed", "file_rename_failed", "performance",
"state_changed", "tracker_error", "tracker_warning",
"scrape_reply", "scrape_failed", "tracker_reply",
"dht_reply", "tracker_announce", "hash_failed",
"peer_ban", "peer_unsnubbed", "peer_snubbed",
"peer_error", "peer_connect", "peer_disconnected",
"invalid_request", "torrent_finished", "piece_finished",
"request_dropped", "block_timeout", "block_finished",
"block_downloading", "unwanted_block", "storage_moved",
"storage_moved_failed", "torrent_deleted",
"torrent_delete_failed", "save_resume_data",
"save_resume_data_failed", "torrent_paused",
"torrent_resumed", "torrent_checked", "url_seed",
"file_error", "metadata_failed", "metadata_received",
"udp_error", "external_ip", "listen_failed",
"listen_succeeded", "portmap_error", "portmap",
"portmap_log", "fastresume_rejected", "peer_blocked",
"dht_announce", "dht_get_peers", "stats",
"cache_flushed", "anonymous_mode", "lsd_peer",
"trackerid", "dht_bootstrap", "", "torrent_error",
"torrent_need_cert", "incoming_connection",
"add_torrent", "state_update",
#if TORRENT_ABI_VERSION == 1
"mmap_cache",
#else
"",
#endif
"session_stats",
#if TORRENT_ABI_VERSION == 1
"torrent_update",
#else
"",
#endif
"", "dht_error", "dht_immutable_item", "dht_mutable_item",
"dht_put", "i2p", "dht_outgoing_get_peers", "log",
"torrent_log", "peer_log", "lsd_error",
"dht_stats", "incoming_request", "dht_log",
"dht_pkt", "dht_get_peers_reply", "dht_direct_response",
"picker_log", "session_error", "dht_live_nodes",
"session_stats_header", "dht_sample_infohashes",
"block_uploaded", "alerts_dropped"
}};
TORRENT_ASSERT(alert_type >= 0);
TORRENT_ASSERT(alert_type < num_alert_types);
return names[std::size_t(alert_type)];
}
std::string alerts_dropped_alert::message() const
{
std::string ret = "dropped alerts: ";
TORRENT_ASSERT(int(dropped_alerts.size()) == num_alert_types);
for (int idx = 0; idx < num_alert_types; ++idx)
{
if (!dropped_alerts.test(std::size_t(idx))) continue;
ret += alert_name(idx);
ret += ' ';
}
return ret;
}
// this will no longer be necessary in C++17
constexpr alert_category_t torrent_removed_alert::static_category;
constexpr alert_category_t read_piece_alert::static_category;
@ -2628,6 +2705,7 @@ namespace {
constexpr alert_category_t session_stats_header_alert::static_category;
constexpr alert_category_t dht_sample_infohashes_alert::static_category;
constexpr alert_category_t block_uploaded_alert::static_category;
constexpr alert_category_t alerts_dropped_alert::static_category;
#if TORRENT_ABI_VERSION == 1
constexpr alert_category_t mmap_cache_alert::static_category;
constexpr alert_category_t torrent_added_alert::static_category;

View File

@ -108,6 +108,11 @@ namespace libtorrent {
if (m_alerts[m_generation].empty()) return;
if (m_dropped.any()) {
emplace_alert<alerts_dropped_alert>(m_dropped);
m_dropped.reset();
}
m_alerts[m_generation].get_pointers(alerts);
// swap buffers
@ -130,12 +135,4 @@ 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::recursive_mutex> lock(m_mutex);
dropped_alerts_t const ret = m_dropped;
m_dropped.reset();
return ret;
}
}

View File

@ -1144,13 +1144,6 @@ 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();
}
#if TORRENT_ABI_VERSION == 1
void session_handle::set_severity_level(alert::severity_t s)
{

View File

@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/session.hpp" // for session::delete_files
#include "libtorrent/stat_cache.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/torrent_status.hpp"
#include <set>

View File

@ -60,7 +60,8 @@ TORRENT_TEST(limit)
mgr.get_all(alerts);
// even though we posted 600, the limit was 500
TEST_EQUAL(alerts.size(), 500);
// +1 for the alerts_dropped_alert
TEST_EQUAL(alerts.size(), 501);
TEST_EQUAL(mgr.pending(), false);
@ -75,7 +76,8 @@ TORRENT_TEST(limit)
mgr.get_all(alerts);
// even though we posted 600, the limit was 200
TEST_EQUAL(alerts.size(), 200);
// +1 for the alerts_dropped_alert
TEST_EQUAL(alerts.size(), 201);
}
TORRENT_TEST(priority_limit)
@ -97,7 +99,8 @@ TORRENT_TEST(priority_limit)
// even though we posted 500, the limit was 100 for half of them and
// 100 + 200 for the other half, meaning we should have 300 alerts now
TEST_EQUAL(alerts.size(), 300);
// +1 for the alerts_dropped_alert
TEST_EQUAL(alerts.size(), 301);
}
namespace {
@ -260,22 +263,33 @@ 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());
// 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 3
auto const d = mgr.dropped_alerts();
std::vector<alert*> alerts;
mgr.get_all(alerts);
auto const d = alert_cast<alerts_dropped_alert>(alerts.back())->dropped_alerts;
TEST_EQUAL(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());
TORRENT_TEST(alerts_dropped_alert)
{
alert_manager mgr(1, alert::all_categories);
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// that last alert got dropped though, since it would have brought the queue
// size to 3
std::vector<alert*> alerts;
mgr.get_all(alerts);
TEST_EQUAL(alerts.back()->message(), "dropped alerts: torrent_finished ");
}
#ifndef TORRENT_DISABLE_EXTENSIONS

View File

@ -58,6 +58,7 @@ TORRENT_TEST(alerts_types)
TEST_EQUAL(name::alert_type, seq); \
TEST_EQUAL(name::static_category, cat); \
TEST_EQUAL(count_alert_types, seq); \
TEST_EQUAL(std::string(alert_name(name::alert_type)) + "_alert", #name); \
count_alert_types++;
#if TORRENT_ABI_VERSION == 1
@ -171,10 +172,11 @@ TORRENT_TEST(alerts_types)
TEST_ALERT_TYPE(session_stats_header_alert, 92, 0, alert::stats_notification);
TEST_ALERT_TYPE(dht_sample_infohashes_alert, 93, 0, alert::dht_operation_notification);
TEST_ALERT_TYPE(block_uploaded_alert, 94, 0, PROGRESS_NOTIFICATION alert::upload_notification);
TEST_ALERT_TYPE(alerts_dropped_alert, 95, 3, alert::error_notification);
#undef TEST_ALERT_TYPE
TEST_EQUAL(num_alert_types, 95);
TEST_EQUAL(num_alert_types, 96);
TEST_EQUAL(num_alert_types, count_alert_types);
}