Browse Source

- Optimized downloadThread memory usage

adaptive-webui-19844
Christophe Dumez 17 years ago
parent
commit
4e0ed1ec4c
  1. 1
      TODO
  2. 192
      src/downloadThread.h

1
TODO

@ -45,6 +45,7 @@
- Windows port (Chris - Peerkoel) - Windows port (Chris - Peerkoel)
- Translations update - Translations update
- .ico support? - .ico support?
- display debug when fastresume data is rejected
* beta2 * beta2
- Wait for some bug fixes in libtorrent : - Wait for some bug fixes in libtorrent :
- upload/download limit per torrent - upload/download limit per torrent

192
src/downloadThread.h

@ -37,57 +37,24 @@ using namespace std;
using namespace ost; using namespace ost;
#endif #endif
class downloadThread : public QThread { class subDownloadThread : public QThread {
Q_OBJECT Q_OBJECT
private: private:
QStringList url_list; QString url;
QMutex mutex; URLStream url_stream;
QWaitCondition condition;
bool abort; bool abort;
URLStream *url_stream;
QList<downloadThread*> subThreads;
bool subThread;
signals:
void downloadFinished(QString url, QString file_path);
void downloadFailure(QString url, QString reason);
// For subthreads
void downloadFinishedST(downloadThread* st, QString url, QString file_path);
void downloadFailureST(downloadThread* st, QString url, QString reason);
public: public:
downloadThread(QObject* parent, bool subThread = false) : QThread(parent){ subDownloadThread(QObject *parent, QString url) : QThread(parent), url(url){
qDebug("Creating downloadThread");
abort = false; abort = false;
this->subThread = subThread;
url_stream = 0;
qDebug("downloadThread created");
} }
~downloadThread(){ ~subDownloadThread(){
mutex.lock();
abort = true; abort = true;
condition.wakeOne();
mutex.unlock();
if(url_stream != 0)
delete url_stream;
wait(); wait();
} }
void downloadUrl(QString url){ static QString errorCodeToString(URLStream::Error status){
if(subThread && url_stream == 0)
url_stream = new URLStream();
QMutexLocker locker(&mutex);
url_list << url;
if(!isRunning()){
start();
}else{
condition.wakeOne();
}
}
QString errorCodeToString(URLStream::Error status){
switch(status){ switch(status){
case URLStream::errUnreachable: case URLStream::errUnreachable:
return tr("Host is unreachable"); return tr("Host is unreachable");
@ -114,6 +81,96 @@ class downloadThread : public QThread {
} }
} }
signals:
// For subthreads
void downloadFinishedST(subDownloadThread* st, QString url, QString file_path);
void downloadFailureST(subDownloadThread* st, QString url, QString reason);
protected:
void run(){
// XXX: Trick to get a unique filename
QString filePath;
QTemporaryFile *tmpfile = new QTemporaryFile();
if (tmpfile->open()) {
filePath = tmpfile->fileName();
}
delete tmpfile;
QFile dest_file(filePath);
if(!dest_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: could't create temporary file: " << (const char*)filePath.toUtf8() << '\n';
return;
}
URLStream::Error status = url_stream.get((const char*)url.toUtf8());
if(status){
// Failure
QString error_msg = errorCodeToString(status);
qDebug("Download failed for %s, reason: %s", (const char*)url.toUtf8(), (const char*)error_msg.toUtf8());
url_stream.close();
emit downloadFailureST(this, url, error_msg);
return;
}
qDebug("Downloading %s...", (const char*)url.toUtf8());
char cbuf[1024];
int len;
while(!url_stream.eof()) {
url_stream.read(cbuf, sizeof(cbuf));
len = url_stream.gcount();
if(len > 0)
dest_file.write(cbuf, len);
if(abort){
dest_file.close();
url_stream.close();
return;
}
}
dest_file.close();
url_stream.close();
emit downloadFinishedST(this, url, filePath);
qDebug("download completed here: %s", (const char*)filePath.toUtf8());
}
};
class downloadThread : public QThread {
Q_OBJECT
private:
QStringList url_list;
QMutex mutex;
QWaitCondition condition;
bool abort;
QList<subDownloadThread*> subThreads;
signals:
void downloadFinished(QString url, QString file_path);
void downloadFailure(QString url, QString reason);
public:
downloadThread(QObject* parent) : QThread(parent){
abort = false;
}
~downloadThread(){
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
subDownloadThread *st;
foreach(st, subThreads){
delete st;
}
wait();
}
void downloadUrl(QString url){
QMutexLocker locker(&mutex);
url_list << url;
if(!isRunning()){
start();
}else{
condition.wakeOne();
}
}
protected: protected:
void run(){ void run(){
forever{ forever{
@ -123,54 +180,11 @@ class downloadThread : public QThread {
if(url_list.size() != 0){ if(url_list.size() != 0){
QString url = url_list.takeFirst(); QString url = url_list.takeFirst();
mutex.unlock(); mutex.unlock();
if(!subThread){ subDownloadThread *st = new subDownloadThread(0, url);
downloadThread *st = new downloadThread(0, true); subThreads << st;
subThreads << st; connect(st, SIGNAL(downloadFinishedST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadedFile(subDownloadThread*, QString, QString)));
connect(st, SIGNAL(downloadFinishedST(downloadThread*, QString, QString)), this, SLOT(propagateDownloadedFile(downloadThread*, QString, QString))); connect(st, SIGNAL(downloadFailureST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadFailure(subDownloadThread*, QString, QString)));
connect(st, SIGNAL(downloadFailureST(downloadThread*, QString, QString)), this, SLOT(propagateDownloadFailure(downloadThread*, QString, QString))); st->start();
st->downloadUrl(url);
continue;
}
// Sub threads code
// XXX: Trick to get a unique filename
QString filePath;
QTemporaryFile *tmpfile = new QTemporaryFile();
if (tmpfile->open()) {
filePath = tmpfile->fileName();
}
delete tmpfile;
QFile dest_file(filePath);
if(!dest_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: could't create temporary file: " << (const char*)filePath.toUtf8() << '\n';
continue;
}
URLStream::Error status = url_stream->get((const char*)url.toUtf8());
if(status){
// Failure
QString error_msg = errorCodeToString(status);
qDebug("Download failed for %s, reason: %s", (const char*)url.toUtf8(), (const char*)error_msg.toUtf8());
url_stream->close();
emit downloadFailureST(this, url, error_msg);
continue;
}
qDebug("Downloading %s...", (const char*)url.toUtf8());
char cbuf[1024];
int len;
while(!url_stream->eof()) {
url_stream->read(cbuf, sizeof(cbuf));
len = url_stream->gcount();
if(len > 0)
dest_file.write(cbuf, len);
if(abort){
dest_file.close();
url_stream->close();
return;
}
}
dest_file.close();
url_stream->close();
emit downloadFinishedST(this, url, filePath);
qDebug("download completed here: %s", (const char*)filePath.toUtf8());
}else{ }else{
condition.wait(&mutex); condition.wait(&mutex);
mutex.unlock(); mutex.unlock();
@ -178,7 +192,7 @@ class downloadThread : public QThread {
} }
} }
protected slots: protected slots:
void propagateDownloadedFile(downloadThread* st, QString url, QString path){ void propagateDownloadedFile(subDownloadThread* st, QString url, QString path){
int index = subThreads.indexOf(st); int index = subThreads.indexOf(st);
if(index == -1) if(index == -1)
std::cerr << "ERROR: Couldn't delete download subThread!\n"; std::cerr << "ERROR: Couldn't delete download subThread!\n";
@ -188,7 +202,7 @@ class downloadThread : public QThread {
emit downloadFinished(url, path); emit downloadFinished(url, path);
} }
void propagateDownloadFailure(downloadThread* st, QString url, QString reason){ void propagateDownloadFailure(subDownloadThread* st, QString url, QString reason){
int index = subThreads.indexOf(st); int index = subThreads.indexOf(st);
if(index == -1) if(index == -1)
std::cerr << "ERROR: Couldn't delete download subThread!\n"; std::cerr << "ERROR: Couldn't delete download subThread!\n";

Loading…
Cancel
Save