From 72604bfdea51a6beb6efbe52b000c5ee0f0b4118 Mon Sep 17 00:00:00 2001 From: DNx5 Date: Fri, 25 Sep 2015 07:20:46 +0700 Subject: [PATCH] improve cached datasource performance. --- src/main/java/fr/xephi/authme/AuthMe.java | 7 +- .../authme/datasource/CacheDataSource.java | 286 +++++++++++++----- .../authme/datasource/DatabaseCalls.java | 13 +- 3 files changed, 220 insertions(+), 86 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 6e11d6122..77a0e5c18 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -37,7 +37,8 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; import org.mcstats.Metrics; -import java.io.*; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.Calendar; @@ -382,10 +383,10 @@ public class AuthMe extends JavaPlugin { if (Settings.isCachingEnabled) { database = new CacheDataSource(this, database); + } else { + database = new DatabaseCalls(database); } - database = new DatabaseCalls(database); - if (Settings.getDataSource == DataSource.DataSourceType.FILE) { Converter converter = new ForceFlatToSqlite(database, this); server.getScheduler().runTaskAsynchronously(this, converter); diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index d4b0772cd..084197104 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -6,24 +6,31 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class CacheDataSource implements DataSource { private final DataSource source; private final AuthMe plugin; - private ConcurrentHashMap cache = new ConcurrentHashMap<>(); + private final ExecutorService exec; + private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); public CacheDataSource(AuthMe pl, DataSource src) { this.plugin = pl; this.source = src; + this.exec = Executors.newCachedThreadPool(); + /* * We need to load all players in cache ... It will took more time to * load the server, but it will be much easier to check for an * isAuthAvailable ! */ - pl.getServer().getScheduler().runTaskAsynchronously(pl, new Runnable() { + exec.execute(new Runnable() { @Override public void run() { for (PlayerAuth auth : source.getAllAuths()) { @@ -50,7 +57,7 @@ public class CacheDataSource implements DataSource { @Override public synchronized boolean saveAuth(final PlayerAuth auth) { cache.put(auth.getNickname(), auth); - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + exec.execute(new Runnable() { @Override public void run() { if (!source.saveAuth(auth)) { @@ -62,45 +69,95 @@ public class CacheDataSource implements DataSource { } @Override - public synchronized boolean updatePassword(PlayerAuth auth) { - if (source.updatePassword(auth)) { - if (cache.containsKey(auth.getNickname())) - cache.get(auth.getNickname()).setHash(auth.getHash()); - return true; + public synchronized boolean updatePassword(final PlayerAuth auth) { + if (!cache.containsKey(auth.getNickname())) { + return false; } - return false; + final String oldHash = cache.get(auth.getNickname()).getHash(); + cache.get(auth.getNickname()).setHash(auth.getHash()); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.updatePassword(auth)) { + if (cache.containsKey(auth.getNickname())) { + cache.get(auth.getNickname()).setHash(oldHash); + } + } + } + }); + return true; } @Override - public boolean updateSession(PlayerAuth auth) { - if (source.updateSession(auth)) { - if (cache.containsKey(auth.getNickname())) { - cache.get(auth.getNickname()).setIp(auth.getIp()); - cache.get(auth.getNickname()).setLastLogin(auth.getLastLogin()); - cache.get(auth.getNickname()).setRealName(auth.getRealName()); - } - return true; + public boolean updateSession(final PlayerAuth auth) { + if (!cache.containsKey(auth.getNickname())) { + return false; } - return false; + PlayerAuth cachedAuth = cache.get(auth.getNickname()); + final String oldIp = cachedAuth.getIp(); + final long oldLastLogin = cachedAuth.getLastLogin(); + final String oldRealName = cachedAuth.getRealName(); + + cachedAuth.setIp(auth.getIp()); + cachedAuth.setLastLogin(auth.getLastLogin()); + cachedAuth.setRealName(auth.getRealName()); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.updateSession(auth)) { + if (cache.containsKey(auth.getNickname())) { + PlayerAuth cachedAuth = cache.get(auth.getNickname()); + cachedAuth.setIp(oldIp); + cachedAuth.setLastLogin(oldLastLogin); + cachedAuth.setRealName(oldRealName); + } + } + } + }); + return true; } @Override - public boolean updateQuitLoc(PlayerAuth auth) { - if (source.updateQuitLoc(auth)) { - if (cache.containsKey(auth.getNickname())) { - cache.get(auth.getNickname()).setQuitLocX(auth.getQuitLocX()); - cache.get(auth.getNickname()).setQuitLocY(auth.getQuitLocY()); - cache.get(auth.getNickname()).setQuitLocZ(auth.getQuitLocZ()); - cache.get(auth.getNickname()).setWorld(auth.getWorld()); - } - return true; + public boolean updateQuitLoc(final PlayerAuth auth) { + if (!cache.containsKey(auth.getNickname())) { + return false; } - return false; + final PlayerAuth cachedAuth = cache.get(auth.getNickname()); + final double oldX = cachedAuth.getQuitLocX(); + final double oldY = cachedAuth.getQuitLocY(); + final double oldZ = cachedAuth.getQuitLocZ(); + final String oldWorld = cachedAuth.getWorld(); + + cachedAuth.setQuitLocX(auth.getQuitLocX()); + cachedAuth.setQuitLocY(auth.getQuitLocY()); + cachedAuth.setQuitLocZ(auth.getQuitLocZ()); + cachedAuth.setWorld(auth.getWorld()); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.updateQuitLoc(auth)) { + if (cache.containsKey(auth.getNickname())) { + PlayerAuth cachedAuth = cache.get(auth.getNickname()); + cachedAuth.setQuitLocX(oldX); + cachedAuth.setQuitLocY(oldY); + cachedAuth.setQuitLocZ(oldZ); + cachedAuth.setWorld(oldWorld); + } + } + } + }); + return true; } @Override public int getIps(String ip) { - return source.getIps(ip); + int count = 0; + for (Map.Entry p : cache.entrySet()) { + if (p.getValue().getIp().equals(ip)) { + count++; + } + } + return count; } @Override @@ -130,75 +187,133 @@ public class CacheDataSource implements DataSource { } @Override - public synchronized boolean removeAuth(String user) { - if (source.removeAuth(user)) { - cache.remove(user); - return true; - } - return false; + public synchronized boolean removeAuth(String username) { + final String user = username.toLowerCase(); + final PlayerAuth auth = cache.get(user); + cache.remove(user); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.removeAuth(user)) { + cache.put(user, auth); + } + } + }); + return true; } @Override public synchronized void close() { + exec.shutdown(); source.close(); } @Override public void reload() { - cache.clear(); - source.reload(); - for (Player player : Utils.getOnlinePlayers()) { - String user = player.getName().toLowerCase(); - if (PlayerCache.getInstance().isAuthenticated(user)) { - PlayerAuth auth = source.getAuth(user); - cache.put(user, auth); + exec.execute(new Runnable() { + @Override + public void run() { + cache.clear(); + source.reload(); + for (Player player : Utils.getOnlinePlayers()) { + String user = player.getName().toLowerCase(); + if (PlayerCache.getInstance().isAuthenticated(user)) { + PlayerAuth auth = source.getAuth(user); + cache.put(user, auth); + } + } } - } + }); } @Override - public synchronized boolean updateEmail(PlayerAuth auth) { - if (source.updateEmail(auth)) { - if (cache.containsKey(auth.getNickname())) - cache.get(auth.getNickname()).setEmail(auth.getEmail()); - return true; + public synchronized boolean updateEmail(final PlayerAuth auth) { + if (!cache.containsKey(auth.getNickname())) { + return false; } - return false; + PlayerAuth cachedAuth = cache.get(auth.getNickname()); + final String oldEmail = cachedAuth.getEmail(); + cachedAuth.setEmail(auth.getEmail()); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.updateEmail(auth)) { + if (cache.containsKey(auth.getNickname())) { + cache.get(auth.getNickname()).setEmail(oldEmail); + } + } + } + }); + return true; } @Override - public synchronized boolean updateSalt(PlayerAuth auth) { - if (source.updateSalt(auth)) { - if (cache.containsKey(auth.getNickname())) - cache.get(auth.getNickname()).setSalt(auth.getSalt()); - return true; + public synchronized boolean updateSalt(final PlayerAuth auth) { + if (!cache.containsKey(auth.getNickname())) { + return false; } - return false; + PlayerAuth cachedAuth = cache.get(auth.getNickname()); + final String oldSalt = cachedAuth.getSalt(); + cachedAuth.setSalt(auth.getSalt()); + exec.execute(new Runnable() { + @Override + public void run() { + if (!source.updateSalt(auth)) { + if (cache.containsKey(auth.getNickname())) { + cache.get(auth.getNickname()).setSalt(oldSalt); + } + } + } + }); + return true; } @Override public synchronized List getAllAuthsByName(PlayerAuth auth) { - return source.getAllAuthsByName(auth); + List result = new ArrayList<>(); + for (Map.Entry stringPlayerAuthEntry : cache.entrySet()) { + PlayerAuth p = stringPlayerAuthEntry.getValue(); + if (p.getIp().equals(auth.getIp())) + result.add(p.getNickname()); + } + return result; } @Override public synchronized List getAllAuthsByIp(String ip) { - return source.getAllAuthsByIp(ip); + List result = new ArrayList<>(); + for (Map.Entry stringPlayerAuthEntry : cache.entrySet()) { + PlayerAuth p = stringPlayerAuthEntry.getValue(); + if (p.getIp().equals(ip)) + result.add(p.getNickname()); + } + return result; } @Override public synchronized List getAllAuthsByEmail(String email) { - return source.getAllAuthsByEmail(email); + List result = new ArrayList<>(); + for (Map.Entry stringPlayerAuthEntry : cache.entrySet()) { + PlayerAuth p = stringPlayerAuthEntry.getValue(); + if (p.getEmail().equals(email)) + result.add(p.getNickname()); + } + return result; } @Override - public synchronized void purgeBanned(List banned) { - source.purgeBanned(banned); - for (PlayerAuth auth : cache.values()) { - if (banned.contains(auth.getNickname())) { - cache.remove(auth.getNickname()); + public synchronized void purgeBanned(final List banned) { + exec.execute(new Runnable() { + @Override + public void run() { + source.purgeBanned(banned); + for (PlayerAuth auth : cache.values()) { + if (banned.contains(auth.getNickname())) { + cache.remove(auth.getNickname()); + } + } } - } + }); } @Override @@ -208,45 +323,66 @@ public class CacheDataSource implements DataSource { @Override public boolean isLogged(String user) { - return source.isLogged(user.toLowerCase()); + user = user.toLowerCase(); + return PlayerCache.getInstance().getCache().containsKey(user); } @Override - public void setLogged(String user) { - source.setLogged(user.toLowerCase()); + public void setLogged(final String user) { + exec.execute(new Runnable() { + @Override + public void run() { + source.setLogged(user.toLowerCase()); + } + }); } @Override - public void setUnlogged(String user) { - source.setUnlogged(user.toLowerCase()); + public void setUnlogged(final String user) { + exec.execute(new Runnable() { + @Override + public void run() { + source.setUnlogged(user.toLowerCase()); + } + }); } @Override public void purgeLogged() { - source.purgeLogged(); + exec.execute(new Runnable() { + @Override + public void run() { + source.purgeLogged(); + } + }); } @Override public int getAccountsRegistered() { - return source.getAccountsRegistered(); + return cache.size(); } @Override - public void updateName(String oldone, String newone) { + public void updateName(final String oldone, final String newone) { if (cache.containsKey(oldone)) { cache.put(newone, cache.get(oldone)); cache.remove(oldone); } - source.updateName(oldone, newone); + exec.execute(new Runnable() { + @Override + public void run() { + source.updateName(oldone, newone); + } + }); } @Override public List getAllAuths() { - return source.getAllAuths(); + return new ArrayList<>(cache.values()); } @Override public List getLoggedPlayers() { - return source.getLoggedPlayers(); + return new ArrayList<>(PlayerCache.getInstance().getCache().values()); } } diff --git a/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java b/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java index 6b84c7d73..20cd97dfb 100644 --- a/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java +++ b/src/main/java/fr/xephi/authme/datasource/DatabaseCalls.java @@ -4,7 +4,9 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class DatabaseCalls implements DataSource { @@ -214,13 +216,8 @@ public class DatabaseCalls implements DataSource { @Override public synchronized void close() { - try { - exec.shutdown(); - exec.awaitTermination(10, TimeUnit.SECONDS); - database.close(); - } catch (Exception e) { - e.printStackTrace(); - } + exec.shutdown(); + database.close(); } @Override