/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * This program 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 Affero General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "DatabaseLoader.h" #include "Config.h" #include "DBUpdater.h" #include "DatabaseEnv.h" #include "Duration.h" #include "Log.h" #include #include #include DatabaseLoader::DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask, std::string_view modulesList) : _logger(logger), _modulesList(modulesList), _autoSetup(sConfigMgr->GetOption("Updates.AutoSetup", true)), _updateFlags(sConfigMgr->GetOption("Updates.EnableDatabases", defaultUpdateMask)) { } template DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::string const& name) { bool const updatesEnabledForThis = DBUpdater::IsEnabled(_updateFlags); _open.push([this, name, updatesEnabledForThis, &pool]() -> bool { std::string const dbString = sConfigMgr->GetOption(name + "DatabaseInfo", ""); if (dbString.empty()) { LOG_ERROR(_logger, "Database {} not specified in configuration file!", name); return false; } uint8 const asyncThreads = sConfigMgr->GetOption(name + "Database.WorkerThreads", 1); if (asyncThreads < 1 || asyncThreads > 32) { LOG_ERROR(_logger, "{} database: invalid number of worker threads specified. " "Please pick a value between 1 and 32.", name); return false; } uint8 const synchThreads = sConfigMgr->GetOption(name + "Database.SynchThreads", 1); pool.SetConnectionInfo(dbString, asyncThreads, synchThreads); if (uint32 error = pool.Open()) { // Try reconnect if (error == CR_CONNECTION_ERROR) { uint8 const attempts = sConfigMgr->GetOption("Database.Reconnect.Attempts", 20); Seconds reconnectSeconds = Seconds(sConfigMgr->GetOption("Database.Reconnect.Seconds", 15)); uint8 reconnectCount = 0; while (reconnectCount < attempts) { LOG_WARN(_logger, "> Retrying after {} seconds", static_cast(reconnectSeconds.count())); std::this_thread::sleep_for(reconnectSeconds); error = pool.Open(); if (error == CR_CONNECTION_ERROR) { reconnectCount++; } else { break; } } } // Database does not exist if ((error == ER_BAD_DB_ERROR) && updatesEnabledForThis && _autoSetup) { // Try to create the database and connect again if auto setup is enabled if (DBUpdater::Create(pool) && (!pool.Open())) { error = 0; } } // If the error wasn't handled quit if (error) { LOG_ERROR(_logger, "DatabasePool {} NOT opened. There were errors opening the MySQL connections. " "Check your log file for specific errors", name); return false; } } // Add the close operation _close.push([&pool] { pool.Close(); }); return true; }); // Populate and update only if updates are enabled for this pool if (updatesEnabledForThis) { _populate.push([this, name, &pool]() -> bool { if (!DBUpdater::Populate(pool)) { LOG_ERROR(_logger, "Could not populate the {} database, see log for details.", name); return false; } return true; }); _update.push([this, name, &pool]() -> bool { if (!DBUpdater::Update(pool, _modulesList)) { LOG_ERROR(_logger, "Could not update the {} database, see log for details.", name); return false; } return true; }); } _prepare.push([this, name, &pool]() -> bool { if (!pool.PrepareStatements()) { LOG_ERROR(_logger, "Could not prepare statements of the {} database, see log for details.", name); return false; } return true; }); return *this; } bool DatabaseLoader::Load() { if (!_updateFlags) LOG_WARN("sql.updates", "> AUTOUPDATER: Automatic database updates are disabled for all databases in the config! This is not recommended!"); if (!OpenDatabases()) return false; if (!PopulateDatabases()) return false; if (!UpdateDatabases()) return false; if (!PrepareStatements()) return false; return true; } bool DatabaseLoader::OpenDatabases() { return Process(_open); } bool DatabaseLoader::PopulateDatabases() { return Process(_populate); } bool DatabaseLoader::UpdateDatabases() { return Process(_update); } bool DatabaseLoader::PrepareStatements() { return Process(_prepare); } bool DatabaseLoader::Process(std::queue& queue) { while (!queue.empty()) { if (!queue.front()()) { // Close all open databases which have a registered close operation while (!_close.empty()) { _close.top()(); _close.pop(); } return false; } queue.pop(); } return true; } template AC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); template AC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); template AC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&);