mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-06-28 03:34:43 +02:00
SQLDatabaseManager optimizations, async profile loading -t00thpick1, zreed
This commit changes our shared connection into a connection pool utility to prevent thread locks from multiple actions attempting to access the database at the same time. In additon, profile loading has been moved off the main thread at login time, to allieviate the performance issues caused by it. Fixes #2138, Fixes #2119, Fixes #1982, Fixes #1953
This commit is contained in:
@ -1,39 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.database.SQLDatabaseManager;
|
||||
|
||||
/**
|
||||
* This task is in charge of sending a MySQL ping over the MySQL connection
|
||||
* every hour to prevent the connection from timing out and losing players'
|
||||
* data when they join.
|
||||
* <p/>
|
||||
* A WeakReference is used to keep the database instance, because
|
||||
* {@link com.gmail.nossr50.commands.database.ConvertDatabaseCommand database
|
||||
* conversion} may create a SQLDatabaseManager that will be thrown out. If a
|
||||
* normal reference was used, the conversion would cause a combined data and
|
||||
* resource leak through this task.
|
||||
*/
|
||||
public class SQLDatabaseKeepaliveTask extends BukkitRunnable {
|
||||
WeakReference<SQLDatabaseManager> databaseInstance;
|
||||
|
||||
public SQLDatabaseKeepaliveTask(SQLDatabaseManager dbman) {
|
||||
databaseInstance = new WeakReference<SQLDatabaseManager>(dbman);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
SQLDatabaseManager dbman = databaseInstance.get();
|
||||
if (dbman != null) {
|
||||
dbman.checkConnected();
|
||||
}
|
||||
else {
|
||||
// This happens when the database was started for a conversion,
|
||||
// or discarded by its creator for any other reason. If this code
|
||||
// was not present, we would leak the connection resources.
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.database.SQLDatabaseManager;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
|
||||
public class SQLReconnectTask extends BukkitRunnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (((SQLDatabaseManager) mcMMO.getDatabaseManager()).checkConnected()) {
|
||||
UserManager.saveAll(); // Save all profiles
|
||||
UserManager.clearAll(); // Clear the profiles
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
UserManager.addUser(player); // Add in new profiles, forcing them to 'load' again from MySQL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.uuid.UUIDFetcher;
|
||||
|
||||
public class UUIDFetcherRunnable extends BukkitRunnable {
|
||||
private List<String> names;
|
||||
|
||||
public UUIDFetcherRunnable(List<String> names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
public UUIDFetcherRunnable(String name) {
|
||||
this.names = new ArrayList<String>();
|
||||
this.names.add(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Map<String, UUID> returns = new UUIDFetcher(this.names).call();
|
||||
new CacheReturnedNames(returns).runTask(mcMMO.p);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private class CacheReturnedNames extends BukkitRunnable {
|
||||
private Map<String, UUID> returns;
|
||||
|
||||
public CacheReturnedNames(Map<String, UUID> returns) {
|
||||
this.returns = returns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (Entry<String, UUID> entry : this.returns.entrySet()) {
|
||||
mcMMO.getDatabaseManager().saveUserUUID(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.gmail.nossr50.runnables.player;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
|
||||
import com.gmail.nossr50.datatypes.player.PlayerProfile;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.runnables.commands.McScoreboardKeepTask;
|
||||
import com.gmail.nossr50.util.Misc;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
|
||||
|
||||
public class PlayerProfileLoadingTask extends BukkitRunnable {
|
||||
private static final int MAX_TRIES = 5;
|
||||
private final Player player;
|
||||
private int attempt = 0;
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
private boolean cancelled = false;
|
||||
|
||||
public PlayerProfileLoadingTask(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
// WARNING: ASYNC TASK
|
||||
// DO NOT MODIFY THE McMMOPLAYER FROM THIS CODE
|
||||
@Override
|
||||
public void run() {
|
||||
lock.lock();
|
||||
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Quit if they logged out
|
||||
if (!player.isOnline()) {
|
||||
mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out");
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment attempt counter and try
|
||||
attempt++;
|
||||
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getName(), player.getUniqueId(), true);
|
||||
// If successful, schedule the apply
|
||||
if (profile.isLoaded()) {
|
||||
new ApplySuccessfulProfile(profile).runTask(mcMMO.p);
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've failed five times, give up
|
||||
if (attempt >= MAX_TRIES) {
|
||||
mcMMO.p.getLogger().severe("Giving up on attempting to load the PlayerProfile for " + player.getName());
|
||||
mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.AdminFailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
|
||||
player.sendMessage(LocaleLoader.getString("Profile.Loading.Failure").split("\n"));
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
private class ApplySuccessfulProfile extends BukkitRunnable {
|
||||
private final PlayerProfile profile;
|
||||
|
||||
private ApplySuccessfulProfile(PlayerProfile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
// Synchronized task
|
||||
// No database access permitted
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline()) {
|
||||
mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out");
|
||||
return;
|
||||
}
|
||||
|
||||
McMMOPlayer mcMMOPlayer = new McMMOPlayer(player, profile);
|
||||
UserManager.track(mcMMOPlayer);
|
||||
mcMMOPlayer.actualizeRespawnATS();
|
||||
ScoreboardManager.setupPlayer(player);
|
||||
|
||||
if (Config.getInstance().getShowProfileLoadedMessage()) {
|
||||
player.sendMessage(LocaleLoader.getString("Profile.Loading.Success"));
|
||||
}
|
||||
|
||||
if (Config.getInstance().getShowStatsAfterLogin()) {
|
||||
ScoreboardManager.enablePlayerStatsScoreboard(player);
|
||||
new McScoreboardKeepTask(player).runTaskLater(mcMMO.p, 1 * Misc.TICK_CONVERSION_FACTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user