From 8fd9982f6994204f9060d5f4616568f4c1f89376 Mon Sep 17 00:00:00 2001 From: zreed Date: Wed, 23 Jul 2014 16:49:07 -0400 Subject: [PATCH] Optimize SQL side of UUID update --- .../nossr50/database/DatabaseManager.java | 2 + .../nossr50/database/SQLDatabaseManager.java | 74 ++++++++++++++++++- src/main/java/com/gmail/nossr50/mcMMO.java | 5 -- .../database/UUIDUpdateAsyncTask.java | 73 +++++++++--------- 4 files changed, 108 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 8b4b23928..7a0093b50 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -124,6 +124,8 @@ public interface DatabaseManager { public boolean saveUserUUID(String userName, UUID uuid); + public boolean saveUserUUIDs(Map user_info); + /** * Retrieve the type of database in use. Custom databases should return CUSTOM. * diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 48744c21a..cef432148 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -26,6 +26,7 @@ import com.gmail.nossr50.datatypes.skills.AbilityType; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.runnables.database.SQLDatabaseKeepaliveTask; import com.gmail.nossr50.runnables.database.SQLReconnectTask; +import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; public final class SQLDatabaseManager implements DatabaseManager { @@ -543,7 +544,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, " + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, " + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, " - + "h.mobhealthbar " + + "h.mobhealthbar, u.uuid " + "FROM " + tablePrefix + "users u " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " @@ -620,6 +621,52 @@ public final class SQLDatabaseManager implements DatabaseManager { // Problem, nothing was returned } + public boolean saveUserUUIDs(Map player_info) { + if (!checkConnected()) { + // return false + return false; + } + + PreparedStatement statement = null; + int count = 0; + + try { + statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE user = ?"); + + for (Map.Entry entry : player_info.entrySet()) { + statement.setString(1, entry.getValue().toString()); + statement.setString(2, entry.getKey()); + + count++; + + if ((count % 500) == 0) { + statement.executeBatch(); + count = 0; + } + } + + if (count != 0) { + statement.executeBatch(); + } + + return true; + } + catch (SQLException ex) { + printErrors(ex); + return false; + } + finally { + if (statement != null) { + try { + statement.close(); + } + catch (SQLException e) { + // Ignore + } + } + } + } + /** * Check connection status and re-establish if dead or stale. *

@@ -788,7 +835,7 @@ public final class SQLDatabaseManager implements DatabaseManager { write("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "users` (" + "`id` int(10) unsigned NOT NULL AUTO_INCREMENT," + "`user` varchar(40) NOT NULL," - + "`uuid` varchar(40) NOT NULL," + + "`uuid` varchar(36) NOT NULL DEFAULT ''," + "`lastlogin` int(32) unsigned NOT NULL," + "PRIMARY KEY (`id`)," + "UNIQUE KEY `user` (`user`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;"); @@ -992,8 +1039,27 @@ public final class SQLDatabaseManager implements DatabaseManager { break; case ADD_UUIDS: - write("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(50) NOT NULL DEFAULT '';"); - return; + try { + statement.executeQuery("SELECT `uuid` FROM `" + tablePrefix + "users` LIMIT 1"); + } + catch (SQLException ex) { + mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table..."); + + statement.executeQuery("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NOT NULL DEFAULT ''"); + + final List names = new ArrayList(); + + resultSet = statement.executeQuery("SELECT `user` FROM `" + tablePrefix + "users`"); + + while(resultSet.next()) { + names.add(resultSet.getString("user")); + } + + new UUIDUpdateAsyncTask(mcMMO.p,names).runTaskAsynchronously(mcMMO.p); + + return; + } + break; default: break; diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index a46511b4a..d4ea83366 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -36,7 +36,6 @@ import com.gmail.nossr50.runnables.CheckDateTask; import com.gmail.nossr50.runnables.SaveTimerTask; import com.gmail.nossr50.runnables.UpdaterResultAsyncTask; import com.gmail.nossr50.runnables.backups.CleanBackupsTask; -import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.runnables.database.UserPurgeTask; import com.gmail.nossr50.runnables.party.PartyAutoKickTask; import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask; @@ -459,10 +458,6 @@ public class mcMMO extends JavaPlugin { long saveIntervalTicks = Config.getInstance().getSaveInterval() * 1200; new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); - // Slowly update every entry in the database with UUIDs - int uuidConvertInterval = HiddenConfig.getInstance().getUUIDConvertInterval(); - new UUIDUpdateAsyncTask(this).runTaskTimerAsynchronously(this, uuidConvertInterval * Misc.TICK_CONVERSION_FACTOR, uuidConvertInterval * Misc.TICK_CONVERSION_FACTOR); - // Cleanup the backups folder new CleanBackupsTask().runTaskAsynchronously(mcMMO.p); diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java index 92b420373..7d03a8efd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.runnables.database; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.UUID; import org.bukkit.scheduler.BukkitRunnable; @@ -8,68 +11,64 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.database.DatabaseManager; import com.gmail.nossr50.datatypes.database.UpgradeType; -import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.uuid.UUIDFetcher; public class UUIDUpdateAsyncTask extends BukkitRunnable { private mcMMO plugin; private static final int MAX_LOOKUP = HiddenConfig.getInstance().getUUIDConvertAmount(); - private boolean conversionNeeded; - private DatabaseManager databaseManager; private List userNames; private int size; private int checkedUsers; private long startMillis; - public UUIDUpdateAsyncTask(mcMMO plugin) { + public UUIDUpdateAsyncTask(mcMMO plugin, List userNames) { this.plugin = plugin; - this.conversionNeeded = !mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS); - - this.databaseManager = mcMMO.getDatabaseManager(); - this.userNames = databaseManager.getStoredUsers(); - this.size = userNames.size(); + this.userNames = userNames; this.checkedUsers = 0; - this.startMillis = System.currentTimeMillis(); - - plugin.getLogger().info("Starting to check and update UUIDs, total amount of users: " + size); } @Override public void run() { - if (!conversionNeeded) { - plugin.debug("No need to update database with UUIDs"); - this.cancel(); - return; - } + + startMillis = System.currentTimeMillis(); + + size = userNames.size(); + + plugin.getLogger().info("Starting to check and update UUIDs, total amount of users: " + size); List userNamesSection; + Map fetchedUUIDs = new HashMap(); - if (size > MAX_LOOKUP) { - userNamesSection = userNames.subList(size - MAX_LOOKUP, size); - size -= MAX_LOOKUP; - } - else { - userNamesSection = userNames.subList(0, size); - size = 0; - this.cancel(); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); - plugin.debug("Database updated with UUIDs!"); - } + while (!userNames.isEmpty()) { - for (String userName : userNamesSection) { - PlayerProfile profile = databaseManager.loadPlayerProfile(userName, false); - - checkedUsers++; - - if (profile == null || !profile.isLoaded() || profile.getUniqueId() != null) { - continue; + if (size > MAX_LOOKUP) { + userNamesSection = userNames.subList(size - MAX_LOOKUP, size); + } + else { + userNamesSection = userNames.subList(0, size); } - new UUIDFetcherRunnable(userName).runTaskAsynchronously(mcMMO.p); + try { + fetchedUUIDs.putAll(new UUIDFetcher(userNamesSection).call()); + } + catch (Exception ex) { + return; + } + + checkedUsers += userNamesSection.size(); + + userNamesSection.clear(); + + size = userNames.size(); + + Misc.printProgress(checkedUsers, DatabaseManager.progressInterval, startMillis); } - Misc.printProgress(checkedUsers, DatabaseManager.progressInterval, startMillis); + if (mcMMO.getDatabaseManager().saveUserUUIDs(fetchedUUIDs)) { + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); + } } }