feat: Torrent::update() returns a bitset of changed properties (#1334)

* refactor: Torrent::update() returns a delta bitset

Setting up for followup PRs where, instead of doing expensive work every
time there is a change, we can be more fine-grained and do the work only
if the relevant Torrent properties changed.

* chore: make uncrustify happy

* chore: fix #includes
This commit is contained in:
Charles Kerr
2020-06-23 16:11:16 -05:00
committed by GitHub
parent 83e4e4ca55
commit f37253a3ab
9 changed files with 154 additions and 82 deletions

View File

@@ -326,8 +326,10 @@ void DetailsDialog::onTorrentsEdited(torrent_ids_t const& ids)
}
}
void DetailsDialog::onTorrentsChanged(torrent_ids_t const& ids)
void DetailsDialog::onTorrentsChanged(torrent_ids_t const& ids, Torrent::fields_t const& fields)
{
Q_UNUSED(fields)
if (have_pending_refresh_)
{
return;

View File

@@ -62,7 +62,7 @@ private slots:
void onTimer();
void onTorrentsEdited(torrent_ids_t const& ids);
void onTorrentsChanged(torrent_ids_t const& ids);
void onTorrentsChanged(torrent_ids_t const& ids, Torrent::fields_t const& fields);
// Tracker tab
void onTrackerSelectionChanged();

View File

@@ -232,7 +232,7 @@ FilterBar::FilterBar(Prefs& prefs, TorrentModel const& torrents, TorrentFilter c
connect(&torrents_, SIGNAL(modelReset()), this, SLOT(recountSoon()));
connect(&torrents_, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(recountSoon()));
connect(&torrents_, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(recountSoon()));
connect(&torrents_, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(recountSoon()));
connect(&torrents_, &TorrentModel::torrentsChanged, this, &FilterBar::onTorrentsChanged);
connect(recount_timer_, SIGNAL(timeout()), this, SLOT(recount()));
recountSoon();
@@ -297,6 +297,14 @@ void FilterBar::refreshPref(int key)
}
}
void FilterBar::onTorrentsChanged(torrent_ids_t const& ids, Torrent::fields_t const& changed_fields)
{
Q_UNUSED(ids);
Q_UNUSED(changed_fields);
recountSoon();
}
void FilterBar::onTextChanged(QString const& str)
{
if (!is_bootstrapping_)

View File

@@ -12,6 +12,9 @@
#include <QWidget>
#include "Torrent.h"
#include "Typedefs.h"
class QLabel;
class QLineEdit;
class QStandardItemModel;
@@ -44,6 +47,7 @@ private slots:
void onActivityIndexChanged(int index);
void onTrackerIndexChanged(int index);
void onTextChanged(QString const&);
void onTorrentsChanged(torrent_ids_t const&, Torrent::fields_t const& fields);
private:
Prefs& prefs_;

View File

@@ -245,7 +245,7 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
connect(&model_, &TorrentModel::modelReset, this, refresh_soon_adapter);
connect(&model_, &TorrentModel::rowsRemoved, this, refresh_soon_adapter);
connect(&model_, &TorrentModel::rowsInserted, this, refresh_soon_adapter);
connect(&model_, &TorrentModel::dataChanged, this, refresh_soon_adapter);
connect(&model_, &TorrentModel::torrentsChanged, this, refresh_soon_adapter);
ui_.listView->setModel(&filter_model_);
connect(ui_.listView->selectionModel(), &QItemSelectionModel::selectionChanged, refresh_action_sensitivity_soon);

View File

@@ -505,9 +505,9 @@ void Torrent::updateMimeIcon()
****
***/
bool Torrent::update(tr_quark const* keys, tr_variant const* const* values, size_t n)
Torrent::fields_t Torrent::update(tr_quark const* keys, tr_variant const* const* values, size_t n)
{
bool changed = false;
auto changed = fields_t{};
for (size_t pos = 0; pos < n; ++pos)
{
@@ -517,71 +517,71 @@ bool Torrent::update(tr_quark const* keys, tr_variant const* const* values, size
switch (key)
{
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
field_changed = change(field ## _, child); break;
#define HANDLE_KEY(key, field, bit) case TR_KEY_ ## key: \
field_changed = change(field ## _, child); \
changed.set(bit, field_changed); \
break;
HANDLE_KEY(activityDate, activity_date)
HANDLE_KEY(addedDate, added_date)
HANDLE_KEY(bandwidthPriority, bandwidth_priority)
HANDLE_KEY(comment, comment)
HANDLE_KEY(corruptEver, failed_ever)
HANDLE_KEY(creator, creator)
HANDLE_KEY(dateCreated, date_created)
HANDLE_KEY(desiredAvailable, desired_available)
HANDLE_KEY(downloadDir, download_dir)
HANDLE_KEY(downloadLimit, download_limit) // KB/s
HANDLE_KEY(downloadLimited, download_limited)
HANDLE_KEY(downloadedEver, downloaded_ever)
HANDLE_KEY(editDate, edit_date)
HANDLE_KEY(error, error)
HANDLE_KEY(errorString, error_string)
HANDLE_KEY(eta, eta)
HANDLE_KEY(fileStats, files)
HANDLE_KEY(files, files)
HANDLE_KEY(hashString, hash_string)
HANDLE_KEY(haveUnchecked, have_unchecked)
HANDLE_KEY(haveValid, have_verified)
HANDLE_KEY(honorsSessionLimits, honors_session_limits)
HANDLE_KEY(isFinished, is_finished)
HANDLE_KEY(isPrivate, is_private)
HANDLE_KEY(isStalled, is_stalled)
HANDLE_KEY(leftUntilDone, left_until_done)
HANDLE_KEY(manualAnnounceTime, manual_announce_time)
HANDLE_KEY(metadataPercentComplete, metadata_percent_complete)
HANDLE_KEY(name, name)
HANDLE_KEY(peer_limit, peer_limit)
HANDLE_KEY(peers, peers)
HANDLE_KEY(peersConnected, peers_connected)
HANDLE_KEY(peersGettingFromUs, peers_getting_from_us)
HANDLE_KEY(peersSendingToUs, peers_sending_to_us)
HANDLE_KEY(percentDone, percent_done)
HANDLE_KEY(pieceCount, piece_count)
HANDLE_KEY(pieceSize, piece_size)
HANDLE_KEY(queuePosition, queue_position)
HANDLE_KEY(rateDownload, download_speed)
HANDLE_KEY(rateUpload, upload_speed)
HANDLE_KEY(recheckProgress, recheck_progress)
HANDLE_KEY(seedIdleLimit, seed_idle_limit)
HANDLE_KEY(seedIdleMode, seed_idle_mode)
HANDLE_KEY(seedRatioLimit, seed_ratio_limit)
HANDLE_KEY(seedRatioMode, seed_ratio_mode)
HANDLE_KEY(sizeWhenDone, size_when_done)
HANDLE_KEY(startDate, start_date)
HANDLE_KEY(status, status)
HANDLE_KEY(totalSize, total_size)
HANDLE_KEY(trackerStats, tracker_stats)
HANDLE_KEY(trackers, tracker_stats)
HANDLE_KEY(uploadLimit, upload_limit) // KB/s
HANDLE_KEY(uploadLimited, upload_limited)
HANDLE_KEY(uploadedEver, uploaded_ever)
HANDLE_KEY(webseedsSendingToUs, webseeds_sending_to_us)
HANDLE_KEY(activityDate, activity_date, ACTIVITY_DATE)
HANDLE_KEY(addedDate, added_date, ADDED_DATE)
HANDLE_KEY(bandwidthPriority, bandwidth_priority, BANDWIDTH_PRIORITY)
HANDLE_KEY(comment, comment, COMMENT)
HANDLE_KEY(corruptEver, failed_ever, FAILED_EVER)
HANDLE_KEY(creator, creator, CREATOR)
HANDLE_KEY(dateCreated, date_created, DATE_CREATED)
HANDLE_KEY(desiredAvailable, desired_available, DESIRED_AVAILABLE)
HANDLE_KEY(downloadDir, download_dir, DOWNLOAD_DIR)
HANDLE_KEY(downloadLimit, download_limit, DOWNLOAD_LIMIT) // KB/s
HANDLE_KEY(downloadLimited, download_limited, DOWNLOAD_LIMITED)
HANDLE_KEY(downloadedEver, downloaded_ever, DOWNLOADED_EVER)
HANDLE_KEY(editDate, edit_date, EDIT_DATE)
HANDLE_KEY(error, error, ERROR)
HANDLE_KEY(errorString, error_string, ERROR_STRING)
HANDLE_KEY(eta, eta, ETA)
HANDLE_KEY(fileStats, files, FILES)
HANDLE_KEY(files, files, FILES)
HANDLE_KEY(hashString, hash_string, HASH_STRING)
HANDLE_KEY(haveUnchecked, have_unchecked, HAVE_UNCHECKED)
HANDLE_KEY(haveValid, have_verified, HAVE_VERIFIED)
HANDLE_KEY(honorsSessionLimits, honors_session_limits, HONORS_SESSION_LIMITS)
HANDLE_KEY(isFinished, is_finished, IS_FINISHED)
HANDLE_KEY(isPrivate, is_private, IS_PRIVATE)
HANDLE_KEY(isStalled, is_stalled, IS_STALLED)
HANDLE_KEY(leftUntilDone, left_until_done, LEFT_UNTIL_DONE)
HANDLE_KEY(manualAnnounceTime, manual_announce_time, MANUAL_ANNOUNCE_TIME)
HANDLE_KEY(metadataPercentComplete, metadata_percent_complete, METADATA_PERCENT_COMPLETE)
HANDLE_KEY(name, name, NAME)
HANDLE_KEY(peer_limit, peer_limit, PEER_LIMIT)
HANDLE_KEY(peers, peers, PEERS)
HANDLE_KEY(peersConnected, peers_connected, PEERS_CONNECTED)
HANDLE_KEY(peersGettingFromUs, peers_getting_from_us, PEERS_GETTING_FROM_US)
HANDLE_KEY(peersSendingToUs, peers_sending_to_us, PEERS_SENDING_TO_US)
HANDLE_KEY(percentDone, percent_done, PERCENT_DONE)
HANDLE_KEY(pieceCount, piece_count, PIECE_COUNT)
HANDLE_KEY(pieceSize, piece_size, PIECE_SIZE)
HANDLE_KEY(queuePosition, queue_position, QUEUE_POSITION)
HANDLE_KEY(rateDownload, download_speed, DOWNLOAD_SPEED)
HANDLE_KEY(rateUpload, upload_speed, UPLOAD_SPEED)
HANDLE_KEY(recheckProgress, recheck_progress, RECHECK_PROGRESS)
HANDLE_KEY(seedIdleLimit, seed_idle_limit, SEED_IDLE_LIMIT)
HANDLE_KEY(seedIdleMode, seed_idle_mode, SEED_IDLE_MODE)
HANDLE_KEY(seedRatioLimit, seed_ratio_limit, SEED_RATIO_LIMIT)
HANDLE_KEY(seedRatioMode, seed_ratio_mode, SEED_RATIO_MODE)
HANDLE_KEY(sizeWhenDone, size_when_done, SIZE_WHEN_DONE)
HANDLE_KEY(startDate, start_date, START_DATE)
HANDLE_KEY(status, status, STATUS)
HANDLE_KEY(totalSize, total_size, TOTAL_SIZE)
HANDLE_KEY(trackerStats, tracker_stats, TRACKER_STATS)
HANDLE_KEY(trackers, tracker_stats, TRACKER_STATS)
HANDLE_KEY(uploadLimit, upload_limit, UPLOAD_LIMIT) // KB/s
HANDLE_KEY(uploadLimited, upload_limited, UPLOAD_LIMITED)
HANDLE_KEY(uploadedEver, uploaded_ever, UPLOADED_EVER)
HANDLE_KEY(webseedsSendingToUs, webseeds_sending_to_us, WEBSEEDS_SENDING_TO_US)
#undef HANDLE_KEY
default:
break;
}
changed = changed || field_changed;
if (field_changed)
{
switch (key)

View File

@@ -8,6 +8,7 @@
#pragma once
#include <bitset>
#include <ctime> // time_t
#include <QIcon>
@@ -499,8 +500,6 @@ public:
return isWaitingToDownload() || isWaitingToSeed();
}
bool update(tr_quark const* keys, tr_variant const* const* values, size_t n);
QIcon getMimeTypeIcon() const
{
return icon_;
@@ -513,10 +512,72 @@ public:
static KeyList const MainInfoKeys;
static KeyList const MainStatKeys;
enum Field
{
ACTIVITY_DATE,
ADDED_DATE,
BANDWIDTH_PRIORITY,
COMMENT,
CREATOR,
DATE_CREATED,
DESIRED_AVAILABLE,
DOWNLOADED_EVER,
DOWNLOAD_DIR,
DOWNLOAD_LIMIT,
DOWNLOAD_LIMITED,
DOWNLOAD_SPEED,
EDIT_DATE,
ERROR,
ERROR_STRING,
ETA,
FAILED_EVER,
FILES,
HASH_STRING,
HAVE_UNCHECKED,
HAVE_VERIFIED,
HONORS_SESSION_LIMITS,
ICON,
IS_FINISHED,
IS_PRIVATE,
IS_STALLED,
LEFT_UNTIL_DONE,
MANUAL_ANNOUNCE_TIME,
METADATA_PERCENT_COMPLETE,
NAME,
PEERS,
PEERS_CONNECTED,
PEERS_GETTING_FROM_US,
PEERS_SENDING_TO_US,
PEER_LIMIT,
PERCENT_DONE,
PIECE_COUNT,
PIECE_SIZE,
QUEUE_POSITION,
RECHECK_PROGRESS,
SEED_IDLE_LIMIT,
SEED_IDLE_MODE,
SEED_RATIO_LIMIT,
SEED_RATIO_MODE,
SIZE_WHEN_DONE,
START_DATE,
STATUS,
TOTAL_SIZE,
TRACKER_STATS,
UPLOADED_EVER,
UPLOAD_LIMIT,
UPLOAD_LIMITED,
UPLOAD_SPEED,
WEBSEEDS_SENDING_TO_US,
N_FIELDS
};
using fields_t = std::bitset<N_FIELDS>;
fields_t update(tr_quark const* keys, tr_variant const* const* values, size_t n);
private:
void updateMimeIcon();
private:
int const id_;
bool download_limited_ = {};

View File

@@ -161,6 +161,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
auto instantiated = torrents_t{};
auto needinfo = torrent_ids_t{};
auto processed = torrents_t{};
auto changed_fields = Torrent::fields_t{};
auto const now = time(nullptr);
auto const recently_added = [now](auto const& tor)
@@ -248,7 +249,6 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
}
Torrent* tor = getTorrentFromId(id);
std::optional<uint64_t> left_until_done;
bool is_new = false;
if (tor == nullptr)
@@ -257,19 +257,16 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
instantiated.push_back(tor);
is_new = true;
}
else
{
left_until_done = tor->leftUntilDone();
}
auto const old_edit_date = tor->dateEdited();
auto const fields = tor->update(keys.data(), values.data(), keys.size());
if (tor->update(keys.data(), values.data(), keys.size()))
if (fields.any())
{
changed_fields |= fields;
changed.insert(id);
}
if (old_edit_date != tor->dateEdited())
if (fields.test(Torrent::EDIT_DATE))
{
edited.insert(id);
}
@@ -285,7 +282,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
already_added_.insert(id);
}
if (left_until_done && (*left_until_done > 0) && (tor->leftUntilDone() == 0) && (tor->downloadedEver() > 0))
if (fields.test(Torrent::LEFT_UNTIL_DONE) && (tor->leftUntilDone() == 0) && (tor->downloadedEver() > 0))
{
completed.insert(id);
}
@@ -324,7 +321,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
if (!changed.empty())
{
emit torrentsChanged(changed);
emit torrentsChanged(changed, changed_fields);
}
if (!completed.empty())

View File

@@ -12,13 +12,13 @@
#include <vector>
#include <QAbstractListModel>
// #include <QVector>
#include <QVector>
#include <Typedefs.h>
#include "Torrent.h"
#include "Typedefs.h"
class Prefs;
class Speed;
class Torrent;
extern "C"
{
@@ -57,7 +57,7 @@ public slots:
signals:
void torrentsAdded(torrent_ids_t const&);
void torrentsChanged(torrent_ids_t const&);
void torrentsChanged(torrent_ids_t const&, Torrent::fields_t const& fields);
void torrentsCompleted(torrent_ids_t const&);
void torrentsEdited(torrent_ids_t const&);
void torrentsNeedInfo(torrent_ids_t const&);