Skip to content

Commit 1c278cc

Browse files
committed
add API to query whether alerts have been dropped or not
1 parent 254f813 commit 1c278cc

9 files changed

+86
-16
lines changed

ChangeLog

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

include/libtorrent/alert.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ namespace libtorrent {
228228
// }
229229
// }
230230
// }
231-
virtual int type() const = 0;
231+
virtual int type() const noexcept = 0;
232232

233233
// returns a string literal describing the type of the alert. It does
234234
// not include any information that might be bundled with the alert.
235-
virtual char const* what() const = 0;
235+
virtual char const* what() const noexcept = 0;
236236

237237
// generate a string describing the alert and the information bundled
238238
// with it. This is mainly intended for debug and development use. It is not suitable
@@ -242,7 +242,7 @@ namespace libtorrent {
242242
virtual std::string message() const = 0;
243243

244244
// returns a bitmask specifying which categories this alert belong to.
245-
virtual alert_category_t category() const = 0;
245+
virtual alert_category_t category() const noexcept = 0;
246246

247247
#ifndef TORRENT_NO_DEPRECATE
248248

include/libtorrent/alert_manager.hpp

+25-9
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,37 @@ POSSIBILITY OF SUCH DAMAGE.
3737
#include "libtorrent/alert.hpp"
3838
#include "libtorrent/heterogeneous_queue.hpp"
3939
#include "libtorrent/stack_allocator.hpp"
40+
#include "libtorrent/alert_types.hpp" // for num_alert_types
4041

4142
#include <functional>
4243
#include <list>
4344
#include <utility> // for std::forward
4445
#include <mutex>
4546
#include <condition_variable>
4647
#include <atomic>
48+
#include <bitset>
4749

4850
namespace libtorrent {
4951

5052
#ifndef TORRENT_DISABLE_EXTENSIONS
5153
struct plugin;
5254
#endif
5355

56+
// this bitset is used to indicate which alert types have been dropped since
57+
// last queried.
58+
using dropped_alerts_t = std::bitset<num_alert_types>;
59+
5460
class TORRENT_EXTRA_EXPORT alert_manager
5561
{
5662
public:
5763
alert_manager(int queue_limit
5864
, alert_category_t alert_mask = alert::error_notification);
5965
~alert_manager();
6066

67+
dropped_alerts_t dropped_alerts();
68+
6169
template <class T, typename... Args>
62-
void emplace_alert(Args&&... args)
70+
void emplace_alert(Args&&... args) try
6371
{
6472
std::unique_lock<std::mutex> lock(m_mutex);
6573

@@ -69,12 +77,8 @@ namespace libtorrent {
6977
if (m_alerts[m_generation].size() >= m_queue_size_limit
7078
* (1 + T::priority))
7179
{
72-
// if (T::priority > 0)
73-
// {
74-
// TODO: there should be a way for the client to detect that an
75-
// alert was dropped. Maybe add a flag to each m_alerts
76-
// generation
77-
// }
80+
// record that we dropped an alert of this type
81+
m_dropped.set(T::alert_type);
7882
return;
7983
}
8084

@@ -83,6 +87,12 @@ namespace libtorrent {
8387

8488
maybe_notify(&alert, lock);
8589
}
90+
catch (std::bad_alloc const&)
91+
{
92+
// record that we dropped an alert of this type
93+
std::unique_lock<std::mutex> lock(m_mutex);
94+
m_dropped.set(T::alert_type);
95+
}
8696

8797
bool pending() const;
8898
void get_all(std::vector<alert*>& alerts);
@@ -105,12 +115,12 @@ namespace libtorrent {
105115
m_alert_mask = m;
106116
}
107117

108-
alert_category_t alert_mask() const
118+
alert_category_t alert_mask() const noexcept
109119
{
110120
return m_alert_mask;
111121
}
112122

113-
int alert_queue_size_limit() const { return m_queue_size_limit; }
123+
int alert_queue_size_limit() const noexcept { return m_queue_size_limit; }
114124
int set_alert_queue_size_limit(int queue_size_limit_);
115125

116126
void set_notify_function(std::function<void()> const& fun);
@@ -133,6 +143,12 @@ namespace libtorrent {
133143
std::atomic<alert_category_t> m_alert_mask;
134144
int m_queue_size_limit;
135145

146+
// a bitfield where each bit represents an alert type. Every time we drop
147+
// an alert (because the queue is full or of some other error) we set the
148+
// corresponding bit in this mask, to communicate to the client that it
149+
// may have missed an update.
150+
dropped_alerts_t m_dropped;
151+
136152
// this function (if set) is called whenever the number of alerts in
137153
// the alert queue goes from 0 to 1. The client is expected to wake up
138154
// its main message loop for it to poll for alerts (using get_alerts()).

include/libtorrent/alert_types.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ namespace libtorrent {
161161
name(name&&) noexcept = default; \
162162
static const int priority = prio; \
163163
static const int alert_type = seq; \
164-
virtual int type() const override { return alert_type; } \
165-
virtual alert_category_t category() const override { return static_category; } \
166-
virtual char const* what() const override { return #name; }
164+
virtual int type() const noexcept override { return alert_type; } \
165+
virtual alert_category_t category() const noexcept override { return static_category; } \
166+
virtual char const* what() const noexcept override { return #name; }
167167

168168
#define TORRENT_DEFINE_ALERT(name, seq) \
169169
TORRENT_DEFINE_ALERT_IMPL(name, seq, 0)

include/libtorrent/session_handle.hpp

+14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
4545
#include "libtorrent/io_service.hpp"
4646
#include "libtorrent/session_types.hpp"
4747
#include "libtorrent/portmap.hpp" // for portmap_protocol
48+
#include "libtorrent/alert_manager.hpp" // for dropped_alerts_t
4849

4950
#include "libtorrent/kademlia/dht_storage.hpp"
5051
#include "libtorrent/kademlia/dht_settings.hpp"
@@ -934,9 +935,22 @@ namespace libtorrent {
934935
// retrieval of alerts should not be done in the callback. In fact, the
935936
// callback should not block. It should not perform any expensive work.
936937
// It really should just notify the main application thread.
938+
//
939+
// The ``dropped_alerts()`` function returns a ``std::bitfield``
940+
// representing which types of alerts have been dropped. Dropped meaning
941+
// that the alert failed to be delivered to the client. The most common
942+
// cause of such failure is that the internal alert queue grew too big
943+
// (controlled by alert_queue_size). This call also clears the internal
944+
// bitfield, so the bitfield starts recording dropped alerts from this
945+
// point forward only.
946+
//
947+
// The type of an alert is returned by the polymorphic function
948+
// ``alert::type()`` but can also be queries from a concrete type via
949+
// ``T::alert_type``, as a static constant.
937950
void pop_alerts(std::vector<alert*>* alerts);
938951
alert* wait_for_alert(time_duration max_wait);
939952
void set_alert_notify(std::function<void()> const& fun);
953+
dropped_alerts_t dropped_alerts();
940954

941955
#ifndef TORRENT_NO_DEPRECATE
942956
#include "libtorrent/aux_/disable_warnings_push.hpp"

include/libtorrent/settings_pack.hpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,11 @@ namespace libtorrent {
14421442

14431443
// ``alert_queue_size`` is the maximum number of alerts queued up
14441444
// internally. If alerts are not popped, the queue will eventually
1445-
// fill up to this level.
1445+
// fill up to this level. Once the alert queue is full, additional
1446+
// alerts will be dropped, and not delievered to the client. Once the
1447+
// client drains the queue, new alerts may be delivered again. In order
1448+
// to know that alerts have been dropped, see
1449+
// session_handle::dropped_alerts().
14461450
alert_queue_size,
14471451

14481452
// ``max_metadata_size`` is the maximum allowed size (in bytes) to be

src/alert_manager.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,12 @@ namespace libtorrent {
146146
std::swap(m_queue_size_limit, queue_size_limit_);
147147
return queue_size_limit_;
148148
}
149+
150+
dropped_alerts_t alert_manager::dropped_alerts()
151+
{
152+
std::unique_lock<std::mutex> lock(m_mutex);
153+
dropped_alerts_t const ret = m_dropped;
154+
m_dropped.reset();
155+
return ret;
156+
}
149157
}

src/session_handle.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,13 @@ namespace {
11301130
s->alerts().set_notify_function(fun);
11311131
}
11321132

1133+
dropped_alerts_t session_handle::dropped_alerts()
1134+
{
1135+
std::shared_ptr<session_impl> s = m_impl.lock();
1136+
if (!s) aux::throw_ex<system_error>(errors::invalid_session_handle);
1137+
return s->alerts().dropped_alerts();
1138+
}
1139+
11331140
#ifndef TORRENT_NO_DEPRECATE
11341141
void session_handle::set_severity_level(alert::severity_t s)
11351142
{

test/test_alert_manager.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,23 @@ TORRENT_TEST(alert_mask)
248248
TEST_CHECK(!mgr.should_post<torrent_paused_alert>());
249249
}
250250

251+
TORRENT_TEST(dropped_alerts)
252+
{
253+
alert_manager mgr(1, alert::all_categories);
254+
255+
// nothing has dropped yet
256+
TEST_CHECK(mgr.dropped_alerts().none());
257+
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
258+
// still nothing, there's space for one alert
259+
TEST_CHECK(mgr.dropped_alerts().none());
260+
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
261+
// that last alert got dropped though, since it would have brought the queue
262+
// size to 2
263+
auto const d = mgr.dropped_alerts();
264+
TEST_CHECK(d.count() == 1);
265+
TEST_CHECK(d.test(torrent_finished_alert::alert_type));
266+
267+
// it should have been cleared now though
268+
TEST_CHECK(mgr.dropped_alerts().none());
269+
}
270+

0 commit comments

Comments
 (0)