Do the compilation processing in the database thread, and make everything lock on the database to ensure two threads don't access it at once.
This commit is contained in:
parent
03d876a599
commit
c834a5f31f
|
@ -139,12 +139,14 @@ void Database::SqliteLike(sqlite3_context* context, int argc, sqlite3_value** ar
|
|||
|
||||
Database::Database(QObject* parent, const QString& database_name)
|
||||
: QObject(parent),
|
||||
mutex_(QMutex::Recursive),
|
||||
injected_database_name_(database_name),
|
||||
query_hash_(0)
|
||||
{
|
||||
directory_ = QDir::toNativeSeparators(
|
||||
QDir::homePath() + "/.config/" + QCoreApplication::organizationName());
|
||||
|
||||
QMutexLocker l(&mutex_);
|
||||
Connect();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ class Database : public QObject {
|
|||
|
||||
QSqlDatabase Connect();
|
||||
bool CheckErrors(const QSqlError& error);
|
||||
QMutex* Mutex() { return &mutex_; }
|
||||
|
||||
signals:
|
||||
void Error(const QString& message);
|
||||
|
@ -49,6 +50,7 @@ class Database : public QObject {
|
|||
|
||||
QString directory_;
|
||||
QMutex connect_mutex_;
|
||||
QMutex mutex_;
|
||||
|
||||
// Used by tests
|
||||
QString injected_database_name_;
|
||||
|
|
|
@ -76,6 +76,8 @@ void Library::WatcherInitialised() {
|
|||
backend_, SLOT(AddOrUpdateSubdirs(SubdirectoryList)));
|
||||
connect(watcher, SIGNAL(SubdirsMTimeUpdated(SubdirectoryList)),
|
||||
backend_, SLOT(AddOrUpdateSubdirs(SubdirectoryList)));
|
||||
connect(watcher, SIGNAL(CompilationsNeedUpdating()),
|
||||
backend_, SLOT(UpdateCompilations()));
|
||||
|
||||
// This will start the watcher checking for updates
|
||||
backend_->LoadDirectoriesAsync();
|
||||
|
|
|
@ -47,6 +47,7 @@ void LibraryBackend::UpdateTotalSongCountAsync() {
|
|||
}
|
||||
|
||||
void LibraryBackend::LoadDirectories() {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("SELECT ROWID, path FROM %1").arg(dirs_table_), db);
|
||||
|
@ -63,6 +64,7 @@ void LibraryBackend::LoadDirectories() {
|
|||
}
|
||||
|
||||
SubdirectoryList LibraryBackend::SubdirsInDirectory(int id) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db = db_->Connect();
|
||||
return SubdirsInDirectory(id, db);
|
||||
}
|
||||
|
@ -87,6 +89,7 @@ SubdirectoryList LibraryBackend::SubdirsInDirectory(int id, QSqlDatabase &db) {
|
|||
}
|
||||
|
||||
void LibraryBackend::UpdateTotalSongCount() {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("SELECT COUNT(*) FROM %1").arg(songs_table_), db);
|
||||
|
@ -98,6 +101,7 @@ void LibraryBackend::UpdateTotalSongCount() {
|
|||
}
|
||||
|
||||
void LibraryBackend::AddDirectory(const QString &path) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("INSERT INTO %1 (path, subdirs)"
|
||||
|
@ -114,6 +118,7 @@ void LibraryBackend::AddDirectory(const QString &path) {
|
|||
}
|
||||
|
||||
void LibraryBackend::RemoveDirectory(const Directory& dir) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
// Remove songs first
|
||||
|
@ -141,6 +146,7 @@ void LibraryBackend::RemoveDirectory(const Directory& dir) {
|
|||
}
|
||||
|
||||
SongList LibraryBackend::FindSongsInDirectory(int id) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("SELECT ROWID, " + Song::kColumnSpec +
|
||||
|
@ -160,6 +166,7 @@ SongList LibraryBackend::FindSongsInDirectory(int id) {
|
|||
}
|
||||
|
||||
void LibraryBackend::AddOrUpdateSubdirs(const SubdirectoryList& subdirs) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
QSqlQuery find_query(QString("SELECT ROWID FROM %1"
|
||||
" WHERE directory = :id AND path = :path")
|
||||
|
@ -208,6 +215,7 @@ void LibraryBackend::AddOrUpdateSubdirs(const SubdirectoryList& subdirs) {
|
|||
}
|
||||
|
||||
void LibraryBackend::AddOrUpdateSongs(const SongList& songs) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery check_dir(QString("SELECT ROWID FROM %1 WHERE ROWID = :id")
|
||||
|
@ -275,6 +283,7 @@ void LibraryBackend::AddOrUpdateSongs(const SongList& songs) {
|
|||
}
|
||||
|
||||
void LibraryBackend::UpdateMTimesOnly(const SongList& songs) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("UPDATE %1 SET mtime = :mtime WHERE ROWID = :id")
|
||||
|
@ -291,6 +300,7 @@ void LibraryBackend::UpdateMTimesOnly(const SongList& songs) {
|
|||
}
|
||||
|
||||
void LibraryBackend::DeleteSongs(const SongList &songs) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("DELETE FROM %1 WHERE ROWID = :id")
|
||||
|
@ -314,6 +324,7 @@ QStringList LibraryBackend::GetAllArtists(const QueryOptions& opt) {
|
|||
query.SetColumnSpec("DISTINCT artist");
|
||||
query.AddCompilationRequirement(false);
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return QStringList();
|
||||
|
||||
QStringList ret;
|
||||
|
@ -339,6 +350,7 @@ SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, c
|
|||
query.AddWhere("artist", artist);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return SongList();
|
||||
|
||||
SongList ret;
|
||||
|
@ -351,6 +363,7 @@ SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, c
|
|||
}
|
||||
|
||||
Song LibraryBackend::GetSongById(int id) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1"
|
||||
|
@ -371,6 +384,7 @@ bool LibraryBackend::HasCompilations(const QueryOptions& opt) {
|
|||
query.SetColumnSpec("ROWID");
|
||||
query.AddCompilationRequirement(true);
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return false;
|
||||
|
||||
return query.Next();
|
||||
|
@ -386,6 +400,7 @@ SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOp
|
|||
query.AddCompilationRequirement(true);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return SongList();
|
||||
|
||||
SongList ret;
|
||||
|
@ -398,6 +413,7 @@ SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOp
|
|||
}
|
||||
|
||||
void LibraryBackend::UpdateCompilations() {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
// Look for albums that have songs by more than one artist in the same
|
||||
|
@ -513,6 +529,7 @@ LibraryBackend::AlbumList LibraryBackend::GetAlbums(const QString& artist,
|
|||
query.AddWhere("artist", artist);
|
||||
}
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return ret;
|
||||
|
||||
QString last_album;
|
||||
|
@ -548,6 +565,7 @@ LibraryBackend::Album LibraryBackend::GetAlbumArt(const QString& artist, const Q
|
|||
query.AddWhere("artist", artist);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
if (!ExecQuery(&query)) return ret;
|
||||
|
||||
if (query.Next()) {
|
||||
|
@ -570,6 +588,7 @@ void LibraryBackend::UpdateManualAlbumArtAsync(const QString &artist,
|
|||
void LibraryBackend::UpdateManualAlbumArt(const QString &artist,
|
||||
const QString &album,
|
||||
const QString &art) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QString sql(QString("UPDATE %1 SET art_manual = :art"
|
||||
|
@ -588,6 +607,7 @@ void LibraryBackend::UpdateManualAlbumArt(const QString &artist,
|
|||
}
|
||||
|
||||
void LibraryBackend::ForceCompilation(const QString& artist, const QString& album, bool on) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
// Get the songs before they're updated
|
||||
|
|
|
@ -36,6 +36,8 @@ class LibraryBackend : public QObject {
|
|||
void Init(boost::shared_ptr<Database> db, const QString& songs_table,
|
||||
const QString& dirs_table, const QString& subdirs_table);
|
||||
|
||||
boost::shared_ptr<Database> db() const { return db_; }
|
||||
|
||||
struct Album {
|
||||
Album() {}
|
||||
Album(const QString& _artist, const QString& _album_name,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "librarybackend.h"
|
||||
#include "libraryitem.h"
|
||||
#include "librarydirectorymodel.h"
|
||||
#include "core/database.h"
|
||||
#include "playlist/songmimedata.h"
|
||||
#include "ui/iconloader.h"
|
||||
|
||||
|
@ -366,6 +367,7 @@ void LibraryModel::LazyPopulate(LibraryItem* parent, bool signal) {
|
|||
}
|
||||
|
||||
// Execute the query
|
||||
QMutexLocker l(backend_->db()->Mutex());
|
||||
if (!backend_->ExecQuery(&q))
|
||||
return;
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList&
|
|||
}
|
||||
}
|
||||
|
||||
backend_->UpdateCompilations();
|
||||
emit CompilationsNeedUpdating();
|
||||
}
|
||||
|
||||
void LibraryWatcher::ScanSubdirectory(
|
||||
|
@ -388,7 +388,7 @@ void LibraryWatcher::RescanPathsNow() {
|
|||
|
||||
rescan_queue_.clear();
|
||||
|
||||
backend_->UpdateCompilations();
|
||||
emit CompilationsNeedUpdating();
|
||||
}
|
||||
|
||||
QString LibraryWatcher::PickBestImage(const QStringList& images) {
|
||||
|
@ -448,5 +448,5 @@ void LibraryWatcher::IncrementalScanNow() {
|
|||
ScanSubdirectory(subdir.path, subdir, &transaction);
|
||||
}
|
||||
}
|
||||
backend_->UpdateCompilations();
|
||||
emit CompilationsNeedUpdating();
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class LibraryWatcher : public QObject {
|
|||
void SongsDeleted(const SongList& songs);
|
||||
void SubdirsDiscovered(const SubdirectoryList& subdirs);
|
||||
void SubdirsMTimeUpdated(const SubdirectoryList& subdirs);
|
||||
void CompilationsNeedUpdating();
|
||||
|
||||
void ScanStarted();
|
||||
void ScanFinished();
|
||||
|
|
|
@ -30,6 +30,7 @@ PlaylistBackend::PlaylistBackend(QObject* parent)
|
|||
}
|
||||
|
||||
PlaylistBackend::PlaylistList PlaylistBackend::GetAllPlaylists() {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
PlaylistList ret;
|
||||
|
@ -51,6 +52,7 @@ PlaylistBackend::PlaylistList PlaylistBackend::GetAllPlaylists() {
|
|||
}
|
||||
|
||||
PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q("SELECT ROWID, name, last_played FROM playlists"
|
||||
|
@ -71,6 +73,7 @@ PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) {
|
|||
}
|
||||
|
||||
PlaylistItemList PlaylistBackend::GetPlaylistItems(int playlist) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
PlaylistItemList ret;
|
||||
|
@ -116,6 +119,7 @@ void PlaylistBackend::SavePlaylistAsync(int playlist, const PlaylistItemList &it
|
|||
|
||||
void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
|
||||
int last_played) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery clear("DELETE FROM playlist_items WHERE playlist = :playlist", db);
|
||||
|
@ -154,6 +158,7 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
|
|||
}
|
||||
|
||||
int PlaylistBackend::CreatePlaylist(const QString &name) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q("INSERT INTO playlists (name) VALUES (:name)", db);
|
||||
|
@ -166,6 +171,7 @@ int PlaylistBackend::CreatePlaylist(const QString &name) {
|
|||
}
|
||||
|
||||
void PlaylistBackend::RemovePlaylist(int id) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
QSqlQuery delete_playlist("DELETE FROM playlists WHERE ROWID=:id", db);
|
||||
QSqlQuery delete_items("DELETE FROM playlist_items WHERE playlist=:id", db);
|
||||
|
@ -187,6 +193,7 @@ void PlaylistBackend::RemovePlaylist(int id) {
|
|||
}
|
||||
|
||||
void PlaylistBackend::RenamePlaylist(int id, const QString &new_name) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
QSqlQuery q("UPDATE playlists SET name=:name WHERE ROWID=:id", db);
|
||||
q.bindValue(":name", new_name);
|
||||
|
@ -197,6 +204,7 @@ void PlaylistBackend::RenamePlaylist(int id, const QString &new_name) {
|
|||
}
|
||||
|
||||
void PlaylistBackend::SetPlaylistOrder(const QList<int>& ids) {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
QSqlQuery q("UPDATE playlists SET ui_order=:index WHERE ROWID=:id", db);
|
||||
|
||||
|
|
Loading…
Reference in New Issue