Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lp1845837: Speed up purging of tracks #2393

Merged
merged 6 commits into from
Dec 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ before_install:
# Virtual X, needed for analyzer waveform tests
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DISPLAY=:99.0 ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh -e /etc/init.d/xvfb start ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
uklotzde marked this conversation as resolved.
Show resolved Hide resolved
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install scons portaudio libsndfile libogg libvorbis portmidi taglib libshout protobuf flac ffmpeg qt chromaprint rubberband libmodplug libid3tag libmad mp4v2 faad2 wavpack opusfile lilv; fi

install:
Expand Down
58 changes: 37 additions & 21 deletions src/library/baseplaylistfeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,45 @@ BasePlaylistFeature::BasePlaylistFeature(QObject* parent,
this, SLOT(slotExportTrackFiles()));

m_pAnalyzePlaylistAction = new QAction(tr("Analyze entire Playlist"), this);
connect(m_pAnalyzePlaylistAction, SIGNAL(triggered()),
this, SLOT(slotAnalyzePlaylist()));

connect(&m_playlistDao, SIGNAL(added(int)),
this, SLOT(slotPlaylistTableChanged(int)));

connect(&m_playlistDao, SIGNAL(deleted(int)),
this, SLOT(slotPlaylistTableChanged(int)));

connect(&m_playlistDao, SIGNAL(renamed(int,QString)),
this, SLOT(slotPlaylistTableRenamed(int,QString)));

connect(&m_playlistDao, SIGNAL(changed(int)),
this, SLOT(slotPlaylistContentChanged(int)));

connect(&m_playlistDao, SIGNAL(lockChanged(int)),
this, SLOT(slotPlaylistTableChanged(int)));
connect(m_pAnalyzePlaylistAction,
&QAction::triggered,
this,
&BasePlaylistFeature::slotAnalyzePlaylist);

connect(&m_playlistDao,
&PlaylistDAO::added,
this,
&BasePlaylistFeature::slotPlaylistTableChanged);

connect(&m_playlistDao,
&PlaylistDAO::deleted,
this,
&BasePlaylistFeature::slotPlaylistTableChanged);

connect(&m_playlistDao,
&PlaylistDAO::renamed,
this,
&BasePlaylistFeature::slotPlaylistTableRenamed);

connect(&m_playlistDao,
&PlaylistDAO::tracksChanged,
this,
&BasePlaylistFeature::slotPlaylistContentChanged);

connect(&m_playlistDao,
&PlaylistDAO::lockChanged,
this,
&BasePlaylistFeature::slotPlaylistTableChanged);

Library* pLibrary = static_cast<Library*>(parent);
connect(pLibrary, SIGNAL(trackSelected(TrackPointer)),
this, SLOT(slotTrackSelected(TrackPointer)));
connect(pLibrary, SIGNAL(switchToView(const QString&)),
this, SLOT(slotResetSelectedTrack()));
connect(pLibrary,
&Library::trackSelected,
this,
&BasePlaylistFeature::slotTrackSelected);
connect(pLibrary,
&Library::switchToView,
this,
&BasePlaylistFeature::slotResetSelectedTrack);
}

BasePlaylistFeature::~BasePlaylistFeature() {
Expand Down
4 changes: 2 additions & 2 deletions src/library/baseplaylistfeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class BasePlaylistFeature : public LibraryFeature {
virtual void htmlLinkClicked(const QUrl& link);

virtual void slotPlaylistTableChanged(int playlistId) = 0;
virtual void slotPlaylistContentChanged(int playlistId) = 0;
virtual void slotPlaylistTableRenamed(int playlistId, QString a_strName) = 0;
virtual void slotPlaylistContentChanged(QSet<int> playlistIds) = 0;
virtual void slotPlaylistTableRenamed(int playlistId, QString newName) = 0;
void slotCreatePlaylist();

protected slots:
Expand Down
60 changes: 34 additions & 26 deletions src/library/dao/playlistdao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ bool PlaylistDAO::isPlaylistLocked(const int playlistId) const {
return false;
}

bool PlaylistDAO::removeTracksFromPlaylist(const int playlistId, const int startIndex) {
bool PlaylistDAO::removeTracksFromPlaylist(int playlistId, int startIndex) {
// Retain the first track if it is loaded in a deck
ScopedTransaction transaction(m_database);
QSqlQuery query(m_database);
Expand All @@ -256,7 +256,7 @@ bool PlaylistDAO::removeTracksFromPlaylist(const int playlistId, const int start
return false;
}
transaction.commit();
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
return true;
}

Expand Down Expand Up @@ -298,7 +298,7 @@ bool PlaylistDAO::appendTracksToPlaylist(const QList<TrackId>& trackIds, const i
// TODO(XXX) don't emit if the track didn't add successfully.
emit(trackAdded(playlistId, trackId, insertPosition++));
}
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
return true;
}

Expand Down Expand Up @@ -406,18 +406,23 @@ void PlaylistDAO::removeHiddenTracks(const int playlistId) {
}

while (query.next()) {
int position = query.value(query.record().indexOf("position")).toInt();
removeTracksFromPlaylistInner(playlistId, position);
int position = query.value(query.record().indexOf("position")).toInt();
removeTracksFromPlaylistInner(playlistId, position);
}

transaction.commit();
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
}


void PlaylistDAO::removeTrackFromPlaylist(const int playlistId, const TrackId& trackId) {
void PlaylistDAO::removeTracksFromPlaylistById(int playlistId, TrackId trackId) {
ScopedTransaction transaction(m_database);
removeTracksFromPlaylistByIdInner(playlistId, trackId);
transaction.commit();
emit tracksChanged(QSet<int>{playlistId});
}

void PlaylistDAO::removeTracksFromPlaylistByIdInner(int playlistId, TrackId trackId) {
QSqlQuery query(m_database);
query.prepare("SELECT position FROM PlaylistTracks WHERE playlist_id=:id "
"AND track_id=:track_id");
Expand All @@ -431,38 +436,33 @@ void PlaylistDAO::removeTrackFromPlaylist(const int playlistId, const TrackId& t
}

while (query.next()) {
int position = query.value(query.record().indexOf("position")).toInt();
int position = query.value(query.record().indexOf("position")).toInt();
removeTracksFromPlaylistInner(playlistId, position);

}

transaction.commit();
emit(changed(playlistId));
}


void PlaylistDAO::removeTrackFromPlaylist(const int playlistId, const int position) {
void PlaylistDAO::removeTrackFromPlaylist(int playlistId, int position) {
// qDebug() << "PlaylistDAO::removeTrackFromPlaylist"
// << QThread::currentThread() << m_database.connectionName();
ScopedTransaction transaction(m_database);
removeTracksFromPlaylistInner(playlistId, position);
transaction.commit();
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
}

void PlaylistDAO::removeTracksFromPlaylist(const int playlistId, QList<int>& positions) {
void PlaylistDAO::removeTracksFromPlaylist(int playlistId, QList<int> positions) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not const QList& ? A copy by value increases the shared counter, which requires qt:as_const() in range based loops to be efficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because a local, writable copy is need for sorting. First line of the function body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The QList is actually not shared, but moved into this function. The caller never accesses it again after calling the function. The copy happens, because instead of move semantics Qt relies on implicit sharing.

I could add a std::move at the caller's site, because QList has a move constructor. This should eliminate the temporary copy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, thank you for explaining.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I omitted to use std::move in the first place because I was recently told not to use it in Qt code ;) What I definitely won't do is checking each and every Qt class before using it. I prefer to use it if it is semantically correct, whether it is supported or not.

// get positions in reversed order
qSort(positions.begin(), positions.end(), qGreater<int>());

//qDebug() << "PlaylistDAO::removeTrackFromPlaylist"
// << QThread::currentThread() << m_database.connectionName();
ScopedTransaction transaction(m_database);
QSqlQuery query(m_database);
foreach (int position , positions) {
removeTracksFromPlaylistInner(playlistId, position);
for (const auto position : qAsConst(positions)) {
removeTracksFromPlaylistInner(playlistId, position);
}
transaction.commit();
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
}

void PlaylistDAO::removeTracksFromPlaylistInner(int playlistId, int position) {
Expand Down Expand Up @@ -550,7 +550,7 @@ bool PlaylistDAO::insertTrackIntoPlaylist(TrackId trackId, const int playlistId,

m_playlistsTrackIsIn.insert(trackId, playlistId);
emit(trackAdded(playlistId, trackId, position));
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
return true;
}

Expand Down Expand Up @@ -611,7 +611,7 @@ int PlaylistDAO::insertTracksIntoPlaylist(const QList<TrackId>& trackIds,
// TODO(XXX) The position is wrong if any track failed to insert.
emit(trackAdded(playlistId, trackId, insertPositon++));
}
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
return tracksAdded;
}

Expand Down Expand Up @@ -724,7 +724,7 @@ bool PlaylistDAO::copyPlaylistTracks(const int sourcePlaylistID, const int targe
m_playlistsTrackIsIn.insert(copiedTrackId, targetPlaylistID);
emit(trackAdded(targetPlaylistID, copiedTrackId, copiedPosition));
}
emit(changed(targetPlaylistID));
emit tracksChanged(QSet<int>{targetPlaylistID});
return true;
}

Expand All @@ -750,14 +750,22 @@ int PlaylistDAO::getMaxPosition(const int playlistId) const {
void PlaylistDAO::removeTracksFromPlaylists(const QList<TrackId>& trackIds) {
// copy the hash, because there is no guarantee that "it" is valid after remove
QMultiHash<TrackId, int> playlistsTrackIsInCopy = m_playlistsTrackIsIn;
for (const auto& trackId: trackIds) {
QSet<int> playlistIds;

ScopedTransaction transaction(m_database);
for (const auto& trackId : trackIds) {
for (auto it = playlistsTrackIsInCopy.constBegin();
it != playlistsTrackIsInCopy.constEnd(); ++it) {
if (it.key() == trackId) {
removeTrackFromPlaylist(it.value(), trackId);
const auto playlistId = it.value();
removeTracksFromPlaylistByIdInner(playlistId, trackId);
playlistIds.insert(playlistId);
}
}
}
transaction.commit();

emit tracksChanged(playlistIds);
}

int PlaylistDAO::tracksInPlaylist(const int playlistId) const {
Expand Down Expand Up @@ -830,7 +838,7 @@ void PlaylistDAO::moveTrack(const int playlistId, const int oldPosition, const i
qDebug() << query.lastError();
}

emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
}

void PlaylistDAO::searchForDuplicateTrack(const int fromPosition,
Expand Down Expand Up @@ -994,7 +1002,7 @@ void PlaylistDAO::shuffleTracks(const int playlistId, const QList<int>& position
}

transaction.commit();
emit(changed(playlistId));
emit tracksChanged(QSet<int>{playlistId});
}

bool PlaylistDAO::isTrackInPlaylist(TrackId trackId, const int playlistId) const {
Expand Down
15 changes: 8 additions & 7 deletions src/library/dao/playlistdao.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ class PlaylistDAO : public QObject, public virtual DAO {
// removes all hidden and purged Tracks from the playlist
void removeHiddenTracks(const int playlistId);
// Remove a track from a playlist
void removeTrackFromPlaylist(const int playlistId, const TrackId& trackId);
void removeTrackFromPlaylist(const int playlistId, const int position);
void removeTracksFromPlaylist(const int playlistId, QList<int>& positions);
void removeTrackFromPlaylist(int playlistId, int position);
void removeTracksFromPlaylist(int playlistId, QList<int> positions);
void removeTracksFromPlaylistById(int playlistId, TrackId trackId);
// Insert a track into a specific position in a playlist
bool insertTrackIntoPlaylist(TrackId trackId, int playlistId, int position);
// Inserts a list of tracks into playlist
Expand Down Expand Up @@ -124,15 +124,16 @@ class PlaylistDAO : public QObject, public virtual DAO {
signals:
void added(int playlistId);
void deleted(int playlistId);
void changed(int playlistId);
void renamed(int playlistId, QString newName);
void lockChanged(int playlistId);
void trackAdded(int playlistId, TrackId trackId, int position);
void trackRemoved(int playlistId, TrackId trackId, int position);
void renamed(int playlistId, QString a_strName);
void lockChanged(int playlistId);
void tracksChanged(QSet<int> playlistIds); // added/removed/reordered

private:
bool removeTracksFromPlaylist(const int playlistId, const int startIndex);
bool removeTracksFromPlaylist(int playlistId, int startIndex);
void removeTracksFromPlaylistInner(int playlistId, int position);
void removeTracksFromPlaylistByIdInner(int playlistId, TrackId trackId);
void searchForDuplicateTrack(const int fromPosition,
const int toPosition,
TrackId trackID,
Expand Down
21 changes: 11 additions & 10 deletions src/library/playlistfeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,23 +232,24 @@ void PlaylistFeature::slotPlaylistTableChanged(int playlistId) {
}
}

void PlaylistFeature::slotPlaylistContentChanged(int playlistId) {
void PlaylistFeature::slotPlaylistContentChanged(QSet<int> playlistIds) {
if (!m_pPlaylistTableModel) {
return;
}

//qDebug() << "slotPlaylistContentChanged() playlistId:" << playlistId;
enum PlaylistDAO::HiddenType type = m_playlistDao.getHiddenType(playlistId);
if (type == PlaylistDAO::PLHT_NOT_HIDDEN ||
type == PlaylistDAO::PLHT_UNKNOWN) { // In case of a deleted Playlist
updateChildModel(playlistId);
for (const auto playlistId : qAsConst(playlistIds)) {
enum PlaylistDAO::HiddenType type = m_playlistDao.getHiddenType(playlistId);
if (type == PlaylistDAO::PLHT_NOT_HIDDEN ||
type == PlaylistDAO::PLHT_UNKNOWN) { // In case of a deleted Playlist
updateChildModel(playlistId);
}
}
}



void PlaylistFeature::slotPlaylistTableRenamed(int playlistId,
QString /* a_strName */) {
void PlaylistFeature::slotPlaylistTableRenamed(
int playlistId,
QString newName) {
Q_UNUSED(newName);
if (!m_pPlaylistTableModel) {
return;
}
Expand Down
6 changes: 3 additions & 3 deletions src/library/playlistfeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class PlaylistFeature : public BasePlaylistFeature {
void onRightClickChild(const QPoint& globalPos, QModelIndex index);

private slots:
void slotPlaylistTableChanged(int playlistId);
void slotPlaylistContentChanged(int playlistId);
void slotPlaylistTableRenamed(int playlistId, QString a_strName);
void slotPlaylistTableChanged(int playlistId) override;
void slotPlaylistContentChanged(QSet<int> playlistIds) override;
void slotPlaylistTableRenamed(int playlistId, QString newName) override;

protected:
QList<BasePlaylistFeature::IdAndLabel> createPlaylistLabels() override;
Expand Down
14 changes: 9 additions & 5 deletions src/library/playlisttablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ void PlaylistTableModel::setTableModel(int playlistId) {
setDefaultSort(fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder);
setSort(defaultSortColumn(), defaultSortOrder());

connect(&m_pTrackCollection->getPlaylistDAO(), SIGNAL(changed(int)),
this, SLOT(playlistChanged(int)));
connect(&m_pTrackCollection->getPlaylistDAO(),
&PlaylistDAO::tracksChanged,
this,
&PlaylistTableModel::playlistsChanged);
}

int PlaylistTableModel::addTracks(const QModelIndex& index,
Expand Down Expand Up @@ -130,7 +132,9 @@ void PlaylistTableModel::removeTracks(const QModelIndexList& indices) {
trackPositions.append(trackPosition);
}

m_pTrackCollection->getPlaylistDAO().removeTracksFromPlaylist(m_iPlaylistId, trackPositions);
m_pTrackCollection->getPlaylistDAO().removeTracksFromPlaylist(
m_iPlaylistId,
std::move(trackPositions));
}

void PlaylistTableModel::moveTrack(const QModelIndex& sourceIndex,
Expand Down Expand Up @@ -259,8 +263,8 @@ TrackModel::CapabilitiesFlags PlaylistTableModel::getCapabilities() const {
return caps;
}

void PlaylistTableModel::playlistChanged(int playlistId) {
if (playlistId == m_iPlaylistId) {
void PlaylistTableModel::playlistsChanged(QSet<int> playlistIds) {
if (playlistIds.contains(m_iPlaylistId)) {
select(); // Repopulate the data model.
}
}
2 changes: 1 addition & 1 deletion src/library/playlisttablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class PlaylistTableModel : public BaseSqlTableModel {
CapabilitiesFlags getCapabilities() const final;

private slots:
void playlistChanged(int playlistId);
void playlistsChanged(QSet<int> playlistIds);

private:
int m_iPlaylistId;
Expand Down