203 lines
9.2 KiB
C++
203 lines
9.2 KiB
C++
/*
|
|
* Copyright (C) 2020 Emeric Poupon
|
|
*
|
|
* This file is part of LMS.
|
|
*
|
|
* LMS is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* LMS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "database/Session.hpp"
|
|
|
|
#include <cassert>
|
|
|
|
#include "utils/Exception.hpp"
|
|
#include "utils/ILogger.hpp"
|
|
|
|
#include "database/Artist.hpp"
|
|
#include "database/AuthToken.hpp"
|
|
#include "database/Cluster.hpp"
|
|
#include "database/Db.hpp"
|
|
#include "database/Listen.hpp"
|
|
#include "database/Release.hpp"
|
|
#include "database/ScanSettings.hpp"
|
|
#include "database/StarredArtist.hpp"
|
|
#include "database/StarredRelease.hpp"
|
|
#include "database/StarredTrack.hpp"
|
|
#include "database/Track.hpp"
|
|
#include "database/TrackBookmark.hpp"
|
|
#include "database/TrackArtistLink.hpp"
|
|
#include "database/TrackList.hpp"
|
|
#include "database/TrackFeatures.hpp"
|
|
#include "database/TransactionChecker.hpp"
|
|
#include "database/User.hpp"
|
|
#include "EnumSetTraits.hpp"
|
|
#include "Migration.hpp"
|
|
|
|
namespace Database
|
|
{
|
|
|
|
WriteTransaction::WriteTransaction(RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
|
|
: _lock{ mutex },
|
|
_transaction{ session }
|
|
{
|
|
TransactionChecker::pushWriteTransaction(_transaction.session());
|
|
}
|
|
|
|
WriteTransaction::~WriteTransaction()
|
|
{
|
|
TransactionChecker::popWriteTransaction(_transaction.session());
|
|
}
|
|
|
|
ReadTransaction::ReadTransaction(Wt::Dbo::Session& session)
|
|
: _transaction{ session }
|
|
{
|
|
TransactionChecker::pushReadTransaction(_transaction.session());
|
|
}
|
|
|
|
ReadTransaction::~ReadTransaction()
|
|
{
|
|
TransactionChecker::popReadTransaction(_transaction.session());
|
|
}
|
|
|
|
Session::Session(Db& db)
|
|
: _db{ db }
|
|
{
|
|
_session.setConnectionPool(_db.getConnectionPool());
|
|
|
|
_session.mapClass<VersionInfo>("version_info");
|
|
_session.mapClass<Artist>("artist");
|
|
_session.mapClass<AuthToken>("auth_token");
|
|
_session.mapClass<Cluster>("cluster");
|
|
_session.mapClass<ClusterType>("cluster_type");
|
|
_session.mapClass<Listen>("listen");
|
|
_session.mapClass<Release>("release");
|
|
_session.mapClass<ScanSettings>("scan_settings");
|
|
_session.mapClass<StarredArtist>("starred_artist");
|
|
_session.mapClass<StarredRelease>("starred_release");
|
|
_session.mapClass<StarredTrack>("starred_track");
|
|
_session.mapClass<Track>("track");
|
|
_session.mapClass<TrackBookmark>("track_bookmark");
|
|
_session.mapClass<TrackArtistLink>("track_artist_link");
|
|
_session.mapClass<TrackFeatures>("track_features");
|
|
_session.mapClass<TrackList>("tracklist");
|
|
_session.mapClass<TrackListEntry>("tracklist_entry");
|
|
_session.mapClass<User>("user");
|
|
}
|
|
|
|
WriteTransaction Session::createWriteTransaction()
|
|
{
|
|
return WriteTransaction{ _db.getMutex(), _session };
|
|
}
|
|
|
|
ReadTransaction Session::createReadTransaction()
|
|
{
|
|
return ReadTransaction{ _session };
|
|
}
|
|
|
|
void Session::prepareTables()
|
|
{
|
|
LMS_LOG(DB, INFO, "Preparing tables...");
|
|
|
|
// Initial creation case
|
|
try
|
|
{
|
|
_session.createTables();
|
|
LMS_LOG(DB, INFO, "Tables created");
|
|
}
|
|
catch (Wt::Dbo::Exception& e)
|
|
{
|
|
LMS_LOG(DB, DEBUG, "Cannot create tables: " << e.what());
|
|
if (std::string_view{ e.what() }.find("already exists") == std::string_view::npos)
|
|
{
|
|
LMS_LOG(DB, ERROR, "Cannot create tables: " << e.what());
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
Migration::doDbMigration(*this);
|
|
|
|
// Indexes
|
|
{
|
|
auto transaction{ createWriteTransaction() };
|
|
_session.execute("CREATE INDEX IF NOT EXISTS artist_name_idx ON artist(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS artist_sort_name_nocase_idx ON artist(sort_name COLLATE NOCASE)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS artist_mbid_idx ON artist(mbid)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS auth_token_user_idx ON auth_token(user_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS auth_token_expiry_idx ON auth_token(expiry)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS auth_token_value_idx ON auth_token(value)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS cluster_name_idx ON cluster(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS cluster_cluster_type_idx ON cluster(cluster_type_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS cluster_type_name_idx ON cluster_type(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS release_name_idx ON release(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS release_name_nocase_idx ON release(name COLLATE NOCASE)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS release_mbid_idx ON release(mbid)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_path_idx ON track(file_path)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_name_idx ON track(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_name_nocase_idx ON track(name COLLATE NOCASE)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_mbid_idx ON track(mbid)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_recording_mbid_idx ON track(recording_mbid)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_file_last_write_idx ON track(file_last_write)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_date_idx ON track(date)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_original_date_idx ON track(original_date)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name_idx ON tracklist(name)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_user_idx ON tracklist(user_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_features_track_idx ON track_features(track_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_artist_idx ON track_artist_link(artist_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_track_idx ON track_artist_link(track_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_type_idx ON track_artist_link(type)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_artist_type_idx ON track_artist_link(artist_id,type)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_bookmark_user_idx ON track_bookmark(user_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS track_bookmark_user_track_idx ON track_bookmark(user_id,track_id)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_backend_idx ON listen(backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_backend_idx ON listen(user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_track_user_backend_idx ON listen(track_id,user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_track_backend_date_time_idx ON listen(user_id,track_id,backend,date_time)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_user_backend_idx ON starred_artist(user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_artist_user_backend_idx ON starred_artist(artist_id,user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_release_user_backend_idx ON starred_release(user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_release_release_user_backend_idx ON starred_release(release_id,user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_track_user_backend_idx ON starred_track(user_id,backend)");
|
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_track_track_user_backend_idx ON starred_track(track_id,user_id,backend)");
|
|
}
|
|
|
|
// Singletons
|
|
{
|
|
auto uniqueTransaction{ createWriteTransaction() };
|
|
ScanSettings::init(*this);
|
|
}
|
|
}
|
|
|
|
void Session::analyze()
|
|
{
|
|
LMS_LOG(DB, INFO, "Analyzing database...");
|
|
{
|
|
auto transaction{ createWriteTransaction() };
|
|
_session.execute("ANALYZE");
|
|
}
|
|
LMS_LOG(DB, INFO, "Database Analyze complete");
|
|
}
|
|
|
|
void Session::optimize()
|
|
{
|
|
LMS_LOG(DB, INFO, "Optimizing database...");
|
|
{
|
|
auto transaction{ createWriteTransaction() };
|
|
_session.execute("PRAGMA optimize");
|
|
}
|
|
LMS_LOG(DB, INFO, "Database optimizing complete");
|
|
}
|
|
|
|
} // namespace Database
|