1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-01 03:40:16 +02:00

After discussion in #qt, I looked at our threading code and it's all wrong/unsafe. This properly threads scanning. Also makes it idle priority and splits it into a separate scan manager

This commit is contained in:
Jeff Mitchell
2011-02-14 20:28:03 -05:00
parent 451c7d6943
commit 10c59d6f9e
12 changed files with 171 additions and 115 deletions

View File

@@ -42,6 +42,7 @@ SET( tomahawkSources ${tomahawkSources}
scrobbler.cpp
shortcuthandler.cpp
scanmanager.cpp
tomahawkapp.cpp
main.cpp
)
@@ -81,6 +82,7 @@ SET( tomahawkHeaders ${tomahawkHeaders}
musicscanner.h
scriptresolver.h
scrobbler.h
scanmanager.h
shortcuthandler.h
)

View File

@@ -8,14 +8,13 @@
using namespace Tomahawk;
MusicScanner::MusicScanner( const QString& dir, quint32 bs )
: QThread()
: QObject()
, m_dir( dir )
, m_batchsize( bs )
, m_dirLister( 0 )
, m_dirListerThreadController( 0 )
{
moveToThread( this );
m_ext2mime.insert( "mp3", "audio/mpeg" );
#ifndef NO_OGG
@@ -31,15 +30,6 @@ MusicScanner::MusicScanner( const QString& dir, quint32 bs )
// m_ext2mime.insert( "mp4", "audio/mp4" );
}
void
MusicScanner::run()
{
QTimer::singleShot( 0, this, SLOT( startScan() ) );
exec();
}
void
MusicScanner::startScan()
{
@@ -74,18 +64,21 @@ MusicScanner::scan()
connect( this, SIGNAL( batchReady( QVariantList ) ),
SLOT( commitBatch( QVariantList ) ), Qt::DirectConnection );
DirLister* lister = new DirLister( QDir( m_dir, 0 ), m_dirmtimes );
m_dirListerThreadController = new QThread( this );
m_dirLister = new DirLister( QDir( m_dir, 0 ), m_dirmtimes );
m_dirLister->moveToThread( m_dirListerThreadController );
connect( lister, SIGNAL( fileToScan( QFileInfo ) ),
connect( m_dirLister, SIGNAL( fileToScan( QFileInfo ) ),
SLOT( scanFile( QFileInfo ) ), Qt::QueuedConnection );
// queued, so will only fire after all dirs have been scanned:
connect( lister, SIGNAL( finished( const QMap<QString, unsigned int>& ) ),
connect( m_dirLister, SIGNAL( finished( const QMap<QString, unsigned int>& ) ),
SLOT( listerFinished( const QMap<QString, unsigned int>& ) ), Qt::QueuedConnection );
connect( lister, SIGNAL( finished() ), lister, SLOT( deleteLater() ) );
lister->start();
connect( m_dirLister, SIGNAL( destroyed(QObject*) ), this, SLOT( listerDestroyed(QObject*) ) );
m_dirListerThreadController->start();
QMetaObject::invokeMethod( m_dirLister, "go" );
}
@@ -111,9 +104,20 @@ MusicScanner::listerFinished( const QMap<QString, unsigned int>& newmtimes )
qDebug() << "Skipped the following files (no tags / no valid audio):";
foreach( const QString& s, m_skippedFiles )
qDebug() << s;
m_dirLister->deleteLater();
}
void
MusicScanner::listerDestroyed( QObject* dirLister )
{
qDebug() << Q_FUNC_INFO;
m_dirLister = 0;
m_dirListerThreadController->deleteLater();
m_dirListerThreadController = 0;
}
void
MusicScanner::commitBatch( const QVariantList& tracks )
{

View File

@@ -5,69 +5,26 @@
#include <taglib/tag.h>
#include <QVariantMap>
#include <QThread>
#include <QDir>
#include <QFileInfo>
#include <QString>
#include <QDebug>
#include <QDateTime>
class MusicScanner : public QThread
{
Q_OBJECT
public:
MusicScanner( const QString& dir, quint32 bs = 0 );
protected:
void run();
signals:
//void fileScanned( QVariantMap );
void finished( int, int );
void batchReady( const QVariantList& );
private:
QVariant readFile( const QFileInfo& fi );
private slots:
void listerFinished( const QMap<QString, unsigned int>& newmtimes );
void scanFile( const QFileInfo& fi );
void startScan();
void scan();
void setMtimes( const QMap<QString, unsigned int>& m );
void commitBatch( const QVariantList& );
private:
QString m_dir;
QMap<QString,QString> m_ext2mime; // eg: mp3 -> audio/mpeg
unsigned int m_scanned;
unsigned int m_skipped;
QList<QString> m_skippedFiles;
QMap<QString, unsigned int> m_dirmtimes;
QMap<QString, unsigned int> m_newdirmtimes;
QList<QVariant> m_scannedfiles;
quint32 m_batchsize;
};
#include <QTimer>
// descend dir tree comparing dir mtimes to last known mtime
// emit signal for any dir with new content, so we can scan it.
// finally, emit the list of new mtimes we observed.
class DirLister : public QThread
class DirLister : public QObject
{
Q_OBJECT
public:
DirLister( QDir d, QMap<QString, unsigned int>& mtimes )
: QThread(), m_dir( d ), m_dirmtimes( mtimes )
: QObject(), m_dir( d ), m_dirmtimes( mtimes )
{
qDebug() << Q_FUNC_INFO;
moveToThread(this);
}
~DirLister()
@@ -75,13 +32,6 @@ public:
qDebug() << Q_FUNC_INFO;
}
protected:
void run()
{
QTimer::singleShot(0,this,SLOT(go()));
exec();
}
signals:
void fileToScan( QFileInfo );
void finished( const QMap<QString, unsigned int>& );
@@ -130,4 +80,46 @@ private:
QMap<QString, unsigned int> m_newdirmtimes;
};
class MusicScanner : public QObject
{
Q_OBJECT
public:
MusicScanner( const QString& dir, quint32 bs = 0 );
signals:
//void fileScanned( QVariantMap );
void finished( int, int );
void batchReady( const QVariantList& );
private:
QVariant readFile( const QFileInfo& fi );
private slots:
void listerFinished( const QMap<QString, unsigned int>& newmtimes );
void listerDestroyed( QObject* dirLister );
void scanFile( const QFileInfo& fi );
void startScan();
void scan();
void setMtimes( const QMap<QString, unsigned int>& m );
void commitBatch( const QVariantList& );
private:
QString m_dir;
QMap<QString,QString> m_ext2mime; // eg: mp3 -> audio/mpeg
unsigned int m_scanned;
unsigned int m_skipped;
QList<QString> m_skippedFiles;
QMap<QString, unsigned int> m_dirmtimes;
QMap<QString, unsigned int> m_newdirmtimes;
QList<QVariant> m_scannedfiles;
quint32 m_batchsize;
DirLister* m_dirLister;
QThread* m_dirListerThreadController;
};
#endif

58
src/scanmanager.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "scanmanager.h"
#include "musicscanner.h"
#include <QDebug>
#include <QThread>
ScanManager* ScanManager::s_instance = 0;
ScanManager*
ScanManager::instance()
{
return s_instance;
}
ScanManager::ScanManager( QObject* parent )
: QObject( parent )
, m_scanner( 0 )
, m_musicScannerThreadController( 0 )
{
s_instance = this;
}
ScanManager::~ScanManager()
{
s_instance = 0;
m_musicScannerThreadController->deleteLater();
m_musicScannerThreadController = 0;
m_scanner->deleteLater();
m_scanner = 0;
}
void
ScanManager::runManualScan( const QString &path )
{
qDebug() << Q_FUNC_INFO;
if ( !m_musicScannerThreadController && !m_scanner ) //still running if these are not zero
{
m_musicScannerThreadController = new QThread( this );
MusicScanner* m_scanner = new MusicScanner( path );
m_scanner->moveToThread( m_musicScannerThreadController );
connect( m_scanner, SIGNAL( finished() ), m_scanner, SLOT( deleteLater() ) );
connect( m_scanner, SIGNAL( destroyed(QObject*) ), this, SLOT( scanDestroyed(QObject*) ) );
m_musicScannerThreadController->start( QThread::IdlePriority );
QMetaObject::invokeMethod( m_scanner, "startScan" );
}
}
void
ScanManager::scannerDestroyed( QObject* scanner )
{
qDebug() << Q_FUNC_INFO;
m_scanner = 0;
m_musicScannerThreadController->deleteLater();
m_musicScannerThreadController = 0;
}

32
src/scanmanager.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef SCANMANAGER_H
#define SCANMANAGER_H
#include <QObject>
#include "dllmacro.h"
class MusicScanner;
class QThread;
class DLLEXPORT ScanManager : public QObject
{
Q_OBJECT
public:
static ScanManager* instance();
explicit ScanManager( QObject* parent = 0 );
virtual ~ScanManager();
void runManualScan( const QString &path );
private slots:
void scannerDestroyed( QObject *scanner );
private:
static ScanManager* s_instance;
MusicScanner* m_scanner;
QThread* m_musicScannerThreadController;
};
#endif

View File

@@ -22,6 +22,7 @@
#include "sip/SipHandler.h"
#include "sip/twitter/tomahawkoauthtwitter.h"
#include <database/database.h>
#include "scanmanager.h"
static QString
md5( const QByteArray& src )
@@ -145,11 +146,7 @@ SettingsDialog::~SettingsDialog()
s->setScriptResolvers( resolvers );
if( rescan )
{
MusicScanner* scanner = new MusicScanner(s->scannerPath() );
connect( scanner, SIGNAL( finished() ), scanner, SLOT( deleteLater() ) );
scanner->start();
}
ScanManager::instance()->runManualScan( s->scannerPath() );
if( rejabber )
{
@@ -180,21 +177,6 @@ SettingsDialog::showPathSelector()
}
void
SettingsDialog::doScan()
{
// TODO this doesnt really belong here..
QString path = ui->lineEditMusicPath->text();
MusicScanner* scanner = new MusicScanner( path );
connect( scanner, SIGNAL( finished() ), scanner, SLOT( deleteLater() ) );
scanner->start();
QMessageBox::information( this, tr( "Scanning Started" ),
tr( "Scanning now, check console output. TODO." ),
QMessageBox::Ok );
}
void
SettingsDialog::onRejected()
{

View File

@@ -48,8 +48,7 @@ protected:
private slots:
void onRejected();
void showPathSelector();
void doScan();
void toggleUpnp( bool preferStaticEnabled );
void showProxySettings();

View File

@@ -5,6 +5,7 @@
#include <QTimer>
#include <QString>
#include <QRegExp>
#include <QThread>
#include <utils/tomahawkutils.h>
using namespace gloox;

View File

@@ -10,7 +10,6 @@
#include <QSharedPointer>
#include <QMap>
#include <QNetworkProxy>
#include <QThread>
#include <string>

View File

@@ -25,6 +25,7 @@
#include "scriptresolver.h"
#include "sourcelist.h"
#include "shortcuthandler.h"
#include "scanmanager.h"
#include "tomahawksettings.h"
#include "audio/audioengine.h"
@@ -149,10 +150,11 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
new TomahawkSettings( this );
m_audioEngine = new AudioEngine;
new ScanManager( this );
new Pipeline( this );
new SourceList( this );
m_servent = new Servent( this );
connect( m_servent, SIGNAL( ready() ), SLOT( setupSIP() ) );

View File

@@ -32,13 +32,13 @@
#include "widgets/welcomewidget.h"
#include "audiocontrols.h"
#include "musicscanner.h"
#include "settingsdialog.h"
#include "tomahawksettings.h"
#include "sourcelist.h"
#include "transferview.h"
#include "tomahawktrayicon.h"
#include "playlist/dynamic/GeneratorInterface.h"
#include "scanmanager.h"
using namespace Tomahawk;
@@ -249,23 +249,9 @@ TomahawkWindow::rescanCollectionManually()
s->scannerPath(), &ok );
s->setValue( "scannerpath", path );
if ( ok && !path.isEmpty() )
{
MusicScanner* scanner = new MusicScanner( path );
connect( scanner, SIGNAL( finished() ), this, SLOT( scanFinished() ) );
scanner->start();
}
ScanManager::instance()->runManualScan( path );
}
void
TomahawkWindow::scanFinished()
{
qDebug() << Q_FUNC_INFO;
MusicScanner* scanner = (MusicScanner*) sender();
scanner->deleteLater();
}
void
TomahawkWindow::addPeerManually()
{

View File

@@ -12,6 +12,7 @@
class QAction;
class MusicScanner;
class AudioControls;
class TomahawkTrayIcon;
@@ -46,11 +47,9 @@ public slots:
void createPlaylist();
void loadSpiff();
void showSettingsDialog();
void rescanCollectionManually();
private slots:
void scanFinished();
void rescanCollectionManually();
void onSipConnected();
void onSipDisconnected();
void onSipError();