From b453b80c36c035535279933d0a816000b8cc4799 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Thu, 7 Nov 2024 00:36:54 -0300 Subject: [PATCH 01/12] feat: create database backup --- .gitignore | 3 +++ config.lua.dist | 1 + src/canary_server.cpp | 2 ++ src/config/config_enums.hpp | 1 + src/config/configmanager.cpp | 1 + src/database/database.cpp | 48 ++++++++++++++++++++++++++++++++++++ src/database/database.hpp | 1 + 7 files changed, 57 insertions(+) diff --git a/.gitignore b/.gitignore index a73a8c3022c..4bd08dd8908 100644 --- a/.gitignore +++ b/.gitignore @@ -395,5 +395,8 @@ canary.old # VCPKG vcpkg_installed +# DB Backups +database_backup + # CLION cmake-build-* diff --git a/config.lua.dist b/config.lua.dist index 7d0360d9360..1ed6c59f367 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -399,6 +399,7 @@ mysqlHost = "127.0.0.1" mysqlUser = "root" mysqlPass = "root" mysqlDatabase = "otservbr-global" +mysqlDatabaseBackup = false mysqlPort = 3306 mysqlSock = "" passwordType = "sha1" diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 687fa51b6cd..2db6e033f03 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -316,6 +316,8 @@ void CanaryServer::initializeDatabase() { )); } + g_database().createDatabaseBackup(); + DatabaseManager::updateDatabase(); if (g_configManager().getBoolean(OPTIMIZE_DATABASE) diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 559045fdb9b..7e417c2dfb5 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -165,6 +165,7 @@ enum ConfigKey_t : uint16_t { MONTH_KILLS_TO_RED, MULTIPLIER_ATTACKONFIST, MYSQL_DB, + MYSQL_DB_BACKUP, MYSQL_HOST, MYSQL_PASS, MYSQL_SOCK, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index 1c00df76c2f..d52096f123d 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -71,6 +71,7 @@ bool ConfigManager::load() { loadStringConfig(L, MAP_DOWNLOAD_URL, "mapDownloadUrl", ""); loadStringConfig(L, MAP_NAME, "mapName", "canary"); loadStringConfig(L, MYSQL_DB, "mysqlDatabase", "canary"); + loadBoolConfig(L, MYSQL_DB_BACKUP, "mysqlDatabaseBackup", false); loadStringConfig(L, MYSQL_HOST, "mysqlHost", "127.0.0.1"); loadStringConfig(L, MYSQL_PASS, "mysqlPass", ""); loadStringConfig(L, MYSQL_SOCK, "mysqlSock", ""); diff --git a/src/database/database.cpp b/src/database/database.cpp index fcb7371708d..8ce5a3fa939 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -12,6 +12,7 @@ #include "config/configmanager.hpp" #include "lib/di/container.hpp" #include "lib/metrics/metrics.hpp" +#include "utils/tools.hpp" Database::~Database() { if (handle != nullptr) { @@ -60,6 +61,53 @@ bool Database::connect(const std::string* host, const std::string* user, const s return true; } +void Database::createDatabaseBackup() const { + if (!g_configManager().getBoolean(MYSQL_DB_BACKUP)) { + return; + } + + std::time_t now = getTimeNow(); + std::string formattedTime = fmt::format("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(now)); + + if (formattedTime.empty()) { + g_logger().error("Failed to format time for database backup."); + return; + } + + std::string backupDir = "database_backup/"; + std::filesystem::create_directories(backupDir); + std::string backupFileName = fmt::format("{}/backup_{}.sql", backupDir, formattedTime); + + std::string tempConfigFile = "database_backup.cnf"; + std::ofstream configFile(tempConfigFile); + if (configFile.is_open()) { + configFile << "[client]\n"; + configFile << "user=" << g_configManager().getString(MYSQL_USER) << "\n"; + configFile << "password=" << g_configManager().getString(MYSQL_PASS) << "\n"; + configFile << "host=" << g_configManager().getString(MYSQL_HOST) << "\n"; + configFile << "port=" << g_configManager().getNumber(SQL_PORT) << "\n"; + configFile.close(); + } else { + g_logger().error("Failed to create temporary MySQL configuration file."); + return; + } + + std::string command = fmt::format( + "mysqldump --defaults-extra-file={} {} > {}", + tempConfigFile, g_configManager().getString(MYSQL_DB), backupFileName + ); + + int result = std::system(command.c_str()); + + std::filesystem::remove(tempConfigFile); + + if (result != 0) { + g_logger().error("Failed to create database backup using mysqldump."); + } else { + g_logger().info("Database backup successfully created at: {}", backupFileName); + } +} + bool Database::beginTransaction() { if (!executeQuery("BEGIN")) { return false; diff --git a/src/database/database.hpp b/src/database/database.hpp index 69c47d324ad..1aa2943aa3c 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -36,6 +36,7 @@ class Database { bool connect(); bool connect(const std::string* host, const std::string* user, const std::string* password, const std::string* database, uint32_t port, const std::string* sock); + void createDatabaseBackup() const; bool retryQuery(std::string_view query, int retries); bool executeQuery(std::string_view query); From 7e94b87e6cd117dee0fa013af7eae4e438f11569 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Tue, 12 Nov 2024 18:07:07 -0300 Subject: [PATCH 02/12] improve: database backup --- src/canary_server.cpp | 2 +- src/database/database.cpp | 81 ++++++++++++++++++++++++---- src/database/database.hpp | 18 ++++++- src/game/scheduling/save_manager.cpp | 2 + 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 2db6e033f03..e8f81137cde 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -316,7 +316,7 @@ void CanaryServer::initializeDatabase() { )); } - g_database().createDatabaseBackup(); + g_database().createDatabaseBackup(false); DatabaseManager::updateDatabase(); diff --git a/src/database/database.cpp b/src/database/database.cpp index 8ce5a3fa939..c5d18d001fe 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -61,23 +61,23 @@ bool Database::connect(const std::string* host, const std::string* user, const s return true; } -void Database::createDatabaseBackup() const { +void Database::createDatabaseBackup(bool compress) const { if (!g_configManager().getBoolean(MYSQL_DB_BACKUP)) { return; } - std::time_t now = getTimeNow(); - std::string formattedTime = fmt::format("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(now)); + // Get current time for formatting + auto now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + std::string formattedDate = fmt::format("{:%Y-%m-%d}", fmt::localtime(now_c)); + std::string formattedTime = fmt::format("{:%H-%M-%S}", fmt::localtime(now_c)); - if (formattedTime.empty()) { - g_logger().error("Failed to format time for database backup."); - return; - } - - std::string backupDir = "database_backup/"; + // Create a backup directory based on the current date + std::string backupDir = fmt::format("database_backup/{}/", formattedDate); std::filesystem::create_directories(backupDir); - std::string backupFileName = fmt::format("{}/backup_{}.sql", backupDir, formattedTime); + std::string backupFileName = fmt::format("{}backup_{}.sql", backupDir, formattedTime); + // Create a temporary configuration file for MySQL credentials std::string tempConfigFile = "database_backup.cnf"; std::ofstream configFile(tempConfigFile); if (configFile.is_open()) { @@ -92,20 +92,79 @@ void Database::createDatabaseBackup() const { return; } + // Execute mysqldump command to create backup file std::string command = fmt::format( "mysqldump --defaults-extra-file={} {} > {}", tempConfigFile, g_configManager().getString(MYSQL_DB), backupFileName ); int result = std::system(command.c_str()); - std::filesystem::remove(tempConfigFile); if (result != 0) { g_logger().error("Failed to create database backup using mysqldump."); + return; + } + + // Compress the backup file if requested + std::string compressedFileName; + if (compress) { + compressedFileName = backupFileName + ".gz"; + gzFile gzFile = gzopen(compressedFileName.c_str(), "wb9"); + if (!gzFile) { + g_logger().error("Failed to open gzip file for compression."); + return; + } + + std::ifstream backupFile(backupFileName, std::ios::binary); + if (!backupFile.is_open()) { + g_logger().error("Failed to open backup file for compression: {}", backupFileName); + gzclose(gzFile); + return; + } + + char buffer[8192]; + while (backupFile.read(buffer, sizeof(buffer)) || backupFile.gcount() > 0) { + gzwrite(gzFile, buffer, backupFile.gcount()); + } + + backupFile.close(); + gzclose(gzFile); + std::filesystem::remove(backupFileName); + + g_logger().info("Database backup successfully compressed to: {}", compressedFileName); } else { g_logger().info("Database backup successfully created at: {}", backupFileName); } + + // Delete old backups + auto twentyFourHoursAgo = std::chrono::system_clock::now() - std::chrono::hours(24); + auto sevenDaysAgo = std::chrono::system_clock::now() - std::chrono::hours(24 * 7); + for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { + if (entry.is_directory()) { + auto dirTime = std::filesystem::last_write_time(entry); + if (!compress && dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { + try { + std::filesystem::remove_all(entry); + g_logger().info("Deleted old backup directory (7 days): {}", entry.path().string()); + } catch (const std::filesystem::filesystem_error& e) { + g_logger().error("Failed to delete old backup directory: {}. Error: {}", entry.path().string(), e.what()); + } + } + if (compress && dirTime.time_since_epoch() < twentyFourHoursAgo.time_since_epoch()) { + for (const auto& file : std::filesystem::directory_iterator(entry)) { + if (file.path().extension() == ".gz") { + try { + std::filesystem::remove(file); + g_logger().info("Deleted compressed backup file (24 hours): {}", file.path().string()); + } catch (const std::filesystem::filesystem_error& e) { + g_logger().error("Failed to delete compressed backup file: {}. Error: {}", file.path().string(), e.what()); + } + } + } + } + } + } } bool Database::beginTransaction() { diff --git a/src/database/database.hpp b/src/database/database.hpp index 1aa2943aa3c..e2a1e248981 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -36,7 +36,23 @@ class Database { bool connect(); bool connect(const std::string* host, const std::string* user, const std::string* password, const std::string* database, uint32_t port, const std::string* sock); - void createDatabaseBackup() const; + + /** + * @brief Creates a backup of the database. + * + * This function generates a backup of the database, with options for compression. + * The backup can be triggered periodically or during specific events like server loading. + * + * The backup operation will only execute if the configuration option `MYSQL_DB_BACKUP` + * is set to true in the `config.lua` file. If this configuration is disabled, the function + * will return without performing any action. + * + * @param compress Indicates whether the backup should be compressed. + * - If `compress` is true, the backup is created during an interval-based save, which occurs every 2 hours. + * This helps prevent excessive growth in the number of backup files. + * - If `compress` is false, the backup is created during the global save, which is triggered once a day when the server loads. + */ + void createDatabaseBackup(bool compress) const; bool retryQuery(std::string_view query, int retries); bool executeQuery(std::string_view query); diff --git a/src/game/scheduling/save_manager.cpp b/src/game/scheduling/save_manager.cpp index 9cccc4052a7..5b6f891e7aa 100644 --- a/src/game/scheduling/save_manager.cpp +++ b/src/game/scheduling/save_manager.cpp @@ -25,6 +25,8 @@ SaveManager &SaveManager::getInstance() { } void SaveManager::saveAll() { + g_database().createDatabaseBackup(true); + Benchmark bm_saveAll; logger.info("Saving server..."); const auto players = game.getPlayers(); From cb227aa51673fe48acdca13139f553a675204e31 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 12 Nov 2024 21:07:47 +0000 Subject: [PATCH 03/12] Code format - (Clang-format) --- src/database/database.cpp | 8 ++++---- src/database/database.hpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index c5d18d001fe..6a81f948841 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -140,24 +140,24 @@ void Database::createDatabaseBackup(bool compress) const { // Delete old backups auto twentyFourHoursAgo = std::chrono::system_clock::now() - std::chrono::hours(24); auto sevenDaysAgo = std::chrono::system_clock::now() - std::chrono::hours(24 * 7); - for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { + for (const auto &entry : std::filesystem::directory_iterator("database_backup")) { if (entry.is_directory()) { auto dirTime = std::filesystem::last_write_time(entry); if (!compress && dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { try { std::filesystem::remove_all(entry); g_logger().info("Deleted old backup directory (7 days): {}", entry.path().string()); - } catch (const std::filesystem::filesystem_error& e) { + } catch (const std::filesystem::filesystem_error &e) { g_logger().error("Failed to delete old backup directory: {}. Error: {}", entry.path().string(), e.what()); } } if (compress && dirTime.time_since_epoch() < twentyFourHoursAgo.time_since_epoch()) { - for (const auto& file : std::filesystem::directory_iterator(entry)) { + for (const auto &file : std::filesystem::directory_iterator(entry)) { if (file.path().extension() == ".gz") { try { std::filesystem::remove(file); g_logger().info("Deleted compressed backup file (24 hours): {}", file.path().string()); - } catch (const std::filesystem::filesystem_error& e) { + } catch (const std::filesystem::filesystem_error &e) { g_logger().error("Failed to delete compressed backup file: {}. Error: {}", file.path().string(), e.what()); } } diff --git a/src/database/database.hpp b/src/database/database.hpp index e2a1e248981..3566425a5cd 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -42,9 +42,9 @@ class Database { * * This function generates a backup of the database, with options for compression. * The backup can be triggered periodically or during specific events like server loading. - * - * The backup operation will only execute if the configuration option `MYSQL_DB_BACKUP` - * is set to true in the `config.lua` file. If this configuration is disabled, the function + * + * The backup operation will only execute if the configuration option `MYSQL_DB_BACKUP` + * is set to true in the `config.lua` file. If this configuration is disabled, the function * will return without performing any action. * * @param compress Indicates whether the backup should be compressed. From 444c519ab56ff3e5c51e8310f893bfc5a590e6f9 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Tue, 12 Nov 2024 18:25:01 -0300 Subject: [PATCH 04/12] fix: sonar --- src/database/database.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index 6a81f948841..0781c3b2d74 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -123,9 +123,9 @@ void Database::createDatabaseBackup(bool compress) const { return; } - char buffer[8192]; - while (backupFile.read(buffer, sizeof(buffer)) || backupFile.gcount() > 0) { - gzwrite(gzFile, buffer, backupFile.gcount()); + std::string buffer(8192, '\0'); + while (backupFile.read(&buffer[0], buffer.size()) || backupFile.gcount() > 0) { + gzwrite(gzFile, buffer.data(), backupFile.gcount()); } backupFile.close(); From b6e1a5cbcd8446bf0b504e333316192a72ad9785 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Thu, 14 Nov 2024 13:51:10 -0300 Subject: [PATCH 05/12] fix: delete backup --- src/database/database.cpp | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index 0781c3b2d74..dc58794e6af 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -123,9 +123,9 @@ void Database::createDatabaseBackup(bool compress) const { return; } - std::string buffer(8192, '\0'); - while (backupFile.read(&buffer[0], buffer.size()) || backupFile.gcount() > 0) { - gzwrite(gzFile, buffer.data(), backupFile.gcount()); + char buffer[8192]; + while (backupFile.read(buffer, sizeof(buffer)) || backupFile.gcount() > 0) { + gzwrite(gzFile, buffer, backupFile.gcount()); } backupFile.close(); @@ -140,28 +140,21 @@ void Database::createDatabaseBackup(bool compress) const { // Delete old backups auto twentyFourHoursAgo = std::chrono::system_clock::now() - std::chrono::hours(24); auto sevenDaysAgo = std::chrono::system_clock::now() - std::chrono::hours(24 * 7); - for (const auto &entry : std::filesystem::directory_iterator("database_backup")) { + for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { if (entry.is_directory()) { - auto dirTime = std::filesystem::last_write_time(entry); - if (!compress && dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { - try { - std::filesystem::remove_all(entry); - g_logger().info("Deleted old backup directory (7 days): {}", entry.path().string()); - } catch (const std::filesystem::filesystem_error &e) { - g_logger().error("Failed to delete old backup directory: {}. Error: {}", entry.path().string(), e.what()); - } - } - if (compress && dirTime.time_since_epoch() < twentyFourHoursAgo.time_since_epoch()) { - for (const auto &file : std::filesystem::directory_iterator(entry)) { - if (file.path().extension() == ".gz") { - try { + try { + auto dirTime = std::filesystem::last_write_time(entry); + if (dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { + // Instead of deleting the entire directory, delete only specific files + for (const auto& file : std::filesystem::directory_iterator(entry)) { + if (file.path().extension() == ".gz" || file.path().extension() == ".sql") { std::filesystem::remove(file); - g_logger().info("Deleted compressed backup file (24 hours): {}", file.path().string()); - } catch (const std::filesystem::filesystem_error &e) { - g_logger().error("Failed to delete compressed backup file: {}. Error: {}", file.path().string(), e.what()); + g_logger().info("Deleted old backup file: {}", file.path().string()); } } } + } catch (const std::filesystem::filesystem_error& e) { + g_logger().error("Failed to check or delete files in backup directory: {}. Error: {}", entry.path().string(), e.what()); } } } From f0fd179fbc01b1ac1e8b878c5ac15b4d6e3bf0e0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 14 Nov 2024 16:51:46 +0000 Subject: [PATCH 06/12] Code format - (Clang-format) --- src/database/database.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index dc58794e6af..9e1d81025da 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -140,20 +140,20 @@ void Database::createDatabaseBackup(bool compress) const { // Delete old backups auto twentyFourHoursAgo = std::chrono::system_clock::now() - std::chrono::hours(24); auto sevenDaysAgo = std::chrono::system_clock::now() - std::chrono::hours(24 * 7); - for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { + for (const auto &entry : std::filesystem::directory_iterator("database_backup")) { if (entry.is_directory()) { try { auto dirTime = std::filesystem::last_write_time(entry); if (dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { // Instead of deleting the entire directory, delete only specific files - for (const auto& file : std::filesystem::directory_iterator(entry)) { + for (const auto &file : std::filesystem::directory_iterator(entry)) { if (file.path().extension() == ".gz" || file.path().extension() == ".sql") { std::filesystem::remove(file); g_logger().info("Deleted old backup file: {}", file.path().string()); } } } - } catch (const std::filesystem::filesystem_error& e) { + } catch (const std::filesystem::filesystem_error &e) { g_logger().error("Failed to check or delete files in backup directory: {}. Error: {}", entry.path().string(), e.what()); } } From 9a87f2734c0f62db07431192a3aa13efea517e58 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Thu, 14 Nov 2024 13:52:44 -0300 Subject: [PATCH 07/12] fix: revert wrong --- src/database/database.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index 9e1d81025da..363dda4ce3a 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -123,9 +123,9 @@ void Database::createDatabaseBackup(bool compress) const { return; } - char buffer[8192]; - while (backupFile.read(buffer, sizeof(buffer)) || backupFile.gcount() > 0) { - gzwrite(gzFile, buffer, backupFile.gcount()); + std::string buffer(8192, '\0'); + while (backupFile.read(&buffer[0], buffer.size()) || backupFile.gcount() > 0) { + gzwrite(gzFile, buffer.data(), backupFile.gcount()); } backupFile.close(); From 08fc766b4153f50ef0db745d6cba3c90aa2b8801 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 27 Nov 2024 04:15:37 -0300 Subject: [PATCH 08/12] fix: database backup on linux --- src/database/database.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index 363dda4ce3a..262122fe0c7 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -137,23 +137,24 @@ void Database::createDatabaseBackup(bool compress) const { g_logger().info("Database backup successfully created at: {}", backupFileName); } - // Delete old backups - auto twentyFourHoursAgo = std::chrono::system_clock::now() - std::chrono::hours(24); - auto sevenDaysAgo = std::chrono::system_clock::now() - std::chrono::hours(24 * 7); - for (const auto &entry : std::filesystem::directory_iterator("database_backup")) { + // Delete backups older than 7 days + auto nowTime = std::chrono::system_clock::now(); + auto sevenDaysAgo = nowTime - std::chrono::hours(7 * 24); // 7 days in hours + for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { if (entry.is_directory()) { try { - auto dirTime = std::filesystem::last_write_time(entry); - if (dirTime.time_since_epoch() < sevenDaysAgo.time_since_epoch()) { - // Instead of deleting the entire directory, delete only specific files - for (const auto &file : std::filesystem::directory_iterator(entry)) { - if (file.path().extension() == ".gz" || file.path().extension() == ".sql") { + for (const auto& file : std::filesystem::directory_iterator(entry)) { + if (file.path().extension() == ".gz") { + auto fileTime = std::filesystem::last_write_time(file); + auto fileTimeSystemClock = std::chrono::clock_cast(fileTime); + + if (fileTimeSystemClock < sevenDaysAgo) { std::filesystem::remove(file); g_logger().info("Deleted old backup file: {}", file.path().string()); } } } - } catch (const std::filesystem::filesystem_error &e) { + } catch (const std::filesystem::filesystem_error& e) { g_logger().error("Failed to check or delete files in backup directory: {}. Error: {}", entry.path().string(), e.what()); } } From 4b688b48f2d78add2ae4b3dd82a3066471990db8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 27 Nov 2024 07:16:14 +0000 Subject: [PATCH 09/12] Code format - (Clang-format) --- src/database/database.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/database.cpp b/src/database/database.cpp index 262122fe0c7..cb9ec58df6b 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -140,10 +140,10 @@ void Database::createDatabaseBackup(bool compress) const { // Delete backups older than 7 days auto nowTime = std::chrono::system_clock::now(); auto sevenDaysAgo = nowTime - std::chrono::hours(7 * 24); // 7 days in hours - for (const auto& entry : std::filesystem::directory_iterator("database_backup")) { + for (const auto &entry : std::filesystem::directory_iterator("database_backup")) { if (entry.is_directory()) { try { - for (const auto& file : std::filesystem::directory_iterator(entry)) { + for (const auto &file : std::filesystem::directory_iterator(entry)) { if (file.path().extension() == ".gz") { auto fileTime = std::filesystem::last_write_time(file); auto fileTimeSystemClock = std::chrono::clock_cast(fileTime); @@ -154,7 +154,7 @@ void Database::createDatabaseBackup(bool compress) const { } } } - } catch (const std::filesystem::filesystem_error& e) { + } catch (const std::filesystem::filesystem_error &e) { g_logger().error("Failed to check or delete files in backup directory: {}. Error: {}", entry.path().string(), e.what()); } } From 9486b1edb6093038a96c3c0904116fdd5a4e08fd Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 27 Nov 2024 04:43:57 -0300 Subject: [PATCH 10/12] test: fix build --- .github/workflows/build-ubuntu.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 6a252630f48..9940bfa682c 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -52,12 +52,12 @@ jobs: run: > sudo apt-get update && sudo apt-get install ccache linux-headers-"$(uname -r)" - - name: Switch to gcc-12 on Ubuntu 22.04 + - name: Switch to gcc-13 on Ubuntu 22.04 if: matrix.os == 'ubuntu-22.04' run: | - sudo apt install gcc-12 g++-12 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12 - sudo update-alternatives --set gcc /usr/bin/gcc-12 + sudo apt install gcc-13 g++-13 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 --slave /usr/bin/gcov gcov /usr/bin/gcov-12 + sudo update-alternatives --set gcc /usr/bin/gcc-13 - name: Switch to gcc-14 on Ubuntu 24.04 if: matrix.os == 'ubuntu-24.04' From 3c0ca2a9ad7c881362d3a67ee16a155103282704 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 27 Nov 2024 04:46:03 -0300 Subject: [PATCH 11/12] fix: build --- .github/workflows/build-ubuntu.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 9940bfa682c..692bafc331c 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -55,7 +55,9 @@ jobs: - name: Switch to gcc-13 on Ubuntu 22.04 if: matrix.os == 'ubuntu-22.04' run: | - sudo apt install gcc-13 g++-13 + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + sudo apt-get update + sudo apt install gcc-13 g++-13 -y sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 --slave /usr/bin/gcov gcov /usr/bin/gcov-12 sudo update-alternatives --set gcc /usr/bin/gcc-13 From c677f2e70627098f01bc8672c5f802e6bf00301b Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 13 Dec 2024 14:55:50 -0300 Subject: [PATCH 12/12] fix: database backup on shutdown --- src/canary_server.cpp | 3 +- src/database/database.cpp | 44 +++++++++++++--------------- src/game/scheduling/save_manager.cpp | 2 -- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 9f9ffc29359..492028093ed 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -316,8 +316,6 @@ void CanaryServer::initializeDatabase() { )); } - g_database().createDatabaseBackup(false); - DatabaseManager::updateDatabase(); if (g_configManager().getBoolean(OPTIMIZE_DATABASE) @@ -392,6 +390,7 @@ void CanaryServer::modulesLoadHelper(bool loaded, std::string moduleName) { } void CanaryServer::shutdown() { + g_database().createDatabaseBackup(true); g_dispatcher().shutdown(); g_metrics().shutdown(); inject().shutdown(); diff --git a/src/database/database.cpp b/src/database/database.cpp index cb9ec58df6b..a6e732694b1 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -108,35 +108,31 @@ void Database::createDatabaseBackup(bool compress) const { // Compress the backup file if requested std::string compressedFileName; - if (compress) { - compressedFileName = backupFileName + ".gz"; - gzFile gzFile = gzopen(compressedFileName.c_str(), "wb9"); - if (!gzFile) { - g_logger().error("Failed to open gzip file for compression."); - return; - } - - std::ifstream backupFile(backupFileName, std::ios::binary); - if (!backupFile.is_open()) { - g_logger().error("Failed to open backup file for compression: {}", backupFileName); - gzclose(gzFile); - return; - } - - std::string buffer(8192, '\0'); - while (backupFile.read(&buffer[0], buffer.size()) || backupFile.gcount() > 0) { - gzwrite(gzFile, buffer.data(), backupFile.gcount()); - } + compressedFileName = backupFileName + ".gz"; + gzFile gzFile = gzopen(compressedFileName.c_str(), "wb9"); + if (!gzFile) { + g_logger().error("Failed to open gzip file for compression."); + return; + } - backupFile.close(); + std::ifstream backupFile(backupFileName, std::ios::binary); + if (!backupFile.is_open()) { + g_logger().error("Failed to open backup file for compression: {}", backupFileName); gzclose(gzFile); - std::filesystem::remove(backupFileName); + return; + } - g_logger().info("Database backup successfully compressed to: {}", compressedFileName); - } else { - g_logger().info("Database backup successfully created at: {}", backupFileName); + std::string buffer(8192, '\0'); + while (backupFile.read(&buffer[0], buffer.size()) || backupFile.gcount() > 0) { + gzwrite(gzFile, buffer.data(), backupFile.gcount()); } + backupFile.close(); + gzclose(gzFile); + std::filesystem::remove(backupFileName); + + g_logger().info("Database backup successfully compressed to: {}", compressedFileName); + // Delete backups older than 7 days auto nowTime = std::chrono::system_clock::now(); auto sevenDaysAgo = nowTime - std::chrono::hours(7 * 24); // 7 days in hours diff --git a/src/game/scheduling/save_manager.cpp b/src/game/scheduling/save_manager.cpp index 0479e3f779e..45cd9392194 100644 --- a/src/game/scheduling/save_manager.cpp +++ b/src/game/scheduling/save_manager.cpp @@ -26,8 +26,6 @@ SaveManager &SaveManager::getInstance() { } void SaveManager::saveAll() { - g_database().createDatabaseBackup(true); - Benchmark bm_saveAll; logger.info("Saving server..."); const auto players = game.getPlayers();