Addition of precautionary restart manager.

This commit is contained in:
MobiusDevelopment
2020-12-19 22:30:07 +00:00
parent c3f1d2b407
commit 66ea8f6540
105 changed files with 5380 additions and 0 deletions
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1438,6 +1444,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -130,6 +130,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -427,6 +428,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -784,6 +784,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1449,6 +1455,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -134,6 +134,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -435,6 +436,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -785,6 +785,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1462,6 +1468,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -134,6 +134,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -435,6 +436,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -772,6 +772,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1449,6 +1455,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -134,6 +134,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -435,6 +436,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -767,6 +767,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1444,6 +1450,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -135,6 +135,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -437,6 +438,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -767,6 +767,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1451,6 +1457,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -135,6 +135,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -437,6 +438,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -768,6 +768,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1473,6 +1479,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -136,6 +136,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -439,6 +440,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -773,6 +773,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1484,6 +1490,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -137,6 +137,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -443,6 +444,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -770,6 +770,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Hardin (Agent of Chaos)
@@ -1481,6 +1487,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -136,6 +136,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -441,6 +442,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -34,6 +34,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -309,6 +310,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -324,6 +330,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -158,6 +158,37 @@ ClanNameTemplate = .*
AllyNameTemplate = .*
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -1127,6 +1127,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
public static int IP_UPDATE_TIME;
public static boolean SHOW_LICENCE;
@@ -1228,6 +1234,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverConfig.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverConfig.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverConfig.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverConfig.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverConfig.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverConfig.getInt("PrecautionaryRestartDelay", 60) * 1000;
}
public static void loadTelnetConfig()
@@ -100,6 +100,7 @@ import org.l2jmobius.gameserver.instancemanager.IdManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.MercTicketManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossPointsManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
@@ -471,6 +472,11 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
System.gc();
Util.printSection("Info");
@@ -29,6 +29,7 @@ import org.l2jmobius.gameserver.instancemanager.CastleManorManager;
import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import org.l2jmobius.gameserver.model.World;
@@ -193,6 +194,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -219,6 +225,11 @@ public class Shutdown extends Thread
{
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
}
/**
@@ -0,0 +1,198 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers(new CreatureSay(-1, ChatType.ANNOUNCEMENT, "", "Server will restart in 10 minutes."));
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers(new CreatureSay(-1, ChatType.ANNOUNCEMENT, "", "Server will restart in 10 minutes."));
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getAllPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player._inEvent || player.atEvent)
{
return true;
}
if (player.getInstanceId() > 0)
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -158,6 +158,37 @@ ClanNameTemplate = .*
AllyNameTemplate = .*
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -1162,6 +1162,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
public static int IP_UPDATE_TIME;
public static boolean SHOW_LICENCE;
@@ -1263,6 +1269,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverConfig.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverConfig.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverConfig.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverConfig.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverConfig.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverConfig.getInt("PrecautionaryRestartDelay", 60) * 1000;
}
public static void loadTelnetConfig()
@@ -104,6 +104,7 @@ import org.l2jmobius.gameserver.instancemanager.IdManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.MercTicketManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossPointsManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
@@ -483,6 +484,11 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
System.gc();
Util.printSection("Info");
@@ -31,6 +31,7 @@ import org.l2jmobius.gameserver.instancemanager.FishingChampionshipManager;
import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import org.l2jmobius.gameserver.model.World;
@@ -195,6 +196,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -221,6 +227,11 @@ public class Shutdown extends Thread
{
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
}
/**
@@ -0,0 +1,198 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers(new CreatureSay(-1, ChatType.ANNOUNCEMENT, "", "Server will restart in 10 minutes."));
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers(new CreatureSay(-1, ChatType.ANNOUNCEMENT, "", "Server will restart in 10 minutes."));
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getAllPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player._inEvent || player.atEvent)
{
return true;
}
if (player.getInstanceId() > 0)
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -184,6 +184,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -897,6 +897,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// MMO Settings
@@ -1482,6 +1488,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -119,6 +119,7 @@ import org.l2jmobius.gameserver.instancemanager.MailManager;
import org.l2jmobius.gameserver.instancemanager.MapRegionManager;
import org.l2jmobius.gameserver.instancemanager.MercTicketManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -439,6 +440,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import org.l2jmobius.gameserver.model.World;
@@ -313,6 +314,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -328,6 +334,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.getInstanceId() > 0)
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
+31
View File
@@ -184,6 +184,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -901,6 +901,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// MMO Settings
@@ -1481,6 +1487,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -120,6 +120,7 @@ import org.l2jmobius.gameserver.instancemanager.MailManager;
import org.l2jmobius.gameserver.instancemanager.MapRegionManager;
import org.l2jmobius.gameserver.instancemanager.MercTicketManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -441,6 +442,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import org.l2jmobius.gameserver.model.World;
@@ -313,6 +314,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -328,6 +334,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.getInstanceId() > 0)
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1380,6 +1386,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -131,6 +131,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -432,6 +433,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1384,6 +1390,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -131,6 +131,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -432,6 +433,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1384,6 +1390,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -131,6 +131,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -432,6 +433,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1384,6 +1390,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -132,6 +132,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -434,6 +435,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -774,6 +774,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1389,6 +1395,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -133,6 +133,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -436,6 +437,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -778,6 +778,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1397,6 +1403,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -134,6 +134,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -440,6 +441,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}
@@ -203,6 +203,37 @@ ClanNameTemplate = .*
CharMaxNumber = 7
# ---------------------------------------------------------------------------
# Precautionary Server Restart
# ---------------------------------------------------------------------------
# Enable server restart when CPU or memory usage is too high.
# Default: False
PrecautionaryRestartEnabled = False
# Enable monitoring system CPU usage.
# Default: True
PrecautionaryRestartCpu = True
# Enable monitoring process memory usage.
# Default: False
PrecautionaryRestartMemory = False
# Check if sieges are in progress
# or players are in olympiad, events, instances
# or have targeted raidbosses.
# Default: True
PrecautionaryRestartChecks = True
# Percentage of used resources.
# Default: 95
PrecautionaryRestartPercentage = 95
# Delay in seconds between each check.
# Default: 60
PrecautionaryRestartDelay = 60
# ---------------------------------------------------------------------------
# Scheduled Server Restart
# ---------------------------------------------------------------------------
@@ -783,6 +783,12 @@ public class Config
public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
public static String[] SERVER_RESTART_SCHEDULE;
public static List<Integer> SERVER_RESTART_DAYS;
public static boolean PRECAUTIONARY_RESTART_ENABLED;
public static boolean PRECAUTIONARY_RESTART_CPU;
public static boolean PRECAUTIONARY_RESTART_MEMORY;
public static boolean PRECAUTIONARY_RESTART_CHECKS;
public static int PRECAUTIONARY_RESTART_PERCENTAGE;
public static int PRECAUTIONARY_RESTART_DELAY;
// --------------------------------------------------
// Vitality Settings
@@ -1398,6 +1404,12 @@ public class Config
SERVER_RESTART_DAYS.add(Integer.parseInt(day));
}
}
PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
// Hosts and Subnets
final IPConfigData ipcd = new IPConfigData();
@@ -130,6 +130,7 @@ import org.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import org.l2jmobius.gameserver.instancemanager.MentorManager;
import org.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
@@ -432,6 +433,10 @@ public class GameServer
ServerRestartManager.getInstance();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
@@ -310,6 +311,11 @@ public class Shutdown extends Thread
_counterInstance._abort();
}
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartEnabled();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
@@ -325,6 +331,12 @@ public class Shutdown extends Thread
if (_counterInstance != null)
{
_counterInstance._abort();
if (Config.PRECAUTIONARY_RESTART_ENABLED)
{
PrecautionaryRestartManager.getInstance().restartAborted();
}
Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.instancemanager;
import java.lang.management.ManagementFactory;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.Shutdown;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
import org.l2jmobius.gameserver.model.siege.Castle;
import org.l2jmobius.gameserver.model.siege.Fort;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Mobius
*/
public class PrecautionaryRestartManager
{
private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
private static boolean _restarting = false;
protected PrecautionaryRestartManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_restarting)
{
return;
}
if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
{
if (serverBizzy())
{
return;
}
LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
Shutdown.getInstance().startShutdown(null, 600, true);
}
}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
}
private static double getCpuLoad(String var)
{
try
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
final AttributeList list = mbs.getAttributes(name, new String[]
{
var
});
if (list.isEmpty())
{
return 0;
}
final Attribute att = (Attribute) list.get(0);
final Double value = (Double) att.getValue();
if (value == -1)
{
return 0;
}
return (value * 1000) / 10d;
}
catch (Exception e)
{
}
return 0;
}
private static double getProcessRamLoad()
{
final Runtime runTime = Runtime.getRuntime();
final long totalMemory = runTime.maxMemory();
final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
return (usedMemory * 100) / totalMemory;
}
private boolean serverBizzy()
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if ((castle != null) && castle.getSiege().isInProgress())
{
return true;
}
}
for (Fort fort : FortManager.getInstance().getForts())
{
if ((fort != null) && fort.getSiege().isInProgress())
{
return true;
}
}
for (PlayerInstance player : World.getInstance().getPlayers())
{
if ((player == null) || player.isInOfflineMode())
{
continue;
}
if (player.isInOlympiadMode())
{
return true;
}
if (player.isOnEvent())
{
return true;
}
if (player.isInInstance())
{
return true;
}
final WorldObject target = player.getTarget();
if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
{
return true;
}
}
return false;
}
public void restartEnabled()
{
_restarting = true;
}
public void restartAborted()
{
_restarting = false;
}
public static PrecautionaryRestartManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
}
}

Some files were not shown because too many files have changed in this diff Show More