Browse Source

- Improved ETA calculation for big torrents

adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
eab216e5a8
  1. 67
      src/bittorrent.cpp
  2. 7
      src/bittorrent.h

67
src/bittorrent.cpp

@ -116,6 +116,8 @@ bittorrent::~bittorrent() {
if(FSWatcher) { if(FSWatcher) {
delete FSWatcher; delete FSWatcher;
} }
if(timerETA)
delete timerETA;
// Delete BT session // Delete BT session
qDebug("Deleting session"); qDebug("Deleting session");
delete s; delete s;
@ -459,21 +461,64 @@ void bittorrent::configureSession() {
qDebug("Session configured"); qDebug("Session configured");
} }
// Calculate the ETA using GASA void bittorrent::takeETASamples() {
// GASA: global Average Speed Algorithm bool change = false;;
qlonglong bittorrent::getETA(QString hash) const { foreach(const QString &hash, ETA_samples.keys()) {
QTorrentHandle h = getTorrentHandle(hash); QTorrentHandle h = getTorrentHandle(hash);
if(!h.is_valid()) return -1; if(h.is_valid() && !h.is_paused() && !h.is_seed()) {
switch(h.state()) { QList<int> samples = ETA_samples.value(h.hash(), QList<int>());
case torrent_status::downloading: { if(samples.size() >= MAX_SAMPLES)
if(h.active_time() == 0) samples.removeFirst();
return -1; samples.append(h.download_payload_rate());
double avg_speed = (double)h.all_time_download() / h.active_time(); ETA_samples[h.hash()] = samples;
return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); change = true;
} else {
ETA_samples.remove(hash);
} }
default: }
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; 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<int>();
}
if(!timerETA) {
timerETA = new QTimer(this);
connect(timerETA, SIGNAL(timeout()), this, SLOT(takeETASamples()));
timerETA->start();
} else {
QList<int> samples = ETA_samples.value(h.hash(), QList<int>());
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<torrent_handle> bittorrent::getTorrents() const { std::vector<torrent_handle> bittorrent::getTorrents() const {

7
src/bittorrent.h

@ -42,6 +42,8 @@
using namespace libtorrent; using namespace libtorrent;
#define MAX_SAMPLES 20
class downloadThread; class downloadThread;
class QTimer; class QTimer;
class FileSystemWatcher; class FileSystemWatcher;
@ -77,6 +79,8 @@ class bittorrent : public QObject {
QHash<QString, QString> savepath_fromurl; QHash<QString, QString> savepath_fromurl;
bool resolve_countries; bool resolve_countries;
bool geoipDBLoaded; bool geoipDBLoaded;
QPointer<QTimer> timerETA;
QHash<QString, QList<int> > ETA_samples;
protected: protected:
QString getSavePath(QString hash); QString getSavePath(QString hash);
@ -106,7 +110,7 @@ class bittorrent : public QObject {
int loadTorrentPriority(QString hash); int loadTorrentPriority(QString hash);
QStringList getConsoleMessages() const; QStringList getConsoleMessages() const;
QStringList getPeerBanMessages() const; QStringList getPeerBanMessages() const;
qlonglong getETA(QString hash) const; qlonglong getETA(QString hash);
bool useTemporaryFolder() const; bool useTemporaryFolder() const;
QString getDefaultSavePath() const; QString getDefaultSavePath() const;
@ -177,6 +181,7 @@ class bittorrent : public QObject {
void readAlerts(); void readAlerts();
void loadTrackerFile(QString hash); void loadTrackerFile(QString hash);
void deleteBigRatios(); void deleteBigRatios();
void takeETASamples();
signals: signals:
void addedTorrent(QTorrentHandle& h); void addedTorrent(QTorrentHandle& h);

Loading…
Cancel
Save