Skip to content

Commit

Permalink
test 2
Browse files Browse the repository at this point in the history
  • Loading branch information
jprzimba committed Jan 13, 2025
1 parent 9a6f934 commit 7ca7c1a
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 5 deletions.
8 changes: 3 additions & 5 deletions .github/workflows/build-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ jobs:
uses: gittools/actions/gitversion/[email protected]

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.7.1
uses: docker/setup-buildx-action@v2
with:
install: true

- name: Login to GitHub Container Registry
uses: docker/login-action@v3.3.0
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
Expand All @@ -73,8 +73,6 @@ jobs:
tags: ghcr.io/${{ github.repository }}:${{ steps.gitversion.outputs.semVer }}
cache-from: type=gha, scope=${{ github.workflow }}
cache-to: type=gha, scope=${{ github.workflow }}
secrets: |
DEBUG=1

- name: Image digest
if: ${{ github.event_name == 'push' }}
Expand All @@ -99,7 +97,7 @@ jobs:
uses: gittools/actions/gitversion/[email protected]

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.7.1
uses: docker/setup-buildx-action@v2
with:
install: true

Expand Down
1 change: 1 addition & 0 deletions src/crystalserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ void CrystalServer::modulesLoadHelper(bool loaded, std::string moduleName) {
}

void CrystalServer::shutdown() {
g_database().createDatabaseBackup(true);
g_dispatcher().shutdown();
g_metrics().shutdown();
inject<ThreadPool>().shutdown();
Expand Down
87 changes: 87 additions & 0 deletions src/database/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,93 @@ bool Database::connect(const std::string* host, const std::string* user, const s
return true;
}

void Database::createDatabaseBackup(bool compress) const {
if (!g_configManager().getBoolean(MYSQL_DB_BACKUP)) {
return;
}
// 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));
// 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);
// Create a temporary configuration file for MySQL credentials
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;
}
// 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;
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());
}
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
for (const auto &entry : std::filesystem::directory_iterator("database_backup")) {
if (entry.is_directory()) {
try {
for (const auto &file : std::filesystem::directory_iterator(entry)) {
if (file.path().extension() == ".gz") {
auto fileTime = std::filesystem::last_write_time(file);
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
fileTime - std::filesystem::file_time_type::clock::now() +
std::chrono::system_clock::now()
);

if (sctp < sevenDaysAgo) {
std::filesystem::remove(file);
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());
}
}
}
}

bool Database::beginTransaction() {
if (!executeQuery("BEGIN")) {
return false;
Expand Down
17 changes: 17 additions & 0 deletions src/database/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ class Database {

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);

/**
* @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);

Expand Down

0 comments on commit 7ca7c1a

Please sign in to comment.