Browse Source

Fix torrent checking issues

Start all torrents auto-managed to prevent simultaneous checking
of multiple torrents.
Handle checking state of paused torrent to prevent it from being
resumed when qBittorrent is closed until checking isn't complete.
adaptive-webui-19844
Vladimir Golovnev (Glassez) 5 years ago
parent
commit
9399b876eb
No known key found for this signature in database
GPG Key ID: 52A2C7DEE2DFA6F7
  1. 100
      src/base/bittorrent/session.cpp
  2. 1
      src/base/bittorrent/session.h
  3. 54
      src/base/bittorrent/torrenthandle.cpp
  4. 11
      src/base/bittorrent/torrenthandle.h

100
src/base/bittorrent/session.cpp

@ -1861,29 +1861,22 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
hash = magnetUri.hash(); hash = magnetUri.hash();
if (m_loadedMetadata.contains(hash)) { if (m_loadedMetadata.contains(hash)) {
// Adding preloaded torrent // Adding preloaded torrent...
m_loadedMetadata.remove(hash); m_addingTorrents.insert(hash, params);
lt::torrent_handle handle = m_nativeSession->find_torrent(hash);
--m_extraLimit;
lt::torrent_handle handle = m_nativeSession->find_torrent(hash);
// We need to pause it first to create TorrentHandle within the same
// underlying state as in other cases.
try { try {
// Preloaded torrent is in "Upload mode" so we need to disable it
// otherwise the torrent never be downloaded (until application restart)
#if (LIBTORRENT_VERSION_NUM < 10200) #if (LIBTORRENT_VERSION_NUM < 10200)
handle.auto_managed(false); handle.auto_managed(false);
handle.set_upload_mode(false);
#else #else
handle.unset_flags(lt::torrent_flags::auto_managed | lt::torrent_flags::upload_mode); handle.unset_flags(lt::torrent_flags::auto_managed);
#endif #endif
handle.pause(); handle.pause();
} }
catch (const std::exception &) {} catch (const std::exception &) {}
adjustLimits();
// use common 2nd step of torrent addition
m_addingTorrents.insert(hash, params);
createTorrentHandle(handle);
return true; return true;
} }
@ -1923,8 +1916,15 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
if (!fromMagnetUri) { if (!fromMagnetUri) {
if (params.restored) { // load from existing fastresume if (params.restored) { // load from existing fastresume
#if (LIBTORRENT_VERSION_NUM < 10200) #if (LIBTORRENT_VERSION_NUM < 10200)
p.resume_data = std::vector<char> {fastresumeData.constData() // Make sure the torrent will be initially checked and then paused
, (fastresumeData.constData() + fastresumeData.size())}; // to perform some service jobs on it. We will start it if needed.
// (Workaround to easily support libtorrent-1.1
QByteArray patchedFastresumeData = fastresumeData;
patchedFastresumeData.replace("6:pausedi0e", "6:pausedi1e");
patchedFastresumeData.replace("12:auto_managedi0e", "12:auto_managedi1e");
p.resume_data = std::vector<char> {patchedFastresumeData.constData()
, (patchedFastresumeData.constData() + patchedFastresumeData.size())};
p.flags |= lt::add_torrent_params::flag_use_resume_save_path; p.flags |= lt::add_torrent_params::flag_use_resume_save_path;
// Still setup the default parameters and let libtorrent handle // Still setup the default parameters and let libtorrent handle
@ -1975,18 +1975,25 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
p.ti = torrentInfo.nativeInfo(); p.ti = torrentInfo.nativeInfo();
} }
if (!hasCompleteFastresume) {
// Common // Common
#if (LIBTORRENT_VERSION_NUM < 10200) #if (LIBTORRENT_VERSION_NUM < 10200)
p.flags |= lt::add_torrent_params::flag_paused; // Start in pause
p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state
p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked
#else #else
p.flags |= lt::torrent_flags::paused; // Start in pause
p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state
p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked
#endif #endif
// Make sure the torrent will be initially checked and then paused
// to perform some service jobs on it. We will start it if needed.
#if (LIBTORRENT_VERSION_NUM < 10200)
p.flags |= lt::add_torrent_params::flag_paused;
p.flags |= lt::add_torrent_params::flag_auto_managed;
p.flags |= lt::add_torrent_params::flag_stop_when_ready;
#else
p.flags |= lt::torrent_flags::paused;
p.flags |= lt::torrent_flags::auto_managed;
p.flags |= lt::torrent_flags::stop_when_ready;
#endif
if (!hasCompleteFastresume) {
// Limits // Limits
p.max_connections = maxConnectionsPerTorrent(); p.max_connections = maxConnectionsPerTorrent();
p.max_uploads = maxUploadsPerTorrent(); p.max_uploads = maxUploadsPerTorrent();
@ -2012,16 +2019,6 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
p.flags &= ~lt::add_torrent_params::flag_seed_mode; p.flags &= ~lt::add_torrent_params::flag_seed_mode;
#else #else
p.flags &= ~lt::torrent_flags::seed_mode; p.flags &= ~lt::torrent_flags::seed_mode;
#endif
}
if (params.restored && !params.paused) {
// Make sure the torrent will restored in "paused" state
// Then we will start it if needed
#if (LIBTORRENT_VERSION_NUM < 10200)
p.flags |= lt::add_torrent_params::flag_stop_when_ready;
#else
p.flags |= lt::torrent_flags::stop_when_ready;
#endif #endif
} }
} }
@ -2105,6 +2102,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
p.flags &= ~lt::torrent_flags::paused; p.flags &= ~lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed; p.flags &= ~lt::torrent_flags::auto_managed;
#endif #endif
// Solution to avoid accidental file writes // Solution to avoid accidental file writes
#if (LIBTORRENT_VERSION_NUM < 10200) #if (LIBTORRENT_VERSION_NUM < 10200)
p.flags |= lt::add_torrent_params::flag_upload_mode; p.flags |= lt::add_torrent_params::flag_upload_mode;
@ -3872,10 +3870,7 @@ void Session::handleAlert(const lt::alert *a)
case lt::tracker_warning_alert::alert_type: case lt::tracker_warning_alert::alert_type:
case lt::fastresume_rejected_alert::alert_type: case lt::fastresume_rejected_alert::alert_type:
case lt::torrent_checked_alert::alert_type: case lt::torrent_checked_alert::alert_type:
dispatchTorrentAlert(a);
break;
case lt::metadata_received_alert::alert_type: case lt::metadata_received_alert::alert_type:
handleMetadataReceivedAlert(static_cast<const lt::metadata_received_alert*>(a));
dispatchTorrentAlert(a); dispatchTorrentAlert(a);
break; break;
case lt::state_update_alert::alert_type: case lt::state_update_alert::alert_type:
@ -3933,8 +3928,19 @@ void Session::handleAlert(const lt::alert *a)
void Session::dispatchTorrentAlert(const lt::alert *a) void Session::dispatchTorrentAlert(const lt::alert *a)
{ {
TorrentHandle *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash()); TorrentHandle *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
if (torrent) if (torrent) {
torrent->handleAlert(a); torrent->handleAlert(a);
return;
}
switch (a->type()) {
case lt::torrent_paused_alert::alert_type:
handleTorrentPausedAlert(static_cast<const lt::torrent_paused_alert*>(a));
break;
case lt::metadata_received_alert::alert_type:
handleMetadataReceivedAlert(static_cast<const lt::metadata_received_alert*>(a));
break;
}
} }
void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle) void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle)
@ -4064,6 +4070,32 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
} }
} }
void Session::handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p)
{
const InfoHash hash {p->handle.info_hash()};
if (m_loadedMetadata.contains(hash)) {
// Adding preloaded torrent
m_loadedMetadata.remove(hash);
lt::torrent_handle handle = p->handle;
--m_extraLimit;
// Preloaded torrent is in "Upload mode" so we need to disable it
// otherwise the torrent never be downloaded (until application restart)
#if (LIBTORRENT_VERSION_NUM < 10200)
handle.set_upload_mode(false);
handle.auto_managed(true);
#else
handle.unset_flags(lt::torrent_flags::upload_mode);
handle.set_flags(lt::torrent_flags::auto_managed);
#endif
adjustLimits();
// use common 2nd step of torrent addition
createTorrentHandle(handle);
}
}
void Session::handleFileErrorAlert(const lt::file_error_alert *p) void Session::handleFileErrorAlert(const lt::file_error_alert *p)
{ {
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash()); TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());

1
src/base/bittorrent/session.h

@ -551,6 +551,7 @@ namespace BitTorrent
void handleAddTorrentAlert(const lt::add_torrent_alert *p); void handleAddTorrentAlert(const lt::add_torrent_alert *p);
void handleStateUpdateAlert(const lt::state_update_alert *p); void handleStateUpdateAlert(const lt::state_update_alert *p);
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p); void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
void handleFileErrorAlert(const lt::file_error_alert *p); void handleFileErrorAlert(const lt::file_error_alert *p);
void handleTorrentRemovedAlert(const lt::torrent_removed_alert *p); void handleTorrentRemovedAlert(const lt::torrent_removed_alert *p);
void handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p); void handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p);

54
src/base/bittorrent/torrenthandle.cpp

@ -191,6 +191,7 @@ TorrentHandle::TorrentHandle(Session *session, const lt::torrent_handle &nativeH
, m_hasRootFolder(params.hasRootFolder) , m_hasRootFolder(params.hasRootFolder)
, m_needsToSetFirstLastPiecePriority(false) , m_needsToSetFirstLastPiecePriority(false)
, m_needsToStartForced(params.forced) , m_needsToStartForced(params.forced)
, m_pauseWhenReady(params.paused)
{ {
if (m_useAutoTMM) if (m_useAutoTMM)
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category)); m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
@ -216,18 +217,18 @@ TorrentHandle::TorrentHandle(Session *session, const lt::torrent_handle &nativeH
m_hasRootFolder = false; m_hasRootFolder = false;
} }
// "started" means "all initialization has completed and torrent has started regular processing". if (!hasMetadata()) {
// When torrent added/restored in "paused" state it become "started" immediately after construction. // There is nothing to prepare
// When it is added/restored in "resumed" state, it become "started" after it is really resumed if (!m_pauseWhenReady) {
// (i.e. after receiving "torrent resumed" alert).
if (params.paused) {
m_startupState = Started;
}
else if (!params.restored || !hasMetadata()) {
// Resume torrent because it was added in "resumed" state // Resume torrent because it was added in "resumed" state
// but it's actually paused during initialization // but it's actually paused during initialization.
m_startupState = Starting; m_startupState = Starting;
resume(params.forced); resume(m_needsToStartForced);
}
else {
m_startupState = Started;
m_pauseWhenReady = false;
}
} }
} }
@ -1346,7 +1347,8 @@ void TorrentHandle::forceRecheck()
#else #else
m_nativeHandle.set_flags(lt::torrent_flags::stop_when_ready); m_nativeHandle.set_flags(lt::torrent_flags::stop_when_ready);
#endif #endif
resume_impl(false); setAutoManaged(true);
m_pauseWhenReady = true;
} }
} }
@ -1618,7 +1620,8 @@ void TorrentHandle::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p
Q_UNUSED(p); Q_UNUSED(p);
qDebug("\"%s\" have just finished checking", qUtf8Printable(name())); qDebug("\"%s\" have just finished checking", qUtf8Printable(name()));
if (m_startupState == NotStarted) { if (m_startupState == Preparing) {
if (!m_pauseWhenReady) {
if (!m_hasMissingFiles) { if (!m_hasMissingFiles) {
// Resume torrent because it was added in "resumed" state // Resume torrent because it was added in "resumed" state
// but it's actually paused during initialization. // but it's actually paused during initialization.
@ -1626,9 +1629,13 @@ void TorrentHandle::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p
resume(m_needsToStartForced); resume(m_needsToStartForced);
} }
else { else {
// Torrent that has missing files is marked as "started" // Torrent that has missing files is paused.
// but it remains paused. m_startupState = Started;
}
}
else {
m_startupState = Started; m_startupState = Started;
m_pauseWhenReady = false;
} }
} }
@ -1652,10 +1659,10 @@ void TorrentHandle::handleTorrentFinishedAlert(const lt::torrent_finished_alert
Q_UNUSED(p); Q_UNUSED(p);
qDebug("Got a torrent finished alert for \"%s\"", qUtf8Printable(name())); qDebug("Got a torrent finished alert for \"%s\"", qUtf8Printable(name()));
qDebug("Torrent has seed status: %s", m_hasSeedStatus ? "yes" : "no"); qDebug("Torrent has seed status: %s", m_hasSeedStatus ? "yes" : "no");
m_hasMissingFiles = false;
if (m_hasSeedStatus) return; if (m_hasSeedStatus) return;
updateStatus(); updateStatus();
m_hasMissingFiles = false;
m_hasSeedStatus = true; m_hasSeedStatus = true;
adjustActualSavePath(); adjustActualSavePath();
@ -1679,10 +1686,15 @@ void TorrentHandle::handleTorrentPausedAlert(const lt::torrent_paused_alert *p)
Q_UNUSED(p); Q_UNUSED(p);
if (m_startupState == Started) { if (m_startupState == Started) {
if (!m_pauseWhenReady) {
updateStatus(); updateStatus();
m_speedMonitor.reset(); m_speedMonitor.reset();
m_session->handleTorrentPaused(this); m_session->handleTorrentPaused(this);
} }
else {
m_pauseWhenReady = false;
}
}
} }
void TorrentHandle::handleTorrentResumedAlert(const lt::torrent_resumed_alert *p) void TorrentHandle::handleTorrentResumedAlert(const lt::torrent_resumed_alert *p)
@ -1710,8 +1722,8 @@ void TorrentHandle::handleSaveResumeDataAlert(const lt::save_resume_data_alert *
if (useDummyResumeData) { if (useDummyResumeData) {
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString(); resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
resumeData["qBt-paused"] = isPaused(); resumeData["paused"] = isPaused();
resumeData["qBt-forced"] = isForced(); resumeData["auto_managed"] = isAutoManaged();
// Both firstLastPiecePriority and sequential need to be stored in the // Both firstLastPiecePriority and sequential need 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:
@ -1733,6 +1745,14 @@ void TorrentHandle::handleSaveResumeDataAlert(const lt::save_resume_data_alert *
resumeData["qBt-queuePosition"] = (static_cast<int>(nativeHandle().queue_position()) + 1); // qBt starts queue at 1 resumeData["qBt-queuePosition"] = (static_cast<int>(nativeHandle().queue_position()) + 1); // qBt starts queue at 1
resumeData["qBt-hasRootFolder"] = m_hasRootFolder; resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
if (m_pauseWhenReady) {
// We need to redefine these values when torrent starting/rechecking
// in "paused" state since native values can be logically wrong
// (torrent can be not paused and auto_managed when it is checking).
resumeData["paused"] = true;
resumeData["auto_managed"] = false;
}
m_session->handleTorrentResumeDataReady(this, resumeData); m_session->handleTorrentResumeDataReady(this, resumeData);
} }

11
src/base/bittorrent/torrenthandle.h

@ -447,12 +447,15 @@ namespace BitTorrent
enum StartupState enum StartupState
{ {
NotStarted, Preparing, // torrent is preparing to start regular processing
Starting, Starting, // torrent is prepared and starting to perform regular processing
Started Started // torrent is performing regular processing
}; };
StartupState m_startupState = Preparing;
// Handle torrent state when it starts performing some service job
// being in Paused state so it might be unpaused internally and then paused again
bool m_pauseWhenReady;
StartupState m_startupState = NotStarted;
bool m_unchecked = false; bool m_unchecked = false;
}; };
} }

Loading…
Cancel
Save