diff --git a/src/libtomahawk/database/database.cpp b/src/libtomahawk/database/database.cpp index f7f26bb4b..e738ba9e0 100644 --- a/src/libtomahawk/database/database.cpp +++ b/src/libtomahawk/database/database.cpp @@ -73,7 +73,15 @@ Database::loadIndex() void -Database::enqueue( QSharedPointer lc ) +Database::enqueue( const QList< QSharedPointer >& lc ) +{ + qDebug() << "Enqueueing" << lc.count() << "commands to rw thread"; + m_workerRW->enqueue( lc ); +} + + +void +Database::enqueue( const QSharedPointer& lc ) { if ( lc->doesMutates() ) { diff --git a/src/libtomahawk/database/database.h b/src/libtomahawk/database/database.h index 89581fee8..123327014 100644 --- a/src/libtomahawk/database/database.h +++ b/src/libtomahawk/database/database.h @@ -66,7 +66,8 @@ signals: void newJobRW( QSharedPointer ); public slots: - void enqueue( QSharedPointer lc ); + void enqueue( const QSharedPointer& lc ); + void enqueue( const QList< QSharedPointer >& lc ); private slots: void setIsReadyTrue() { m_ready = true; } diff --git a/src/libtomahawk/database/databasecommand.h b/src/libtomahawk/database/databasecommand.h index 4b31c0fff..1126412f7 100644 --- a/src/libtomahawk/database/databasecommand.h +++ b/src/libtomahawk/database/databasecommand.h @@ -70,6 +70,7 @@ public: const Tomahawk::source_ptr& source() const; virtual bool loggable() const { return false; } + virtual bool groupable() const { return false; } virtual bool singletonCmd() const { return false; } virtual bool localOnly() const { return false; } diff --git a/src/libtomahawk/database/databasecommand_addfiles.cpp b/src/libtomahawk/database/databasecommand_addfiles.cpp index 4e776178f..414fbcc11 100644 --- a/src/libtomahawk/database/databasecommand_addfiles.cpp +++ b/src/libtomahawk/database/databasecommand_addfiles.cpp @@ -24,7 +24,6 @@ #include "album.h" #include "collection.h" #include "database/database.h" -#include "databasecommand_collectionstats.h" #include "databaseimpl.h" #include "network/dbsyncconnection.h" #include "network/servent.h" @@ -73,15 +72,7 @@ DatabaseCommand_AddFiles::postCommitHook() emit notify( m_ids ); if ( source()->isLocal() ) - { Servent::instance()->triggerDBSync(); - - // Re-calculate local db stats - DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( SourceList::instance()->getLocal() ); - connect( cmd, SIGNAL( done( QVariantMap ) ), - SourceList::instance()->getLocal().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection ); - Database::instance()->enqueue( QSharedPointer( cmd ) ); - } } diff --git a/src/libtomahawk/database/databasecommand_deletefiles.cpp b/src/libtomahawk/database/databasecommand_deletefiles.cpp index 65e54755a..3a6b171d9 100644 --- a/src/libtomahawk/database/databasecommand_deletefiles.cpp +++ b/src/libtomahawk/database/databasecommand_deletefiles.cpp @@ -25,7 +25,6 @@ #include "collection.h" #include "source.h" #include "database/database.h" -#include "databasecommand_collectionstats.h" #include "databaseimpl.h" #include "network/servent.h" #include "utils/logger.h" @@ -54,7 +53,7 @@ DatabaseCommand_DeleteFiles::postCommitHook() ids << id.toUInt(); emit notify( ids ); - if( source()->isLocal() ) + if ( source()->isLocal() ) Servent::instance()->triggerDBSync(); } diff --git a/src/libtomahawk/database/databasecommand_deletefiles.h b/src/libtomahawk/database/databasecommand_deletefiles.h index fd007b145..06ecce813 100644 --- a/src/libtomahawk/database/databasecommand_deletefiles.h +++ b/src/libtomahawk/database/databasecommand_deletefiles.h @@ -64,6 +64,7 @@ public: virtual void exec( DatabaseImpl* ); virtual bool doesMutates() const { return true; } virtual bool localOnly() const { return false; } + virtual bool groupable() const { return true; } virtual void postCommitHook(); QVariantList ids() const { return m_ids; } diff --git a/src/libtomahawk/database/databasecommand_logplayback.h b/src/libtomahawk/database/databasecommand_logplayback.h index 7b9b2cf3c..9157a5afc 100644 --- a/src/libtomahawk/database/databasecommand_logplayback.h +++ b/src/libtomahawk/database/databasecommand_logplayback.h @@ -68,6 +68,7 @@ public: virtual bool doesMutates() const { return true; } virtual bool singletonCmd() const { return ( m_action == Started ); } virtual bool localOnly() const; + virtual bool groupable() const { return true; } QString artist() const { return m_artist; } void setArtist( const QString& s ) { m_artist = s; } diff --git a/src/libtomahawk/database/databasecommand_socialaction.h b/src/libtomahawk/database/databasecommand_socialaction.h index 9f62259e9..40e23ecf0 100644 --- a/src/libtomahawk/database/databasecommand_socialaction.h +++ b/src/libtomahawk/database/databasecommand_socialaction.h @@ -170,6 +170,7 @@ public: void setTimestamp( const int ts ) { m_timestamp = ts; } virtual bool doesMutates() const { return true; } + virtual bool groupable() const { return true; } private: Tomahawk::result_ptr m_result; diff --git a/src/libtomahawk/database/databaseworker.cpp b/src/libtomahawk/database/databaseworker.cpp index ba95d0326..ab22f60d4 100644 --- a/src/libtomahawk/database/databaseworker.cpp +++ b/src/libtomahawk/database/databaseworker.cpp @@ -72,16 +72,21 @@ DatabaseWorker::run() } +void +DatabaseWorker::enqueue( const QList< QSharedPointer >& cmds ) +{ + QMutexLocker lock( &m_mut ); + m_outstanding += cmds.count(); + m_commands << cmds; + + if ( m_outstanding == cmds.count() ) + QTimer::singleShot( 0, this, SLOT( doWork() ) ); +} + + void DatabaseWorker::enqueue( const QSharedPointer& cmd ) { - if ( QThread::currentThread() != thread() ) - { -// qDebug() << Q_FUNC_INFO << "Reinvoking in correct thread."; - QMetaObject::invokeMethod( this, "enqueue", Qt::QueuedConnection, Q_ARG( QSharedPointer, cmd ) ); - return; - } - QMutexLocker lock( &m_mut ); m_outstanding++; m_commands << cmd; @@ -107,6 +112,7 @@ DatabaseWorker::doWork() timer.start(); #endif + QList< QSharedPointer > cmdGroup; QSharedPointer cmd; { QMutexLocker lock( &m_mut ); @@ -119,45 +125,66 @@ DatabaseWorker::doWork() Q_ASSERT( transok ); Q_UNUSED( transok ); } + + unsigned int completed = 0; try { + bool finished = false; { - cmd->_exec( m_dbimpl ); // runs actual SQL stuff - - if ( cmd->loggable() ) + while ( !finished ) { - // We only save our own ops to the oplog, since incoming ops from peers - // are applied immediately. - // - // Crazy idea: if peers had keypairs and could sign ops/msgs, in theory it - // would be safe to sync ops for friend A from friend B's cache, if he saved them, - // which would mean you could get updates even if a peer was offline. - if ( cmd->source()->isLocal() && !cmd->localOnly() ) + completed++; + cmd->_exec( m_dbimpl ); // runs actual SQL stuff + + if ( cmd->loggable() ) { - // save to op-log - DatabaseCommandLoggable* command = (DatabaseCommandLoggable*)cmd.data(); - logOp( command ); - } - else - { - // Make a note of the last guid we applied for this source - // so we can always request just the newer ops in future. + // We only save our own ops to the oplog, since incoming ops from peers + // are applied immediately. // - if ( !cmd->singletonCmd() ) + // Crazy idea: if peers had keypairs and could sign ops/msgs, in theory it + // would be safe to sync ops for friend A from friend B's cache, if he saved them, + // which would mean you could get updates even if a peer was offline. + if ( cmd->source()->isLocal() && !cmd->localOnly() ) { -// qDebug() << "Setting lastop for source" << cmd->source()->id() << "to" << cmd->guid(); - - TomahawkSqlQuery query = m_dbimpl->newquery(); - query.prepare( "UPDATE source SET lastop = ? WHERE id = ?" ); - query.addBindValue( cmd->guid() ); - query.addBindValue( cmd->source()->id() ); - - if ( !query.exec() ) + // save to op-log + DatabaseCommandLoggable* command = (DatabaseCommandLoggable*)cmd.data(); + logOp( command ); + } + else + { + // Make a note of the last guid we applied for this source + // so we can always request just the newer ops in future. + // + if ( !cmd->singletonCmd() ) { - throw "Failed to set lastop"; + TomahawkSqlQuery query = m_dbimpl->newquery(); + query.prepare( "UPDATE source SET lastop = ? WHERE id = ?" ); + query.addBindValue( cmd->guid() ); + query.addBindValue( cmd->source()->id() ); + + if ( !query.exec() ) + { + throw "Failed to set lastop"; + } } } } + + cmdGroup << cmd; + if ( cmd->groupable() && !m_commands.isEmpty() ) + { + QMutexLocker lock( &m_mut ); + if ( m_commands.first()->groupable() ) + { + cmd = m_commands.takeFirst(); + } + else + { + finished = true; + } + } + else + finished = true; } if ( cmd->doesMutates() ) @@ -175,7 +202,8 @@ DatabaseWorker::doWork() tDebug() << "DBCmd Duration:" << duration << "ms, now running postcommit for" << cmd->commandname(); #endif - cmd->postCommit(); + foreach ( QSharedPointer c, cmdGroup ) + c->postCommit(); #ifdef DEBUG_TIMING tDebug() << "Post commit finished in" << timer.elapsed() - duration << "ms for" << cmd->commandname(); @@ -192,7 +220,7 @@ DatabaseWorker::doWork() << m_dbimpl->database().lastError().driverText() << endl; - if( cmd->doesMutates() ) + if ( cmd->doesMutates() ) m_dbimpl->database().rollback(); Q_ASSERT( false ); @@ -200,17 +228,19 @@ DatabaseWorker::doWork() catch(...) { qDebug() << "Uncaught exception processing dbcmd"; - if( cmd->doesMutates() ) + if ( cmd->doesMutates() ) m_dbimpl->database().rollback(); Q_ASSERT( false ); throw; } - cmd->emitFinished(); + foreach ( QSharedPointer c, cmdGroup ) + c->emitFinished(); QMutexLocker lock( &m_mut ); - if ( --m_outstanding > 0 ) + m_outstanding -= completed; + if ( m_outstanding > 0 ) QTimer::singleShot( 0, this, SLOT( doWork() ) ); } diff --git a/src/libtomahawk/database/databaseworker.h b/src/libtomahawk/database/databaseworker.h index 9eae47c44..44029bac1 100644 --- a/src/libtomahawk/database/databaseworker.h +++ b/src/libtomahawk/database/databaseworker.h @@ -47,6 +47,7 @@ public: public slots: void enqueue( const QSharedPointer& ); + void enqueue( const QList< QSharedPointer >& ); protected: void run(); diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index 82cc265ce..9bc8519a6 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -24,6 +24,7 @@ #include "network/controlconnection.h" #include "database/databasecommand_addsource.h" +#include "database/databasecommand_collectionstats.h" #include "database/databasecommand_sourceoffline.h" #include "database/databasecommand_updatesearchindex.h" #include "database/database.h" @@ -116,6 +117,7 @@ Source::friendlyName() const return m_friendlyname; } + #ifndef ENABLE_HEADLESS void Source::setAvatar( const QPixmap& avatar ) @@ -140,6 +142,7 @@ Source::avatar( AvatarStyle style ) const } #endif + void Source::setFriendlyName( const QString& fname ) { @@ -231,9 +234,7 @@ Source::scanningFinished( unsigned int files ) if ( m_updateIndexWhenSynced ) { m_updateIndexWhenSynced = false; - - DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); - Database::instance()->enqueue( QSharedPointer( cmd ) ); + updateTracks(); } emit stateChanged(); @@ -351,10 +352,28 @@ Source::executeCommands() { if ( !m_cmds.isEmpty() ) { + QList< QSharedPointer > cmdGroup; QSharedPointer cmd = m_cmds.takeFirst(); + while ( cmd->groupable() ) + { + cmdGroup << cmd; + if ( !m_cmds.isEmpty() && m_cmds.first()->groupable() && m_cmds.first()->commandname() == cmd->commandname() ) + cmd = m_cmds.takeFirst(); + else + break; + } + // return here when the last command finished connect( cmd.data(), SIGNAL( finished() ), SLOT( executeCommands() ) ); - Database::instance()->enqueue( cmd ); + + if ( cmdGroup.count() ) + { + Database::instance()->enqueue( cmdGroup ); + } + else + { + Database::instance()->enqueue( cmd ); + } int percentage = ( float( m_commandCount - m_cmds.count() ) / (float)m_commandCount ) * 100.0; m_textStatus = tr( "Saving (%1%)" ).arg( percentage ); @@ -365,9 +384,7 @@ Source::executeCommands() if ( m_updateIndexWhenSynced ) { m_updateIndexWhenSynced = false; - - DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); - Database::instance()->enqueue( QSharedPointer( cmd ) ); + updateTracks(); } m_textStatus = QString(); @@ -400,6 +417,26 @@ Source::reportSocialAttributesChanged( DatabaseCommand_SocialAction* action ) } +void +Source::updateTracks() +{ + { + DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); + Database::instance()->enqueue( QSharedPointer( cmd ) ); + } + + { + // Re-calculate local db stats + DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( SourceList::instance()->get( id() ) ); + connect( cmd, SIGNAL( done( QVariantMap ) ), + SourceList::instance()->getLocal().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); + + connect( cmd, SIGNAL( finished() ), SIGNAL( stateChanged() ) ); + } +} + + void Source::updateIndexWhenSynced() { diff --git a/src/libtomahawk/source.h b/src/libtomahawk/source.h index ae9d537e8..95499f5d5 100644 --- a/src/libtomahawk/source.h +++ b/src/libtomahawk/source.h @@ -130,7 +130,7 @@ private slots: private: void addCommand( const QSharedPointer& command ); - + void updateTracks(); void reportSocialAttributesChanged( DatabaseCommand_SocialAction* action ); QList< QSharedPointer > m_collections;