diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6ab0aa329..14ad97c97 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -169,6 +169,7 @@ ServerLobby::~ServerLobby() void ServerLobby::initDatabase() { #ifdef ENABLE_SQLITE3 + m_last_cleanup_db_time = StkTime::getMonoTimeMs(); m_db = NULL; sqlite3_stmt* stmt = NULL;; m_ip_ban_table_exists = false; @@ -438,7 +439,7 @@ void ServerLobby::initServerStatsTable() // Update disconnected time (if stk crashed it will not be written) query = StringUtils::insertValues( - "UPDATE %s SET disconnected_time = datetime('now')" + "UPDATE %s SET disconnected_time = datetime('now') " "WHERE connected_time = disconnected_time;", m_server_stats_table.c_str()); ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0); @@ -781,6 +782,81 @@ void ServerLobby::createServerIdFile() } } // createServerIdFile +//----------------------------------------------------------------------------- +#ifdef ENABLE_SQLITE3 +/* Every 1 minute STK will clean up database: + * 1. Set disconnected time to now for non-exists host. + */ +void ServerLobby::cleanupDatabase() +{ + if (!ServerConfig::m_sql_management || !m_db) + return; + + if (StkTime::getMonoTimeMs() < m_last_cleanup_db_time + 60000) + return; + + m_last_cleanup_db_time = StkTime::getMonoTimeMs(); + + if (m_server_stats_table.empty()) + return; + + std::string query; + auto peers = STKHost::get()->getPeers(); + std::vector exist_hosts; + if (!peers.empty()) + { + for (auto& peer : peers) + { + if (!peer->isValidated()) + continue; + exist_hosts.push_back(peer->getHostId()); + } + } + if (peers.empty() || exist_hosts.empty()) + { + query = StringUtils::insertValues( + "UPDATE %s SET disconnected_time = datetime('now') " + "WHERE connected_time = disconnected_time;", + m_server_stats_table.c_str()); + } + else + { + std::ostringstream oss; + oss << "UPDATE " << m_server_stats_table + << " SET disconnected_time = datetime('now')" + << " WHERE connected_time = disconnected_time AND" + << " host_id NOT IN ("; + for (unsigned i = 0; i < exist_hosts.size(); i++) + { + oss << exist_hosts[i]; + if (i != (exist_hosts.size() - 1)) + oss << ","; + } + oss << ");"; + query = oss.str(); + } + + sqlite3_stmt* stmt = NULL; + int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0); + if (ret == SQLITE_OK) + { + ret = sqlite3_step(stmt); + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) + { + Log::error("ServerLobby", + "Error finalize database for query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + } + } + else + { + Log::error("ServerLobby", "Error preparing database for query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + } +} // cleanupDatabase +#endif + //----------------------------------------------------------------------------- /** Find out the public IP server or poll STK server asynchronously. */ void ServerLobby::asynchronousUpdate() @@ -792,6 +868,10 @@ void ServerLobby::asynchronousUpdate() m_rs_state.store(RS_NONE); } +#ifdef ENABLE_SQLITE3 + cleanupDatabase(); +#endif + // Check if server owner has left updateServerOwner(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index c99c8cd02..e9712e4c1 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -79,6 +79,9 @@ private: bool m_online_id_ban_table_exists; + uint64_t m_last_cleanup_db_time; + + void cleanupDatabase(); #endif void initDatabase(); @@ -131,10 +134,6 @@ private: /** Timeout counter for various state. */ std::atomic m_timeout; - /** Lock this mutex whenever a client is connect / disconnect or - * starting race. */ - mutable std::mutex m_connection_mutex; - TransportAddress m_server_address; std::mutex m_keys_mutex; @@ -333,8 +332,6 @@ public: void finishedLoadingWorld() OVERRIDE; ServerState getCurrentState() const { return m_state.load(); } void updateBanList(); - std::unique_lock acquireConnectionMutex() const - { return std::unique_lock(m_connection_mutex); } bool waitingForPlayers() const; virtual bool allPlayersReady() const OVERRIDE { return m_state.load() >= WAIT_FOR_RACE_STARTED; }