Merge pull request #13400 from glassez/sequential

Improve sequentialDownload/firstLastPiecePriority handling
This commit is contained in:
Vladimir Golovnev 2020-09-20 08:00:33 +03:00 committed by GitHub
commit 04d345251e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 61 deletions

View file

@ -1974,7 +1974,6 @@ LoadTorrentParams Session::initLoadTorrentParams(const AddTorrentParams &addTorr
loadTorrentParams.name = addTorrentParams.name; loadTorrentParams.name = addTorrentParams.name;
loadTorrentParams.tags = addTorrentParams.tags; loadTorrentParams.tags = addTorrentParams.tags;
loadTorrentParams.sequential = addTorrentParams.sequential;
loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority; loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority;
loadTorrentParams.hasSeedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping loadTorrentParams.hasSeedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping
loadTorrentParams.hasRootFolder = ((addTorrentParams.createSubfolder == TriStateBool::Undefined) loadTorrentParams.hasRootFolder = ((addTorrentParams.createSubfolder == TriStateBool::Undefined)
@ -2079,6 +2078,11 @@ bool Session::addTorrent_impl(const AddTorrentParams &addTorrentParams, const Ma
// Preallocation mode // Preallocation mode
p.storage_mode = isPreallocationEnabled() ? lt::storage_mode_allocate : lt::storage_mode_sparse; p.storage_mode = isPreallocationEnabled() ? lt::storage_mode_allocate : lt::storage_mode_sparse;
if (addTorrentParams.sequential)
p.flags |= lt::torrent_flags::sequential_download;
else
p.flags &= ~lt::torrent_flags::sequential_download;
// Seeding mode // Seeding mode
// Skip checking and directly start seeding // Skip checking and directly start seeding
if (addTorrentParams.skipChecking) if (addTorrentParams.skipChecking)
@ -3983,7 +3987,6 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m
torrentParams.name = fromLTString(root.dict_find_string_value("qBt-name")); torrentParams.name = fromLTString(root.dict_find_string_value("qBt-name"));
torrentParams.savePath = Profile::instance()->fromPortablePath( torrentParams.savePath = Profile::instance()->fromPortablePath(
Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath")))); Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath"))));
torrentParams.sequential = root.dict_find_int_value("qBt-sequential");
torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus"); torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus");
torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority"); torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority");
torrentParams.hasRootFolder = root.dict_find_int_value("qBt-hasRootFolder"); torrentParams.hasRootFolder = root.dict_find_int_value("qBt-hasRootFolder");
@ -4043,9 +4046,16 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m
if (addedTimeNode.type() == lt::bdecode_node::int_t) if (addedTimeNode.type() == lt::bdecode_node::int_t)
p.added_time = addedTimeNode.int_value(); p.added_time = addedTimeNode.int_value();
const lt::bdecode_node sequentialNode = root.dict_find("qBt-sequential");
if (sequentialNode.type() == lt::bdecode_node::int_t) {
if (static_cast<bool>(sequentialNode.int_value()))
p.flags |= lt::torrent_flags::sequential_download;
else
p.flags &= ~lt::torrent_flags::sequential_download;
}
if (torrentParams.name.isEmpty() && !p.name.empty()) if (torrentParams.name.isEmpty() && !p.name.empty())
torrentParams.name = QString::fromStdString(p.name); torrentParams.name = QString::fromStdString(p.name);
} }
// === END DEPRECATED CODE === // // === END DEPRECATED CODE === //
else { else {

View file

@ -126,6 +126,7 @@ TorrentHandleImpl::TorrentHandleImpl(Session *session, const lt::torrent_handle
, m_hasSeedStatus(params.hasSeedStatus) , m_hasSeedStatus(params.hasSeedStatus)
, m_hasRootFolder(params.hasRootFolder) , m_hasRootFolder(params.hasRootFolder)
, m_useAutoTMM(params.savePath.isEmpty()) , m_useAutoTMM(params.savePath.isEmpty())
, m_hasFirstLastPiecePriority(params.firstLastPiecePriority)
, m_ltAddTorrentParams(params.ltAddTorrentParams) , m_ltAddTorrentParams(params.ltAddTorrentParams)
{ {
if (m_useAutoTMM) if (m_useAutoTMM)
@ -134,22 +135,13 @@ TorrentHandleImpl::TorrentHandleImpl(Session *session, const lt::torrent_handle
updateStatus(); updateStatus();
m_hash = InfoHash(m_nativeStatus.info_hash); m_hash = InfoHash(m_nativeStatus.info_hash);
// NB: the following two if statements are present because we don't want if (hasMetadata()) {
// to set either sequential download or first/last piece priority to false applyFirstLastPiecePriority(m_hasFirstLastPiecePriority);
// if their respective flags in data are false when a torrent is being
// resumed. This is because, in that circumstance, this constructor is
// called with those flags set to false, even if the torrent was set to
// download sequentially or have first/last piece priority enabled when
// its resume data was saved. These two settings are restored later. But
// if we set them to false now, both will erroneously not be restored.
if (!params.restored || params.sequential)
setSequentialDownload(params.sequential);
if (!params.restored || params.firstLastPiecePriority)
setFirstLastPiecePriority(params.firstLastPiecePriority);
if (!params.restored && hasMetadata()) { if (!params.restored) {
if (filesCount() == 1) if (filesCount() == 1)
m_hasRootFolder = false; m_hasRootFolder = false;
}
} }
// TODO: Remove the following upgrade code in v.4.4 // TODO: Remove the following upgrade code in v.4.4
@ -749,21 +741,7 @@ bool TorrentHandleImpl::isSequentialDownload() const
bool TorrentHandleImpl::hasFirstLastPiecePriority() const bool TorrentHandleImpl::hasFirstLastPiecePriority() const
{ {
if (!hasMetadata()) return m_hasFirstLastPiecePriority;
return m_needsToSetFirstLastPiecePriority;
const std::vector<lt::download_priority_t> filePriorities = nativeHandle().get_file_priorities();
for (int i = 0; i < static_cast<int>(filePriorities.size()); ++i) {
if (filePriorities[i] <= lt::download_priority_t {0})
continue;
const TorrentInfo::PieceRange extremities = info().filePieces(i);
const lt::download_priority_t firstPiecePrio = nativeHandle().piece_priority(lt::piece_index_t {extremities.first()});
const lt::download_priority_t lastPiecePrio = nativeHandle().piece_priority(lt::piece_index_t {extremities.last()});
return ((firstPiecePrio == lt::download_priority_t {7}) && (lastPiecePrio == lt::download_priority_t {7}));
}
return false;
} }
TorrentState TorrentHandleImpl::state() const TorrentState TorrentHandleImpl::state() const
@ -1245,17 +1223,24 @@ void TorrentHandleImpl::setSequentialDownload(const bool enable)
void TorrentHandleImpl::setFirstLastPiecePriority(const bool enabled) void TorrentHandleImpl::setFirstLastPiecePriority(const bool enabled)
{ {
setFirstLastPiecePriorityImpl(enabled); if (m_hasFirstLastPiecePriority == enabled)
return;
m_hasFirstLastPiecePriority = enabled;
if (hasMetadata())
applyFirstLastPiecePriority(enabled);
LogMsg(tr("Download first and last piece first: %1, torrent: '%2'")
.arg((enabled ? tr("On") : tr("Off")), name()));
saveResumeData();
} }
void TorrentHandleImpl::setFirstLastPiecePriorityImpl(const bool enabled, const QVector<DownloadPriority> &updatedFilePrio) void TorrentHandleImpl::applyFirstLastPiecePriority(const bool enabled, const QVector<DownloadPriority> &updatedFilePrio)
{ {
// Download first and last pieces first for every file in the torrent Q_ASSERT(hasMetadata());
if (!hasMetadata()) { // Download first and last pieces first for every file in the torrent
m_needsToSetFirstLastPiecePriority = enabled;
return;
}
const std::vector<lt::download_priority_t> filePriorities = !updatedFilePrio.isEmpty() ? toLTDownloadPriorities(updatedFilePrio) const std::vector<lt::download_priority_t> filePriorities = !updatedFilePrio.isEmpty() ? toLTDownloadPriorities(updatedFilePrio)
: nativeHandle().get_file_priorities(); : nativeHandle().get_file_priorities();
@ -1281,11 +1266,6 @@ void TorrentHandleImpl::setFirstLastPiecePriorityImpl(const bool enabled, const
} }
m_nativeHandle.prioritize_pieces(piecePriorities); m_nativeHandle.prioritize_pieces(piecePriorities);
LogMsg(tr("Download first and last piece first: %1, torrent: '%2'")
.arg((enabled ? tr("On") : tr("Off")), name()));
saveResumeData();
} }
void TorrentHandleImpl::pause() void TorrentHandleImpl::pause()
@ -1500,10 +1480,9 @@ void TorrentHandleImpl::handleSaveResumeDataAlert(const lt::save_resume_data_ale
const bool useDummyResumeData = !p; const bool useDummyResumeData = !p;
if (useDummyResumeData) { if (useDummyResumeData) {
resumeData["qBt-magnetUri"] = createMagnetURI().toStdString(); resumeData["qBt-magnetUri"] = createMagnetURI().toStdString();
// Both firstLastPiecePriority and sequential need to be stored in the // sequentialDownload needs to be stored in the
// resume data if there is no metadata, otherwise they won't be // resume data if there is no metadata, otherwise they won't be
// restored if qBittorrent quits before the metadata are retrieved: // restored if qBittorrent quits before the metadata are retrieved:
resumeData["qBt-firstLastPiecePriority"] = hasFirstLastPiecePriority();
resumeData["qBt-sequential"] = isSequentialDownload(); resumeData["qBt-sequential"] = isSequentialDownload();
resumeData["qBt-addedTime"] = addedTime().toSecsSinceEpoch(); resumeData["qBt-addedTime"] = addedTime().toSecsSinceEpoch();
@ -1518,6 +1497,7 @@ void TorrentHandleImpl::handleSaveResumeDataAlert(const lt::save_resume_data_ale
resumeData["qBt-name"] = m_name.toStdString(); resumeData["qBt-name"] = m_name.toStdString();
resumeData["qBt-seedStatus"] = m_hasSeedStatus; resumeData["qBt-seedStatus"] = m_hasSeedStatus;
resumeData["qBt-hasRootFolder"] = m_hasRootFolder; resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
resumeData["qBt-firstLastPiecePriority"] = m_hasFirstLastPiecePriority;
m_session->handleTorrentResumeDataReady(this, resumeDataPtr); m_session->handleTorrentResumeDataReady(this, resumeDataPtr);
} }
@ -1649,12 +1629,10 @@ void TorrentHandleImpl::handleMetadataReceivedAlert(const lt::metadata_received_
m_session->handleTorrentPaused(this); m_session->handleTorrentPaused(this);
} }
// If first/last piece priority was specified when adding this torrent, we can set it // If first/last piece priority was specified when adding this torrent,
// now that we have metadata: // we should apply it now that we have metadata:
if (m_needsToSetFirstLastPiecePriority) { if (m_hasFirstLastPiecePriority)
setFirstLastPiecePriority(true); applyFirstLastPiecePriority(true);
m_needsToSetFirstLastPiecePriority = false;
}
} }
void TorrentHandleImpl::handlePerformanceAlert(const lt::performance_alert *p) const void TorrentHandleImpl::handlePerformanceAlert(const lt::performance_alert *p) const
@ -1898,9 +1876,6 @@ void TorrentHandleImpl::prioritizeFiles(const QVector<DownloadPriority> &priorit
if (!hasMetadata()) return; if (!hasMetadata()) return;
if (priorities.size() != filesCount()) return; if (priorities.size() != filesCount()) return;
// Save first/last piece first option state
const bool firstLastPieceFirst = hasFirstLastPiecePriority();
// Reset 'm_hasSeedStatus' if needed in order to react again to // Reset 'm_hasSeedStatus' if needed in order to react again to
// 'torrent_finished_alert' and eg show tray notifications // 'torrent_finished_alert' and eg show tray notifications
const QVector<qreal> progress = filesProgress(); const QVector<qreal> progress = filesProgress();
@ -1918,8 +1893,8 @@ void TorrentHandleImpl::prioritizeFiles(const QVector<DownloadPriority> &priorit
m_nativeHandle.prioritize_files(toLTDownloadPriorities(priorities)); m_nativeHandle.prioritize_files(toLTDownloadPriorities(priorities));
// Restore first/last piece first option if necessary // Restore first/last piece first option if necessary
if (firstLastPieceFirst) if (m_hasFirstLastPiecePriority)
setFirstLastPiecePriorityImpl(true, priorities); applyFirstLastPiecePriority(true, priorities);
} }
QVector<qreal> TorrentHandleImpl::availableFileFractions() const QVector<qreal> TorrentHandleImpl::availableFileFractions() const

View file

@ -62,7 +62,6 @@ namespace BitTorrent
QString category; QString category;
QSet<QString> tags; QSet<QString> tags;
QString savePath; QString savePath;
bool sequential = false;
bool firstLastPiecePriority = false; bool firstLastPiecePriority = false;
bool hasSeedStatus = false; bool hasSeedStatus = false;
bool hasRootFolder = true; bool hasRootFolder = true;
@ -281,7 +280,7 @@ namespace BitTorrent
void move_impl(QString path, MoveStorageMode mode); void move_impl(QString path, MoveStorageMode mode);
void moveStorage(const QString &newPath, MoveStorageMode mode); void moveStorage(const QString &newPath, MoveStorageMode mode);
void manageIncompleteFiles(); void manageIncompleteFiles();
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {}); void applyFirstLastPiecePriority(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
Session *const m_session; Session *const m_session;
lt::torrent_handle m_nativeHandle; lt::torrent_handle m_nativeHandle;
@ -315,7 +314,7 @@ namespace BitTorrent
bool m_fastresumeDataRejected = false; bool m_fastresumeDataRejected = false;
bool m_hasMissingFiles = false; bool m_hasMissingFiles = false;
bool m_hasRootFolder; bool m_hasRootFolder;
bool m_needsToSetFirstLastPiecePriority = false; bool m_hasFirstLastPiecePriority = false;
bool m_useAutoTMM; bool m_useAutoTMM;
bool m_unchecked = false; bool m_unchecked = false;