mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-27 06:54:20 +00:00
Handle tracker status updates asynchronously
* Add a helper for performing jobs in Session context * Handle tracker status updates asynchronously PR #18010.
This commit is contained in:
parent
a31755bbc8
commit
1b2ff0f6f8
@ -468,6 +468,6 @@ namespace BitTorrent
|
||||
void trackersRemoved(Torrent *torrent, const QStringList &trackers);
|
||||
void trackerSuccess(Torrent *torrent, const QString &tracker);
|
||||
void trackerWarning(Torrent *torrent, const QString &tracker);
|
||||
void trackerEntriesUpdated(const QHash<Torrent *, QSet<QString>> &updateInfos);
|
||||
void trackerEntriesUpdated(Torrent *torrent, const QHash<QString, TrackerEntry> &updatedTrackerEntries);
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -35,7 +35,6 @@
|
||||
#include <ctime>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
@ -118,6 +117,24 @@ const Path CATEGORIES_FILE_NAME {u"categories.json"_qs};
|
||||
const int MAX_PROCESSING_RESUMEDATA_COUNT = 50;
|
||||
const int STATISTICS_SAVE_INTERVAL = std::chrono::milliseconds(15min).count();
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
namespace std
|
||||
{
|
||||
uint qHash(const std::string &key, uint seed = 0)
|
||||
{
|
||||
return qHash(QByteArray::fromRawData(key.data(), static_cast<int>(key.length())), seed);
|
||||
}
|
||||
}
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
uint qHash(const libtorrent::torrent_handle &key)
|
||||
{
|
||||
return static_cast<uint>(libtorrent::hash_value(key));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
const char PEER_ID[] = "qB";
|
||||
@ -5809,13 +5826,12 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *a)
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
const auto trackerURL = QString::fromUtf8(a->tracker_url());
|
||||
m_updatedTrackerEntries[torrent].insert(trackerURL);
|
||||
QMap<TrackerEntry::Endpoint, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())];
|
||||
|
||||
if (a->type() == lt::tracker_reply_alert::alert_type)
|
||||
{
|
||||
const int numPeers = static_cast<const lt::tracker_reply_alert *>(a)->num_peers;
|
||||
torrent->updatePeerCount(trackerURL, a->local_endpoint, numPeers);
|
||||
updateInfo.insert(a->local_endpoint, numPeers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5869,20 +5885,50 @@ void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *a
|
||||
|
||||
void SessionImpl::processTrackerStatuses()
|
||||
{
|
||||
if (m_updatedTrackerEntries.isEmpty())
|
||||
return;
|
||||
|
||||
for (auto it = m_updatedTrackerEntries.cbegin(); it != m_updatedTrackerEntries.cend(); ++it)
|
||||
{
|
||||
auto torrent = static_cast<TorrentImpl *>(it.key());
|
||||
const QSet<QString> &updatedTrackers = it.value();
|
||||
invokeAsync([this, torrentHandle = it.key(), updatedTrackers = it.value()]() mutable
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector<lt::announce_entry> nativeTrackers = torrentHandle.trackers();
|
||||
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers)
|
||||
, updatedTrackers = std::move(updatedTrackers)]
|
||||
{
|
||||
TorrentImpl *torrent = m_torrents.value(torrentHandle.info_hash());
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
for (const QString &trackerURL : updatedTrackers)
|
||||
torrent->invalidateTrackerEntry(trackerURL);
|
||||
QHash<QString, TrackerEntry> updatedTrackerEntries;
|
||||
updatedTrackerEntries.reserve(updatedTrackers.size());
|
||||
for (const lt::announce_entry &announceEntry : nativeTrackers)
|
||||
{
|
||||
const auto updatedTrackersIter = updatedTrackers.find(announceEntry.url);
|
||||
if (updatedTrackersIter == updatedTrackers.end())
|
||||
continue;
|
||||
|
||||
const QMap<TrackerEntry::Endpoint, int> &updateInfo = updatedTrackersIter.value();
|
||||
TrackerEntry trackerEntry = torrent->updateTrackerEntry(announceEntry, updateInfo);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
updatedTrackerEntries[trackerEntry.url] = std::move(trackerEntry);
|
||||
#else
|
||||
updatedTrackerEntries.emplace(trackerEntry.url, std::move(trackerEntry));
|
||||
#endif
|
||||
}
|
||||
|
||||
emit trackerEntriesUpdated(torrent, updatedTrackerEntries);
|
||||
});
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!m_updatedTrackerEntries.isEmpty())
|
||||
{
|
||||
emit trackerEntriesUpdated(m_updatedTrackerEntries);
|
||||
m_updatedTrackerEntries.clear();
|
||||
}
|
||||
m_updatedTrackerEntries.clear();
|
||||
}
|
||||
|
||||
void SessionImpl::saveStatistics() const
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
@ -36,11 +37,11 @@
|
||||
#include <libtorrent/portmap.hpp>
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
|
||||
#include <QtContainerFwd>
|
||||
#include <QElapsedTimer>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QtContainerFwd>
|
||||
#include <QVector>
|
||||
|
||||
#include "base/path.h"
|
||||
@ -438,6 +439,12 @@ namespace BitTorrent
|
||||
void addMappedPorts(const QSet<quint16> &ports);
|
||||
void removeMappedPorts(const QSet<quint16> &ports);
|
||||
|
||||
template <typename Func>
|
||||
void invoke(Func &&func)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, std::forward<Func>(func));
|
||||
}
|
||||
|
||||
void invokeAsync(std::function<void ()> func);
|
||||
|
||||
private slots:
|
||||
@ -719,7 +726,9 @@ namespace BitTorrent
|
||||
QMap<QString, CategoryOptions> m_categories;
|
||||
QSet<QString> m_tags;
|
||||
|
||||
QHash<Torrent *, QSet<QString>> m_updatedTrackerEntries;
|
||||
// This field holds amounts of peers reported by trackers in their responses to announces
|
||||
// (torrent.tracker_name.tracker_local_endpoint.num_peers)
|
||||
QHash<lt::torrent_handle, QHash<std::string, QMap<TrackerEntry::Endpoint, int>>> m_updatedTrackerEntries;
|
||||
|
||||
// I/O errored torrents
|
||||
QSet<TorrentID> m_recentErroredTorrents;
|
||||
|
@ -82,10 +82,10 @@ namespace
|
||||
|
||||
#ifdef QBT_USES_LIBTORRENT2
|
||||
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
||||
, const lt::info_hash_t &hashes, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
||||
, const lt::info_hash_t &hashes, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
||||
#else
|
||||
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
||||
, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
||||
, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
||||
#endif
|
||||
{
|
||||
Q_ASSERT(trackerEntry.url == QString::fromStdString(nativeEntry.url));
|
||||
@ -522,9 +522,6 @@ void TorrentImpl::setAutoManaged(const bool enable)
|
||||
|
||||
QVector<TrackerEntry> TorrentImpl::trackers() const
|
||||
{
|
||||
if (!m_updatedTrackerEntries.isEmpty())
|
||||
refreshTrackerEntries();
|
||||
|
||||
return m_trackerEntries;
|
||||
}
|
||||
|
||||
@ -1515,43 +1512,25 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
|
||||
endReceivedMetadataHandling(savePath, fileNames);
|
||||
}
|
||||
|
||||
void TorrentImpl::updatePeerCount(const QString &trackerURL, const TrackerEntry::Endpoint &endpoint, const int count)
|
||||
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
||||
{
|
||||
m_updatedTrackerEntries[trackerURL][endpoint] = count;
|
||||
}
|
||||
|
||||
void TorrentImpl::invalidateTrackerEntry(const QString &trackerURL)
|
||||
{
|
||||
std::ignore = m_updatedTrackerEntries[trackerURL];
|
||||
}
|
||||
|
||||
void TorrentImpl::refreshTrackerEntries() const
|
||||
{
|
||||
const std::vector<lt::announce_entry> nativeTrackers = m_nativeHandle.trackers();
|
||||
Q_ASSERT(nativeTrackers.size() == m_trackerEntries.size());
|
||||
|
||||
for (TrackerEntry &trackerEntry : m_trackerEntries)
|
||||
const auto it = std::find_if(m_trackerEntries.begin(), m_trackerEntries.end()
|
||||
, [&announceEntry](const TrackerEntry &trackerEntry)
|
||||
{
|
||||
const auto updatedTrackerIter = m_updatedTrackerEntries.find(trackerEntry.url);
|
||||
if (updatedTrackerIter == m_updatedTrackerEntries.end())
|
||||
continue;
|
||||
return (trackerEntry.url == QString::fromStdString(announceEntry.url));
|
||||
});
|
||||
|
||||
const auto nativeTrackerIter = std::find_if(nativeTrackers.cbegin(), nativeTrackers.cend()
|
||||
, [trackerURL = trackerEntry.url.toStdString()](const lt::announce_entry &announceEntry)
|
||||
{
|
||||
return (announceEntry.url == trackerURL);
|
||||
});
|
||||
Q_ASSERT(nativeTrackerIter != nativeTrackers.cend());
|
||||
Q_ASSERT(it != m_trackerEntries.end());
|
||||
// TODO: use [[unlikely]] in C++20
|
||||
if (Q_UNLIKELY(it == m_trackerEntries.end()))
|
||||
return {};
|
||||
|
||||
const lt::announce_entry &announceEntry = *nativeTrackerIter;
|
||||
#ifdef QBT_USES_LIBTORRENT2
|
||||
updateTrackerEntry(trackerEntry, announceEntry, m_nativeHandle.info_hashes(), updatedTrackerIter.value());
|
||||
::updateTrackerEntry(*it, announceEntry, nativeHandle().info_hashes(), updateInfo);
|
||||
#else
|
||||
updateTrackerEntry(trackerEntry, announceEntry, updatedTrackerIter.value());
|
||||
::updateTrackerEntry(*it, announceEntry, updateInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_updatedTrackerEntries.clear();
|
||||
return *it;
|
||||
}
|
||||
|
||||
std::shared_ptr<const libtorrent::torrent_info> TorrentImpl::nativeTorrentInfo() const
|
||||
|
@ -248,15 +248,13 @@ namespace BitTorrent
|
||||
void saveResumeData(lt::resume_data_flags_t flags = {});
|
||||
void handleMoveStorageJobFinished(const Path &path, bool hasOutstandingJob);
|
||||
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
||||
void updatePeerCount(const QString &trackerURL, const TrackerEntry::Endpoint &endpoint, int count);
|
||||
void invalidateTrackerEntry(const QString &trackerURL);
|
||||
TrackerEntry updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo);
|
||||
|
||||
private:
|
||||
using EventTrigger = std::function<void ()>;
|
||||
|
||||
std::shared_ptr<const lt::torrent_info> nativeTorrentInfo() const;
|
||||
|
||||
void refreshTrackerEntries() const;
|
||||
void updateStatus(const lt::torrent_status &nativeStatus);
|
||||
void updateState();
|
||||
|
||||
@ -316,10 +314,7 @@ namespace BitTorrent
|
||||
|
||||
MaintenanceJob m_maintenanceJob = MaintenanceJob::None;
|
||||
|
||||
// TODO: Use QHash<TrackerEntry::Endpoint, int> once Qt5 is dropped.
|
||||
using TrackerEntryUpdateInfo = QMap<TrackerEntry::Endpoint, int>;
|
||||
mutable QHash<QString, TrackerEntryUpdateInfo> m_updatedTrackerEntries;
|
||||
mutable QVector<TrackerEntry> m_trackerEntries;
|
||||
QVector<TrackerEntry> m_trackerEntries;
|
||||
FileErrorInfo m_lastFileError;
|
||||
|
||||
// Persistent data
|
||||
|
@ -599,60 +599,52 @@ void TrackerFiltersList::setDownloadTrackerFavicon(bool value)
|
||||
}
|
||||
}
|
||||
|
||||
void TrackerFiltersList::handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos)
|
||||
void TrackerFiltersList::handleTrackerEntriesUpdated(const BitTorrent::Torrent *torrent
|
||||
, const QHash<QString, BitTorrent::TrackerEntry> &updatedTrackerEntries)
|
||||
{
|
||||
for (auto torrentsIt = updateInfos.cbegin(); torrentsIt != updateInfos.cend(); ++torrentsIt)
|
||||
const BitTorrent::TorrentID id = torrent->id();
|
||||
|
||||
auto errorHashesIt = m_errors.find(id);
|
||||
auto warningHashesIt = m_warnings.find(id);
|
||||
|
||||
for (const BitTorrent::TrackerEntry &trackerEntry : updatedTrackerEntries)
|
||||
{
|
||||
const BitTorrent::Torrent *torrent = torrentsIt.key();
|
||||
const QSet<QString> &trackerURLs = torrentsIt.value();
|
||||
const BitTorrent::TorrentID id = torrent->id();
|
||||
|
||||
auto errorHashesIt = m_errors.find(id);
|
||||
auto warningHashesIt = m_warnings.find(id);
|
||||
|
||||
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
for (const BitTorrent::TrackerEntry &trackerEntry : trackers)
|
||||
if (trackerEntry.status == BitTorrent::TrackerEntry::Working)
|
||||
{
|
||||
if (!trackerURLs.contains(trackerEntry.url))
|
||||
continue;
|
||||
|
||||
if (trackerEntry.status == BitTorrent::TrackerEntry::Working)
|
||||
if (errorHashesIt != m_errors.end())
|
||||
{
|
||||
if (errorHashesIt != m_errors.end())
|
||||
{
|
||||
QSet<QString> &errored = errorHashesIt.value();
|
||||
errored.remove(trackerEntry.url);
|
||||
}
|
||||
QSet<QString> &errored = errorHashesIt.value();
|
||||
errored.remove(trackerEntry.url);
|
||||
}
|
||||
|
||||
if (trackerEntry.message.isEmpty())
|
||||
if (trackerEntry.message.isEmpty())
|
||||
{
|
||||
if (warningHashesIt != m_warnings.end())
|
||||
{
|
||||
if (warningHashesIt != m_warnings.end())
|
||||
{
|
||||
QSet<QString> &warned = *warningHashesIt;
|
||||
warned.remove(trackerEntry.url);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (warningHashesIt == m_warnings.end())
|
||||
warningHashesIt = m_warnings.insert(id, {});
|
||||
warningHashesIt.value().insert(trackerEntry.url);
|
||||
QSet<QString> &warned = *warningHashesIt;
|
||||
warned.remove(trackerEntry.url);
|
||||
}
|
||||
}
|
||||
else if (trackerEntry.status == BitTorrent::TrackerEntry::NotWorking)
|
||||
else
|
||||
{
|
||||
if (errorHashesIt == m_errors.end())
|
||||
errorHashesIt = m_errors.insert(id, {});
|
||||
errorHashesIt.value().insert(trackerEntry.url);
|
||||
if (warningHashesIt == m_warnings.end())
|
||||
warningHashesIt = m_warnings.insert(id, {});
|
||||
warningHashesIt.value().insert(trackerEntry.url);
|
||||
}
|
||||
}
|
||||
|
||||
if ((errorHashesIt != m_errors.end()) && errorHashesIt.value().isEmpty())
|
||||
m_errors.erase(errorHashesIt);
|
||||
if ((warningHashesIt != m_warnings.end()) && warningHashesIt.value().isEmpty())
|
||||
m_warnings.erase(warningHashesIt);
|
||||
else if (trackerEntry.status == BitTorrent::TrackerEntry::NotWorking)
|
||||
{
|
||||
if (errorHashesIt == m_errors.end())
|
||||
errorHashesIt = m_errors.insert(id, {});
|
||||
errorHashesIt.value().insert(trackerEntry.url);
|
||||
}
|
||||
}
|
||||
|
||||
if ((errorHashesIt != m_errors.end()) && errorHashesIt.value().isEmpty())
|
||||
m_errors.erase(errorHashesIt);
|
||||
if ((warningHashesIt != m_warnings.end()) && warningHashesIt.value().isEmpty())
|
||||
m_warnings.erase(warningHashesIt);
|
||||
|
||||
item(ERROR_ROW)->setText(tr("Error (%1)").arg(m_errors.size()));
|
||||
item(WARNING_ROW)->setText(tr("Warning (%1)").arg(m_warnings.size()));
|
||||
|
||||
@ -920,9 +912,10 @@ void TransferListFiltersWidget::changeTrackerless(const BitTorrent::Torrent *tor
|
||||
m_trackerFilters->changeTrackerless(torrent, trackerless);
|
||||
}
|
||||
|
||||
void TransferListFiltersWidget::trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos)
|
||||
void TransferListFiltersWidget::trackerEntriesUpdated(const BitTorrent::Torrent *torrent
|
||||
, const QHash<QString, BitTorrent::TrackerEntry> &updatedTrackerEntries)
|
||||
{
|
||||
m_trackerFilters->handleTrackerEntriesUpdated(updateInfos);
|
||||
m_trackerFilters->handleTrackerEntriesUpdated(torrent, updatedTrackerEntries);
|
||||
}
|
||||
|
||||
void TransferListFiltersWidget::onCategoryFilterStateChanged(bool enabled)
|
||||
|
@ -131,7 +131,8 @@ public:
|
||||
void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers);
|
||||
void refreshTrackers(const BitTorrent::Torrent *torrent);
|
||||
void changeTrackerless(const BitTorrent::Torrent *torrent, bool trackerless);
|
||||
void handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos);
|
||||
void handleTrackerEntriesUpdated(const BitTorrent::Torrent *torrent
|
||||
, const QHash<QString, BitTorrent::TrackerEntry> &updatedTrackerEntries);
|
||||
void setDownloadTrackerFavicon(bool value);
|
||||
|
||||
private slots:
|
||||
@ -180,7 +181,8 @@ public slots:
|
||||
void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers);
|
||||
void refreshTrackers(const BitTorrent::Torrent *torrent);
|
||||
void changeTrackerless(const BitTorrent::Torrent *torrent, bool trackerless);
|
||||
void trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos);
|
||||
void trackerEntriesUpdated(const BitTorrent::Torrent *torrent
|
||||
, const QHash<QString, BitTorrent::TrackerEntry> &updatedTrackerEntries);
|
||||
|
||||
private slots:
|
||||
void onCategoryFilterStateChanged(bool enabled);
|
||||
|
Loading…
x
Reference in New Issue
Block a user