From eea7785b7f1281b63cefa86363dd4ffbf5d3f54e Mon Sep 17 00:00:00 2001 From: snowleo Date: Mon, 28 Nov 2011 18:53:38 +0100 Subject: [PATCH] Calculation of /balancetop is now async to prevent slowdown of the server --- .../src/com/earth2me/essentials/UserMap.java | 20 +-- .../commands/Commandbalancetop.java | 154 +++++++++++++++--- 2 files changed, 138 insertions(+), 36 deletions(-) diff --git a/Essentials/src/com/earth2me/essentials/UserMap.java b/Essentials/src/com/earth2me/essentials/UserMap.java index 3de18080a..c30d97214 100644 --- a/Essentials/src/com/earth2me/essentials/UserMap.java +++ b/Essentials/src/com/earth2me/essentials/UserMap.java @@ -5,12 +5,10 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.collect.ConcurrentHashMultiset; import java.io.File; -import java.util.HashSet; +import java.util.Collections; import java.util.Locale; import java.util.Set; import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -104,21 +102,9 @@ public class UserMap extends CacheLoader implements IConf users.invalidate(name.toLowerCase(Locale.ENGLISH)); } - public Set getAllUsers() + public Set getAllUniqueUsers() { - final Set userSet = new HashSet(); - for (String name : keys) - { - try - { - userSet.add(users.get(name)); - } - catch (ExecutionException ex) - { - Bukkit.getLogger().log(Level.INFO, "Failed to load user " + name, ex); - } - } - return userSet; + return Collections.unmodifiableSet(keys.elementSet()); } public int getUniqueUsers() diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java b/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java index 838e27628..0a02ee7a7 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java @@ -1,10 +1,10 @@ package com.earth2me.essentials.commands; import static com.earth2me.essentials.I18n._; -import com.earth2me.essentials.User; import com.earth2me.essentials.Util; import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.bukkit.Server; import org.bukkit.command.CommandSender; @@ -15,6 +15,12 @@ public class Commandbalancetop extends EssentialsCommand { super("balancetop"); } + + private static final int CACHETIME = 5 * 60 * 1000; + public static final int MINUSERS = 50; + private static List cache = new ArrayList(); + private static long cacheage = 0; + private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); @Override protected void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception @@ -24,7 +30,7 @@ public class Commandbalancetop extends EssentialsCommand { try { - if (Integer.parseInt(args[0]) < 10) + if (Integer.parseInt(args[0]) < 19) { max = Integer.parseInt(args[0]); } @@ -34,31 +40,141 @@ public class Commandbalancetop extends EssentialsCommand //catch it because they tried to enter a string not number. } } - final Map balances = new HashMap(); - for (User u : ess.getUserMap().getAllUsers()) + + if (lock.readLock().tryLock()) { - balances.put(u, u.getMoney()); + try + { + if (cacheage > System.currentTimeMillis() - CACHETIME) + { + outputCache(sender, max); + return; + } + if (ess.getUserMap().getUniqueUsers() > MINUSERS) + { + sender.sendMessage("Calculating results"); + } + } + finally + { + lock.readLock().unlock(); + } + ess.scheduleAsyncDelayedTask(new Viewer(sender, max)); + } + else + { + if (ess.getUserMap().getUniqueUsers() > MINUSERS) + { + sender.sendMessage("Calculating results"); + } + ess.scheduleAsyncDelayedTask(new Viewer(sender, max)); } - final List> sortedEntries = new ArrayList>(balances.entrySet()); - Collections.sort(sortedEntries, new Comparator>() - { - @Override - public int compare(final Entry entry1, final Entry entry2) - { - return -entry1.getValue().compareTo(entry2.getValue()); - } - }); - int count = 0; + } + + private static void outputCache(final CommandSender sender, int max) + { sender.sendMessage(_("balanceTop", max)); - for (Map.Entry entry : sortedEntries) + for (String line : cache) { - if (count == max) + if (max == 0) { break; } - sender.sendMessage(entry.getKey().getDisplayName() + ", " + Util.formatCurrency(entry.getValue(), ess)); - count++; + max--; + sender.sendMessage(line); + } + } + + + private class Calculator implements Runnable + { + private final transient Viewer viewer; + + public Calculator(final Viewer viewer) + { + this.viewer = viewer; + } + + @Override + public void run() + { + lock.writeLock().lock(); + try + { + if (cacheage < System.currentTimeMillis() - 5 * 60 * 1000) + { + final Map balances = new HashMap(); + for (String u : ess.getUserMap().getAllUniqueUsers()) + { + try + { + balances.put(u, ess.getUserMap().getUser(u).getMoney()); + } + catch (NullPointerException ex) + { + } + } + + final List> sortedEntries = new ArrayList>(balances.entrySet()); + Collections.sort(sortedEntries, new Comparator>() + { + @Override + public int compare(final Entry entry1, final Entry entry2) + { + return -entry1.getValue().compareTo(entry2.getValue()); + } + }); + int count = 0; + for (Map.Entry entry : sortedEntries) + { + if (count == 20) + { + break; + } + cache.add(entry.getKey() + ", " + Util.formatCurrency(entry.getValue(), ess)); + count++; + } + cacheage = System.currentTimeMillis(); + } + } + finally + { + lock.writeLock().unlock(); + } + ess.scheduleAsyncDelayedTask(viewer); + } + } + + + private class Viewer implements Runnable + { + private final transient CommandSender sender; + private final transient int max; + + public Viewer(final CommandSender sender, final int max) + { + this.sender = sender; + this.max = max; + } + + @Override + public void run() + { + lock.readLock().lock(); + try + { + if (cacheage > System.currentTimeMillis() - 5 * 60 * 1000) + { + outputCache(sender, max); + return; + } + } + finally + { + lock.readLock().unlock(); + } + ess.scheduleAsyncDelayedTask(new Calculator(new Viewer(sender, max))); } } }