mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-29 13:58:51 +03:00
Merge pull request #1779 from sorokin/move-storage
Speedup and fix a bug in torrent moving.
This commit is contained in:
commit
3ad1cc8289
4 changed files with 167 additions and 43 deletions
|
@ -80,6 +80,7 @@
|
||||||
|
|
||||||
//initialize static member variables
|
//initialize static member variables
|
||||||
QHash<QString, TorrentTempData::TorrentData> TorrentTempData::data = QHash<QString, TorrentTempData::TorrentData>();
|
QHash<QString, TorrentTempData::TorrentData> TorrentTempData::data = QHash<QString, TorrentTempData::TorrentData>();
|
||||||
|
QHash<QString, TorrentMoveState> TorrentTempData::torrentMoveStates = QHash<QString, TorrentMoveState>();
|
||||||
QHash<QString, bool> HiddenData::data = QHash<QString, bool>();
|
QHash<QString, bool> HiddenData::data = QHash<QString, bool>();
|
||||||
unsigned int HiddenData::metadata_counter = 0;
|
unsigned int HiddenData::metadata_counter = 0;
|
||||||
|
|
||||||
|
@ -2160,6 +2161,9 @@ void QBtSession::handleAlert(libtorrent::alert* a) {
|
||||||
case storage_moved_alert::alert_type:
|
case storage_moved_alert::alert_type:
|
||||||
handleStorageMovedAlert(static_cast<storage_moved_alert*>(a));
|
handleStorageMovedAlert(static_cast<storage_moved_alert*>(a));
|
||||||
break;
|
break;
|
||||||
|
case storage_moved_failed_alert::alert_type:
|
||||||
|
handleStorageMovedFailedAlert(static_cast<storage_moved_failed_alert*>(a));
|
||||||
|
break;
|
||||||
case metadata_received_alert::alert_type:
|
case metadata_received_alert::alert_type:
|
||||||
handleMetadataReceivedAlert(static_cast<metadata_received_alert*>(a));
|
handleMetadataReceivedAlert(static_cast<metadata_received_alert*>(a));
|
||||||
break;
|
break;
|
||||||
|
@ -2401,22 +2405,73 @@ void QBtSession::handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p)
|
||||||
|
|
||||||
void QBtSession::handleStorageMovedAlert(libtorrent::storage_moved_alert* p) {
|
void QBtSession::handleStorageMovedAlert(libtorrent::storage_moved_alert* p) {
|
||||||
QTorrentHandle h(p->handle);
|
QTorrentHandle h(p->handle);
|
||||||
if (h.is_valid()) {
|
if (!h.is_valid()) {
|
||||||
// Attempt to remove old folder if empty
|
qWarning("invalid handle received in storage_moved_alert");
|
||||||
const QString old_save_path = fsutils::fromNativePath(TorrentPersistentData::getPreviousPath(h.hash()));
|
return;
|
||||||
const QString new_save_path = fsutils::fromNativePath(misc::toQStringU(p->path.c_str()));
|
}
|
||||||
qDebug("Torrent moved from %s to %s", qPrintable(old_save_path), qPrintable(new_save_path));
|
|
||||||
QDir old_save_dir(old_save_path);
|
QString hash = h.hash();
|
||||||
if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) {
|
|
||||||
qDebug("Attempting to remove %s", qPrintable(old_save_path));
|
if (!TorrentTempData::isMoveInProgress(hash)) {
|
||||||
QDir().rmpath(old_save_path);
|
qWarning("unexpected storage_moved_alert received");
|
||||||
}
|
return;
|
||||||
if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) {
|
}
|
||||||
qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path));
|
|
||||||
TorrentPersistentData::saveSavePath(h.hash(), new_save_path);
|
QString new_save_path = fsutils::fromNativePath(misc::toQStringU(p->path.c_str()));
|
||||||
}
|
if (new_save_path != TorrentTempData::getNewPath(hash)) {
|
||||||
emit savePathChanged(h);
|
qWarning("new path received in handleStorageMovedAlert() doesn't match a path in a queue");
|
||||||
//h.force_recheck();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString oldPath = TorrentTempData::getOldPath(hash);
|
||||||
|
|
||||||
|
qDebug("Torrent is successfully moved from %s to %s", qPrintable(oldPath), qPrintable(new_save_path));
|
||||||
|
|
||||||
|
// Attempt to remove old folder if empty
|
||||||
|
QDir old_save_dir(oldPath);
|
||||||
|
if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) {
|
||||||
|
qDebug("Attempting to remove %s", qPrintable(oldPath));
|
||||||
|
QDir().rmpath(oldPath);
|
||||||
|
}
|
||||||
|
if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) {
|
||||||
|
qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path));
|
||||||
|
TorrentPersistentData::saveSavePath(h.hash(), new_save_path);
|
||||||
|
}
|
||||||
|
emit savePathChanged(h);
|
||||||
|
//h.force_recheck();
|
||||||
|
|
||||||
|
QString queued = TorrentTempData::getQueuedPath(hash);
|
||||||
|
if (queued != QString()) {
|
||||||
|
TorrentTempData::finishMove(hash);
|
||||||
|
h.move_storage(queued);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TorrentTempData::finishMove(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QBtSession::handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p) {
|
||||||
|
|
||||||
|
QTorrentHandle h(p->handle);
|
||||||
|
if (!h.is_valid()) {
|
||||||
|
qWarning("invalid handle received in storage_moved_failed_alert");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString hash = h.hash();
|
||||||
|
|
||||||
|
if (!TorrentTempData::isMoveInProgress(hash)) {
|
||||||
|
qWarning("unexpected storage_moved_alert received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString queued = TorrentTempData::getQueuedPath(hash);
|
||||||
|
if (queued != QString()) {
|
||||||
|
TorrentTempData::finishMove(hash);
|
||||||
|
h.move_storage(queued);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TorrentTempData::finishMove(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2968,7 +3023,6 @@ void QBtSession::recoverPersistentData(const QString &hash, const std::vector<ch
|
||||||
QString savePath = fsutils::fromNativePath(QString::fromUtf8(fast.dict_find_string_value("qBt-savePath").c_str()));
|
QString savePath = fsutils::fromNativePath(QString::fromUtf8(fast.dict_find_string_value("qBt-savePath").c_str()));
|
||||||
qreal ratioLimit = QString::fromUtf8(fast.dict_find_string_value("qBt-ratioLimit").c_str()).toDouble();
|
qreal ratioLimit = QString::fromUtf8(fast.dict_find_string_value("qBt-ratioLimit").c_str()).toDouble();
|
||||||
QDateTime addedDate = QDateTime::fromTime_t(fast.dict_find_int_value("added_time"));
|
QDateTime addedDate = QDateTime::fromTime_t(fast.dict_find_int_value("added_time"));
|
||||||
QString previousSavePath = QString::fromUtf8(fast.dict_find_string_value("qBt-previousSavePath").c_str());
|
|
||||||
QString label = QString::fromUtf8(fast.dict_find_string_value("qBt-label").c_str());
|
QString label = QString::fromUtf8(fast.dict_find_string_value("qBt-label").c_str());
|
||||||
int priority = fast.dict_find_int_value("qBt-queuePosition");
|
int priority = fast.dict_find_int_value("qBt-queuePosition");
|
||||||
bool seedStatus = fast.dict_find_int_value("qBt-seedStatus");
|
bool seedStatus = fast.dict_find_int_value("qBt-seedStatus");
|
||||||
|
@ -2976,7 +3030,6 @@ void QBtSession::recoverPersistentData(const QString &hash, const std::vector<ch
|
||||||
TorrentPersistentData::saveSavePath(hash, savePath);
|
TorrentPersistentData::saveSavePath(hash, savePath);
|
||||||
TorrentPersistentData::setRatioLimit(hash, ratioLimit);
|
TorrentPersistentData::setRatioLimit(hash, ratioLimit);
|
||||||
TorrentPersistentData::setAddedDate(hash, addedDate);
|
TorrentPersistentData::setAddedDate(hash, addedDate);
|
||||||
TorrentPersistentData::setPreviousSavePath(hash, previousSavePath);
|
|
||||||
TorrentPersistentData::saveLabel(hash, label);
|
TorrentPersistentData::saveLabel(hash, label);
|
||||||
TorrentPersistentData::savePriority(hash, priority);
|
TorrentPersistentData::savePriority(hash, priority);
|
||||||
TorrentPersistentData::saveSeedStatus(hash, seedStatus);
|
TorrentPersistentData::saveSeedStatus(hash, seedStatus);
|
||||||
|
@ -2985,7 +3038,6 @@ void QBtSession::recoverPersistentData(const QString &hash, const std::vector<ch
|
||||||
void QBtSession::backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data) {
|
void QBtSession::backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data) {
|
||||||
(*data)["qBt-savePath"] = fsutils::fromNativePath(TorrentPersistentData::getSavePath(hash)).toUtf8().constData();
|
(*data)["qBt-savePath"] = fsutils::fromNativePath(TorrentPersistentData::getSavePath(hash)).toUtf8().constData();
|
||||||
(*data)["qBt-ratioLimit"] = QString::number(TorrentPersistentData::getRatioLimit(hash)).toUtf8().constData();
|
(*data)["qBt-ratioLimit"] = QString::number(TorrentPersistentData::getRatioLimit(hash)).toUtf8().constData();
|
||||||
(*data)["qBt-previousSavePath"] = fsutils::fromNativePath(TorrentPersistentData::getPreviousPath(hash)).toUtf8().constData();
|
|
||||||
(*data)["qBt-label"] = TorrentPersistentData::getLabel(hash).toUtf8().constData();
|
(*data)["qBt-label"] = TorrentPersistentData::getLabel(hash).toUtf8().constData();
|
||||||
(*data)["qBt-queuePosition"] = TorrentPersistentData::getPriority(hash);
|
(*data)["qBt-queuePosition"] = TorrentPersistentData::getPriority(hash);
|
||||||
(*data)["qBt-seedStatus"] = (int)TorrentPersistentData::isSeed(hash);
|
(*data)["qBt-seedStatus"] = (int)TorrentPersistentData::isSeed(hash);
|
||||||
|
|
|
@ -200,6 +200,7 @@ private:
|
||||||
void handleFileRenamedAlert(libtorrent::file_renamed_alert* p);
|
void handleFileRenamedAlert(libtorrent::file_renamed_alert* p);
|
||||||
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p);
|
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p);
|
||||||
void handleStorageMovedAlert(libtorrent::storage_moved_alert* p);
|
void handleStorageMovedAlert(libtorrent::storage_moved_alert* p);
|
||||||
|
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p);
|
||||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p);
|
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p);
|
||||||
void handleFileErrorAlert(libtorrent::file_error_alert* p);
|
void handleFileErrorAlert(libtorrent::file_error_alert* p);
|
||||||
void handleFileCompletedAlert(libtorrent::file_completed_alert* p);
|
void handleFileCompletedAlert(libtorrent::file_completed_alert* p);
|
||||||
|
|
|
@ -445,15 +445,28 @@ void QTorrentHandle::set_tracker_login(const QString& username, const QString& p
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::move_storage(const QString& new_path) const {
|
void QTorrentHandle::move_storage(const QString& new_path) const {
|
||||||
if (QDir(save_path()) == QDir(new_path))
|
QString hashstr = hash();
|
||||||
return;
|
|
||||||
|
|
||||||
TorrentPersistentData::setPreviousSavePath(hash(), save_path());
|
if (TorrentTempData::isMoveInProgress(hashstr)) {
|
||||||
// Create destination directory if necessary
|
qDebug("enqueue move storage to %s", qPrintable(new_path));
|
||||||
// or move_storage() will fail...
|
TorrentTempData::enqueueMove(hashstr, new_path);
|
||||||
QDir().mkpath(new_path);
|
}
|
||||||
// Actually move the storage
|
else {
|
||||||
torrent_handle::move_storage(fsutils::toNativePath(new_path).toUtf8().constData());
|
QString old_path = save_path();
|
||||||
|
|
||||||
|
qDebug("move storage: %s to %s", qPrintable(old_path), qPrintable(new_path));
|
||||||
|
|
||||||
|
if (QDir(old_path) == QDir(new_path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TorrentTempData::startMove(hashstr, old_path, new_path);
|
||||||
|
|
||||||
|
// Create destination directory if necessary
|
||||||
|
// or move_storage() will fail...
|
||||||
|
QDir().mkpath(new_path);
|
||||||
|
// Actually move the storage
|
||||||
|
torrent_handle::move_storage(fsutils::toNativePath(new_path).toUtf8().constData());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::save_torrent_file(const QString& path) const {
|
bool QTorrentHandle::save_torrent_file(const QString& path) const {
|
||||||
|
|
|
@ -42,6 +42,20 @@
|
||||||
#include "qinisettings.h"
|
#include "qinisettings.h"
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|
||||||
|
struct TorrentMoveState
|
||||||
|
{
|
||||||
|
TorrentMoveState(QString oldPath, QString newPath)
|
||||||
|
: oldPath(oldPath)
|
||||||
|
, newPath(newPath)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// the moving occurs from oldPath to newPath
|
||||||
|
// queuedPath is where files should be moved to, when current moving is completed
|
||||||
|
QString oldPath;
|
||||||
|
QString newPath;
|
||||||
|
QString queuedPath;
|
||||||
|
};
|
||||||
|
|
||||||
class TorrentTempData {
|
class TorrentTempData {
|
||||||
// This class stores strings w/o modifying separators
|
// This class stores strings w/o modifying separators
|
||||||
public:
|
public:
|
||||||
|
@ -101,6 +115,65 @@ public:
|
||||||
fp = data.value(hash).files_priority;
|
fp = data.value(hash).files_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isMoveInProgress(const QString &hash) {
|
||||||
|
return torrentMoveStates.find(hash) != torrentMoveStates.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enqueueMove(const QString &hash, const QString &queuedPath) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i == torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i->queuedPath = queuedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startMove(const QString &hash, const QString &oldPath, const QString& newPath) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i != torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
torrentMoveStates.insert(hash, TorrentMoveState(oldPath, newPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finishMove(const QString &hash) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i == torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
torrentMoveStates.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString getOldPath(const QString &hash) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i == torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return i->oldPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString getNewPath(const QString &hash) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i == torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return i->newPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString getQueuedPath(const QString &hash) {
|
||||||
|
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||||
|
if (i == torrentMoveStates.end()) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return i->queuedPath;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TorrentData {
|
struct TorrentData {
|
||||||
TorrentData(): sequential(false), seed(false) {}
|
TorrentData(): sequential(false), seed(false) {}
|
||||||
|
@ -113,6 +186,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
static QHash<QString, TorrentData> data;
|
static QHash<QString, TorrentData> data;
|
||||||
|
static QHash<QString, TorrentMoveState> torrentMoveStates;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HiddenData {
|
class HiddenData {
|
||||||
|
@ -240,22 +314,6 @@ public:
|
||||||
return data.value("has_error", false).toBool();
|
return data.value("has_error", false).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setPreviousSavePath(const QString &hash, const QString &previous_path) {
|
|
||||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents").toHash();
|
|
||||||
QHash<QString, QVariant> data = all_data.value(hash).toHash();
|
|
||||||
data["previous_path"] = previous_path;
|
|
||||||
all_data[hash] = data;
|
|
||||||
settings.setValue("torrents", all_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString getPreviousPath(const QString &hash) {
|
|
||||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
|
||||||
const QHash<QString, QVariant> all_data = settings.value("torrents").toHash();
|
|
||||||
const QHash<QString, QVariant> data = all_data.value(hash).toHash();
|
|
||||||
return data.value("previous_path").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static QDateTime getSeedDate(const QString &hash) {
|
static QDateTime getSeedDate(const QString &hash) {
|
||||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
const QHash<QString, QVariant> all_data = settings.value("torrents").toHash();
|
const QHash<QString, QVariant> all_data = settings.value("torrents").toHash();
|
||||||
|
|
Loading…
Reference in a new issue