From c3a64b3d6c75fd1b91eb69f9ee2da89146ccec15 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sun, 13 Feb 2022 08:07:30 +0300 Subject: [PATCH] Cache file priorities Speedup access to file priorities by avoiding extra blocking call to libtorrent thread. Improve the Torrent interface by hiding the asynchrony of file priority changes behind the scenes. PR #16425. --- src/base/bittorrent/torrentimpl.cpp | 47 +++++++++++++++++------------ src/base/bittorrent/torrentimpl.h | 3 +- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 8543f33c7..e90574808 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -234,6 +234,14 @@ namespace status.pieces = params.have_pieces; status.verified_pieces = params.verified_pieces; } + + template + Vector resized(const Vector &inVector, const typename Vector::size_type size, const typename Vector::value_type &defaultValue) + { + Vector outVector = inVector; + outVector.resize(size, defaultValue); + return outVector; + } } // TorrentImpl @@ -275,16 +283,23 @@ TorrentImpl::TorrentImpl(Session *session, lt::session *nativeSession const int filesCount = m_torrentInfo.filesCount(); m_filePaths.reserve(filesCount); m_indexMap.reserve(filesCount); + m_filePriorities.reserve(filesCount); const std::shared_ptr currentInfo = m_nativeHandle.torrent_file(); const lt::file_storage &fileStorage = currentInfo->files(); + const std::vector filePriorities = + resized(m_ltAddTorrentParams.file_priorities, fileStorage.num_files(), LT::toNative(DownloadPriority::Normal)); for (int i = 0; i < filesCount; ++i) { const lt::file_index_t nativeIndex = m_torrentInfo.nativeIndexes().at(i); m_indexMap[nativeIndex] = i; + Path filePath {fileStorage.file_path(nativeIndex)}; if (filePath.hasExtension(QB_EXT)) filePath.removeExtension(); m_filePaths.append(filePath); + + const auto priority = LT::fromNative(filePriorities[LT::toUnderlyingType(nativeIndex)]); + m_filePriorities.append(priority); } } @@ -821,20 +836,7 @@ PathList TorrentImpl::filePaths() const QVector TorrentImpl::filePriorities() const { - if (!hasMetadata()) - return {}; - - const std::vector fp = m_nativeHandle.get_file_priorities(); - - QVector ret; - ret.reserve(filesCount()); - for (const lt::file_index_t nativeIndex : asConst(m_torrentInfo.nativeIndexes())) - { - const auto priority = LT::fromNative(fp[LT::toUnderlyingType(nativeIndex)]); - ret.append(priority); - } - - return ret; + return m_filePriorities; } TorrentInfo TorrentImpl::info() const @@ -1444,21 +1446,19 @@ void TorrentImpl::setFirstLastPiecePriority(const bool enabled) m_session->handleTorrentNeedSaveResumeData(this); } -void TorrentImpl::applyFirstLastPiecePriority(const bool enabled, const QVector &updatedFilePrio) +void TorrentImpl::applyFirstLastPiecePriority(const bool enabled) { Q_ASSERT(hasMetadata()); // Download first and last pieces first for every file in the torrent - const QVector filePriorities = - !updatedFilePrio.isEmpty() ? updatedFilePrio : this->filePriorities(); std::vector piecePriorities = nativeHandle().get_piece_priorities(); // Updating file priorities is an async operation in libtorrent, when we just updated it and immediately query it // we might get the old/wrong values, so we rely on `updatedFilePrio` in this case. - for (int index = 0; index < filePriorities.size(); ++index) + for (int index = 0; index < m_filePriorities.size(); ++index) { - const DownloadPriority filePrio = filePriorities[index]; + const DownloadPriority filePrio = m_filePriorities[index]; if (filePrio <= DownloadPriority::Ignored) continue; @@ -1499,7 +1499,10 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi const std::shared_ptr metadata = std::const_pointer_cast(m_nativeHandle.torrent_file()); m_torrentInfo = TorrentInfo(*metadata); m_indexMap.reserve(filesCount()); + m_filePriorities.reserve(filesCount()); const auto nativeIndexes = m_torrentInfo.nativeIndexes(); + const std::vector filePriorities = + resized(p.file_priorities, metadata->files().num_files(), LT::toNative(DownloadPriority::Normal)); for (int i = 0; i < fileNames.size(); ++i) { const auto nativeIndex = nativeIndexes.at(i); @@ -1511,6 +1514,9 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi if (filePath.hasExtension(QB_EXT)) filePath.removeExtension(); m_filePaths.append(filePath); + + const auto priority = LT::fromNative(filePriorities[LT::toUnderlyingType(nativeIndex)]); + m_filePriorities.append(priority); } p.save_path = savePath.toString().toStdString(); p.ti = metadata; @@ -2218,9 +2224,10 @@ void TorrentImpl::prioritizeFiles(const QVector &priorities) qDebug() << Q_FUNC_INFO << "Changing files priorities..."; m_nativeHandle.prioritize_files(nativePriorities); + m_filePriorities = priorities; // Restore first/last piece first option if necessary if (m_hasFirstLastPiecePriority) - applyFirstLastPiecePriority(true, priorities); + applyFirstLastPiecePriority(true); } QVector TorrentImpl::availableFileFractions() const diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 1a2f3223b..4de0724dc 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -272,7 +272,7 @@ namespace BitTorrent void adjustStorageLocation(); void moveStorage(const Path &newPath, MoveStorageMode mode); void manageIncompleteFiles(); - void applyFirstLastPiecePriority(bool enabled, const QVector &updatedFilePrio = {}); + void applyFirstLastPiecePriority(bool enabled); void prepareResumeData(const lt::add_torrent_params ¶ms); void endReceivedMetadataHandling(const Path &savePath, const PathList &fileNames); @@ -286,6 +286,7 @@ namespace BitTorrent TorrentInfo m_torrentInfo; PathList m_filePaths; QHash m_indexMap; + QVector m_filePriorities; SpeedMonitor m_speedMonitor; InfoHash m_infoHash;