Browse Source

Merge pull request #16268 from glassez/fix-15955

Store hybrid torrents using "torrent ID" as basename
adaptive-webui-19844
Vladimir Golovnev 3 years ago committed by GitHub
parent
commit
adf7c4ffb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      src/base/bittorrent/infohash.cpp
  2. 6
      src/base/bittorrent/infohash.h
  3. 117
      src/base/bittorrent/session.cpp
  4. 36
      src/base/digest32.h

7
src/base/bittorrent/infohash.cpp

@ -36,6 +36,13 @@ BitTorrent::InfoHash::InfoHash(const WrappedType &nativeHash)
{ {
} }
#ifdef QBT_USES_LIBTORRENT2
BitTorrent::InfoHash::InfoHash(const SHA1Hash &v1, const SHA256Hash &v2)
: InfoHash {WrappedType(v1, v2)}
{
}
#endif
bool BitTorrent::InfoHash::isValid() const bool BitTorrent::InfoHash::isValid() const
{ {
return m_valid; return m_valid;

6
src/base/bittorrent/infohash.h

@ -65,6 +65,9 @@ namespace BitTorrent
InfoHash() = default; InfoHash() = default;
InfoHash(const WrappedType &nativeHash); InfoHash(const WrappedType &nativeHash);
#ifdef QBT_USES_LIBTORRENT2
InfoHash(const SHA1Hash &v1, const SHA256Hash &v2);
#endif
bool isValid() const; bool isValid() const;
SHA1Hash v1() const; SHA1Hash v1() const;
@ -85,3 +88,6 @@ namespace BitTorrent
} }
Q_DECLARE_METATYPE(BitTorrent::TorrentID) Q_DECLARE_METATYPE(BitTorrent::TorrentID)
// We can declare it as Q_MOVABLE_TYPE to improve performance
// since base type uses QSharedDataPointer as the only member
Q_DECLARE_TYPEINFO(BitTorrent::TorrentID, Q_MOVABLE_TYPE);

117
src/base/bittorrent/session.cpp

@ -4346,53 +4346,114 @@ void Session::startUpTorrents()
const QVector<TorrentID> torrents = startupStorage->registeredTorrents(); const QVector<TorrentID> torrents = startupStorage->registeredTorrents();
int resumedTorrentsCount = 0; int resumedTorrentsCount = 0;
QVector<TorrentID> queue; QVector<TorrentID> queue;
for (const TorrentID &torrentID : torrents) #ifdef QBT_USES_LIBTORRENT2
const QSet<TorrentID> indexedTorrents {torrents.cbegin(), torrents.cend()};
QSet<TorrentID> skippedIDs;
#endif
for (TorrentID torrentID : torrents)
{ {
#ifdef QBT_USES_LIBTORRENT2
if (skippedIDs.contains(torrentID))
continue;
#endif
const std::optional<LoadTorrentParams> loadResumeDataResult = startupStorage->load(torrentID); const std::optional<LoadTorrentParams> loadResumeDataResult = startupStorage->load(torrentID);
if (loadResumeDataResult) if (!loadResumeDataResult)
{ {
LoadTorrentParams resumeData = *loadResumeDataResult; LogMsg(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.")
bool needStore = false; .arg(torrentID.toString()), Log::CRITICAL);
continue;
}
LoadTorrentParams resumeData = *loadResumeDataResult;
bool needStore = false;
if (m_resumeDataStorage != startupStorage) #ifdef QBT_USES_LIBTORRENT2
const lt::info_hash_t infoHash = (resumeData.ltAddTorrentParams.ti
? resumeData.ltAddTorrentParams.ti->info_hashes()
: resumeData.ltAddTorrentParams.info_hashes);
if (infoHash.has_v1() && infoHash.has_v2())
{
const auto torrentIDv1 = TorrentID::fromInfoHash(lt::info_hash_t(infoHash.v1));
const auto torrentIDv2 = TorrentID::fromInfoHash(infoHash);
if (torrentID == torrentIDv2)
{ {
needStore = true; if (indexedTorrents.contains(torrentIDv1))
if (isQueueingSystemEnabled() && !resumeData.hasSeedStatus) {
queue.append(torrentID); // if we has no metadata trying to find it in alternative "resume data"
} if (!resumeData.ltAddTorrentParams.ti)
{
const std::optional<LoadTorrentParams> loadAltResumeDataResult = startupStorage->load(torrentIDv1);
if (loadAltResumeDataResult)
{
LoadTorrentParams altResumeData = *loadAltResumeDataResult;
resumeData.ltAddTorrentParams.ti = altResumeData.ltAddTorrentParams.ti;
}
}
// TODO: Remove the following upgrade code in v4.5 // remove alternative "resume data" and skip the attempt to load it
// == BEGIN UPGRADE CODE == m_resumeDataStorage->remove(torrentIDv1);
if (m_needUpgradeDownloadPath && isDownloadPathEnabled()) skippedIDs.insert(torrentIDv1);
}
}
else
{ {
if (!resumeData.useAutoTMM) torrentID = torrentIDv2;
needStore = true;
m_resumeDataStorage->remove(torrentIDv1);
if (indexedTorrents.contains(torrentID))
{ {
resumeData.downloadPath = downloadPath(); skippedIDs.insert(torrentID);
needStore = true;
const std::optional<LoadTorrentParams> loadPreferredResumeDataResult = startupStorage->load(torrentID);
if (loadPreferredResumeDataResult)
{
LoadTorrentParams preferredResumeData = *loadPreferredResumeDataResult;
std::shared_ptr<lt::torrent_info> ti = resumeData.ltAddTorrentParams.ti;
if (!preferredResumeData.ltAddTorrentParams.ti)
preferredResumeData.ltAddTorrentParams.ti = ti;
resumeData = preferredResumeData;
}
} }
} }
// == END UPGRADE CODE == }
#endif
if (needStore) if (m_resumeDataStorage != startupStorage)
m_resumeDataStorage->store(torrentID, resumeData); {
needStore = true;
if (isQueueingSystemEnabled() && !resumeData.hasSeedStatus)
queue.append(torrentID);
}
qDebug() << "Starting up torrent" << torrentID.toString() << "..."; // TODO: Remove the following upgrade code in v4.6
if (!loadTorrent(resumeData)) // == BEGIN UPGRADE CODE ==
if (m_needUpgradeDownloadPath && isDownloadPathEnabled())
{
if (!resumeData.useAutoTMM)
{ {
LogMsg(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.") resumeData.downloadPath = downloadPath();
.arg(torrentID.toString()), Log::CRITICAL); needStore = true;
} }
}
// == END UPGRADE CODE ==
// process add torrent messages before message queue overflow if (needStore)
if ((resumedTorrentsCount % 100) == 0) readAlerts(); m_resumeDataStorage->store(torrentID, resumeData);
++resumedTorrentsCount; qDebug() << "Starting up torrent" << torrentID.toString() << "...";
} if (!loadTorrent(resumeData))
else
{ {
LogMsg(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.") LogMsg(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.")
.arg(torrentID.toString()), Log::CRITICAL); .arg(torrentID.toString()), Log::CRITICAL);
} }
// process add torrent messages before message queue overflow
if ((resumedTorrentsCount % 100) == 0) readAlerts();
++resumedTorrentsCount;
} }
if (m_resumeDataStorage != startupStorage) if (m_resumeDataStorage != startupStorage)

36
src/base/digest32.h

@ -32,6 +32,8 @@
#include <QByteArray> #include <QByteArray>
#include <QHash> #include <QHash>
#include <QSharedData>
#include <QSharedDataPointer>
#include <QString> #include <QString>
template <int N> template <int N>
@ -41,13 +43,15 @@ public:
using UnderlyingType = lt::digest32<N>; using UnderlyingType = lt::digest32<N>;
Digest32() = default; Digest32() = default;
Digest32(const Digest32 &other) = default;
Digest32(Digest32 &&other) = default;
Digest32(const UnderlyingType &nativeDigest) Digest32(const UnderlyingType &nativeDigest)
: m_valid {true}
, m_nativeDigest {nativeDigest}
{ {
m_dataPtr->valid = true;
m_dataPtr->nativeDigest = nativeDigest;
const QByteArray raw = QByteArray::fromRawData(nativeDigest.data(), length()); const QByteArray raw = QByteArray::fromRawData(nativeDigest.data(), length());
m_hashString = QString::fromLatin1(raw.toHex()); m_dataPtr->hashString = QString::fromLatin1(raw.toHex());
} }
static constexpr int length() static constexpr int length()
@ -57,12 +61,15 @@ public:
bool isValid() const bool isValid() const
{ {
return m_valid; return m_dataPtr->valid;
} }
Digest32 &operator=(const Digest32 &other) = default;
Digest32 &operator=(Digest32 &&other) = default;
operator UnderlyingType() const operator UnderlyingType() const
{ {
return m_nativeDigest; return m_dataPtr->nativeDigest;
} }
static Digest32 fromString(const QString &digestString) static Digest32 fromString(const QString &digestString)
@ -75,22 +82,27 @@ public:
return {}; return {};
Digest32 result; Digest32 result;
result.m_valid = true; result.m_dataPtr->valid = true;
result.m_hashString = digestString; result.m_dataPtr->hashString = digestString;
result.m_nativeDigest.assign(raw.constData()); result.m_dataPtr->nativeDigest.assign(raw.constData());
return result; return result;
} }
QString toString() const QString toString() const
{ {
return m_hashString; return m_dataPtr->hashString;
} }
private: private:
bool m_valid = false; struct Data : public QSharedData
UnderlyingType m_nativeDigest; {
QString m_hashString; bool valid = false;
UnderlyingType nativeDigest;
QString hashString;
};
QSharedDataPointer<Data> m_dataPtr {new Data};
}; };
template <int N> template <int N>

Loading…
Cancel
Save