/// <summary> /// Queue initial heartbeats to active servers /// </summary> public void QueueInitialHeartbeats() { DateTime Now = DateTime.UtcNow; uint HeartbeatsStarted = 0; lock (ActiveServerTable) { foreach (var Pair in ActiveServerTable) { NWGameServer Server = Pair.Value; lock (Server) { if (!Server.Online) { continue; } Server.InitialHeartbeat = true; Server.StartHeartbeat(); HeartbeatsStarted += 1; } } } Logger.Log(LogLevel.Normal, "NWServerTracker.QueueInitialHeartbeats(): Queued {0} initial server heartbeat requests.", HeartbeatsStarted); PendingGameServersSweepTimer.Start(); ScavengerSweepTimer.Start(); BlacklistSweepTimer.Start(); }
/// <summary> /// This method disables future heartbeats and flushes any servers that /// may be in the heartbeat path out of that code path before further /// forward progress is allowed. /// </summary> public void DrainHeartbeats() { // // Prevent new requestors from spinning up new heartbeat requests. // HeartbeatsEnabled = false; // // Flush any in-flight requestors out of the heartbeat path by // ensuring that they have released synchronization. // Monitor.Enter(HeartbeatLock); Monitor.Exit(HeartbeatLock); // // Stop all of the active timers. New timers that have elapsed // will have already completed starting the timer again or will now // observe that future timer restarts are already forbidden. // PendingGameServersSweepTimer.Stop(); ScavengerSweepTimer.Stop(); BlacklistSweepTimer.Stop(); }
/// <summary> /// This timer callback runs when the pending game servers sweep timer /// elapses. It checks whether there is a pending query queue, and if /// so, flushes it as appropriate. /// </summary> /// <param name="sender">Unused.</param> /// <param name="e">Unused.</param> private void PendingGameServersSweepTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { try { uint HighestPendingServerId = 0; bool DataReturned = false; string Query = String.Format( @"SELECT `pending_game_server_id`, `server_address` FROM `pending_game_servers` WHERE `product_id` = {0} GROUP BY `pending_game_server_id` ORDER BY `pending_game_server_id` LIMIT 100 ", MasterServer.ProductID); using (MySqlDataReader Reader = MasterServer.ExecuteQuery(Query)) { while (Reader.Read()) { uint PendingServerId = Reader.GetUInt32(0); string Hostname = Reader.GetString(1); IPEndPoint ServerAddress; if (PendingServerId > HighestPendingServerId) { HighestPendingServerId = PendingServerId; } if (DataReturned == false) { DataReturned = true; } ServerAddress = ConvertServerHostnameToIPEndPoint(Hostname); if (ServerAddress == null) { Logger.Log(LogLevel.Error, "NWServerTracker.PendingGameServersSweepTimer_Elapsed(): Server {0} has invalid hostname '{1}'.", PendingServerId, Hostname); continue; } NWGameServer Server = LookupServerByAddress(ServerAddress, false); if (Server == null || Server.Online == false) { MasterServer.SendServerInfoRequest(ServerAddress); } } } if (DataReturned) { // // Remove records that have already been processed. // MasterServer.ExecuteQueryNoReader(String.Format( @"DELETE FROM `pending_game_servers` WHERE `product_id` = {0} AND `pending_game_server_id` < {1}", MasterServer.ProductID, HighestPendingServerId + 1)); } } catch (Exception ex) { Logger.Log(LogLevel.Error, "NWServerTracker.PendingGameServersSweepTimer_Elapsed(): Exception processing pending servers list: {0}.", ex); } lock (HeartbeatLock) { if (!HeartbeatsEnabled) { return; } PendingGameServersSweepTimer.Start(); } }