Only hold community data in memory when a member is online
This should save a ton of memory and processing power, but needs to be tested
This commit is contained in:
parent
d7eec02bdd
commit
482e603af6
@ -12,6 +12,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -19,10 +20,11 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import mineplex.core.Managers;
|
||||
import mineplex.core.MiniDbClientPlugin;
|
||||
import mineplex.core.ReflectivelyCreateMiniPlugin;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.account.ILoginProcessor;
|
||||
import mineplex.core.account.permissions.Permission;
|
||||
@ -69,8 +71,8 @@ import mineplex.serverdata.data.DataRepository;
|
||||
import mineplex.serverdata.data.PlayerStatus;
|
||||
import mineplex.serverdata.redis.RedisDataRepository;
|
||||
import mineplex.serverdata.servers.ServerManager;
|
||||
import mineplex.serverdata.servers.ServerRepository;
|
||||
|
||||
@ReflectivelyCreateMiniPlugin
|
||||
public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
{
|
||||
public enum Perm implements Permission
|
||||
@ -104,33 +106,33 @@ public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
public final List<Integer> BrowserIds = new LinkedList<>();
|
||||
private final List<UUID> _creating = new ArrayList<>();
|
||||
|
||||
public final DataRepository<PlayerStatus> StatusRepository;
|
||||
// private final DataRepository<PlayerStatus> StatusRepository;
|
||||
|
||||
private ServerRepository _serverRepo;
|
||||
// private ServerRepository _serverRepo;
|
||||
private boolean _us;
|
||||
|
||||
private final Set<Community> dirty = Collections.newSetFromMap(new ConcurrentHashMap<>()); // Communities with redis updates
|
||||
private int _updateCycleCount; // The number of update cycles since we've updated all communities
|
||||
private volatile boolean _cycling = false;
|
||||
|
||||
private CoreClientManager _clientManager;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public CommunityManager(JavaPlugin plugin, CoreClientManager clientManager)
|
||||
public CommunityManager()
|
||||
{
|
||||
super("Communities", plugin, clientManager);
|
||||
super("Communities");
|
||||
|
||||
DataRepository<PlayerStatus> statusRepo = new RedisDataRepository<>(ServerManager.getMasterConnection(),
|
||||
ServerManager.getSlaveConnection(), Region.currentRegion(), PlayerStatus.class, "playerStatus");
|
||||
|
||||
StatusRepository = new RedisDataRepository<PlayerStatus>(ServerManager.getMasterConnection(), ServerManager.getSlaveConnection(),
|
||||
Region.currentRegion(), PlayerStatus.class, "playerStatus");
|
||||
|
||||
_us = plugin.getConfig().getBoolean("serverstatus.us");
|
||||
|
||||
Region region = _us ? Region.US : Region.EU;
|
||||
_serverRepo = ServerManager.getServerRepository(region);
|
||||
|
||||
_repo = new CommunityRepository(plugin, StatusRepository, _us);
|
||||
_us = _plugin.getConfig().getBoolean("serverstatus.us");
|
||||
|
||||
_repo = new CommunityRepository(_plugin, statusRepo, _us);
|
||||
|
||||
_loadedCommunities = new ConcurrentHashMap<>();
|
||||
|
||||
clientManager.addStoredProcedureLoginProcessor(new ILoginProcessor()
|
||||
|
||||
_clientManager = require(CoreClientManager.class);
|
||||
_clientManager.addStoredProcedureLoginProcessor(new ILoginProcessor()
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
@ -158,7 +160,7 @@ public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
}
|
||||
});
|
||||
|
||||
Bukkit.getScheduler().scheduleAsyncRepeatingTask(plugin, () ->
|
||||
Bukkit.getScheduler().scheduleAsyncRepeatingTask(_plugin, () ->
|
||||
{
|
||||
_updateCycleCount++;
|
||||
|
||||
@ -174,23 +176,20 @@ public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
_updateCycleCount = 0;
|
||||
dirty.clear();
|
||||
|
||||
_loadedCommunities.values().forEach(communities::add);
|
||||
communities.addAll(_loadedCommunities.values());
|
||||
}
|
||||
else
|
||||
{
|
||||
dirty.forEach(communities::add);
|
||||
communities.addAll(dirty);
|
||||
dirty.clear();
|
||||
}
|
||||
|
||||
_repo.updateMembersAndJoinRequests(communities);
|
||||
}, 0L, 20 * UPDATE_CYCLE_SECONDS);
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () ->
|
||||
{
|
||||
cycleBrowser();
|
||||
}, 0L, 20 * 30);
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(_plugin, this::cycleBrowser, 0L, 20 * 30);
|
||||
|
||||
_repo.loadCommunities(_loadedCommunities);
|
||||
// _repo.loadCommunities(_loadedCommunities);
|
||||
|
||||
addCommand(new CommunityCommand(this));
|
||||
|
||||
@ -262,7 +261,12 @@ public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public int getCount()
|
||||
{
|
||||
return _loadedCommunities.size();
|
||||
}
|
||||
|
||||
public Community getLoadedCommunity(Integer id)
|
||||
{
|
||||
return _loadedCommunities.get(id);
|
||||
@ -827,6 +831,43 @@ public class CommunityManager extends MiniDbClientPlugin<CommunityMemberData>
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event)
|
||||
{
|
||||
// Load their communities if it hasn't already been done
|
||||
Player player = event.getPlayer();
|
||||
Set<Integer> communityIds = Get(player).getCommunityIds();
|
||||
|
||||
final List<Integer> load = communityIds.stream().filter(id -> getLoadedCommunity(id) == null).collect(Collectors.toList());
|
||||
if (load.isEmpty()) return;
|
||||
|
||||
final int accountId = _clientManager.getAccountId(player);
|
||||
|
||||
runAsync(() -> _repo.loadCommunities(_loadedCommunities, load, accountId));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event)
|
||||
{
|
||||
// Remove their communities from memory if they're the last player
|
||||
Player player = event.getPlayer();
|
||||
List<Community> communities = Get(player).getCommunities();
|
||||
com: for (Community community : communities)
|
||||
{
|
||||
for (UUID uuid : community.getMembers().keySet())
|
||||
{
|
||||
// See if there's anyone else online besides our quitting player
|
||||
if (!player.getUniqueId().equals(uuid) && Bukkit.getPlayer(uuid) != null)
|
||||
{
|
||||
break com;
|
||||
}
|
||||
}
|
||||
|
||||
// Unload this community from memory
|
||||
_loadedCommunities.remove(community.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommunityMemberData addPlayer(UUID uuid)
|
||||
{
|
||||
|
@ -1,10 +1,14 @@
|
||||
package mineplex.core.communities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import mineplex.core.Managers;
|
||||
|
||||
public class CommunityMemberData
|
||||
@ -39,19 +43,25 @@ public class CommunityMemberData
|
||||
{
|
||||
_chattingTo = community.getId();
|
||||
}
|
||||
|
||||
public Community[] getCommunities()
|
||||
|
||||
Set<Integer> getCommunityIds()
|
||||
{
|
||||
Community[] communities = new Community[_communities.size()];
|
||||
int index = 0;
|
||||
for (Integer comId : _communities.keySet())
|
||||
{
|
||||
communities[index] = Managers.get(CommunityManager.class).getLoadedCommunity(comId);
|
||||
index++;
|
||||
}
|
||||
return communities;
|
||||
return _communities.keySet();
|
||||
}
|
||||
|
||||
|
||||
public List<Community> getCommunities()
|
||||
{
|
||||
List<Community> ret = new ArrayList<>(_communities.size());
|
||||
for (int id : _communities.keySet())
|
||||
{
|
||||
Community community = Managers.get(CommunityManager.class).getLoadedCommunity(id);
|
||||
if (community != null)
|
||||
ret.add(community);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isMemberOf(Community community)
|
||||
{
|
||||
return _communities.containsKey(community.getId());
|
||||
|
@ -90,7 +90,7 @@ public class CommunityOverviewPage extends CommunitiesGUIPage
|
||||
Inv.setItem(clear, null);
|
||||
}
|
||||
}
|
||||
List<Community> coms = Arrays.asList(getCommunityManager().Get(Viewer).getCommunities());
|
||||
List<Community> coms = getCommunityManager().Get(Viewer).getCommunities();
|
||||
coms.sort((c1, c2) ->
|
||||
{
|
||||
if (c1.getMembers().get(Viewer.getUniqueId()).Role == c2.getMembers().get(Viewer.getUniqueId()).Role)
|
||||
|
@ -6,6 +6,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -29,13 +30,16 @@ import mineplex.serverdata.database.column.ColumnVarChar;
|
||||
|
||||
public class CommunityRepository extends RepositoryBase
|
||||
{
|
||||
private static final String GET_COMMUNITIES_BY_ID = "SELECT * FROM communities";
|
||||
private static final String GET_COMMUNITY_MEMBERS = "SELECT cm.communityId, cm.accountId, cm.communityRole, ac.name, ac.uuid, ac.lastLogin, cm.readingChat FROM communityMembers cm INNER JOIN accounts ac ON ac.id=cm.accountId";
|
||||
private static final String GET_COMMUNITY_JOIN_REQUESTS = "SELECT cjr.communityId, cjr.accountId, ac.name, ac.uuid FROM communityJoinRequests cjr INNER JOIN accounts ac ON ac.id=cjr.accountId WHERE cjr.accountId=?;";
|
||||
private static final String GET_COMMUNITY_SETTINGS = "SELECT communityId, settingId, settingValue FROM communitySettings";
|
||||
|
||||
// Old queries
|
||||
private static final String GET_ALL_COMMUNITIES = "SELECT * FROM communities WHERE region=?;";
|
||||
private static final String GET_COMMUNITY_BY_ID = "SELECT * FROM communities WHERE id=?;";
|
||||
private static final String GET_COMMUNITY_BY_NAME = "SELECT * FROM communities WHERE name=? AND region=?;";
|
||||
private static final String GET_COMMUNITY_MEMBERS = "SELECT cm.communityId, cm.accountId, cm.communityRole, ac.name, ac.uuid, ac.lastLogin, cm.readingChat FROM communityMembers cm INNER JOIN accounts ac ON ac.id=cm.accountId;";
|
||||
private static final String GET_COMMUNITY_JOIN_REQUESTS = "SELECT cjr.communityId, cjr.accountId, ac.name, ac.uuid FROM communityJoinRequests cjr INNER JOIN accounts ac ON ac.id=cjr.accountId;";
|
||||
private static final String GET_COMMUNITY_SETTINGS = "SELECT communityId, settingId, settingValue FROM communitySettings;";
|
||||
|
||||
|
||||
private static final String REMOVE_FROM_COMMUNITY = "DELETE FROM communityMembers WHERE accountId=? AND communityId=?;";
|
||||
private static final String UPDATE_COMMUNITY_ROLE = "UPDATE communityMembers SET communityRole=? WHERE accountId=? AND communityId=?;";
|
||||
private static final String ADD_TO_COMMUNITY = "INSERT INTO communityMembers (accountId, communityId, communityRole, readingChat) VALUES (?, ?, ?, true);";
|
||||
@ -61,7 +65,100 @@ public class CommunityRepository extends RepositoryBase
|
||||
_us = us;
|
||||
}
|
||||
|
||||
public void loadCommunities(final Map<Integer, Community> communityMap)
|
||||
// TODO this could probably be further optimized, either way it needs to be tested
|
||||
public void loadCommunities(final Map<Integer, Community> store, final List<Integer> load, final int accountId)
|
||||
{
|
||||
try (Connection connection = getConnection())
|
||||
{
|
||||
// Only load the info for communities with the given IDs
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(" WHERE id IN (");
|
||||
|
||||
for (int index = 0; index < load.size(); index++)
|
||||
{
|
||||
if (index != 0)
|
||||
builder.append(", ");
|
||||
builder.append("?");
|
||||
}
|
||||
|
||||
builder.append(");");
|
||||
|
||||
String inClause = builder.toString();
|
||||
ColumnInt[] idColumns = load.stream().map(i -> new ColumnInt("id", i)).toArray(x -> new ColumnInt[0]);
|
||||
|
||||
executeQuery(connection, GET_COMMUNITIES_BY_ID + inClause, resultSet ->
|
||||
{
|
||||
final int id = resultSet.getInt("id");
|
||||
final String cName = resultSet.getString("name");
|
||||
final Community community = new Community(id, cName);
|
||||
|
||||
store.put(id, community);
|
||||
}, idColumns);
|
||||
|
||||
executeQuery(connection, GET_COMMUNITY_MEMBERS + inClause, memberSet ->
|
||||
{
|
||||
while (memberSet.next())
|
||||
{
|
||||
final int communityId = memberSet.getInt("communityId");
|
||||
final int accountId1 = memberSet.getInt("accountId");
|
||||
final String name = memberSet.getString("name");
|
||||
final UUID uuid = UUID.fromString(memberSet.getString("uuid"));
|
||||
final CommunityRole role = CommunityRole.parseRole(memberSet.getString("communityRole"));
|
||||
final long lastLogin = memberSet.getTimestamp("lastLogin").getTime();
|
||||
boolean readingChat = memberSet.getBoolean("readingChat");
|
||||
|
||||
CommunityMemberInfo info = new CommunityMemberInfo(name, uuid, accountId1, role, lastLogin);
|
||||
info.ReadingChat = readingChat;
|
||||
|
||||
Community community = store.get(communityId);
|
||||
if (community != null)
|
||||
{
|
||||
community.getMembers().put(info.UUID, info);
|
||||
}
|
||||
}
|
||||
}, idColumns);
|
||||
|
||||
executeQuery(connection, GET_COMMUNITY_JOIN_REQUESTS, requestSet ->
|
||||
{
|
||||
while (requestSet.next())
|
||||
{
|
||||
final int communityId = requestSet.getInt("communityId");
|
||||
// final int accountId = requestSet.getInt("accountId");
|
||||
final UUID uuid = UUID.fromString(requestSet.getString("uuid"));
|
||||
final String name = requestSet.getString("name");
|
||||
|
||||
Community community = store.get(communityId);
|
||||
if (community != null)
|
||||
{
|
||||
community.getJoinRequests().put(uuid, new CommunityJoinRequestInfo(name, uuid, accountId));
|
||||
}
|
||||
}
|
||||
}, new ColumnInt("cjr.accountId", accountId));
|
||||
|
||||
executeQuery(connection, GET_COMMUNITY_SETTINGS + inClause, settingSet ->
|
||||
{
|
||||
while (settingSet.next())
|
||||
{
|
||||
final int communityId = settingSet.getInt("communityId");
|
||||
final int settingId = settingSet.getInt("settingId");
|
||||
final String value = settingSet.getString("settingValue");
|
||||
|
||||
Community community = store.get(communityId);
|
||||
CommunitySetting setting = CommunitySetting.getSetting(settingId);
|
||||
if (community != null && setting != null)
|
||||
{
|
||||
setting.parseValueInto(value, community);
|
||||
}
|
||||
}
|
||||
}, idColumns);
|
||||
} catch (SQLException ex)
|
||||
{
|
||||
System.err.println("Encountered an SQL exception loading communities " + load);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* public void loadCommunities(final Map<Integer, Community> communityMap)
|
||||
{
|
||||
try (Connection connection = getConnection())
|
||||
{
|
||||
@ -142,7 +239,7 @@ public class CommunityRepository extends RepositoryBase
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
public void updateMembersAndJoinRequests(List<Community> communities)
|
||||
{
|
||||
|
@ -11,12 +11,14 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import mineplex.core.Managers;
|
||||
import mineplex.core.MiniPlugin;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.account.permissions.Permission;
|
||||
import mineplex.core.account.permissions.PermissionGroup;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.communities.CommunityManager;
|
||||
import mineplex.core.updater.UpdateType;
|
||||
import mineplex.core.updater.event.UpdateEvent;
|
||||
|
||||
@ -30,6 +32,8 @@ public class LagMeter extends MiniPlugin
|
||||
}
|
||||
|
||||
private CoreClientManager _clientManager;
|
||||
private CommunityManager _communities;
|
||||
|
||||
private long _lastRun = -1;
|
||||
private int _count;
|
||||
private double _ticksPerSecond;
|
||||
@ -166,6 +170,23 @@ public class LagMeter extends MiniPlugin
|
||||
player.sendMessage(F.main(getName(), ChatColor.YELLOW + "MEM"));
|
||||
player.sendMessage(F.main(getName(), ChatColor.GRAY + "Free-------" + ChatColor.YELLOW + (Runtime.getRuntime().freeMemory() / 1048576) + "MB"));
|
||||
player.sendMessage(F.main(getName(), ChatColor.GRAY + "Max--------" + ChatColor.YELLOW + (Runtime.getRuntime().maxMemory() / 1048576)) + "MB");
|
||||
player.sendMessage(F.main(getName(), ChatColor.YELLOW + String.valueOf(player.getWorld().getLoadedChunks().length) + ChatColor.GRAY + " chunks loaded"));
|
||||
|
||||
// Statistics for Dan; should be temporary
|
||||
if (_clientManager.Get(player).getPrimaryGroup().inheritsFrom(PermissionGroup.DEV))
|
||||
{
|
||||
player.sendMessage(" ");
|
||||
player.sendMessage(F.main(getName(), ChatColor.GRAY + "Dev Stats -----"));
|
||||
|
||||
player.sendMessage(F.main(getName(),
|
||||
ChatColor.YELLOW + String.valueOf(player.getWorld().getLoadedChunks().length) + ChatColor.GRAY +
|
||||
" chunks loaded"));
|
||||
|
||||
if (_communities == null)
|
||||
_communities = Managers.get(CommunityManager.class);
|
||||
|
||||
player.sendMessage(F.main(getName(),
|
||||
ChatColor.YELLOW + String.valueOf(_communities.getCount()) + ChatColor.GRAY +
|
||||
" communities loaded"));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user