diff options
| author | Carbenium <carbenium@outlook.com> | 2015-08-21 17:54:47 +0200 |
|---|---|---|
| committer | Carbenium <carbenium@outlook.com> | 2015-08-21 17:54:47 +0200 |
| commit | e4c97f66529ecfc2e9b3f675e5ebecd199c1d4dc (patch) | |
| tree | dc7332aaa75ad7c10d2bff9c35e5032b46eb3633 /src/server/shared/Updater | |
| parent | e9feddf862fd84eb106dd1d305e4a148ad1662bd (diff) | |
| parent | 1d2aafd39bcb79a67357d198ce9b2345642fdd39 (diff) | |
Merge pull request #15312 from StormBytePP/6.x_merge_common_and_move_database_out_of_shared
Core/Build: Merge common library and move database out of shared
Diffstat (limited to 'src/server/shared/Updater')
| -rw-r--r-- | src/server/shared/Updater/DBUpdater.cpp | 452 | ||||
| -rw-r--r-- | src/server/shared/Updater/DBUpdater.h | 92 | ||||
| -rw-r--r-- | src/server/shared/Updater/UpdateFetcher.cpp | 410 | ||||
| -rw-r--r-- | src/server/shared/Updater/UpdateFetcher.h | 132 |
4 files changed, 0 insertions, 1086 deletions
diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp deleted file mode 100644 index c0dfd400efc..00000000000 --- a/src/server/shared/Updater/DBUpdater.cpp +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * - * This program 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 2 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 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 <http://www.gnu.org/licenses/>. - */ - -#include "DBUpdater.h" -#include "Log.h" -#include "GitRevision.h" -#include "UpdateFetcher.h" -#include "DatabaseLoader.h" -#include "Config.h" - -#include <fstream> -#include <iostream> -#include <unordered_map> -#include <boost/process.hpp> -#include <boost/iostreams/device/file_descriptor.hpp> -#include <boost/system/system_error.hpp> - -using namespace boost::process; -using namespace boost::process::initializers; -using namespace boost::iostreams; - -template<class T> -std::string DBUpdater<T>::GetSourceDirectory() -{ - std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", ""); - if (!entry.empty()) - return entry; - else - return GitRevision::GetSourceDirectory(); -} - -template<class T> -std::string DBUpdater<T>::GetMySqlCli() -{ - std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", ""); - if (!entry.empty()) - return entry; - else - return GitRevision::GetMySQLExecutable(); -} - -// Auth Database -template<> -std::string DBUpdater<LoginDatabaseConnection>::GetConfigEntry() -{ - return "Updates.Auth"; -} - -template<> -std::string DBUpdater<LoginDatabaseConnection>::GetTableName() -{ - return "Auth"; -} - -template<> -std::string DBUpdater<LoginDatabaseConnection>::GetBaseFile() -{ - return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/sql/base/auth_database.sql"; -} - -template<> -bool DBUpdater<LoginDatabaseConnection>::IsEnabled(uint32 const updateMask) -{ - // This way silences warnings under msvc - return (updateMask & DatabaseLoader::DATABASE_LOGIN) ? true : false; -} - -// World Database -template<> -std::string DBUpdater<WorldDatabaseConnection>::GetConfigEntry() -{ - return "Updates.World"; -} - -template<> -std::string DBUpdater<WorldDatabaseConnection>::GetTableName() -{ - return "World"; -} - -template<> -std::string DBUpdater<WorldDatabaseConnection>::GetBaseFile() -{ - return GitRevision::GetFullDatabase(); -} - -template<> -bool DBUpdater<WorldDatabaseConnection>::IsEnabled(uint32 const updateMask) -{ - // This way silences warnings under msvc - return (updateMask & DatabaseLoader::DATABASE_WORLD) ? true : false; -} - -template<> -BaseLocation DBUpdater<WorldDatabaseConnection>::GetBaseLocationType() -{ - return LOCATION_DOWNLOAD; -} - -// Character Database -template<> -std::string DBUpdater<CharacterDatabaseConnection>::GetConfigEntry() -{ - return "Updates.Character"; -} - -template<> -std::string DBUpdater<CharacterDatabaseConnection>::GetTableName() -{ - return "Character"; -} - -template<> -std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFile() -{ - return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/sql/base/characters_database.sql"; -} - -template<> -bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask) -{ - // This way silences warnings under msvc - return (updateMask & DatabaseLoader::DATABASE_CHARACTER) ? true : false; -} - -// Hotfix Database -template<> -std::string DBUpdater<HotfixDatabaseConnection>::GetConfigEntry() -{ - return "Updates.Hotfix"; -} - -template<> -std::string DBUpdater<HotfixDatabaseConnection>::GetTableName() -{ - return "Hotfixes"; -} - -template<> -std::string DBUpdater<HotfixDatabaseConnection>::GetBaseFile() -{ - return GitRevision::GetHotfixesDatabase(); -} - -template<> -bool DBUpdater<HotfixDatabaseConnection>::IsEnabled(uint32 const updateMask) -{ - // This way silences warnings under msvc - return (updateMask & DatabaseLoader::DATABASE_HOTFIX) ? true : false; -} - -template<> -BaseLocation DBUpdater<HotfixDatabaseConnection>::GetBaseLocationType() -{ - return LOCATION_DOWNLOAD; -} - -// All -template<class T> -BaseLocation DBUpdater<T>::GetBaseLocationType() -{ - return LOCATION_REPOSITORY; -} - -template<class T> -bool DBUpdater<T>::CheckExecutable() -{ - DBUpdater<T>::Path const exe(DBUpdater<T>::GetMySqlCli()); - if (!exists(exe)) - { - // Check for mysql in path - std::vector<std::string> args = {"--version"}; - uint32 ret; - try - { - child c = execute(run_exe("mysql"), set_args(args), throw_on_error(), close_stdout()); - ret = wait_for_exit(c); - } - catch (boost::system::system_error&) - { - ret = EXIT_FAILURE; - } - - if (ret == EXIT_FAILURE) - { - TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\', correct the path in the *.conf (\"Updates.MySqlCLIPath\").", - absolute(exe).generic_string().c_str()); - - return false; - } - } - return true; -} - -template<class T> -bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool) -{ - TC_LOG_INFO("sql.updates", "Database \"%s\" does not exist, do you want to create it? [yes (default) / no]: ", - pool.GetConnectionInfo()->database.c_str()); - - std::string answer; - std::getline(std::cin, answer); - if (!answer.empty() && !(answer.substr(0, 1) == "y")) - return false; - - TC_LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str()); - - // Path of temp file - static Path const temp("create_table.sql"); - - // Create temporary query to use external mysql cli - std::ofstream file(temp.generic_string()); - if (!file.is_open()) - { - TC_LOG_FATAL("sql.updates", "Failed to create temporary query file \"%s\"!", temp.generic_string().c_str()); - return false; - } - - file << "CREATE DATABASE `" << pool.GetConnectionInfo()->database << "` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci\n\n"; - - file.close(); - - try - { - DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, - pool.GetConnectionInfo()->port_or_socket, "", temp); - } - catch (UpdateException&) - { - TC_LOG_FATAL("sql.updates", "Failed to create database %s! Has the user `CREATE` priviliges?", pool.GetConnectionInfo()->database.c_str()); - boost::filesystem::remove(temp); - return false; - } - - TC_LOG_INFO("sql.updates", "Done."); - boost::filesystem::remove(temp); - return true; -} - -template<class T> -bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool) -{ - if (!DBUpdater<T>::CheckExecutable()) - return false; - - TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str()); - - Path const sourceDirectory(GetSourceDirectory()); - - if (!is_directory(sourceDirectory)) - { - TC_LOG_ERROR("sql.updates", "DBUpdater: Given source directory %s does not exist, skipped!", sourceDirectory.generic_string().c_str()); - return false; - } - - UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const& query) { DBUpdater<T>::Apply(pool, query); }, - [&](Path const& file) { DBUpdater<T>::ApplyFile(pool, file); }, - [&](std::string const& query) -> QueryResult { return DBUpdater<T>::Retrieve(pool, query); }); - - UpdateResult result; - try - { - result = updateFetcher.Update( - sConfigMgr->GetBoolDefault("Updates.Redundancy", true), - sConfigMgr->GetBoolDefault("Updates.AllowRehash", true), - sConfigMgr->GetBoolDefault("Updates.ArchivedRedundancy", false), - sConfigMgr->GetIntDefault("Updates.CleanDeadRefMaxCount", 3)); - } - catch (UpdateException&) - { - return false; - } - - std::string const info = Trinity::StringFormat("Containing " SZFMTD " new and " SZFMTD " archived updates.", - result.recent, result.archived); - - if (!result.updated) - TC_LOG_INFO("sql.updates", ">> %s database is up-to-date! %s", DBUpdater<T>::GetTableName().c_str(), info.c_str()); - else - TC_LOG_INFO("sql.updates", ">> Applied " SZFMTD " %s. %s", result.updated, result.updated == 1 ? "query" : "queries", info.c_str()); - - return true; -} - -template<class T> -bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool) -{ - { - QueryResult const result = Retrieve(pool, "SHOW TABLES"); - if (result && (result->GetRowCount() > 0)) - return true; - } - - if (!DBUpdater<T>::CheckExecutable()) - return false; - - TC_LOG_INFO("sql.updates", "Database %s is empty, auto populating it...", DBUpdater<T>::GetTableName().c_str()); - - std::string const p = DBUpdater<T>::GetBaseFile(); - if (p.empty()) - { - TC_LOG_INFO("sql.updates", ">> No base file provided, skipped!"); - return true; - } - - Path const base(p); - if (!exists(base)) - { - switch (DBUpdater<T>::GetBaseLocationType()) - { - case LOCATION_REPOSITORY: - { - TC_LOG_ERROR("sql.updates", ">> Base file \"%s\" is missing, try to clone the source again.", - base.generic_string().c_str()); - - break; - } - case LOCATION_DOWNLOAD: - { - TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"http://www.trinitycore.org/f/files/category/1-database/\"" \ - " and place it in your server directory.", base.filename().generic_string().c_str()); - break; - } - } - return false; - } - - // Update database - TC_LOG_INFO("sql.updates", ">> Applying \'%s\'...", base.generic_string().c_str()); - try - { - ApplyFile(pool, base); - } - catch (UpdateException&) - { - return false; - } - - TC_LOG_INFO("sql.updates", ">> Done!"); - return true; -} - -template<class T> -QueryResult DBUpdater<T>::Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query) -{ - return pool.PQuery(query.c_str()); -} - -template<class T> -void DBUpdater<T>::Apply(DatabaseWorkerPool<T>& pool, std::string const& query) -{ - pool.DirectExecute(query.c_str()); -} - -template<class T> -void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path) -{ - DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, - pool.GetConnectionInfo()->port_or_socket, pool.GetConnectionInfo()->database, path); -} - -template<class T> -void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, - std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path) -{ - std::vector<std::string> args; - args.reserve(7); - - // CLI Client connection info - args.push_back("-h" + host); - args.push_back("-u" + user); - - if (!password.empty()) - args.push_back("-p" + password); - - // Check if we want to connect through ip or socket (Unix only) -#ifdef _WIN32 - - args.push_back("-P" + port_or_socket); - -#else - - if (!std::isdigit(port_or_socket[0])) - { - // We can't check here if host == "." because is named localhost if socket option is enabled - args.push_back("-P0"); - args.push_back("--protocol=SOCKET"); - args.push_back("-S" + port_or_socket); - } - else - // generic case - args.push_back("-P" + port_or_socket); - -#endif - - // Set the default charset to utf8 - args.push_back("--default-character-set=utf8"); - - // Set max allowed packet to 1 GB - args.push_back("--max-allowed-packet=1GB"); - - // Database - if (!database.empty()) - args.push_back(database); - - // ToDo: use the existing query in memory as virtual file if possible - file_descriptor_source source(path); - - uint32 ret; - try - { - child c = execute(run_exe(DBUpdater<T>::GetMySqlCli().empty() ? "mysql" : - boost::filesystem::absolute(DBUpdater<T>::GetMySqlCli()).generic_string()), - set_args(args), bind_stdin(source), throw_on_error()); - - ret = wait_for_exit(c); - } - catch (boost::system::system_error&) - { - ret = EXIT_FAILURE; - } - - source.close(); - - if (ret != EXIT_SUCCESS) - { - TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \ - " If you are an user pull the latest revision from the repository. If you are a developer fix your sql query.", - path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str()); - - throw UpdateException("update failed"); - } -} - -template class DBUpdater<LoginDatabaseConnection>; -template class DBUpdater<WorldDatabaseConnection>; -template class DBUpdater<CharacterDatabaseConnection>; -template class DBUpdater<HotfixDatabaseConnection>; diff --git a/src/server/shared/Updater/DBUpdater.h b/src/server/shared/Updater/DBUpdater.h deleted file mode 100644 index a2b12bed235..00000000000 --- a/src/server/shared/Updater/DBUpdater.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * - * This program 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 2 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 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 <http://www.gnu.org/licenses/>. - */ - -#ifndef DBUpdater_h__ -#define DBUpdater_h__ - -#include "DatabaseEnv.h" - -#include <string> -#include <boost/filesystem.hpp> - -class UpdateException : public std::exception -{ -public: - UpdateException(std::string const& msg) : _msg(msg) { } - ~UpdateException() throw() { } - - char const* what() const throw() override { return _msg.c_str(); } - -private: - std::string const _msg; -}; - -enum BaseLocation -{ - LOCATION_REPOSITORY, - LOCATION_DOWNLOAD -}; - -struct UpdateResult -{ - UpdateResult() - : updated(0), recent(0), archived(0) { } - - UpdateResult(size_t const updated_, size_t const recent_, size_t const archived_) - : updated(updated_), recent(recent_), archived(archived_) { } - - size_t updated; - size_t recent; - size_t archived; -}; - -template <class T> -class DBUpdater -{ -public: - using Path = boost::filesystem::path; - - static std::string GetSourceDirectory(); - - static inline std::string GetConfigEntry(); - - static inline std::string GetTableName(); - - static std::string GetBaseFile(); - - static bool IsEnabled(uint32 const updateMask); - - static BaseLocation GetBaseLocationType(); - - static bool Create(DatabaseWorkerPool<T>& pool); - - static bool Update(DatabaseWorkerPool<T>& pool); - - static bool Populate(DatabaseWorkerPool<T>& pool); - -private: - static std::string GetMySqlCli(); - static bool CheckExecutable(); - - static QueryResult Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query); - static void Apply(DatabaseWorkerPool<T>& pool, std::string const& query); - static void ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path); - static void ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, - std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path); -}; - -#endif // DBUpdater_h__ diff --git a/src/server/shared/Updater/UpdateFetcher.cpp b/src/server/shared/Updater/UpdateFetcher.cpp deleted file mode 100644 index ec023928b99..00000000000 --- a/src/server/shared/Updater/UpdateFetcher.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * - * This program 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 2 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 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 <http://www.gnu.org/licenses/>. - */ - -#include "UpdateFetcher.h" -#include "Log.h" -#include "Util.h" - -#include <fstream> -#include <chrono> -#include <vector> -#include <sstream> -#include <exception> -#include <unordered_map> -#include <openssl/sha.h> - -using namespace boost::filesystem; - -UpdateFetcher::UpdateFetcher(Path const& sourceDirectory, - std::function<void(std::string const&)> const& apply, - std::function<void(Path const& path)> const& applyFile, - std::function<QueryResult(std::string const&)> const& retrieve) : - _sourceDirectory(sourceDirectory), _apply(apply), _applyFile(applyFile), - _retrieve(retrieve) -{ -} - -UpdateFetcher::LocaleFileStorage UpdateFetcher::GetFileList() const -{ - LocaleFileStorage files; - DirectoryStorage directories = ReceiveIncludedDirectories(); - for (auto const& entry : directories) - FillFileListRecursively(entry.path, files, entry.state, 1); - - return files; -} - -void UpdateFetcher::FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const -{ - static uint32 const MAX_DEPTH = 10; - static directory_iterator const end; - - for (directory_iterator itr(path); itr != end; ++itr) - { - if (is_directory(itr->path())) - { - if (depth < MAX_DEPTH) - FillFileListRecursively(itr->path(), storage, state, depth + 1); - } - else if (itr->path().extension() == ".sql") - { - TC_LOG_TRACE("sql.updates", "Added locale file \"%s\".", itr->path().filename().generic_string().c_str()); - - LocaleFileEntry const entry = { itr->path(), state }; - - // Check for doubled filenames - // Since elements are only compared through their filenames this is ok - if (storage.find(entry) != storage.end()) - { - TC_LOG_FATAL("sql.updates", "Duplicated filename occurred \"%s\", since updates are ordered " \ - "through its filename every name needs to be unique!", itr->path().generic_string().c_str()); - - throw UpdateException("Updating failed, see the log for details."); - } - - storage.insert(entry); - } - } -} - -UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() const -{ - DirectoryStorage directories; - - QueryResult const result = _retrieve("SELECT `path`, `state` FROM `updates_include`"); - if (!result) - return directories; - - do - { - Field* fields = result->Fetch(); - - std::string path = fields[0].GetString(); - if (path.substr(0, 1) == "$") - path = _sourceDirectory.generic_string() + path.substr(1); - - Path const p(path); - - if (!is_directory(p)) - { - TC_LOG_WARN("sql.updates", "DBUpdater: Given update include directory \"%s\" isn't existing, skipped!", p.generic_string().c_str()); - continue; - } - - DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert(fields[1].GetString()) }; - directories.push_back(entry); - - TC_LOG_TRACE("sql.updates", "Added applied file \"%s\" from remote.", p.filename().generic_string().c_str()); - - } while (result->NextRow()); - - return directories; -} - -UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const -{ - AppliedFileStorage map; - - QueryResult result = _retrieve("SELECT `name`, `hash`, `state`, UNIX_TIMESTAMP(`timestamp`) FROM `updates` ORDER BY `name` ASC"); - if (!result) - return map; - - do - { - Field* fields = result->Fetch(); - - AppliedFileEntry const entry = { fields[0].GetString(), fields[1].GetString(), - AppliedFileEntry::StateConvert(fields[2].GetString()), fields[3].GetUInt64() }; - - map.insert(std::make_pair(entry.name, entry)); - } - while (result->NextRow()); - - return map; -} - -UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const -{ - std::ifstream in(file.c_str()); - WPFatal(in.is_open(), "Could not read an update file."); - - auto const start_pos = in.tellg(); - in.ignore(std::numeric_limits<std::streamsize>::max()); - auto const char_count = in.gcount(); - in.seekg(start_pos); - - SQLUpdate const update(new std::string(char_count, char{})); - - in.read(&(*update)[0], update->size()); - in.close(); - return update; -} - -UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const -{ - LocaleFileStorage const available = GetFileList(); - AppliedFileStorage applied = ReceiveAppliedFiles(); - - size_t countRecentUpdates = 0; - size_t countArchivedUpdates = 0; - - // Count updates - for (auto const& entry : applied) - if (entry.second.state == RELEASED) - ++countRecentUpdates; - else - ++countArchivedUpdates; - - // Fill hash to name cache - HashToFileNameStorage hashToName; - for (auto entry : applied) - hashToName.insert(std::make_pair(entry.second.hash, entry.first)); - - size_t importedUpdates = 0; - - for (auto const& availableQuery : available) - { - TC_LOG_DEBUG("sql.updates", "Checking update \"%s\"...", availableQuery.first.filename().generic_string().c_str()); - - AppliedFileStorage::const_iterator iter = applied.find(availableQuery.first.filename().string()); - if (iter != applied.end()) - { - // If redundancy is disabled skip it since the update is already applied. - if (!redundancyChecks) - { - TC_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks."); - applied.erase(iter); - continue; - } - - // If the update is in an archived directory and is marked as archived in our database skip redundancy checks (archived updates never change). - if (!archivedRedundancy && (iter->second.state == ARCHIVED) && (availableQuery.second == ARCHIVED)) - { - TC_LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks."); - applied.erase(iter); - continue; - } - } - - // Read update from file - SQLUpdate const update = ReadSQLUpdate(availableQuery.first); - - // Calculate hash - std::string const hash = CalculateHash(update); - - UpdateMode mode = MODE_APPLY; - - // Update is not in our applied list - if (iter == applied.end()) - { - // Catch renames (different filename but same hash) - HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash); - if (hashIter != hashToName.end()) - { - // Check if the original file was removed if not we've got a problem. - LocaleFileStorage::const_iterator localeIter; - // Push localeIter forward - for (localeIter = available.begin(); (localeIter != available.end()) && - (localeIter->first.filename().string() != hashIter->second); ++localeIter); - - // Conflict! - if (localeIter != available.end()) - { - TC_LOG_WARN("sql.updates", ">> Seems like update \"%s\" \'%s\' was renamed, but the old file is still there! " \ - "Trade it as a new file! (Probably its an unmodified copy of file \"%s\")", - availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str(), - localeIter->first.filename().string().c_str()); - } - // Its save to trade the file as renamed here - else - { - TC_LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.", - hashIter->second.c_str(), availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str()); - - RenameEntry(hashIter->second, availableQuery.first.filename().string()); - applied.erase(hashIter->second); - continue; - } - } - // Apply the update if it was never seen before. - else - { - TC_LOG_INFO("sql.updates", ">> Applying update \"%s\" \'%s\'...", - availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str()); - } - } - // Rehash the update entry if it is contained in our database but with an empty hash. - else if (allowRehash && iter->second.hash.empty()) - { - mode = MODE_REHASH; - - TC_LOG_INFO("sql.updates", ">> Re-hashing update \"%s\" \'%s\'...", availableQuery.first.filename().string().c_str(), - hash.substr(0, 7).c_str()); - } - else - { - // If the hash of the files differs from the one stored in our database reapply the update (because it was changed). - if (iter->second.hash != hash) - { - TC_LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", availableQuery.first.filename().string().c_str(), - iter->second.hash.substr(0, 7).c_str(), hash.substr(0, 7).c_str()); - } - else - { - // If the file wasn't changed and just moved update its state if necessary. - if (iter->second.state != availableQuery.second) - { - TC_LOG_DEBUG("sql.updates", ">> Updating state of \"%s\" to \'%s\'...", - availableQuery.first.filename().string().c_str(), AppliedFileEntry::StateConvert(availableQuery.second).c_str()); - - UpdateState(availableQuery.first.filename().string(), availableQuery.second); - } - - TC_LOG_DEBUG("sql.updates", ">> Update is already applied and is matching hash \'%s\'.", hash.substr(0, 7).c_str()); - - applied.erase(iter); - continue; - } - } - - uint32 speed = 0; - AppliedFileEntry const file = { availableQuery.first.filename().string(), hash, availableQuery.second, 0 }; - - switch (mode) - { - case MODE_APPLY: - speed = Apply(availableQuery.first); - /*no break*/ - case MODE_REHASH: - UpdateEntry(file, speed); - break; - } - - if (iter != applied.end()) - applied.erase(iter); - - if (mode == MODE_APPLY) - ++importedUpdates; - } - - // Cleanup up orphaned entries if enabled - if (!applied.empty()) - { - bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast<size_t>(cleanDeadReferencesMaxCount)); - - for (auto const& entry : applied) - { - TC_LOG_WARN("sql.updates", ">> File \'%s\' was applied to the database but is missing in" \ - " your update directory now!", entry.first.c_str()); - - if (doCleanup) - TC_LOG_INFO("sql.updates", "Deleting orphaned entry \'%s\'...", entry.first.c_str()); - } - - if (doCleanup) - CleanUp(applied); - else - { - TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There are " SZFMTD " dirty files that were applied to your database " \ - "but are now missing in your source directory!", applied.size()); - } - } - - return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates); -} - -std::string UpdateFetcher::CalculateHash(SQLUpdate const& query) const -{ - // Calculate a Sha1 hash based on query content. - unsigned char digest[SHA_DIGEST_LENGTH]; - SHA1((unsigned char*)query->c_str(), query->length(), (unsigned char*)&digest); - - return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH); -} - -uint32 UpdateFetcher::Apply(Path const& path) const -{ - using Time = std::chrono::high_resolution_clock; - - // Benchmark query speed - auto const begin = Time::now(); - - // Update database - _applyFile(path); - - // Return time the query took to apply - return std::chrono::duration_cast<std::chrono::milliseconds>(Time::now() - begin).count(); -} - -void UpdateFetcher::UpdateEntry(AppliedFileEntry const& entry, uint32 const speed) const -{ - std::string const update = "REPLACE INTO `updates` (`name`, `hash`, `state`, `speed`) VALUES (\"" + - entry.name + "\", \"" + entry.hash + "\", \'" + entry.GetStateAsString() + "\', " + std::to_string(speed) + ")"; - - // Update database - _apply(update); -} - -void UpdateFetcher::RenameEntry(std::string const& from, std::string const& to) const -{ - // Delete target if it exists - { - std::string const update = "DELETE FROM `updates` WHERE `name`=\"" + to + "\""; - - // Update database - _apply(update); - } - - // Rename - { - std::string const update = "UPDATE `updates` SET `name`=\"" + to + "\" WHERE `name`=\"" + from + "\""; - - // Update database - _apply(update); - } -} - -void UpdateFetcher::CleanUp(AppliedFileStorage const& storage) const -{ - if (storage.empty()) - return; - - std::stringstream update; - size_t remaining = storage.size(); - - update << "DELETE FROM `updates` WHERE `name` IN("; - - for (auto const& entry : storage) - { - update << "\"" << entry.first << "\""; - if ((--remaining) > 0) - update << ", "; - } - - update << ")"; - - // Update database - _apply(update.str()); -} - -void UpdateFetcher::UpdateState(std::string const& name, State const state) const -{ - std::string const update = "UPDATE `updates` SET `state`=\'" + AppliedFileEntry::StateConvert(state) + "\' WHERE `name`=\"" + name + "\""; - - // Update database - _apply(update); -} diff --git a/src/server/shared/Updater/UpdateFetcher.h b/src/server/shared/Updater/UpdateFetcher.h deleted file mode 100644 index 4ff8c93bc76..00000000000 --- a/src/server/shared/Updater/UpdateFetcher.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * - * This program 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 2 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 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 <http://www.gnu.org/licenses/>. - */ - -#ifndef UpdateFetcher_h__ -#define UpdateFetcher_h__ - -#include <DBUpdater.h> - -#include <functional> -#include <string> -#include <memory> -#include <vector> - -class UpdateFetcher -{ - typedef boost::filesystem::path Path; - -public: - UpdateFetcher(Path const& updateDirectory, - std::function<void(std::string const&)> const& apply, - std::function<void(Path const& path)> const& applyFile, - std::function<QueryResult(std::string const&)> const& retrieve); - - UpdateResult Update(bool const redundancyChecks, bool const allowRehash, - bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const; - -private: - enum UpdateMode - { - MODE_APPLY, - MODE_REHASH - }; - - enum State - { - RELEASED, - ARCHIVED - }; - - struct AppliedFileEntry - { - AppliedFileEntry(std::string const& name_, std::string const& hash_, State state_, uint64 timestamp_) - : name(name_), hash(hash_), state(state_), timestamp(timestamp_) { } - - std::string const name; - - std::string const hash; - - State const state; - - uint64 const timestamp; - - static inline State StateConvert(std::string const& state) - { - return (state == "RELEASED") ? RELEASED : ARCHIVED; - } - - static inline std::string StateConvert(State const state) - { - return (state == RELEASED) ? "RELEASED" : "ARCHIVED"; - } - - std::string GetStateAsString() const - { - return StateConvert(state); - } - }; - - struct DirectoryEntry - { - DirectoryEntry(Path const& path_, State state_) : path(path_), state(state_) { } - - Path const path; - - State const state; - }; - - typedef std::pair<Path, State> LocaleFileEntry; - - struct PathCompare - { - inline bool operator() (LocaleFileEntry const& left, LocaleFileEntry const& right) const - { - return left.first.filename().string() < right.first.filename().string(); - } - }; - - typedef std::set<LocaleFileEntry, PathCompare> LocaleFileStorage; - typedef std::unordered_map<std::string, std::string> HashToFileNameStorage; - typedef std::unordered_map<std::string, AppliedFileEntry> AppliedFileStorage; - typedef std::vector<UpdateFetcher::DirectoryEntry> DirectoryStorage; - typedef std::shared_ptr<std::string> SQLUpdate; - - LocaleFileStorage GetFileList() const; - void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const; - - DirectoryStorage ReceiveIncludedDirectories() const; - AppliedFileStorage ReceiveAppliedFiles() const; - - SQLUpdate ReadSQLUpdate(Path const& file) const; - std::string CalculateHash(SQLUpdate const& query) const; - - uint32 Apply(Path const& path) const; - - void UpdateEntry(AppliedFileEntry const& entry, uint32 const speed = 0) const; - void RenameEntry(std::string const& from, std::string const& to) const; - void CleanUp(AppliedFileStorage const& storage) const; - - void UpdateState(std::string const& name, State const state) const; - - Path const _sourceDirectory; - - std::function<void(std::string const&)> const _apply; - std::function<void(Path const& path)> const _applyFile; - std::function<QueryResult(std::string const&)> const _retrieve; -}; - -#endif // UpdateFetcher_h__ |
