diff --git a/Changelog b/Changelog index 1a94355a0..eea393768 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ - BUGFIX: RSS feed downloader can only process unread articles now - BUGFIX: Fixed memory leak in RSS parser - BUGFIX: Fixed possible crash in search autocompletion + - BUGFIX: Improved ETA calculation for big torrents * Wed Nov 4 2009 - Christophe Dumez - v1.5.5 - BUGFIX: Fixed man page diff --git a/src/Icons/qBittorrent.desktop b/src/Icons/qBittorrent.desktop index 02610abf7..8fd497466 100644 --- a/src/Icons/qBittorrent.desktop +++ b/src/Icons/qBittorrent.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Categories=Qt;Network;P2P; -Comment=V1.5.5 +Comment=V1.5.6 Exec=qbittorrent %f GenericName=Bittorrent client GenericName[bg]=Торент клиент diff --git a/src/Icons/skin/splash.png b/src/Icons/skin/splash.png index 6064e0b43..5f806cc47 100644 Binary files a/src/Icons/skin/splash.png and b/src/Icons/skin/splash.png differ diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index 64cd14622..4df1515d1 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -114,6 +114,8 @@ bittorrent::~bittorrent() { delete FSWatcher; delete FSMutex; } + if(timerETA) + delete timerETA; // Delete BT session qDebug("Deleting session"); delete s; @@ -215,21 +217,64 @@ int bittorrent::getUpTorrentPriority(QString hash) const { return h.queue_position(); } -// Calculate the ETA using GASA -// GASA: global Average Speed Algorithm -qlonglong bittorrent::getETA(QString hash) const { - QTorrentHandle h = getTorrentHandle(hash); - if(!h.is_valid()) return -1; - switch(h.state()) { - case torrent_status::downloading: { - if(h.active_time() == 0) - return -1; - double avg_speed = (double)h.all_time_download() / h.active_time(); - return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); +void bittorrent::takeETASamples() { + bool change = false;; + foreach(const QString &hash, ETA_samples.keys()) { + QTorrentHandle h = getTorrentHandle(hash); + if(h.is_valid() && !h.is_paused() && !h.is_seed()) { + QList samples = ETA_samples.value(h.hash(), QList()); + if(samples.size() >= MAX_SAMPLES) + samples.removeFirst(); + samples.append(h.download_payload_rate()); + ETA_samples[h.hash()] = samples; + change = true; + } else { + ETA_samples.remove(hash); } - default: - return -1; } + if(!change && timerETA) { + delete timerETA; + } +} + +// This algorithm was inspired from KTorrent - http://www.ktorrent.org +// Calculate the ETA using a combination of several algorithms: +// GASA: Global Average Speed Algorithm +// CSA: Current Speed Algorithm +// WINX: Window of X Algorithm +qlonglong bittorrent::getETA(QString hash) { + QTorrentHandle h = getTorrentHandle(hash); + if(!h.is_valid() || h.state() != torrent_status::downloading || !h.active_time()) + return -1; + // See if the torrent is going to be completed soon + qulonglong bytes_left = h.actual_size() - h.total_wanted_done(); + if(h.actual_size() > 10485760L) { // Size > 10MiB + if(h.progress() >= (float)0.99 && bytes_left < 10485760L) { // Progress>99% but less than 10MB left. + // Compute by taking samples + if(!ETA_samples.contains(h.hash())) { + ETA_samples[h.hash()] = QList(); + } + if(!timerETA) { + timerETA = new QTimer(this); + connect(timerETA, SIGNAL(timeout()), this, SLOT(takeETASamples())); + timerETA->start(); + } else { + QList samples = ETA_samples.value(h.hash(), QList()); + int nb_samples = samples.size(); + if(nb_samples > 3) { + long sum_samples = 0; + foreach(int val, samples) { + sum_samples += val; + } + // Use WINX + return (qlonglong)(((double)bytes_left) / (((double)sum_samples) / ((double)nb_samples))); + } + } + } + } + // Normal case: Use GASA + double avg_speed = (double)h.all_time_download() / h.active_time(); + return (qlonglong) floor((double) (bytes_left) / avg_speed); } std::vector bittorrent::getTorrents() const { diff --git a/src/bittorrent.h b/src/bittorrent.h index 7e753adf7..5432cf6d0 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -42,6 +42,8 @@ using namespace libtorrent; +#define MAX_SAMPLES 20 + class downloadThread; class QTimer; class QFileSystemWatcher; @@ -77,6 +79,8 @@ class bittorrent : public QObject { bool queueingEnabled; QStringList url_skippingDlg; QHash savepath_fromurl; + QPointer timerETA; + QHash > ETA_samples; protected: QString getSavePath(QString hash); @@ -107,7 +111,7 @@ class bittorrent : public QObject { int loadTorrentPriority(QString hash); QStringList getConsoleMessages() const; QStringList getPeerBanMessages() const; - qlonglong getETA(QString hash) const; + qlonglong getETA(QString hash); bool useTemporaryFolder() const; QString getDefaultSavePath() const; @@ -177,6 +181,7 @@ class bittorrent : public QObject { void readAlerts(); void loadTrackerFile(QString hash); void deleteBigRatios(); + void takeETASamples(); signals: void addedTorrent(QTorrentHandle& h); diff --git a/src/src.pro b/src/src.pro index f9ed8f4c7..e327b2070 100644 --- a/src/src.pro +++ b/src/src.pro @@ -14,10 +14,10 @@ CONFIG += qt \ network # Update this VERSION for each release -DEFINES += VERSION=\\\"v1.5.5\\\" +DEFINES += VERSION=\\\"v1.5.6\\\" DEFINES += VERSION_MAJOR=1 DEFINES += VERSION_MINOR=5 -DEFINES += VERSION_BUGFIX=5 +DEFINES += VERSION_BUGFIX=6 !mac:QMAKE_LFLAGS += -Wl,--as-needed contains(DEBUG_MODE, 1) { CONFIG += debug