diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java index 83dba25af..7bab26d9b 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java @@ -29,6 +29,8 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + import me.lucko.luckperms.common.plugin.SchedulerAdapter; import org.bukkit.scheduler.BukkitTask; @@ -37,7 +39,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class BukkitSchedulerAdapter implements SchedulerAdapter { @@ -69,7 +72,7 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter { this.plugin = plugin; this.sync = new SyncExecutor(); - this.asyncFallback = Executors.newCachedThreadPool(); + this.asyncFallback = new FallbackAsyncExecutor(); this.asyncBukkit = new BukkitAsyncExecutor(); this.async = new AsyncExecutor(); } @@ -144,4 +147,10 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter { } } + private static final class FallbackAsyncExecutor extends ThreadPoolExecutor { + private FallbackAsyncExecutor() { + super(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadFactoryBuilder().setNameFormat("luckperms-fallback-%d").build()); + } + } + } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index aed3adf8c..6e7bd84a8 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -134,7 +134,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { private ContextManager contextManager; private CalculatorFactory calculatorFactory; private BufferedRequest updateTaskBuffer; - private boolean started = false; private CountDownLatch enableLatch = new CountDownLatch(1); private VerboseHandler verboseHandler; private BukkitSenderFactory senderFactory; @@ -174,7 +173,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { try { enable(); - started = true; } finally { // count down the latch when onEnable has been called // we don't care about the result here @@ -328,8 +326,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { // Switch back to the fallback executor, the bukkit one won't allow new tasks scheduler.setUseFallback(true); - started = false; - defaultsProvider.close(); permissionVault.shutdown(); verboseHandler.shutdown(); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java index aa4298e6a..a1fe54a48 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java @@ -64,7 +64,7 @@ public class BukkitConnectionListener implements Listener { /* wait for the plugin to enable. because these events are fired async, they can be called before the plugin has enabled. */ try { - plugin.getEnableLatch().await(30, TimeUnit.SECONDS); + plugin.getEnableLatch().await(60, TimeUnit.SECONDS); } catch (InterruptedException ex) { ex.printStackTrace(); } @@ -73,21 +73,6 @@ public class BukkitConnectionListener implements Listener { plugin.getLog().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName()); } - /* there was an issue connecting to the DB, performing file i/o, etc. - we don't let players join in this case, because it means they can connect to the server without their permissions data. - some server admins rely on negating perms to stop users from causing damage etc, so it's really important that - this data is loaded. */ - if (!plugin.isStarted() || !plugin.getStorage().isAcceptingLogins()) { - - // log that the user tried to login, but was denied at this stage. - deniedAsyncLogin.add(e.getUniqueId()); - - // actually deny the connection. - plugin.getLog().warn("Permissions storage is not loaded. Denying connection from: " + e.getUniqueId() + " - " + e.getName()); - e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(plugin.getLocaleManager())); - return; - } - plugin.getUniqueConnections().add(e.getUniqueId()); /* Actually process the login for the connection. @@ -103,9 +88,10 @@ public class BukkitConnectionListener implements Listener { User user = LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName(), false); plugin.getApiProvider().getEventFactory().handleUserLoginProcess(e.getUniqueId(), e.getName(), user); } catch (Exception ex) { + plugin.getLog().severe("Exception occured whilst loading data for " + e.getUniqueId() + " - " + e.getName()); ex.printStackTrace(); - // there was some error loading data. deny the connection + // deny the connection deniedAsyncLogin.add(e.getUniqueId()); e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(plugin.getLocaleManager())); } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/listeners/BungeeConnectionListener.java b/bungee/src/main/java/me/lucko/luckperms/bungee/listeners/BungeeConnectionListener.java index 9d62cc792..5ce8f92fd 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/listeners/BungeeConnectionListener.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/listeners/BungeeConnectionListener.java @@ -68,25 +68,6 @@ public class BungeeConnectionListener implements Listener { plugin.getLog().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName()); } - /* there was an issue connecting to the DB, performing file i/o, etc. - as this is bungeecord, we will still allow the login, as players can't really do much harm without permissions data. - the proxy will just fallback to using the config file perms. */ - if (!plugin.getStorage().isAcceptingLogins()) { - - if (plugin.getConfiguration().get(ConfigKeys.CANCEL_FAILED_LOGINS)) { - // cancel the login attempt - e.setCancelReason(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager()))); - e.setCancelled(true); - } else { - // log that the user tried to login, but was denied at this stage. - plugin.getLog().warn("Permissions storage is not loaded. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName()); - } - - e.completeIntent(plugin); - return; - } - - plugin.getScheduler().doAsync(() -> { plugin.getUniqueConnections().add(c.getUniqueId()); @@ -103,6 +84,7 @@ public class BungeeConnectionListener implements Listener { User user = LoginHelper.loadUser(plugin, c.getUniqueId(), c.getName(), true); plugin.getApiProvider().getEventFactory().handleUserLoginProcess(c.getUniqueId(), c.getName(), user); } catch (Exception ex) { + plugin.getLog().severe("Exception occured whilst loading data for " + c.getUniqueId() + " - " + c.getName()); ex.printStackTrace(); // there was some error loading @@ -110,10 +92,7 @@ public class BungeeConnectionListener implements Listener { // cancel the login attempt e.setCancelReason(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager()))); e.setCancelled(true); - } else { - plugin.getLog().warn("Error loading data. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName()); } - } // finally, complete our intent to modify state, so the proxy can continue handling the connection. diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiStorage.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiStorage.java index e2b927549..efc7b9d33 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiStorage.java @@ -61,7 +61,7 @@ public class ApiStorage implements Storage { @Override public boolean isAcceptingLogins() { - return handle.isAcceptingLogins(); + return true; } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java index 7d725502e..93f95ef06 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java @@ -28,7 +28,6 @@ package me.lucko.luckperms.common.storage; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.LogEntry; @@ -64,8 +63,6 @@ public class AbstractStorage implements Storage { } private final LuckPermsPlugin plugin; - - @Delegate(types = Delegated.class) private final AbstractDao dao; @Getter @@ -81,11 +78,41 @@ public class AbstractStorage implements Storage { return CompletableFuture.supplyAsync(supplier, dao.getPlugin().getScheduler().async()); } + @Override + public String getName() { + return dao.getName(); + } + @Override public Storage noBuffer() { return this; } + @Override + public void init() { + try { + dao.init(); + } catch (Exception e) { + plugin.getLog().severe("Failed to init storage dao"); + e.printStackTrace(); + } + } + + @Override + public void shutdown() { + try { + dao.shutdown(); + } catch (Exception e) { + plugin.getLog().severe("Failed to shutdown storage dao"); + e.printStackTrace(); + } + } + + @Override + public Map getMeta() { + return dao.getMeta(); + } + @Override public CompletableFuture logAction(LogEntry entry) { return makeFuture(() -> dao.logAction(entry)); @@ -259,13 +286,4 @@ public class AbstractStorage implements Storage { public CompletableFuture getName(UUID uuid) { return makeFuture(() -> dao.getName(uuid)); } - - private interface Delegated { - String getName(); - boolean isAcceptingLogins(); - void setAcceptingLogins(boolean b); - void init(); - void shutdown(); - Map getMeta(); - } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java index 432269404..6d1f5f709 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java @@ -51,10 +51,6 @@ public interface Storage { String getName(); - boolean isAcceptingLogins(); - - void setAcceptingLogins(boolean acceptingLogins); - Storage noBuffer(); void init(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/AbstractDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/AbstractDao.java index e85613644..49965229e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/AbstractDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/AbstractDao.java @@ -28,7 +28,6 @@ package me.lucko.luckperms.common.storage.dao; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.LogEntry; @@ -54,10 +53,6 @@ public abstract class AbstractDao { @Getter public final String name; - @Getter - @Setter - private boolean acceptingLogins = false; - public abstract void init(); public abstract void shutdown(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/SplitStorageDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/SplitStorageDao.java index 40f6d88bd..d0ba2c8e1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/SplitStorageDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/SplitStorageDao.java @@ -54,12 +54,18 @@ public class SplitStorageDao extends AbstractDao { @Override public void init() { - boolean success = true; + boolean failed = false; for (AbstractDao ds : backing.values()) { - ds.init(); - success = success && ds.isAcceptingLogins(); + try { + ds.init(); + } catch (Exception ex) { + failed = true; + ex.printStackTrace(); + } + } + if (failed) { + throw new RuntimeException("One of the backing failed to init"); } - setAcceptingLogins(success); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/ConfigurateDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/ConfigurateDao.java index 80a2d14a8..417a64906 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/ConfigurateDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/ConfigurateDao.java @@ -192,8 +192,6 @@ public abstract class ConfigurateDao extends AbstractDao { } catch (Exception e) { e.printStackTrace(); } - - setAcceptingLogins(true); } private static void mkdir(File file) throws IOException { diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java index aaa5da5d1..cabbbdd7e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java @@ -117,7 +117,6 @@ public class MongoDao extends AbstractDao { } database = mongoClient.getDatabase(configuration.getDatabase()); - setAcceptingLogins(true); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/SqlDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/SqlDao.java index 47950e82c..b28915a32 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/SqlDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/SqlDao.java @@ -207,10 +207,9 @@ public class SqlDao extends AbstractDao { } } - setAcceptingLogins(true); } catch (Exception e) { - e.printStackTrace(); plugin.getLog().severe("Error occurred whilst initialising the database."); + e.printStackTrace(); shutdown(); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/hikari/HikariConnectionFactory.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/hikari/HikariConnectionFactory.java index 9545c7837..12a75a7d2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/hikari/HikariConnectionFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/hikari/HikariConnectionFactory.java @@ -91,6 +91,10 @@ public abstract class HikariConnectionFactory extends AbstractConnectionFactory // The drivers are really old in some of the older Spigot binaries, so Connection#isValid doesn't work. config.setConnectionTestQuery("/* LuckPerms ping */ SELECT 1"); + // don't perform any initial connection validation - we subsequently call #getConnection + // to setup the schema anyways + config.setInitializationFailTimeout(-1); + hikari = new HikariDataSource(config); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java index 41cb951de..2383f5e38 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java @@ -27,7 +27,6 @@ package me.lucko.luckperms.common.storage.wrappings; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.LogEntry; @@ -59,16 +58,30 @@ public class PhasedStorage implements Storage { return new PhasedStorage(storage); } - @Delegate(types = Delegated.class) private final Storage delegate; private final Phaser phaser = new Phaser(); + @Override + public ApiStorage getDelegate() { + return delegate.getDelegate(); + } + + @Override + public String getName() { + return delegate.getName(); + } + @Override public Storage noBuffer() { return this; } + @Override + public void init() { + delegate.init(); + } + @Override public void shutdown() { // Wait for other threads to finish. @@ -81,6 +94,11 @@ public class PhasedStorage implements Storage { delegate.shutdown(); } + @Override + public Map getMeta() { + return delegate.getMeta(); + } + @Override public CompletableFuture logAction(LogEntry entry) { phaser.register(); @@ -290,13 +308,4 @@ public class PhasedStorage implements Storage { phaser.arriveAndDeregister(); } } - - private interface Delegated { - ApiStorage getDelegate(); - String getName(); - boolean isAcceptingLogins(); - void setAcceptingLogins(boolean b); - void init(); - Map getMeta(); - } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/listeners/SpongeConnectionListener.java b/sponge/src/main/java/me/lucko/luckperms/sponge/listeners/SpongeConnectionListener.java index 90bfe62be..29cfafd6c 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/listeners/SpongeConnectionListener.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/listeners/SpongeConnectionListener.java @@ -67,24 +67,6 @@ public class SpongeConnectionListener { plugin.getLog().info("Processing auth event for " + p.getUniqueId() + " - " + p.getName()); } - /* either the plugin hasn't finished starting yet, or there was an issue connecting to the DB, performing file i/o, etc. - we don't let players join in this case, because it means they can connect to the server without their permissions data. - some server admins rely on negating perms to stop users from causing damage etc, so it's really important that - this data is loaded. */ - if (!plugin.getStorage().isAcceptingLogins()) { - - // log that the user tried to login, but was denied at this stage. - deniedAsyncLogin.add(p.getUniqueId()); - - // actually deny the connection. - plugin.getLog().warn("Permissions storage is not loaded. Denying connection from: " + p.getUniqueId() + " - " + p.getName()); - e.setCancelled(true); - e.setMessageCancelled(false); - //noinspection deprecation - e.setMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(Message.LOADING_ERROR.asString(plugin.getLocaleManager()))); - return; - } - plugin.getUniqueConnections().add(p.getUniqueId()); /* Actually process the login for the connection. @@ -100,6 +82,7 @@ public class SpongeConnectionListener { User user = LoginHelper.loadUser(plugin, p.getUniqueId(), username, false); plugin.getApiProvider().getEventFactory().handleUserLoginProcess(p.getUniqueId(), username, user); } catch (Exception ex) { + plugin.getLog().severe("Exception occured whilst loading data for " + p.getUniqueId() + " - " + p.getName()); ex.printStackTrace(); deniedAsyncLogin.add(p.getUniqueId());