From 9327e715193dad5a6ffb6c5a58e7d6a266a8313c Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Wed, 6 Nov 2013 01:03:02 -0800 Subject: [PATCH] MOre work on dynamic server baby! --- .../core/status/ServerStatusRepository.java | 7 +- Plugins/Mineplex.ServerMonitor/.classpath | 2 +- .../servermonitor/GroupStatusData.java | 7 + .../mineplex/servermonitor/Repository.java | 100 +++++++++++-- .../mineplex/servermonitor/ServerMonitor.java | 134 +++++++++++++++++- .../servermonitor/ServerStatusData.java | 2 +- 6 files changed, 232 insertions(+), 20 deletions(-) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/status/ServerStatusRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/status/ServerStatusRepository.java index 5abf2b47d..1d99114ce 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/status/ServerStatusRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/status/ServerStatusRepository.java @@ -15,9 +15,10 @@ public class ServerStatusRepository private String _userName; private String _password; - private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), updated LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));"; + private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), updated LONG, lastTimeWithPlayers LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));"; private static String INSERT_PLAYER_COUNT = "INSERT INTO ServerStatus (serverName, serverGroup, address, updated, motd, players, maxPlayers, tps, ram, maxRam) values(default, ?, ?, ?, now(), 'Configuring server.', ?, ?, 0, ?, ?);"; - private static String UPDATE_PLAYER_COUNT = "UPDATE ServerStatus SET updated = now(), serverName = ?, serverGroup = ?, motd = ?, players = ?, maxPlayers = ?, tps = ?, ram = ?, maxRam = ? WHERE id = ?;"; + private static String UPDATE_PLAYER_COUNT_WITH_PLAYERS = "UPDATE ServerStatus SET updated = now(), serverName = ?, serverGroup = ?, motd = ?, players = ?, maxPlayers = ?, tps = ?, ram = ?, maxRam = ?, lastTimeWithPlayers = now() WHERE id = ?;"; + private static String UPDATE_PLAYER_COUNT_WITHOUT_PLAYERS = "UPDATE ServerStatus SET updated = now(), serverName = ?, serverGroup = ?, motd = ?, players = ?, maxPlayers = ?, tps = ?, ram = ?, maxRam = ? WHERE id = ?;"; private static String RETRIEVE_ID = "SELECT id FROM ServerStatus WHERE address = ?;"; private static String RETRIEVE_SERVER_STATUSES = "SELECT serverName, motd, players, maxPlayers FROM ServerStatus WHERE TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.updated)) < 10;"; @@ -173,7 +174,7 @@ public class ServerStatusRepository { connection = DriverManager.getConnection(_connectionString, _userName, _password); - preparedStatement = connection.prepareStatement(UPDATE_PLAYER_COUNT, Statement.RETURN_GENERATED_KEYS); + preparedStatement = connection.prepareStatement(players != 0 ? UPDATE_PLAYER_COUNT_WITH_PLAYERS : UPDATE_PLAYER_COUNT_WITHOUT_PLAYERS, Statement.RETURN_GENERATED_KEYS); preparedStatement.setString(1, _serverName); preparedStatement.setString(2, _serverGroup); diff --git a/Plugins/Mineplex.ServerMonitor/.classpath b/Plugins/Mineplex.ServerMonitor/.classpath index fb5011632..8325d3454 100644 --- a/Plugins/Mineplex.ServerMonitor/.classpath +++ b/Plugins/Mineplex.ServerMonitor/.classpath @@ -1,6 +1,6 @@ - + diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/GroupStatusData.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/GroupStatusData.java index a2d4c4377..471666d49 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/GroupStatusData.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/GroupStatusData.java @@ -11,6 +11,7 @@ public class GroupStatusData public int Players; public int MaxPlayers; + public List EmptyServers = new ArrayList(); public List Servers = new ArrayList(); public void addServer(ServerStatusData serverStatusData) @@ -22,6 +23,7 @@ public class GroupStatusData { if (serverStatusData.Players < serverStatusData.MaxPlayers) { + // Lobby joinable checking if (serverStatusData.Motd.isEmpty() || serverStatusData.Motd.equals("")) { if (serverStatusData.Players / serverStatusData.MaxPlayers < .9) @@ -36,6 +38,11 @@ public class GroupStatusData _totalCount++; + if (serverStatusData.Empty) + { + EmptyServers.add(serverStatusData); + } + Servers.add(serverStatusData); } diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/Repository.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/Repository.java index df2f67dff..2ca8fb5c4 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/Repository.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/Repository.java @@ -11,7 +11,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; - public class Repository { private String _connectionString = "jdbc:mysql://localhost:3306/ServerStatus"; @@ -21,10 +20,10 @@ public class Repository private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), updated LONG, lastTimeWithPlayers LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));"; private static String RETRIEVE_OLD_SERVER_STATUSES = "SELECT serverName, address, motd, players, maxPlayers FROM ServerStatus WHERE TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.updated)) > 10;"; - private static String CREATE_DYNAMIC_TABLE = "CREATE TABLE IF NOT EXISTS DynamicServers (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), address VARCHAR(256), PRIMARY KEY (id));"; - private static String RETRIEVE_AVAILABLE_SERVERS = "SELECT `DynamicServers`.`serverName`, `DynamicServers`.`address`, `ServerStatus`.`serverGroup`, COUNT(*) As serverCount FROM `DynamicServers` INNER JOIN `ServerStatus` ON `ServerStatus`.`address` LIKE CONCAT(`DynamicServers`.`address`, '%') GROUP BY `DynamicServers`.`address`, `ServerStatus`.`serverGroup`"; - private static String RETRIEVE_SERVERGROUP_STATUSES = "SELECT serverName, serverGroup, address, players, maxPlayers, lastTimeWithPlayers FROM ServerStatus WHERE TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.updated)) <= 10;"; - private static String RETRIEVE_SERVER_GROUP_DATA = "SELECT groupName, scriptName, requiredRam, cpuRequired, requiredTotal, requiredJoinable FROM ServerGroups;"; + private static String CREATE_DYNAMIC_TABLE = "CREATE TABLE IF NOT EXISTS DynamicServers (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), address VARCHAR(256), US BOOLEAN NOT NULL DEFAULT 'true', PRIMARY KEY (id));"; + private static String RETRIEVE_AVAILABLE_SERVERS = "SELECT DynamicServers.serverName, DynamicServers.address, ServerStatus.serverGroup, COUNT(*) As serverCount FROM DynamicServers LEFT JOIN ServerStatus ON ServerStatus.address LIKE CONCAT(DynamicServers.address, '%') WHERE DynamicServers.US = 'false' GROUP BY DynamicServers.address, ServerStatus.serverGroup;"; + private static String RETRIEVE_SERVERGROUP_STATUSES = "SELECT ServerStatus.serverName, serverGroup, ServerStatus.address, players, maxPlayers, case when TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.lastTimeWithPlayers)) > 300 then 1 else 0 end as empty FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address LIKE CONCAT(DynamicServers.address, '%') WHERE DynamicServers.US = 'false' AND TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.updated)) <= 10"; + private static String RETRIEVE_SERVER_GROUP_DATA = "SELECT groupName, prefix, scriptName, requiredRam, cpuRequired, requiredTotal, requiredJoinable FROM ServerGroups;"; public void initialize() @@ -200,7 +199,7 @@ public class Repository ResultSet resultSet = null; PreparedStatement preparedStatement = null; HashMap groupData = new HashMap(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { connection = DriverManager.getConnection(_connectionString, _userName, _password); @@ -219,7 +218,7 @@ public class Repository serverStatusData.Port = Integer.parseInt(addressPortString.split(":")[1]); serverStatusData.Players = resultSet.getInt(4); serverStatusData.MaxPlayers = resultSet.getInt(5); - serverStatusData.LastTimeWithPlayers = dateFormat.parse(resultSet.getString(6)).getTime(); + serverStatusData.Empty = resultSet.getBoolean(7); if (!groupData.containsKey(serverGroup)) { @@ -295,11 +294,12 @@ public class Repository ServerGroupData serverGroupData = new ServerGroupData(); serverGroupData.Name = resultSet.getString(1); - serverGroupData.ScriptName = resultSet.getString(2); - serverGroupData.RequiredRAM = resultSet.getInt(3); - serverGroupData.RequiredCPU = resultSet.getInt(4); - serverGroupData.RequiredTotalServers = resultSet.getInt(5); - serverGroupData.RequiredJoinableServers = resultSet.getInt(6); + serverGroupData.Prefix = resultSet.getString(2); + serverGroupData.ScriptName = resultSet.getString(3); + serverGroupData.RequiredRAM = resultSet.getInt(4); + serverGroupData.RequiredCPU = resultSet.getInt(5); + serverGroupData.RequiredTotalServers = resultSet.getInt(6); + serverGroupData.RequiredJoinableServers = resultSet.getInt(7); if (!serverGroupMap.containsKey(serverGroupData.Name)) serverGroupMap.put(serverGroupData.Name, serverGroupData); @@ -368,4 +368,80 @@ public class Repository return serverMap.values(); } + + public Collection retrieveServerGroups() + { + Connection connection = null; + ResultSet resultSet = null; + PreparedStatement preparedStatement = null; + HashMap serverGroupMap = new HashMap(); + + try + { + connection = DriverManager.getConnection(_connectionString, _userName, _password); + + preparedStatement = connection.prepareStatement(RETRIEVE_SERVER_GROUP_DATA); + resultSet = preparedStatement.executeQuery(); + + while (resultSet.next()) + { + ServerGroupData serverGroupData = new ServerGroupData(); + + serverGroupData.Name = resultSet.getString(1); + serverGroupData.Prefix = resultSet.getString(2); + serverGroupData.ScriptName = resultSet.getString(3); + serverGroupData.RequiredRAM = resultSet.getInt(4); + serverGroupData.RequiredCPU = resultSet.getInt(5); + serverGroupData.RequiredTotalServers = resultSet.getInt(6); + serverGroupData.RequiredJoinableServers = resultSet.getInt(7); + + if (!serverGroupMap.containsKey(serverGroupData.Name)) + serverGroupMap.put(serverGroupData.Name, serverGroupData); + } + } + catch (Exception exception) + { + exception.printStackTrace(); + } + finally + { + if (preparedStatement != null) + { + try + { + preparedStatement.close(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + if (resultSet != null) + { + try + { + resultSet.close(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + if (connection != null) + { + try + { + connection.close(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + } + + return serverGroupMap.values(); + } } diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java index 89920948a..14c212936 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; @@ -61,10 +62,109 @@ public class ServerMonitor */ if (_count % 10 == 0) { - Collection dynamicServers = _repository.retrieveDynamicServers(); - List targetList = new ArrayList(); - HashMap groupStatusList = _repository.retrieveGroupStatusData(); + List dynamicServers = new ArrayList(_repository.retrieveDynamicServers()); + Collection serverGroups = _repository.retrieveServerGroups(); + HashMap groupStatusList = _repository.retrieveGroupStatusData(); + for (ServerGroupData serverGroup : serverGroups) + { + System.out.println("Checking Server Group " + serverGroup.Name); + + if (!groupStatusList.containsKey(serverGroup.Name)) + { + groupStatusList.put(serverGroup.Name, new GroupStatusData()); + } + + GroupStatusData groupStatus = groupStatusList.get(serverGroup.Name); + + int serversToAdd = Math.max(serverGroup.RequiredTotalServers - groupStatus.getTotalServers(), serverGroup.RequiredJoinableServers - groupStatus.getJoinableCount()); + int serversToKill = groupStatus.EmptyServers.size() - serverGroup.RequiredJoinableServers; + + if (serversToAdd > 0) + { + while (serversToAdd > 0) + { + Collections.sort(dynamicServers, new DynamicServerSorter()); + DynamicServerData bestServer = getBestDynamicServer(dynamicServers, serverGroup); + + if (bestServer == null) + { + System.out.println("No best dynamic server available for group " + serverGroup.Name); + break; + } + + String cmd = "/home/mineplex/easyRemoteStartServer.sh"; + Process process = null; + + try + { + process = new ProcessBuilder(new String[] {"/bin/sh", "-x", cmd, bestServer.Address, serverGroup.Prefix + "-" + (groupStatus.getTotalServers() + 1)}).start(); + process.waitFor(); + BufferedReader reader=new BufferedReader(new InputStreamReader(process.getInputStream())); + String line = reader.readLine(); + + while(line != null) + { + System.out.println(line); + line=reader.readLine(); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + if (process != null) + { + process.destroy(); + } + } + + bestServer.setServerGroupCount(serverGroup, bestServer.ServerGroupCount.containsKey(serverGroup.Name) ? (bestServer.ServerGroupCount.get(serverGroup.Name) + 1) : 1); + System.out.println("Sent start command to " + bestServer.Address + " for " + serverGroup.Prefix + "-" + (groupStatus.getTotalServers() + 1)); + serversToAdd--; + } + } + else if (serversToKill > 0) + { + while (serversToKill > 0) + { + String cmd = "/home/mineplex/easyRemoteKillServer.sh"; + Process process = null; + + ServerStatusData serverToKill = groupStatus.EmptyServers.get(0); + + try + { + process = new ProcessBuilder(new String[] {"/bin/sh", "-x", cmd, serverToKill.Address, serverToKill.Name}).start(); + process.waitFor(); + BufferedReader reader=new BufferedReader(new InputStreamReader(process.getInputStream())); + String line = reader.readLine(); + + while(line != null) + { + System.out.println(line); + line=reader.readLine(); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + if (process != null) + { + process.destroy(); + } + } + + System.out.println("Sent start command to " + serverToKill.Address + " for " + serverToKill.Name); + serversToKill--; + } + } + } } try @@ -80,4 +180,32 @@ public class ServerMonitor _count %= 20; } } + + private static DynamicServerData getBestDynamicServer(Collection dynamicServers, ServerGroupData serverGroup) + { + DynamicServerData bestServer = null; + + for (DynamicServerData serverData : dynamicServers) + { + System.out.println("Checking Dynamic Server " + serverData.Name); + + if (serverData.AvailableRAM > serverGroup.RequiredRAM && serverData.AvailableCPU > serverGroup.RequiredCPU) + { + if (bestServer == null) + { + bestServer = serverData; + + if (!serverData.ServerGroupCount.containsKey(serverGroup.Name)) + break; + } + else if (serverData.ServerGroupCount.containsKey(serverGroup.Name)) + { + if (serverData.ServerGroupCount.get(serverGroup.Name) < bestServer.ServerGroupCount.get(serverGroup.Name)) + bestServer = serverData; + } + } + } + + return bestServer; + } } diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerStatusData.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerStatusData.java index a87d35435..092498d42 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerStatusData.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerStatusData.java @@ -8,5 +8,5 @@ public class ServerStatusData public int MaxPlayers; public String Address; public int Port; - public long LastTimeWithPlayers; + public boolean Empty = false; }