Rework DB session + transactions. Now can handle multiple read only transactions in parallel

This commit is contained in:
emeric
2019-07-16 13:17:23 +02:00
parent 2a1fb0182b
commit 38ce2600d2
79 changed files with 1840 additions and 1369 deletions
+85 -80
View File
@@ -19,12 +19,15 @@
#include "PlayQueueView.hpp"
#include <Wt/WText.h>
#include <Wt/WText.h>
#include "database/Track.hpp"
#include "database/TrackList.hpp"
#include "main/Service.hpp"
#include "similarity/SimilaritySearcher.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
@@ -35,7 +38,7 @@ PlayQueue::PlayQueue()
addFunction("tr", &Wt::WTemplate::Functions::tr);
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
_repeatAll = LmsApp->getUser()->isRepeatAllSet();
_radioMode = LmsApp->getUser()->isRadioSet();
}
@@ -62,9 +65,15 @@ PlayQueue::PlayQueue()
shuffleBtn->clicked().connect([=]
{
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
getTrackList().modify()->shuffle();
Database::TrackList::pointer trackList {getTrackList()};
auto entries {trackList->getEntries()};
shuffleContainer(entries);
getTrackList().modify()->clear();
for (const auto& entry : entries)
Database::TrackListEntry::create(LmsApp->getDbSession(), entry->getTrack(), trackList);
}
_entriesContainer->clear();
addSome();
@@ -77,7 +86,7 @@ PlayQueue::PlayQueue()
_repeatAll = !_repeatAll;
updateRepeatBtn();
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
if (!LmsApp->getUser()->isDemo())
LmsApp->getUser().modify()->setRepeatAll(_repeatAll);
@@ -91,7 +100,7 @@ PlayQueue::PlayQueue()
_radioMode = !_radioMode;
updateRadioBtn();
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
if (!LmsApp->getUser()->isDemo())
LmsApp->getUser().modify()->setRadio(_radioMode);
@@ -102,23 +111,21 @@ PlayQueue::PlayQueue()
LmsApp->preQuit().connect([=]
{
if (_tracklistId)
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
if (LmsApp->getUser()->isDemo())
{
LMS_LOG(UI, DEBUG) << "Removing tracklist id " << *_tracklistId;
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto tracklist = Database::TrackList::getById(LmsApp->getDboSession(), *_tracklistId);
LMS_LOG(UI, DEBUG) << "Removing tracklist id " << _tracklistId;
auto tracklist = Database::TrackList::getById(LmsApp->getDbSession(), _tracklistId);
if (tracklist)
tracklist.remove();
}
});
updateInfo();
addSome();
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
Database::TrackList::pointer trackList;
if (!LmsApp->getUser()->isDemo())
{
@@ -126,8 +133,19 @@ PlayQueue::PlayQueue()
{
load(LmsApp->getUser()->getCurPlayingTrackPos(), false);
});
trackList = LmsApp->getUser()->getQueuedTrackList(LmsApp->getDbSession());
}
else
{
static const std::string currentPlayQueueName {"__current__playqueue__"};
trackList = Database::TrackList::create(LmsApp->getDbSession(), currentPlayQueueName, Database::TrackList::Type::Internal, false, LmsApp->getUser());
}
_tracklistId = trackList.id();
}
updateInfo();
addSome();
}
void
@@ -145,32 +163,17 @@ PlayQueue::updateRadioBtn()
Database::TrackList::pointer
PlayQueue::getTrackList()
{
Database::TrackList::pointer res;
if (LmsApp->getUser()->isDemo())
{
static const std::string currentPlayQueueName = "__current__playqueue__";
if (!_tracklistId)
{
res = Database::TrackList::create(LmsApp->getDboSession(), currentPlayQueueName, Database::TrackList::Type::Internal, false, LmsApp->getUser());
LmsApp->getDboSession().flush();
_tracklistId = res.id();
return res;
}
return Database::TrackList::getById(LmsApp->getDboSession(), *_tracklistId);
}
return LmsApp->getUser()->getQueuedTrackList();
return Database::TrackList::getById(LmsApp->getDbSession(), _tracklistId);
}
void
PlayQueue::clearTracks()
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
{
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
getTrackList().modify()->clear();
}
getTrackList().modify()->clear();
_showMore->setHidden(true);
_entriesContainer->clear();
updateInfo();
@@ -189,11 +192,12 @@ PlayQueue::load(std::size_t pos, bool play)
{
updateCurrentTrack(false);
Database::IdType trackId;
Database::IdType trackId {};
bool addRadioTrack {};
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
auto tracklist = getTrackList();
Database::TrackList::pointer tracklist {getTrackList()};
// If out of range, stop playing
if (pos >= tracklist->getCount())
@@ -209,19 +213,22 @@ PlayQueue::load(std::size_t pos, bool play)
// If last and radio mode, fill the next song
if (_radioMode && pos == tracklist->getCount() - 1)
addRadioTrack();
addRadioTrack = true;
_trackPos = pos;
auto track = tracklist->getEntry(*_trackPos)->getTrack();
trackId = track.id();
updateCurrentTrack(true);
if (!LmsApp->getUser()->isDemo())
LmsApp->getUser().modify()->setCurPlayingTrackPos(pos);
}
if (addRadioTrack)
enqueueRadioTrack();
updateCurrentTrack(true);
loadTrack.emit(trackId, play);
}
@@ -252,7 +259,7 @@ PlayQueue::playNext()
void
PlayQueue::updateInfo()
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
_nbTracks->setText(Wt::WString::tr("Lms.PlayQueue.nb-tracks").arg(static_cast<unsigned>(getTrackList()->getCount())));
}
@@ -274,55 +281,58 @@ PlayQueue::updateCurrentTrack(bool selected)
}
void
PlayQueue::enqueueTracks(const std::vector<Database::Track::pointer>& tracks)
PlayQueue::enqueueTracks(const std::vector<Database::IdType>& trackIds)
{
// Use a "session" playqueue in order to store the current playqueue
// so that the user can disconnect and get its playqueue back
{
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
auto tracklist = getTrackList();
auto tracklist = getTrackList();
for (Database::IdType trackId : trackIds)
{
Database::Track::pointer track {Database::Track::getById(LmsApp->getDbSession(), trackId)};
if (!track)
continue;
for (auto track : tracks)
Database::TrackListEntry::create(LmsApp->getDboSession(), track, tracklist);
Database::TrackListEntry::create(LmsApp->getDbSession(), track, tracklist);
}
}
updateInfo();
addSome();
}
void
PlayQueue::enqueueTrack(Database::Track::pointer track)
PlayQueue::enqueueTrack(Database::IdType trackId)
{
enqueueTracks(std::vector<Database::Track::pointer>(1, track));
enqueueTracks({trackId});
}
void
PlayQueue::addTracks(const std::vector<Database::Track::pointer>& tracks)
PlayQueue::addTracks(const std::vector<Database::IdType>& trackIds)
{
enqueueTracks(tracks);
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", tracks.size()).arg(tracks.size()), std::chrono::milliseconds(2000));
enqueueTracks(trackIds);
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000));
}
void
PlayQueue::playTracks(const std::vector<Database::Track::pointer>& tracks)
PlayQueue::playTracks(const std::vector<Database::IdType>& trackIds)
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
clearTracks();
enqueueTracks(tracks);
enqueueTracks(trackIds);
load(0, true);
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-playing", tracks.size()).arg(tracks.size()), std::chrono::milliseconds(2000));
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-playing", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000));
}
void
PlayQueue::addSome()
{
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
auto tracklist = getTrackList();
auto tracklistEntries = tracklist->getEntries(_entriesContainer->count(), 50);
for (auto tracklistEntry : tracklistEntries)
for (const Database::TrackListEntry::pointer& tracklistEntry : tracklistEntries)
{
auto tracklistEntryId = tracklistEntry.id();
auto track = tracklistEntry->getTrack();
@@ -367,15 +377,15 @@ PlayQueue::addSome()
{
// Remove the entry n both the widget tree and the playqueue
{
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
auto entryToRemove = Database::TrackListEntry::getById(LmsApp->getDboSession(), tracklistEntryId);
Database::TrackListEntry::pointer entryToRemove {Database::TrackListEntry::getById(LmsApp->getDbSession(), tracklistEntryId)};
entryToRemove.remove();
}
if (_trackPos)
{
auto pos = _entriesContainer->indexOf(entry);
auto pos {_entriesContainer->indexOf(entry)};
if (pos > 0 && *_trackPos >= static_cast<std::size_t>(pos))
(*_trackPos)--;
}
@@ -391,28 +401,23 @@ PlayQueue::addSome()
}
void
PlayQueue::addRadioTrack()
PlayQueue::enqueueRadioTrack()
{
auto tracklist = getTrackList();
std::vector<Database::IdType> trackIds;
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
Database::TrackList::pointer tracklist {getTrackList()};
trackIds = getTrackList()->getTrackIds();
}
std::vector<Database::IdType> trackIds = getTrackList()->getTrackIds();
if (trackIds.empty())
return;
auto res = getService<Similarity::Searcher>()->getSimilarTracks(LmsApp->getDboSession(), std::set<Database::IdType>(trackIds.begin(), trackIds.end()), 1);
for (auto trackId : res)
{
auto trackToAdd = Database::Track::getById(LmsApp->getDboSession(), trackId);
enqueueTrack(trackToAdd);
}
const std::vector<Database::IdType> trackToAddIds {getService<Similarity::Searcher>()->getSimilarTracks(LmsApp->getDbSession(), std::set<Database::IdType>(std::cbegin(trackIds), std::cend(trackIds)), 1)};
enqueueTracks(trackToAddIds);
}
void addRadioTrackFromSimilarity(std::shared_ptr<Similarity::Searcher> similaritySearcher)
{
}
} // namespace UserInterface