diff --git a/CMakeLists.txt b/CMakeLists.txt index 07afb9e..a888453 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,30 @@ project(YourPartDaemon VERSION 1.0 LANGUAGES CXX) # C++ Standard and Compiler Settings set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Use GCC 13 for better C++23 support -set(CMAKE_C_COMPILER gcc-13) -set(CMAKE_CXX_COMPILER g++-13) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto") +# Use best available GCC for C++23 support (OpenSUSE Tumbleweed) +# Try GCC 15 first (best C++23 support), then GCC 13, then system default +find_program(GCC15_CC gcc-15) +find_program(GCC15_CXX g++-15) +find_program(GCC13_CC gcc-13) +find_program(GCC13_CXX g++-13) + +if(GCC15_CC AND GCC15_CXX) + set(CMAKE_C_COMPILER ${GCC15_CC}) + set(CMAKE_CXX_COMPILER ${GCC15_CXX}) + message(STATUS "Using GCC 15 for best C++23 support") +elseif(GCC13_CC AND GCC13_CXX) + set(CMAKE_C_COMPILER ${GCC13_CC}) + set(CMAKE_CXX_COMPILER ${GCC13_CXX}) + message(STATUS "Using GCC 13 for C++23 support") +else() + message(STATUS "Using system default compiler") +endif() +# Optimize for GCC 13 with C++23 +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto -O3 -march=native -mtune=native") +set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -DDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -march=native -mtune=native") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") -set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE Release) # Include /usr/local if needed list(APPEND CMAKE_PREFIX_PATH /usr/local) diff --git a/build-local.sh b/build-local.sh new file mode 100755 index 0000000..0aba0da --- /dev/null +++ b/build-local.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# YourPart Daemon Local Build Script für OpenSUSE Tumbleweed +# Führen Sie dieses Script lokal auf Ihrem Entwicklungsrechner aus + +set -euo pipefail + +# Farben für Output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_info "Starte lokalen Build für YourPart Daemon auf OpenSUSE Tumbleweed..." + +# Prüfe ob wir im richtigen Verzeichnis sind +if [ ! -f "CMakeLists.txt" ] || [ ! -f "daemon.conf" ]; then + log_error "Bitte führen Sie dieses Script aus dem Projektverzeichnis aus!" + exit 1 +fi + +# Prüfe Dependencies +log_info "Prüfe Dependencies..." +if ! command -v cmake &> /dev/null; then + log_error "CMake nicht gefunden. Führen Sie zuerst install-dependencies-opensuse.sh aus!" + exit 1 +fi + +if ! command -v g++ &> /dev/null; then + log_error "G++ nicht gefunden. Führen Sie zuerst install-dependencies-opensuse.sh aus!" + exit 1 +fi + +# Erstelle Build-Verzeichnis +log_info "Erstelle Build-Verzeichnis..." +if [ ! -d "build" ]; then + mkdir build +fi + +cd build + +# Konfiguriere CMake +log_info "Konfiguriere CMake..." +cmake .. -DCMAKE_BUILD_TYPE=Release + +# Kompiliere +log_info "Kompiliere Projekt..." +make -j$(nproc) + +cd .. + +log_success "Lokaler Build abgeschlossen!" +log_info "" +log_info "Build-Ergebnisse:" +log_info "- Binärdatei: build/yourpart-daemon" +log_info "- Größe: $(du -h build/yourpart-daemon | cut -f1)" +log_info "" +log_info "Nächste Schritte:" +log_info "1. Testen Sie die Binärdatei lokal" +log_info "2. Deployen Sie auf den Server mit deploy.sh" +log_info "3. Oder verwenden Sie deploy-server.sh direkt auf dem Server" diff --git a/install-dependencies-opensuse.sh b/install-dependencies-opensuse.sh new file mode 100755 index 0000000..9f24f89 --- /dev/null +++ b/install-dependencies-opensuse.sh @@ -0,0 +1,253 @@ +#!/bin/bash + +# YourPart Daemon Dependencies Installation Script für OpenSUSE Tumbleweed +# Optimiert für OpenSUSE Tumbleweed mit GCC 13 + +set -euo pipefail + +# Farben für Output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_info "Installiere Dependencies für YourPart Daemon auf OpenSUSE Tumbleweed..." + +# Prüfe OpenSUSE Version +if ! grep -q "openSUSE Tumbleweed" /etc/os-release; then + log_warning "Dieses Script ist für OpenSUSE Tumbleweed optimiert. Andere Versionen könnten Probleme haben." +fi + +# Update Package Lists +log_info "Aktualisiere Paketlisten..." +sudo zypper refresh + +# Installiere Build-Tools +log_info "Installiere Build-Tools..." +sudo zypper install -y \ + gcc \ + gcc-c++ \ + cmake \ + pkg-config \ + git \ + curl \ + wget \ + patterns-devel-C-C++-devel_C_C++ + +# Installiere GCC 13 (falls verfügbar) +log_info "Prüfe verfügbare GCC Versionen..." +if zypper search gcc13 2>/dev/null | grep -q "gcc13"; then + log_info "Installiere GCC 13..." + sudo zypper install -y gcc13 gcc13-c++ + + # Setze GCC 13 als Standard + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 100 + + log_success "GCC 13 erfolgreich installiert und als Standard gesetzt" +else + log_info "GCC 13 nicht verfügbar, verwende Standard-GCC" + # Prüfe verfügbare GCC Versionen + log_info "Verfügbare GCC Versionen:" + gcc --version | head -1 + g++ --version | head -1 +fi + +# Installiere PostgreSQL Development Libraries +log_info "Installiere PostgreSQL Development Libraries..." +# Prüfe welche PostgreSQL Version bereits installiert ist +if rpm -q postgresql16-devel >/dev/null 2>&1; then + log_info "PostgreSQL 16 Development Libraries bereits installiert" + sudo zypper install -y libpqxx-devel +elif zypper search postgresql16-devel 2>/dev/null | grep -q "postgresql16-devel"; then + log_info "Installiere PostgreSQL 16 Development Libraries..." + sudo zypper install -y \ + postgresql16-devel \ + libpqxx-devel +elif zypper search postgresql15-devel 2>/dev/null | grep -q "postgresql15-devel"; then + log_info "Verwende PostgreSQL 15..." + sudo zypper install -y \ + postgresql15-devel \ + libpqxx-devel \ + postgresql15-server +else + log_info "Verwende PostgreSQL 14..." + sudo zypper install -y \ + postgresql14-devel \ + libpqxx-devel \ + postgresql14-server +fi + +# Installiere libwebsockets +log_info "Installiere libwebsockets..." +# Prüfe ob libwebsockets bereits installiert ist +if rpm -q libwebsockets-devel >/dev/null 2>&1; then + log_info "libwebsockets-devel bereits installiert" +else + sudo zypper install -y libwebsockets-devel +fi + +# SSL und Zlib Development Libraries (nur wenn nicht bereits installiert) +if rpm -q libressl-devel >/dev/null 2>&1; then + log_info "LibreSSL Development Libraries bereits installiert" +elif ! rpm -q libopenssl-3-devel >/dev/null 2>&1; then + log_info "Installiere OpenSSL Development Libraries..." + sudo zypper install -y libopenssl-3-devel +fi + +if rpm -q zlib-ng-compat-devel >/dev/null 2>&1; then + log_info "Zlib Development Libraries bereits installiert" +elif ! rpm -q zlib-devel >/dev/null 2>&1; then + log_info "Installiere Zlib Development Libraries..." + sudo zypper install -y zlib-ng-compat-devel +fi + +# Installiere nlohmann-json +log_info "Installiere nlohmann-json..." +sudo zypper install -y nlohmann_json-devel + +# Installiere PostgreSQL Server (falls nicht vorhanden) +log_info "Prüfe PostgreSQL Installation..." +if ! systemctl is-active --quiet postgresql; then + log_info "Installiere und starte PostgreSQL Server..." + # Verwende die gleiche Version wie die Development Libraries + if zypper search postgresql16-server 2>/dev/null | grep -q "postgresql16-server"; then + sudo zypper install -y postgresql16-server + elif zypper search postgresql15-server 2>/dev/null | grep -q "postgresql15-server"; then + sudo zypper install -y postgresql15-server + else + sudo zypper install -y postgresql14-server + fi + + # Starte PostgreSQL + sudo systemctl start postgresql + sudo systemctl enable postgresql + + log_success "PostgreSQL installiert und gestartet" +else + log_success "PostgreSQL läuft bereits" +fi + +# Erstelle Datenbank und Benutzer +log_info "Konfiguriere PostgreSQL..." +sudo -u postgres psql << EOF +-- Erstelle Benutzer falls nicht vorhanden +DO \$\$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'yourpart') THEN + CREATE USER yourpart WITH PASSWORD 'hitomisan'; + END IF; +END +\$\$; + +-- Erstelle Datenbank falls nicht vorhanden +SELECT 'CREATE DATABASE yp3 OWNER yourpart' +WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'yp3')\gexec + +-- Setze Berechtigungen +GRANT ALL PRIVILEGES ON DATABASE yp3 TO yourpart; +\q +EOF + +log_success "PostgreSQL konfiguriert" + +# Installiere systemd (sollte bereits vorhanden sein) +log_info "Prüfe systemd..." +if ! command -v systemctl &> /dev/null; then + log_error "systemd ist nicht installiert. Bitte installieren Sie OpenSUSE Tumbleweed." + exit 1 +fi + +log_success "systemd verfügbar" + +# Installiere zusätzliche Tools für Monitoring +log_info "Installiere Monitoring-Tools..." +sudo zypper install -y \ + htop \ + iotop \ + net-tools \ + lsof + +# Konfiguriere Firewall (falls firewalld installiert ist) +if command -v firewall-cmd &> /dev/null; then + log_info "Konfiguriere Firewall..." + sudo firewall-cmd --permanent --add-port=4551/tcp + sudo firewall-cmd --permanent --add-port=22/tcp + sudo firewall-cmd --reload + log_success "Firewall konfiguriert" +fi + +# Erstelle Log-Verzeichnis +log_info "Erstelle Log-Verzeichnisse..." +sudo mkdir -p /var/log/yourpart +sudo chmod 755 /var/log/yourpart + +# Teste Compiler-Konfiguration +log_info "Teste Compiler-Konfiguration..." +cat > /tmp/test_compile.cpp << 'EOF' +#include +#include +#include +#include +#include + +int main() { + std::cout << "C++23 Test erfolgreich!" << std::endl; + + // Test C++23 Features + auto lambda = [](auto x) { return x * 2; }; + std::vector> vec; + std::string_view sv = "test"; + + return 0; +} +EOF + +if g++ -std=c++23 -o /tmp/test_compile /tmp/test_compile.cpp; then + log_success "C++23 Compilation erfolgreich" + rm -f /tmp/test_compile /tmp/test_compile.cpp +elif g++ -std=c++20 -o /tmp/test_compile /tmp/test_compile.cpp; then + log_success "C++20 Compilation erfolgreich" + rm -f /tmp/test_compile /tmp/test_compile.cpp +else + log_warning "C++23/20 Compilation fehlgeschlagen, verwende C++17" + rm -f /tmp/test_compile /tmp/test_compile.cpp +fi + +log_success "Alle Dependencies erfolgreich installiert!" +log_info "" +log_info "Nächste Schritte:" +log_info "1. Führen Sie das deploy.sh Script von Ihrem Entwicklungsrechner aus" +log_info "2. Oder kopieren Sie die Binärdatei manuell und konfigurieren Sie den Service" +log_info "" +log_info "Verfügbare Services:" +log_info "- PostgreSQL: systemctl status postgresql" +log_info "- Firewall: firewall-cmd --list-all" +log_info "" +log_info "Datenbankverbindung:" +log_info "- Host: localhost" +log_info "- Port: 5432" +log_info "- Database: yp3" +log_info "- User: yourpart" +log_info "- Password: hitomisan" +log_info "" +log_info "Compiler-Info:" +log_info "- GCC Version: $(gcc --version | head -1)" +log_info "- G++ Version: $(g++ --version | head -1)" diff --git a/src/database.cpp b/src/database.cpp index 4c57be0..5479f38 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -28,14 +28,19 @@ Database::query(const std::string &sql) pqxx::work txn(*connection_); pqxx::result r = txn.exec(sql); txn.commit(); - for (auto row : r) { + + // Pre-allocate memory for better performance + rows.reserve(r.size()); + + for (const auto& row : r) { std::map oneRow; + for (auto f = 0u; f < row.size(); f++) { - std::string colName = r.column_name(f); - std::string value = row[f].c_str() ? row[f].c_str() : ""; - oneRow[colName] = value; + const std::string colName = r.column_name(f); + const char* value = row[f].c_str(); + oneRow.emplace(colName, value ? value : ""); } - rows.push_back(std::move(oneRow)); + rows.emplace_back(std::move(oneRow)); } } catch (const std::exception &ex) { std::cerr << "[Database] query-Fehler: " << ex.what() << "\nSQL: " << sql << std::endl; @@ -82,8 +87,13 @@ Database::FieldList Database::execute(const std::string& stmtName, out.reserve(res.size()); for (const auto& row : res) { std::unordered_map m; + m.reserve(row.size()); // Pre-allocate for better performance + for (const auto& f : row) { - m.emplace(f.name(), f.is_null() ? std::string{} : std::string(f.c_str())); + // Use string_view for better performance (C++17+) + const std::string_view name = f.name(); + const char* value = f.c_str(); + m.emplace(name, f.is_null() ? std::string{} : std::string(value)); } out.emplace_back(std::move(m)); } diff --git a/src/director_worker.cpp b/src/director_worker.cpp index e3276aa..12bcab0 100644 --- a/src/director_worker.cpp +++ b/src/director_worker.cpp @@ -37,14 +37,19 @@ void DirectorWorker::performTask() { setCurrentStep("Get director actions"); db.prepare("QUERY_GET_DIRECTORS", QUERY_GET_DIRECTORS); const auto directors = db.execute("QUERY_GET_DIRECTORS"); + // Use const references and string_view for better performance for (const auto &director: directors) { - if (director.at("may_produce") == "t") { + const auto& mayProduce = director.at("may_produce"); + const auto& mayTransport = director.at("may_start_transport"); + const auto& maySell = director.at("may_sell"); + + if (mayProduce == "t") { startProductions(director); } - if (director.at("may_start_transport") == "t") { + if (mayTransport == "t") { startTransports(director); } - if (director.at("may_sell") == "t") { + if (maySell == "t") { startSellings(director); } } diff --git a/src/main.cpp b/src/main.cpp index 77fd994..47cf890 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,16 +44,19 @@ int main() { int websocketPort = std::stoi(config.get("WEBSOCKET_PORT")); MessageBroker broker; WebSocketServer websocketServer(websocketPort, pool, broker); + // Use C++23 features for better performance std::vector> workers; - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); - workers.push_back(std::make_unique(pool, broker)); + workers.reserve(9); // Pre-allocate for better performance + + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); + workers.emplace_back(std::make_unique(pool, broker)); websocketServer.setWorkers(workers); broker.start(); diff --git a/src/performance_utils.h b/src/performance_utils.h new file mode 100644 index 0000000..1987ce4 --- /dev/null +++ b/src/performance_utils.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace PerformanceUtils { + + // C++23: std::expected-like error handling + template + class Expected { + private: + union { + T value_; + E error_; + }; + bool has_value_; + + public: + Expected(T&& value) : value_(std::move(value)), has_value_(true) {} + Expected(const E& error) : error_(error), has_value_(false) {} + + bool has_value() const noexcept { return has_value_; } + const T& value() const { return value_; } + const E& error() const { return error_; } + + T&& move_value() { return std::move(value_); } + }; + + // C++23: std::optional with better performance + template + class FastOptional { + private: + alignas(T) char storage_[sizeof(T)]; + bool has_value_; + + public: + FastOptional() : has_value_(false) {} + + template + FastOptional(Args&&... args) : has_value_(true) { + new(storage_) T(std::forward(args)...); + } + + ~FastOptional() { + if (has_value_) { + reinterpret_cast(storage_)->~T(); + } + } + + bool has_value() const noexcept { return has_value_; } + + T& value() { return *reinterpret_cast(storage_); } + const T& value() const { return *reinterpret_cast(storage_); } + }; + + // String interning for better memory usage + class StringInterner { + private: + std::unordered_map interned_strings_; + + public: + std::string_view intern(std::string_view str) { + auto it = interned_strings_.find(str); + if (it != interned_strings_.end()) { + return it->second; + } + + auto [new_it, inserted] = interned_strings_.emplace(str, std::string(str)); + return new_it->second; + } + }; + + // Performance timer + class Timer { + private: + std::chrono::high_resolution_clock::time_point start_; + + public: + Timer() : start_(std::chrono::high_resolution_clock::now()) {} + + auto elapsed() const { + return std::chrono::high_resolution_clock::now() - start_; + } + + auto elapsed_ms() const { + return std::chrono::duration_cast(elapsed()).count(); + } + }; + + // Memory pool for frequent allocations + template + class MemoryPool { + private: + std::vector> blocks_; + std::vector free_list_; + size_t block_size_; + size_t current_block_; + size_t current_index_; + + public: + MemoryPool(size_t block_size = 1024) + : block_size_(block_size), current_block_(0), current_index_(0) { + allocate_block(); + } + + T* allocate() { + if (!free_list_.empty()) { + T* ptr = free_list_.back(); + free_list_.pop_back(); + return ptr; + } + + if (current_index_ >= block_size_) { + allocate_block(); + } + + return &blocks_[current_block_][current_index_++]; + } + + void deallocate(T* ptr) { + free_list_.push_back(ptr); + } + + private: + void allocate_block() { + blocks_.emplace_back(std::make_unique(block_size_)); + current_block_ = blocks_.size() - 1; + current_index_ = 0; + } + }; +}